diff --git a/renderer/package-lock.json b/renderer/package-lock.json index 92b19e8..e547bb3 100644 --- a/renderer/package-lock.json +++ b/renderer/package-lock.json @@ -11,6 +11,8 @@ "core-js": "^3.8.3", "element-plus": "^2.9.7", "katex": "^0.16.21", + "loadash": "^1.0.0", + "lodash": "^4.17.21", "markdown-it": "^14.1.0", "markdown-it-katex": "^2.0.3", "openai": "^4.93.0", @@ -20,6 +22,7 @@ "vue-router": "^4.0.3" }, "devDependencies": { + "@types/lodash": "^4.17.16", "@types/markdown-it": "^14.1.2", "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", @@ -8620,6 +8623,13 @@ "uc.micro": "^2.0.0" } }, + "node_modules/loadash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loadash/-/loadash-1.0.0.tgz", + "integrity": "sha512-xlX5HBsXB3KG0FJbJJG/3kYWCfsCyCSus3T+uHVu6QL6YxAdggmm3QeyLgn54N2yi5/UE6xxL5ZWJAAiHzHYEg==", + "deprecated": "Package is unsupport. Please use the lodash package instead.", + "license": "ISC" + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", @@ -8690,7 +8700,7 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, diff --git a/renderer/package.json b/renderer/package.json index 31082f4..adee342 100644 --- a/renderer/package.json +++ b/renderer/package.json @@ -11,6 +11,7 @@ "core-js": "^3.8.3", "element-plus": "^2.9.7", "katex": "^0.16.21", + "lodash": "^4.17.21", "markdown-it": "^14.1.0", "markdown-it-katex": "^2.0.3", "openai": "^4.93.0", @@ -20,6 +21,7 @@ "vue-router": "^4.0.3" }, "devDependencies": { + "@types/lodash": "^4.17.16", "@types/markdown-it": "^14.1.2", "@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/parser": "^5.4.0", diff --git a/renderer/public/mcp.css b/renderer/public/mcp.css index 543573c..5a1f2be 100644 --- a/renderer/public/mcp.css +++ b/renderer/public/mcp.css @@ -65,7 +65,6 @@ body::-webkit-scrollbar { } .el-textarea__inner { - border-radius: .9em !important; padding: 10px !important; box-shadow: 0 0 0 1px var(--main-color) !important; } diff --git a/renderer/src/components/k-cute-textarea/index.vue b/renderer/src/components/k-cute-textarea/index.vue index 583fb4d..f42bee5 100644 --- a/renderer/src/components/k-cute-textarea/index.vue +++ b/renderer/src/components/k-cute-textarea/index.vue @@ -7,6 +7,7 @@ :placeholder="placeholder" :resize="resize" :class="customClass" + class="k-cute-textarea" @keydown.enter="handleKeydown" @compositionstart="handleCompositionStart" @compositionend="handleCompositionEnd" @@ -67,4 +68,12 @@ const handleCompositionStart = () => { const handleCompositionEnd = () => { isComposing.value = false; }; - \ No newline at end of file + + + \ No newline at end of file diff --git a/renderer/src/components/main-panel/chat/options/system-prompt.ts b/renderer/src/components/main-panel/chat/options/system-prompt.ts index 80fdeba..3822fdc 100644 --- a/renderer/src/components/main-panel/chat/options/system-prompt.ts +++ b/renderer/src/components/main-panel/chat/options/system-prompt.ts @@ -1,4 +1,5 @@ import { useMessageBridge } from "@/api/message-bridge"; +import { pinkLog } from "@/views/setting/util"; import { ref } from "vue"; interface SystemPrompt { @@ -6,14 +7,50 @@ interface SystemPrompt { content: string; } -export const systemPrompt = ref({ - name: '默认', +export const systemPrompts = ref([{ + name: 'Default', content: '你是一个AI助手, 你可以回答任何问题。' -}); +}]); -export function saveSystemPrompts() { +export async function saveSystemPrompts() { const bridge = useMessageBridge(); - return new Promise(resolve => { - - }) + + const payload = JSON.parse(JSON.stringify(systemPrompts.value)); + const res = await bridge.commandRequest('system-prompts/save', { prompts: payload }); + if (res.code === 200) { + pinkLog('system prompt 保存成功'); + } +} + +export async function setSystemPrompt(name: string, content: string) { + const bridge = useMessageBridge(); + const res = await bridge.commandRequest('system-prompts/set', { name, content }); + if (res.code === 200) { + pinkLog('system prompt 添加成功'); + if (!systemPrompts.value.some(prompt => prompt.name === name)) { + systemPrompts.value.push({ name, content }); + } + } + return res; +} + +export async function deleteSystemPrompt(name: string) { + const bridge = useMessageBridge(); + const res = await bridge.commandRequest('system-prompts/delete', { name }); + if (res.code === 200) { + pinkLog('system prompt 删除成功'); + systemPrompts.value = systemPrompts.value.filter((prompt) => prompt.name !== name); + } + return res; +} + +export async function loadSystemPrompts() { + const bridge = useMessageBridge(); + const res = await bridge.commandRequest('system-prompts/load'); + if (res.code === 200) { + pinkLog('system prompt 加载成功'); + systemPrompts.value = res.msg; + } + + return res; } \ No newline at end of file diff --git a/renderer/src/components/main-panel/chat/options/system-prompt.vue b/renderer/src/components/main-panel/chat/options/system-prompt.vue index c325d88..e128a25 100644 --- a/renderer/src/components/main-panel/chat/options/system-prompt.vue +++ b/renderer/src/components/main-panel/chat/options/system-prompt.vue @@ -6,33 +6,165 @@ - - - + + + + + + {{ prompt.name }} + + + + + + + + {{ t('delete') }} + + + + + + + + + + + + + + + + + + + + {{ t("cancel") }} - {{ t("save") }} + + + {{ t("cancel") }} + {{ t("save") }} + + - \ No newline at end of file + \ No newline at end of file diff --git a/renderer/src/components/main-panel/chat/options/tool-use.vue b/renderer/src/components/main-panel/chat/options/tool-use.vue index cf2a087..345318a 100644 --- a/renderer/src/components/main-panel/chat/options/tool-use.vue +++ b/renderer/src/components/main-panel/chat/options/tool-use.vue @@ -35,10 +35,11 @@ \ No newline at end of file diff --git a/renderer/src/i18n/ar.json b/renderer/src/i18n/ar.json index 85d6e35..c5656df 100644 --- a/renderer/src/i18n/ar.json +++ b/renderer/src/i18n/ar.json @@ -145,5 +145,6 @@ "multi-dialog": "محادثة متعددة الجولات", "press-and-run": "اكتب سؤالاً لبدء الاختبار", "connect-sigature": "توقيع الاتصال", - "finish-refresh": "تم التحديث" + "finish-refresh": "تم التحديث", + "add-system-prompt.name-placeholder": "عنوان prompt المخصص" } \ No newline at end of file diff --git a/renderer/src/i18n/de.json b/renderer/src/i18n/de.json index 4f8ef60..eae497b 100644 --- a/renderer/src/i18n/de.json +++ b/renderer/src/i18n/de.json @@ -145,5 +145,6 @@ "multi-dialog": "Mehrrundengespräch", "press-and-run": "Geben Sie eine Frage ein, um den Test zu starten", "connect-sigature": "Verbindungssignatur", - "finish-refresh": "Aktualisierung abgeschlossen" + "finish-refresh": "Aktualisierung abgeschlossen", + "add-system-prompt.name-placeholder": "Titel für benutzerdefinierte Eingabeaufforderung" } \ No newline at end of file diff --git a/renderer/src/i18n/en.json b/renderer/src/i18n/en.json index be37a10..09c4488 100644 --- a/renderer/src/i18n/en.json +++ b/renderer/src/i18n/en.json @@ -145,5 +145,6 @@ "multi-dialog": "Multi-turn conversation", "press-and-run": "Type a question to start the test", "connect-sigature": "Connection signature", - "finish-refresh": "Refresh completed" + "finish-refresh": "Refresh completed", + "add-system-prompt.name-placeholder": "Title for custom prompt" } \ No newline at end of file diff --git a/renderer/src/i18n/fr.json b/renderer/src/i18n/fr.json index 84fd9b9..be9733f 100644 --- a/renderer/src/i18n/fr.json +++ b/renderer/src/i18n/fr.json @@ -145,5 +145,6 @@ "multi-dialog": "Conversation multi-tours", "press-and-run": "Tapez une question pour commencer le test", "connect-sigature": "Signature de connexion", - "finish-refresh": "Actualisation terminée" + "finish-refresh": "Actualisation terminée", + "add-system-prompt.name-placeholder": "Titre de l'invite personnalisée" } \ No newline at end of file diff --git a/renderer/src/i18n/ja.json b/renderer/src/i18n/ja.json index dae39a5..8ed46ba 100644 --- a/renderer/src/i18n/ja.json +++ b/renderer/src/i18n/ja.json @@ -145,5 +145,6 @@ "multi-dialog": "マルチターン会話", "press-and-run": "テストを開始するには質問を入力してください", "connect-sigature": "接続署名", - "finish-refresh": "更新が完了しました" + "finish-refresh": "更新が完了しました", + "add-system-prompt.name-placeholder": "カスタムプロンプトのタイトル" } \ No newline at end of file diff --git a/renderer/src/i18n/ko.json b/renderer/src/i18n/ko.json index dbb3937..4eb61eb 100644 --- a/renderer/src/i18n/ko.json +++ b/renderer/src/i18n/ko.json @@ -145,5 +145,6 @@ "multi-dialog": "다중 턴 대화", "press-and-run": "테스트를 시작하려면 질문을 입력하세요", "connect-sigature": "연결 서명", - "finish-refresh": "새로 고침 완료" + "finish-refresh": "새로 고침 완료", + "add-system-prompt.name-placeholder": "사용자 지정 프롬프트 제목" } \ No newline at end of file diff --git a/renderer/src/i18n/ru.json b/renderer/src/i18n/ru.json index 70edc40..6a087ed 100644 --- a/renderer/src/i18n/ru.json +++ b/renderer/src/i18n/ru.json @@ -145,5 +145,6 @@ "multi-dialog": "Многораундовый разговор", "press-and-run": "Введите вопрос, чтобы начать тест", "connect-sigature": "Подпись соединения", - "finish-refresh": "Обновление завершено" + "finish-refresh": "Обновление завершено", + "add-system-prompt.name-placeholder": "Заголовок пользовательского prompt" } \ No newline at end of file diff --git a/renderer/src/i18n/zh-cn.json b/renderer/src/i18n/zh-cn.json index c54e781..cc1149d 100644 --- a/renderer/src/i18n/zh-cn.json +++ b/renderer/src/i18n/zh-cn.json @@ -145,5 +145,6 @@ "multi-dialog": "多轮对话", "press-and-run": "键入问题以开始测试", "connect-sigature": "连接签名", - "finish-refresh": "完成刷新" + "finish-refresh": "完成刷新", + "add-system-prompt.name-placeholder": "输入自定义 prompt 的标题" } \ No newline at end of file diff --git a/renderer/src/i18n/zh-tw.json b/renderer/src/i18n/zh-tw.json index d594731..162744f 100644 --- a/renderer/src/i18n/zh-tw.json +++ b/renderer/src/i18n/zh-tw.json @@ -145,5 +145,6 @@ "multi-dialog": "多輪對話", "press-and-run": "輸入問題以開始測試", "connect-sigature": "連接簽名", - "finish-refresh": "刷新完成" + "finish-refresh": "刷新完成", + "add-system-prompt.name-placeholder": "自定義提示的標題" } \ No newline at end of file diff --git a/service/src/hook/db.ts b/service/src/hook/db.ts index 5ee4d63..dd8d961 100644 --- a/service/src/hook/db.ts +++ b/service/src/hook/db.ts @@ -146,7 +146,13 @@ interface OcrItem extends Entity { createTime: number; } +interface SystemPromptItem extends Entity { + name: string; + content: string; +} + export const diskStorage = new DiskStorage(); export const settingDB = new LocalDB('setting'); -export const ocrDB = new LocalDB('ocr'); \ No newline at end of file +export const ocrDB = new LocalDB('ocr'); +export const systemPromptDB = new LocalDB('systemPrompt'); \ No newline at end of file diff --git a/service/src/panel/panel.controller.ts b/service/src/panel/panel.controller.ts index facf750..f7239a1 100644 --- a/service/src/panel/panel.controller.ts +++ b/service/src/panel/panel.controller.ts @@ -1,5 +1,6 @@ import { Controller, RequestClientType } from "../common"; import { PostMessageble } from "../hook/adapter"; +import { systemPromptDB } from "../hook/db"; import { loadTabSaveConfig, saveTabSaveConfig } from "./panel.service"; export class PanelController { @@ -25,4 +26,66 @@ export class PanelController { msg: config }; } + + @Controller('system-prompts/set') + async setSystemPrompt(client: RequestClientType, data: any, webview: PostMessageble) { + const { name, content } = data; + + await systemPromptDB.insert({ + id: name, + name, + content + }); + + return { + code: 200, + msg: 'Settings saved successfully' + } + } + + @Controller('system-prompts/delete') + async deleteSystemPrompt(client: RequestClientType, data: any, webview: PostMessageble) { + const { name } = data; + await systemPromptDB.delete(name); + return { + code: 200, + msg: 'Settings saved successfully' + } + } + + @Controller('system-prompts/save') + async saveSystemPrompts(client: RequestClientType, data: any, webview: PostMessageble) { + const { prompts } = data; + + await Promise.all(prompts.map((prompt: any) => { + systemPromptDB.insert({ + id: prompt.name, + name: prompt.name, + content: prompt.content + }) + })); + + return { + code: 200, + msg: 'Settings saved successfully' + } + } + + @Controller('system-prompts/load') + async loadSystemPrompts(client: RequestClientType, data: any, webview: PostMessageble) { + + const queryPrompts = await systemPromptDB.findAll(); + const prompts = []; + for (const prompt of queryPrompts) { + prompts.push({ + name: prompt.name, + content: prompt.content + }) + } + + return { + code: 200, + msg: prompts + } + } } \ No newline at end of file