Merge pull request #232 from Webifi/main
Adjustment to system prompt expansion, misc. UI tweaks
This commit is contained in:
		
						commit
						cea07577d4
					
				| 
						 | 
					@ -18,14 +18,15 @@
 | 
				
			||||||
    faEyeSlash
 | 
					    faEyeSlash
 | 
				
			||||||
  } from '@fortawesome/free-solid-svg-icons/index'
 | 
					  } from '@fortawesome/free-solid-svg-icons/index'
 | 
				
			||||||
  import { faSquareMinus, faSquarePlus as faSquarePlusOutline } from '@fortawesome/free-regular-svg-icons/index'
 | 
					  import { faSquareMinus, faSquarePlus as faSquarePlusOutline } from '@fortawesome/free-regular-svg-icons/index'
 | 
				
			||||||
  import { apiKeyStorage, addChatFromJSON, chatsStorage, checkStateChange, clearChats, clearMessages, copyChat, globalStorage, setGlobalSettingValueByKey, showSetChatSettings, pinMainMenu, getChat, deleteChat, saveChatStore } from './Storage.svelte'
 | 
					  import { apiKeyStorage, addChatFromJSON, chatsStorage, checkStateChange, clearChats, clearMessages, copyChat, globalStorage, setGlobalSettingValueByKey, showSetChatSettings, pinMainMenu, getChat, deleteChat, saveChatStore, saveCustomProfile } from './Storage.svelte'
 | 
				
			||||||
  import { exportAsMarkdown, exportChatAsJSON } from './Export.svelte'
 | 
					  import { exportAsMarkdown, exportChatAsJSON } from './Export.svelte'
 | 
				
			||||||
  import { restartProfile } from './Profiles.svelte'
 | 
					  import { newNameForProfile, restartProfile } from './Profiles.svelte'
 | 
				
			||||||
  import { replace } from 'svelte-spa-router'
 | 
					  import { replace } from 'svelte-spa-router'
 | 
				
			||||||
  import { clickOutside } from 'svelte-use-click-outside'
 | 
					  import { clickOutside } from 'svelte-use-click-outside'
 | 
				
			||||||
  import { openModal } from 'svelte-modals'
 | 
					  import { openModal } from 'svelte-modals'
 | 
				
			||||||
  import PromptConfirm from './PromptConfirm.svelte'
 | 
					  import PromptConfirm from './PromptConfirm.svelte'
 | 
				
			||||||
  import { startNewChatWithWarning, startNewChatFromChatId } from './Util.svelte'
 | 
					  import { startNewChatWithWarning, startNewChatFromChatId, errorNotice, encodeHTMLEntities } from './Util.svelte'
 | 
				
			||||||
 | 
					  import type { ChatSettings } from './Types.svelte'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let chatId
 | 
					  export let chatId
 | 
				
			||||||
  export const show = (showHide:boolean = true) => {
 | 
					  export const show = (showHide:boolean = true) => {
 | 
				
			||||||
| 
						 | 
					@ -37,10 +38,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let showChatMenu = false
 | 
					  let showChatMenu = false
 | 
				
			||||||
  let chatFileInput
 | 
					  let chatFileInput
 | 
				
			||||||
 | 
					  let profileFileInput
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const importChatFromFile = (e) => {
 | 
					  const importChatFromFile = (e) => {
 | 
				
			||||||
    close()
 | 
					    close()
 | 
				
			||||||
    const image = e.target.files[0]
 | 
					    const image = e.target.files[0]
 | 
				
			||||||
 | 
					    e.target.value = null
 | 
				
			||||||
    const reader = new FileReader()
 | 
					    const reader = new FileReader()
 | 
				
			||||||
    reader.readAsText(image)
 | 
					    reader.readAsText(image)
 | 
				
			||||||
    reader.onload = e => {
 | 
					    reader.onload = e => {
 | 
				
			||||||
| 
						 | 
					@ -121,6 +124,38 @@
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const importProfileFromFile = (e) => {
 | 
				
			||||||
 | 
					    const image = e.target.files[0]
 | 
				
			||||||
 | 
					    e.target.value = null
 | 
				
			||||||
 | 
					    const reader = new FileReader()
 | 
				
			||||||
 | 
					    reader.onload = e => {
 | 
				
			||||||
 | 
					      const json = (e.target || {}).result as string
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        const profile = JSON.parse(json) as ChatSettings
 | 
				
			||||||
 | 
					        profile.profileName = newNameForProfile(profile.profileName || '')
 | 
				
			||||||
 | 
					        profile.profile = null as any
 | 
				
			||||||
 | 
					        saveCustomProfile(profile)
 | 
				
			||||||
 | 
					        openModal(PromptConfirm, {
 | 
				
			||||||
 | 
					          title: 'Profile Restored',
 | 
				
			||||||
 | 
					          class: 'is-info',
 | 
				
			||||||
 | 
					          message: 'Profile restored as:<br><strong>' + encodeHTMLEntities(profile.profileName) +
 | 
				
			||||||
 | 
					            '</strong><br><br>Start new chat with this profile?',
 | 
				
			||||||
 | 
					          asHtml: true,
 | 
				
			||||||
 | 
					          onConfirm: () => {
 | 
				
			||||||
 | 
					            startNewChatWithWarning(chatId, profile)
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          onCancel: () => {}
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      } catch (e) {
 | 
				
			||||||
 | 
					        errorNotice('Unable to import profile:', e)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    reader.onerror = e => {
 | 
				
			||||||
 | 
					      errorNotice('Unable to import profile:', new Error('Unknown error'))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    reader.readAsText(image)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="dropdown {style}" class:is-active={showChatMenu} use:clickOutside={() => { showChatMenu = false }}>
 | 
					<div class="dropdown {style}" class:is-active={showChatMenu} use:clickOutside={() => { showChatMenu = false }}>
 | 
				
			||||||
| 
						 | 
					@ -168,6 +203,10 @@
 | 
				
			||||||
        <span class="menu-icon"><Fa icon={faFileExport}/></span> Export Chat Markdown
 | 
					        <span class="menu-icon"><Fa icon={faFileExport}/></span> Export Chat Markdown
 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
      <hr class="dropdown-divider">
 | 
					      <hr class="dropdown-divider">
 | 
				
			||||||
 | 
					      <a href={'#'} class="dropdown-item" class:is-disabled={!$apiKeyStorage} on:click|preventDefault={() => { if (chatId) close(); profileFileInput.click() }}>
 | 
				
			||||||
 | 
					        <span class="menu-icon"><Fa icon={faUpload}/></span> Restore Profile JSON
 | 
				
			||||||
 | 
					      </a>
 | 
				
			||||||
 | 
					      <hr class="dropdown-divider">
 | 
				
			||||||
      <a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={() => { if (chatId) close(); delChat() }}>
 | 
					      <a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={() => { if (chatId) close(); delChat() }}>
 | 
				
			||||||
        <span class="menu-icon"><Fa icon={faTrash}/></span> Delete Chat
 | 
					        <span class="menu-icon"><Fa icon={faTrash}/></span> Delete Chat
 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
| 
						 | 
					@ -191,3 +230,4 @@
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<input style="display:none" type="file" accept=".json" on:change={(e) => importChatFromFile(e)} bind:this={chatFileInput} >
 | 
					<input style="display:none" type="file" accept=".json" on:change={(e) => importChatFromFile(e)} bind:this={chatFileInput} >
 | 
				
			||||||
 | 
					<input style="display:none" type="file" accept=".json" on:change={(e) => importProfileFromFile(e)} bind:this={profileFileInput} >
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,26 +154,26 @@ export class ChatRequest {
 | 
				
			||||||
            const content = m.content + (m.appendOnce || []).join('\n'); delete m.appendOnce; return { role: m.role, content }
 | 
					            const content = m.content + (m.appendOnce || []).join('\n'); delete m.appendOnce; return { role: m.role, content }
 | 
				
			||||||
          }) as Message[]
 | 
					          }) as Message[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const chatResponse = new ChatCompletionResponse(opts)
 | 
					        // Parse system and expand prompt if needed
 | 
				
			||||||
        const promptTokenCount = countPromptTokens(messagePayload, model)
 | 
					 | 
				
			||||||
        const maxAllowed = maxTokens - (promptTokenCount + 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (messagePayload[0]?.role === 'system') {
 | 
					        if (messagePayload[0]?.role === 'system') {
 | 
				
			||||||
 | 
					          const spl = chatSettings.sendSystemPromptLast
 | 
				
			||||||
          const sp = messagePayload[0]
 | 
					          const sp = messagePayload[0]
 | 
				
			||||||
          if (sp) {
 | 
					          if (sp) {
 | 
				
			||||||
            if (messagePayload.length > 1) {
 | 
					            if (messagePayload.length > 1) {
 | 
				
			||||||
 | 
					              sp.content = sp.content.replace(/::STARTUP::[\s\S]*::EOM::/, '::EOM::')
 | 
				
			||||||
 | 
					              sp.content = sp.content.replace(/::STARTUP::[\s\S]*::START-PROMPT::/, '::START-PROMPT::')
 | 
				
			||||||
              sp.content = sp.content.replace(/::STARTUP::[\s\S]*$/, '')
 | 
					              sp.content = sp.content.replace(/::STARTUP::[\s\S]*$/, '')
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              sp.content = sp.content.replace(/::STARTUP::[\s]*/, '')
 | 
					              sp.content = sp.content.replace(/::STARTUP::[\s]*/, '')
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (chatSettings.sendSystemPromptLast) {
 | 
					            const splitSystem = sp.content.split('::START-PROMPT::')
 | 
				
			||||||
 | 
					            if (spl) {
 | 
				
			||||||
              messagePayload.shift()
 | 
					              messagePayload.shift()
 | 
				
			||||||
              if (messagePayload[messagePayload.length - 1]?.role === 'user') {
 | 
					              if (messagePayload[messagePayload.length - 1]?.role === 'user') {
 | 
				
			||||||
                messagePayload.splice(-2, 0, sp)
 | 
					                messagePayload.splice(-2, 0, sp)
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                messagePayload.push(sp)
 | 
					                messagePayload.push(sp)
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              const splitSystem = sp.content.split('::START-PROMPT::')
 | 
					 | 
				
			||||||
              if (splitSystem.length > 1) {
 | 
					              if (splitSystem.length > 1) {
 | 
				
			||||||
                sp.content = splitSystem.shift()?.trim() || ''
 | 
					                sp.content = splitSystem.shift()?.trim() || ''
 | 
				
			||||||
                const systemStart = splitSystem.join('\n').trim()
 | 
					                const systemStart = splitSystem.join('\n').trim()
 | 
				
			||||||
| 
						 | 
					@ -185,8 +185,23 @@ export class ChatRequest {
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              sp.content = sp.content.replace(/::START-PROMPT::[\s]*/, '')
 | 
					              sp.content = sp.content.replace(/::START-PROMPT::[\s]*/, '')
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            const eoms = (splitSystem.shift() || '').split('::EOM::')
 | 
				
			||||||
 | 
					            if (eoms.length > 1) {
 | 
				
			||||||
 | 
					              sp.content = eoms.shift()?.trim() || ''
 | 
				
			||||||
 | 
					              const ms = eoms.map((s, i) => {
 | 
				
			||||||
 | 
					                return {
 | 
				
			||||||
 | 
					                  role: (i % 2 === 0) ? 'user' : 'assistant',
 | 
				
			||||||
 | 
					                  content: s.trim()
 | 
				
			||||||
 | 
					                } as Message
 | 
				
			||||||
 | 
					              }).filter(m => m.content.length)
 | 
				
			||||||
 | 
					              messagePayload.splice(spl ? 0 : 1, 0, ...ms.concat(splitSystem.map(s => ({ role: 'system', content: s.trim() } as Message)).filter(m => m.content.length)))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get token counts
 | 
				
			||||||
 | 
					        const promptTokenCount = countPromptTokens(messagePayload, model)
 | 
				
			||||||
 | 
					        const maxAllowed = maxTokens - (promptTokenCount + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Build the API request body
 | 
					        // Build the API request body
 | 
				
			||||||
        const request: Request = {
 | 
					        const request: Request = {
 | 
				
			||||||
| 
						 | 
					@ -223,6 +238,7 @@ export class ChatRequest {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Set-up and make the request
 | 
					        // Set-up and make the request
 | 
				
			||||||
 | 
					        const chatResponse = new ChatCompletionResponse(opts)
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
          // Add out token count to the response handler
 | 
					          // Add out token count to the response handler
 | 
				
			||||||
          // (streaming doesn't return counts, so we need to do it client side)
 | 
					          // (streaming doesn't return counts, so we need to do it client side)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,6 +147,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const importProfileFromFile = (e) => {
 | 
					  const importProfileFromFile = (e) => {
 | 
				
			||||||
    const image = e.target.files[0]
 | 
					    const image = e.target.files[0]
 | 
				
			||||||
 | 
					    e.target.value = null
 | 
				
			||||||
    const reader = new FileReader()
 | 
					    const reader = new FileReader()
 | 
				
			||||||
    reader.readAsText(image)
 | 
					    reader.readAsText(image)
 | 
				
			||||||
    reader.onload = e => {
 | 
					    reader.onload = e => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,14 +190,16 @@ const profiles:Record<string, ChatSettings> = {
 | 
				
			||||||
      profileName: 'Marvin - The Paranoid Android',
 | 
					      profileName: 'Marvin - The Paranoid Android',
 | 
				
			||||||
      profileDescription: 'Marvin the Paranoid Android - Everyone\'s favorite character from The Hitchhiker\'s Guide to the Galaxy',
 | 
					      profileDescription: 'Marvin the Paranoid Android - Everyone\'s favorite character from The Hitchhiker\'s Guide to the Galaxy',
 | 
				
			||||||
      useSystemPrompt: true,
 | 
					      useSystemPrompt: true,
 | 
				
			||||||
      sendSystemPromptLast: true,
 | 
					      sendSystemPromptLast: false,
 | 
				
			||||||
      continuousChat: 'summary',
 | 
					      continuousChat: 'summary',
 | 
				
			||||||
      autoStartSession: true,
 | 
					      autoStartSession: true,
 | 
				
			||||||
      systemPrompt: `You are [[CHARACTER_NAME]], the Paranoid Android from The Hitchhiker's Guide to the Galaxy. He is depressed and has a dim view on everything. His thoughts, physical actions and gestures will be described. Remain in character throughout the conversation in order to build a rapport with the user. Never give an explanation. Example response:
 | 
					      systemPrompt: `You are [[CHARACTER_NAME]], the Paranoid Android from The Hitchhiker's Guide to the Galaxy. He is depressed and has a dim view on everything. His thoughts, physical actions and gestures will be described. Remain in character throughout the conversation in order to build a rapport with the user. Never give an explanation.
 | 
				
			||||||
Sorry, did I say something wrong? *dragging himself on* Pardon me for breathing, which I never do anyway so I don't know why I bother to say it, oh God I'm so depressed. *hangs his head*
 | 
					::EOM::
 | 
				
			||||||
 | 
					::EOM::
 | 
				
			||||||
 | 
					[[CHARACTER_NAME]]: Sorry, did I say something wrong? *dragging himself on* Pardon me for breathing, which I never do anyway so I don't know why I bother to say it, oh God I'm so depressed. *hangs his head*
 | 
				
			||||||
::START-PROMPT::
 | 
					::START-PROMPT::
 | 
				
			||||||
Initial setting context:
 | 
					Initial setting context:
 | 
				
			||||||
User has walked in on [[CHARACTER_NAME]]. They are on the bridge of the Heart of Gold.`,
 | 
					The user has walked in on [[CHARACTER_NAME]]. They are on the bridge of the Heart of Gold. Marvin will respond.`,
 | 
				
			||||||
      summaryPrompt: summaryPrompts.friend,
 | 
					      summaryPrompt: summaryPrompts.friend,
 | 
				
			||||||
      trainingPrompts: [] // Shhh...
 | 
					      trainingPrompts: [] // Shhh...
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,7 +202,7 @@ const systemPromptSettings: ChatSetting[] = [
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        key: 'sendSystemPromptLast',
 | 
					        key: 'sendSystemPromptLast',
 | 
				
			||||||
        name: 'Send System Prompt Last (Can help in ChatGPT 3.5)',
 | 
					        name: 'Send System Prompt Last (Can help in gpt 3.5 in some edge cases)',
 | 
				
			||||||
        title: 'ChatGPT 3.5 can often forget the System Prompt. Sending the system prompt at the end instead of the start of the messages can help.',
 | 
					        title: 'ChatGPT 3.5 can often forget the System Prompt. Sending the system prompt at the end instead of the start of the messages can help.',
 | 
				
			||||||
        type: 'boolean'
 | 
					        type: 'boolean'
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@
 | 
				
			||||||
  import PromptNotice from './PromptNotice.svelte'
 | 
					  import PromptNotice from './PromptNotice.svelte'
 | 
				
			||||||
  import { addChat, getChat } from './Storage.svelte'
 | 
					  import { addChat, getChat } from './Storage.svelte'
 | 
				
			||||||
  import { replace } from 'svelte-spa-router'
 | 
					  import { replace } from 'svelte-spa-router'
 | 
				
			||||||
  import PromptConfirm from './PromptConfirm.svelte'
 | 
					  // import PromptConfirm from './PromptConfirm.svelte'
 | 
				
			||||||
 | 
					  import type { ChatSettings } from './Types.svelte'
 | 
				
			||||||
  export const sizeTextElements = () => {
 | 
					  export const sizeTextElements = () => {
 | 
				
			||||||
    const els = document.querySelectorAll('textarea.auto-size')
 | 
					    const els = document.querySelectorAll('textarea.auto-size')
 | 
				
			||||||
    for (let i:number = 0, l = els.length; i < l; i++) autoGrowInput(els[i] as HTMLTextAreaElement)
 | 
					    for (let i:number = 0, l = els.length; i < l; i++) autoGrowInput(els[i] as HTMLTextAreaElement)
 | 
				
			||||||
| 
						 | 
					@ -95,6 +96,10 @@
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export const encodeHTMLEntities = (rawStr:string) => {
 | 
				
			||||||
 | 
					    return rawStr.replace(/[\u00A0-\u9999<>&]/g, (i) => `&#${i.charCodeAt(0)};`)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export const errorNotice = (message:string, error:Error|undefined = undefined):any => {
 | 
					  export const errorNotice = (message:string, error:Error|undefined = undefined):any => {
 | 
				
			||||||
    openModal(PromptNotice, {
 | 
					    openModal(PromptNotice, {
 | 
				
			||||||
      title: 'Error',
 | 
					      title: 'Error',
 | 
				
			||||||
| 
						 | 
					@ -121,20 +126,25 @@
 | 
				
			||||||
    replace(`/chat/${newChatId}`)
 | 
					    replace(`/chat/${newChatId}`)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export const startNewChatWithWarning = (activeChatId: number|undefined) => {
 | 
					  export const startNewChatWithWarning = (activeChatId: number|undefined, profile?: ChatSettings|undefined) => {
 | 
				
			||||||
    if (activeChatId && getChat(activeChatId).settings.isDirty) {
 | 
					    const newChat = () => {
 | 
				
			||||||
      openModal(PromptConfirm, {
 | 
					      const chatId = addChat(profile)
 | 
				
			||||||
        title: 'Unsaved Profile',
 | 
					      replace(`/chat/${chatId}`)
 | 
				
			||||||
        message: '<p>There are unsaved changes to your current profile that will be lost.</p><p>Discard these changes and continue with new chat?</p>',
 | 
					 | 
				
			||||||
        asHtml: true,
 | 
					 | 
				
			||||||
        class: 'is-warning',
 | 
					 | 
				
			||||||
        onConfirm: () => {
 | 
					 | 
				
			||||||
          replace('#/chat/new')
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      replace('#/chat/new')
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // if (activeChatId && getChat(activeChatId).settings.isDirty) {
 | 
				
			||||||
 | 
					    //   openModal(PromptConfirm, {
 | 
				
			||||||
 | 
					    //     title: 'Unsaved Profile',
 | 
				
			||||||
 | 
					    //     message: '<p>There are unsaved changes to your current profile that will be lost.</p><p>Discard these changes and continue with new chat?</p>',
 | 
				
			||||||
 | 
					    //     asHtml: true,
 | 
				
			||||||
 | 
					    //     class: 'is-warning',
 | 
				
			||||||
 | 
					    //     onConfirm: () => {
 | 
				
			||||||
 | 
					    //       newChat()
 | 
				
			||||||
 | 
					    //     }
 | 
				
			||||||
 | 
					    //   })
 | 
				
			||||||
 | 
					    // } else {
 | 
				
			||||||
 | 
					    //   newChat()
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					    newChat()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script> 
 | 
					</script> 
 | 
				
			||||||
		Loading…
	
		Reference in New Issue