-
Notifications
You must be signed in to change notification settings - Fork 185
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf: optimize the display of session content (#8)
- Loading branch information
Showing
15 changed files
with
338 additions
and
291 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,2 @@ | ||
import { fetch, Body } from '@tauri-apps/api/http' | ||
import { dialogErrorMessage } from '@/utils' | ||
import type { FetchOptions } from '@tauri-apps/api/http' | ||
import type { RecordData } from '@/types' | ||
import { useSessionStore, useSettingsStore } from '@/stores' | ||
import { | ||
fetchEventSource, | ||
type EventSourceMessage | ||
} from '@microsoft/fetch-event-source' | ||
|
||
/** | ||
* 请求总入口 | ||
* @param url 请求地址 | ||
* @param options 请求参数 | ||
*/ | ||
export const request = async (url: string, options?: FetchOptions) => { | ||
try { | ||
const { method, headers } = options || {} | ||
|
||
const { data }: Record<string, any> = await fetch(url, { | ||
...options, | ||
method: method || 'GET', | ||
timeout: 1000 * 60, | ||
headers: { | ||
...headers, | ||
'user-agent': | ||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' | ||
} | ||
}) | ||
|
||
const { error, usage, choices } = data | ||
|
||
if (error) throw new Error(error.message) | ||
|
||
return { | ||
usage, | ||
message: choices[0].message | ||
} | ||
} catch (error: any) { | ||
console.log('error', error) | ||
dialogErrorMessage('请求出错:' + error.message) | ||
} | ||
} | ||
|
||
/** | ||
* 获取 openai 对话消息 | ||
* @param messages 消息列表 | ||
*/ | ||
export const getOpenAIResultApi = async (messages: RecordData[]) => { | ||
if (!messages.length) return | ||
|
||
const { apiKey } = useSettingsStore() | ||
|
||
return await request(import.meta.env.VITE_OPEN_AI_URL, { | ||
method: 'POST', | ||
body: Body.json({ | ||
model: 'gpt-3.5-turbo-0301', | ||
messages, | ||
temperature: 0.6, | ||
stream: false | ||
}), | ||
headers: { | ||
Authorization: `Bearer ${apiKey || import.meta.env.VITE_OPEN_AI_API_KEY}` | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* 获取 openai 对话消息(流) | ||
* @param messages 消息列表 | ||
*/ | ||
export const getOpenAIResultStream = async (messages: RecordData[]) => { | ||
if (!messages.length) return | ||
|
||
const { apiKey } = useSettingsStore() | ||
const { addSessionData } = useSessionStore() | ||
const { streamReply } = storeToRefs(useSessionStore()) | ||
streamReply.value = '' | ||
|
||
await fetchEventSource(import.meta.env.VITE_OPEN_AI_URL, { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
model: 'gpt-3.5-turbo-0301', | ||
messages, | ||
temperature: 0.6, | ||
stream: true | ||
}), | ||
headers: { | ||
Authorization: `Bearer ${apiKey || import.meta.env.VITE_OPEN_AI_API_KEY}`, | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json' | ||
}, | ||
onmessage(msg: EventSourceMessage) { | ||
if (msg.data !== '[DONE]') { | ||
const { choices } = JSON.parse(msg.data) | ||
|
||
if (!choices[0].delta.content) return | ||
streamReply.value += choices[0].delta.content | ||
} | ||
}, | ||
onclose() { | ||
const res: RecordData = { | ||
role: 'assistant', | ||
content: streamReply.value | ||
} | ||
addSessionData(false, '', res) | ||
}, | ||
onerror({ message }: any) { | ||
throw new Error(`流输出出错:${message}`) | ||
} | ||
}) | ||
} | ||
export * from './request' | ||
export * from './openAi' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import { Body } from '@tauri-apps/api/http' | ||
import { request } from '.' | ||
import { OPEN_AI_MODEL } from '@/constants' | ||
import { dialogErrorMessage } from '@/utils' | ||
import { | ||
fetchEventSource, | ||
type EventSourceMessage | ||
} from '@microsoft/fetch-event-source' | ||
import { useSessionStore, useSettingsStore, useRoleStore } from '@/stores' | ||
import { executeSQL } from '@/sqls' | ||
import type { MessageData, SessionData } from '@/types' | ||
|
||
/** | ||
* 获取 openai 对话消息 | ||
* @param messages 消息列表 | ||
*/ | ||
export const getOpenAIResultApi = async (messages: MessageData[]) => { | ||
if (!messages.length) return | ||
|
||
const { apiKey } = useSettingsStore() | ||
|
||
return await request(import.meta.env.VITE_OPEN_AI_URL, { | ||
method: 'POST', | ||
body: Body.json({ | ||
model: OPEN_AI_MODEL, | ||
messages | ||
}), | ||
headers: { | ||
Authorization: `Bearer ${apiKey || import.meta.env.VITE_OPEN_AI_API_KEY}` | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* 获取 openai 对话消息(流) | ||
* @param messages 消息列表 | ||
*/ | ||
export const getOpenAIResultStreamApi = async (messages: MessageData[]) => { | ||
if (!messages.length) return | ||
|
||
const { apiKey } = useSettingsStore() | ||
const { updateSessionData } = useSessionStore() | ||
const { sessionDataList } = storeToRefs(useSessionStore()) | ||
|
||
await fetchEventSource(import.meta.env.VITE_OPEN_AI_URL, { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
model: OPEN_AI_MODEL, | ||
messages, | ||
temperature: 0.6, | ||
stream: true | ||
}), | ||
headers: { | ||
Authorization: `Bearer ${apiKey || import.meta.env.VITE_OPEN_AI_API_KEY}`, | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json' | ||
}, | ||
onmessage(msg: EventSourceMessage) { | ||
if (msg.data !== '[DONE]') { | ||
const { choices } = JSON.parse(msg.data) | ||
|
||
if (!choices[0].delta.content) return | ||
|
||
sessionDataList.value.at(-1)!.message.content += | ||
choices[0].delta.content | ||
} | ||
}, | ||
onclose() { | ||
updateSessionData(sessionDataList.value.at(-1)!) | ||
}, | ||
onerror({ message }: any) { | ||
throw new Error(`流输出出错:${message}`) | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* 获取 ai 回答 | ||
* @param value 消息内容 | ||
*/ | ||
export const getAiMessage = async (value?: string) => { | ||
const { isThinking } = storeToRefs(useSessionStore()) | ||
|
||
try { | ||
const { currentRole } = useRoleStore() | ||
|
||
if (!currentRole) return | ||
|
||
const messages: MessageData[] = [] | ||
|
||
const { currentSession, sessionDataList } = useSessionStore() | ||
const { isMemory } = useSettingsStore() | ||
|
||
const lastQuestion = sessionDataList.filter((item) => item.is_ask).at(-1) | ||
|
||
// 记忆模式,或者是第一次对话,都要生成角色描述 | ||
if (sessionDataList.length < 3 || isMemory) { | ||
messages.push({ | ||
role: 'system', | ||
content: currentRole.description | ||
}) | ||
} | ||
|
||
// 获取记忆(限制5条),往前推直到出现 is_momery 为 false 的 | ||
// TODO 应该进行限流,防止出现过多的记忆,导致token超出 | ||
const addMemory = async () => { | ||
if (isMemory) { | ||
// TODO: 优化 sql | ||
const sql = `SELECT * FROM session_data WHERE session_id = '${currentSession?.id}' ORDER BY id DESC LIMIT 5;` | ||
const memoryList = (await executeSQL(sql)) as SessionData[] | ||
|
||
let count = 0 | ||
const arr = [] | ||
while (count < memoryList.length) { | ||
if (!memoryList[count].is_memory) break | ||
arr.push(memoryList[count++].message) | ||
} | ||
messages.push(...arr.reverse()) | ||
} | ||
} | ||
|
||
// 再次生成上一次问题 | ||
if (!value) { | ||
if (!lastQuestion) return | ||
|
||
// 为了保证统一,这之后的内容全部删掉 | ||
const deleteSql = `DELETE FROM session_data WHERE session_id = '${lastQuestion?.session_id}' AND id >= ${lastQuestion?.id};` | ||
await executeSQL(deleteSql) | ||
|
||
await addMemory() | ||
messages.push(lastQuestion?.message) | ||
} else { | ||
await addMemory() | ||
messages.push({ | ||
role: 'user', | ||
content: value | ||
}) | ||
} | ||
|
||
const { isThinking } = storeToRefs(useSessionStore()) | ||
const { addSessionData } = useSessionStore() | ||
|
||
isThinking.value = true | ||
|
||
await addSessionData({ | ||
isAsk: true, | ||
data: messages.at(-1)! | ||
}) | ||
|
||
await addSessionData({ | ||
isAsk: false, | ||
data: { | ||
role: 'assistant', | ||
content: '' | ||
} | ||
}) | ||
|
||
await getOpenAIResultStreamApi(messages) | ||
|
||
isThinking.value = false | ||
} catch ({ message }: any) { | ||
dialogErrorMessage(message) | ||
|
||
isThinking.value = false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { fetch, type FetchOptions } from '@tauri-apps/api/http' | ||
import { dialogErrorMessage } from '@/utils' | ||
|
||
/** | ||
* 普通请求 | ||
* @param url 请求地址 | ||
* @param options 请求参数 | ||
*/ | ||
export const request = async (url: string, options?: FetchOptions) => { | ||
try { | ||
const { method, headers } = options || {} | ||
|
||
const { data }: Record<string, any> = await fetch(url, { | ||
...options, | ||
method: method || 'GET', | ||
timeout: 1000 * 60, | ||
headers: { | ||
...headers, | ||
'user-agent': | ||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' | ||
} | ||
}) | ||
|
||
const { error, usage, choices } = data | ||
|
||
if (error) throw new Error(error.message) | ||
|
||
return { | ||
usage, | ||
message: choices[0].message | ||
} | ||
} catch (error: any) { | ||
dialogErrorMessage('请求出错:' + error.message) | ||
} | ||
} |
Oops, something went wrong.