完成全部配置的保存
This commit is contained in:
parent
05080e2b72
commit
3d372dafae
@ -15,6 +15,7 @@ import { setDefaultCss } from './hook/css';
|
|||||||
import { pinkLog } from './views/setting/util';
|
import { pinkLog } from './views/setting/util';
|
||||||
import { acquireVsCodeApi, useMessageBridge } from './api/message-bridge';
|
import { acquireVsCodeApi, useMessageBridge } from './api/message-bridge';
|
||||||
import { connectionArgs, connectionMethods, connectionResult, doConnect } from './views/connect/connection';
|
import { connectionArgs, connectionMethods, connectionResult, doConnect } from './views/connect/connection';
|
||||||
|
import { loadSetting } from './hook/setting';
|
||||||
|
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
@ -25,21 +26,10 @@ bridge.addCommandListener('hello', data => {
|
|||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
|
|
||||||
// 发送消息
|
|
||||||
const sendPing = () => {
|
|
||||||
bridge.postMessage({
|
|
||||||
command: 'ping',
|
|
||||||
data: { timestamp: Date.now() }
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 初始化 css
|
// 初始化 css
|
||||||
setDefaultCss();
|
setDefaultCss();
|
||||||
|
|
||||||
// 初始化 设置
|
|
||||||
|
|
||||||
document.addEventListener('click', () => {
|
document.addEventListener('click', () => {
|
||||||
Connection.showPanel = false;
|
Connection.showPanel = false;
|
||||||
});
|
});
|
||||||
@ -58,6 +48,9 @@ onMounted(() => {
|
|||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
// 初始化 设置
|
||||||
|
loadSetting();
|
||||||
|
|
||||||
doConnect();
|
doConnect();
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ export type CommandHandler = (data: any) => void;
|
|||||||
export const acquireVsCodeApi = (window as any)['acquireVsCodeApi'];
|
export const acquireVsCodeApi = (window as any)['acquireVsCodeApi'];
|
||||||
|
|
||||||
interface AddCommandListenerOption {
|
interface AddCommandListenerOption {
|
||||||
once: boolean // 只调用一次就销毁
|
once: boolean // 只调用一次就销毁
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageBridge {
|
class MessageBridge {
|
||||||
@ -97,19 +97,37 @@ class MessageBridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 注册一个命令的执行器
|
* @description 注册一个命令的执行器(支持一次性或持久监听)
|
||||||
* @returns
|
* @example
|
||||||
|
* // 基本用法(持久监听)
|
||||||
|
* const removeListener = bridge.addCommandListener('message', (data) => {
|
||||||
|
* console.log('收到消息:', data.msg.text);
|
||||||
|
* }, { once: false });
|
||||||
|
*
|
||||||
|
* // 稍后取消监听
|
||||||
|
* removeListener();
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // 一次性监听(自动移除)
|
||||||
|
* bridge.addCommandListener('connect', (data) => {
|
||||||
|
* const { code, msg } = data;
|
||||||
|
* console.log(`连接结果: ${code === 200 ? '成功' : '失败'}`);
|
||||||
|
* }, { once: true });
|
||||||
*/
|
*/
|
||||||
public addCommandListener(command: string, commandHandler: CommandHandler, option: AddCommandListenerOption) {
|
public addCommandListener(
|
||||||
|
command: string,
|
||||||
|
commandHandler: CommandHandler,
|
||||||
|
option: AddCommandListenerOption
|
||||||
|
): () => boolean {
|
||||||
if (!this.handlers.has(command)) {
|
if (!this.handlers.has(command)) {
|
||||||
this.handlers.set(command, new Set<CommandHandler>());
|
this.handlers.set(command, new Set<CommandHandler>());
|
||||||
}
|
}
|
||||||
const commandHandlers = this.handlers.get(command)!;
|
const commandHandlers = this.handlers.get(command)!;
|
||||||
|
|
||||||
const wrapperCommandHandler = option.once ? (data: any) => {
|
const wrapperCommandHandler = option.once ? (data: any) => {
|
||||||
commandHandler(data);
|
commandHandler(data);
|
||||||
commandHandlers.delete(wrapperCommandHandler);
|
commandHandlers.delete(wrapperCommandHandler);
|
||||||
} : commandHandler;
|
} : commandHandler;
|
||||||
|
|
||||||
commandHandlers.add(wrapperCommandHandler);
|
commandHandlers.add(wrapperCommandHandler);
|
||||||
return () => commandHandlers.delete(wrapperCommandHandler);
|
return () => commandHandlers.delete(wrapperCommandHandler);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
<span :class="`iconfont ${tab.icon}`"></span>
|
<span :class="`iconfont ${tab.icon}`"></span>
|
||||||
<span>{{ tab.name }}</span>
|
<span class="tab-name">{{ tab.name }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="iconfont icon-close"
|
class="iconfont icon-close"
|
||||||
@ -33,8 +33,6 @@
|
|||||||
<div class="main-panel">
|
<div class="main-panel">
|
||||||
<router-view />
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -83,6 +81,7 @@ defineComponent({ name: 'main-panel' });
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tabs-container .tab {
|
.tabs-container .tab {
|
||||||
|
white-space: nowrap;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
@ -101,6 +100,12 @@ defineComponent({ name: 'main-panel' });
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabs-container .tab .tab-name {
|
||||||
|
max-width: 70px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.tabs-container .tab:hover {
|
.tabs-container .tab:hover {
|
||||||
background-color: var(--input-active-background);
|
background-color: var(--input-active-background);
|
||||||
}
|
}
|
||||||
|
@ -4,46 +4,61 @@ import Resource from './resource/index.vue';
|
|||||||
import Chat from './chat/index.vue';
|
import Chat from './chat/index.vue';
|
||||||
import Prompt from './prompt/index.vue';
|
import Prompt from './prompt/index.vue';
|
||||||
import Tool from './tool/index.vue';
|
import Tool from './tool/index.vue';
|
||||||
|
import I18n from '@/i18n/index';
|
||||||
|
|
||||||
|
const { t } = I18n.global;
|
||||||
|
|
||||||
interface Tab {
|
interface Tab {
|
||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
type: string;
|
type: string;
|
||||||
component: any;
|
component: any;
|
||||||
storage: Record<string, any>;
|
storage: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const debugModes = [
|
export const debugModes = [
|
||||||
Resource, Prompt, Tool, Chat
|
Resource, Prompt, Tool, Chat
|
||||||
]
|
]
|
||||||
|
|
||||||
// TODO: 实现对于 tabs 这个数据的可持久化
|
// TODO: 实现对于 tabs 这个数据的可持久化
|
||||||
export const tabs = reactive({
|
export const tabs = reactive<{
|
||||||
|
content: Tab[]
|
||||||
|
activeIndex: number
|
||||||
|
activeTab: Tab
|
||||||
|
}>({
|
||||||
content: [
|
content: [
|
||||||
{
|
createTab('blank', 1)
|
||||||
name: '空白测试 1',
|
],
|
||||||
icon: 'icon-blank',
|
|
||||||
type: 'blank',
|
|
||||||
component: undefined,
|
|
||||||
storage: {}
|
|
||||||
}
|
|
||||||
] as Tab[],
|
|
||||||
activeIndex: 0,
|
activeIndex: 0,
|
||||||
get activeTab() {
|
get activeTab() {
|
||||||
return this.content[this.activeIndex];
|
return this.content[this.activeIndex];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let tabCounter = 1;
|
let tabCounter = 1;
|
||||||
|
|
||||||
export function addNewTab() {
|
function createTab(type: string, index: number): Tab {
|
||||||
const newTab = {
|
let customName: string | null = null;
|
||||||
name: `空白测试 ${++ tabCounter}`,
|
|
||||||
|
return {
|
||||||
|
get name() {
|
||||||
|
if (customName !== null) {
|
||||||
|
return customName;
|
||||||
|
}
|
||||||
|
return t('blank-test') + ` ${index}`;
|
||||||
|
},
|
||||||
|
set name(value: string) {
|
||||||
|
customName = value; // 允许外部修改 name
|
||||||
|
},
|
||||||
icon: 'icon-blank',
|
icon: 'icon-blank',
|
||||||
type: 'blank',
|
type,
|
||||||
component: undefined,
|
component: undefined,
|
||||||
storage: {}
|
storage: {},
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addNewTab() {
|
||||||
|
const newTab = createTab('blank', ++tabCounter);
|
||||||
tabs.content.push(newTab);
|
tabs.content.push(newTab);
|
||||||
tabs.activeIndex = tabs.content.length - 1;
|
tabs.activeIndex = tabs.content.length - 1;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div class="left">
|
<div class="left">
|
||||||
<h2>
|
<h2>
|
||||||
<span class="iconfont icon-file"></span>
|
<span class="iconfont icon-file"></span>
|
||||||
资源模块
|
{{ t("resources") + t("module") }}
|
||||||
</h2>
|
</h2>
|
||||||
<h3><code>resources/templates/list</code></h3>
|
<h3><code>resources/templates/list</code></h3>
|
||||||
|
|
||||||
@ -26,10 +26,13 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps } from 'vue';
|
import { defineProps } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import ResourceTemplates from './resource-templates.vue';
|
import ResourceTemplates from './resource-templates.vue';
|
||||||
import ResourceReader from './resouce-reader.vue';
|
import ResourceReader from './resouce-reader.vue';
|
||||||
import ResourceLogger from './resource-logger.vue';
|
import ResourceLogger from './resource-logger.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
tabId: {
|
tabId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -1,14 +1,48 @@
|
|||||||
import { useMessageBridge } from "@/api/message-bridge";
|
import { useMessageBridge } from "@/api/message-bridge";
|
||||||
|
import { llmManager, llms } from "@/views/setting/llm";
|
||||||
|
import { pinkLog } from "@/views/setting/util";
|
||||||
|
import I18n from '@/i18n/index';
|
||||||
|
|
||||||
export function loadSetting() {
|
export function loadSetting() {
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
bridge.addCommandListener('setting/load', () => {
|
|
||||||
|
bridge.addCommandListener('setting/load', data => {
|
||||||
|
const persistConfig = data.msg;
|
||||||
|
|
||||||
|
llmManager.currentModelIndex = persistConfig.MODEL_INDEX;
|
||||||
|
I18n.global.locale.value = persistConfig.LANG;
|
||||||
|
|
||||||
|
persistConfig.LLM_INFO.forEach((element: any) => {
|
||||||
|
llms.push(element);
|
||||||
|
});
|
||||||
|
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'setting/load'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveSetting() {
|
export function saveSetting(saveHandler?: () => void) {
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
|
const saveConfig = {
|
||||||
|
MODEL_INDEX: llmManager.currentModelIndex,
|
||||||
|
LLM_INFO: JSON.parse(JSON.stringify(llms)),
|
||||||
|
LANG: I18n.global.locale.value
|
||||||
|
};
|
||||||
|
|
||||||
|
bridge.addCommandListener('setting/save', data => {
|
||||||
|
const saveStatusCode = data.code;
|
||||||
|
pinkLog('配置保存状态:' + saveStatusCode);
|
||||||
|
|
||||||
|
if (saveHandler) {
|
||||||
|
saveHandler();
|
||||||
|
}
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'setting/save',
|
||||||
|
data: saveConfig
|
||||||
|
});
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "إعادة تعيين",
|
"reset": "إعادة تعيين",
|
||||||
"read-resource": "قراءة الموارد",
|
"read-resource": "قراءة الموارد",
|
||||||
"enter": "إدخال",
|
"enter": "إدخال",
|
||||||
"refresh": "تحديث",
|
"blank-test": "اختبار فارغ",
|
||||||
"finish-refresh": "تم التحديث",
|
"connect.appearance.reconnect": "إعادة الاتصال",
|
||||||
|
"connect.appearance.connect": "اتصال",
|
||||||
"response": "الاستجابة",
|
"response": "الاستجابة",
|
||||||
"read-prompt": "استخراج الكلمات الرئيسية",
|
"refresh": "تحديث",
|
||||||
"execute-tool": "تشغيل الأداة"
|
"read-prompt": "قراءة المطالبة",
|
||||||
|
"execute-tool": "تشغيل",
|
||||||
|
"save": "حفظ"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "Zurücksetzen",
|
"reset": "Zurücksetzen",
|
||||||
"read-resource": "Ressourcen lesen",
|
"read-resource": "Ressourcen lesen",
|
||||||
"enter": "Eingabe",
|
"enter": "Eingabe",
|
||||||
"refresh": "Aktualisieren",
|
"blank-test": "Leertest",
|
||||||
"finish-refresh": "Aktualisierung abgeschlossen",
|
"connect.appearance.reconnect": "Neuverbindung",
|
||||||
|
"connect.appearance.connect": "Verbindung",
|
||||||
"response": "Antwort",
|
"response": "Antwort",
|
||||||
"read-prompt": "Stichwörter extrahieren",
|
"refresh": "Aktualisieren",
|
||||||
"execute-tool": "Werkzeug ausführen"
|
"read-prompt": "Prompt lesen",
|
||||||
|
"execute-tool": "Ausführen",
|
||||||
|
"save": "Speichern"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"read-resource": "Read resources",
|
"read-resource": "Read resources",
|
||||||
"enter": "Input",
|
"enter": "Input",
|
||||||
"refresh": "Refresh",
|
"blank-test": "Blank test",
|
||||||
"finish-refresh": "Refresh completed",
|
"connect.appearance.reconnect": "Reconnect",
|
||||||
|
"connect.appearance.connect": "Connection",
|
||||||
"response": "Response",
|
"response": "Response",
|
||||||
"read-prompt": "Extract keywords",
|
"refresh": "Refresh",
|
||||||
"execute-tool": "Run tool"
|
"read-prompt": "Read prompt",
|
||||||
|
"execute-tool": "Run",
|
||||||
|
"save": "Save"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "Réinitialiser",
|
"reset": "Réinitialiser",
|
||||||
"read-resource": "Lire les ressources",
|
"read-resource": "Lire les ressources",
|
||||||
"enter": "Entrée",
|
"enter": "Entrée",
|
||||||
"refresh": "Rafraîchir",
|
"blank-test": "Test vide",
|
||||||
"finish-refresh": "Actualisation terminée",
|
"connect.appearance.reconnect": "Reconnexion",
|
||||||
|
"connect.appearance.connect": "Connexion",
|
||||||
"response": "Réponse",
|
"response": "Réponse",
|
||||||
"read-prompt": "Extraire des mots-clés",
|
"refresh": "Rafraîchir",
|
||||||
"execute-tool": "Exécuter l'outil"
|
"read-prompt": "Lire l'invite",
|
||||||
|
"execute-tool": "Exécuter",
|
||||||
|
"save": "Enregistrer"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "リセット",
|
"reset": "リセット",
|
||||||
"read-resource": "リソースを読み込む",
|
"read-resource": "リソースを読み込む",
|
||||||
"enter": "入力",
|
"enter": "入力",
|
||||||
"refresh": "更新",
|
"blank-test": "空白テスト",
|
||||||
"finish-refresh": "更新が完了しました",
|
"connect.appearance.reconnect": "再接続",
|
||||||
|
"connect.appearance.connect": "接続",
|
||||||
"response": "応答",
|
"response": "応答",
|
||||||
"read-prompt": "キーワードを抽出",
|
"refresh": "更新",
|
||||||
"execute-tool": "ツールを実行"
|
"read-prompt": "プロンプトを読み取る",
|
||||||
|
"execute-tool": "実行",
|
||||||
|
"save": "保存"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "재설정",
|
"reset": "재설정",
|
||||||
"read-resource": "리소스 읽기",
|
"read-resource": "리소스 읽기",
|
||||||
"enter": "입력",
|
"enter": "입력",
|
||||||
"refresh": "새로 고침",
|
"blank-test": "빈 테스트",
|
||||||
"finish-refresh": "새로 고침 완료",
|
"connect.appearance.reconnect": "재연결",
|
||||||
|
"connect.appearance.connect": "연결",
|
||||||
"response": "응답",
|
"response": "응답",
|
||||||
"read-prompt": "키워드 추출",
|
"refresh": "새로 고침",
|
||||||
"execute-tool": "도구 실행"
|
"read-prompt": "프롬프트 읽기",
|
||||||
|
"execute-tool": "실행",
|
||||||
|
"save": "저장"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "Сброс",
|
"reset": "Сброс",
|
||||||
"read-resource": "Чтение ресурсов",
|
"read-resource": "Чтение ресурсов",
|
||||||
"enter": "Ввод",
|
"enter": "Ввод",
|
||||||
"refresh": "Обновить",
|
"blank-test": "Пустой тест",
|
||||||
"finish-refresh": "Обновление завершено",
|
"connect.appearance.reconnect": "Переподключение",
|
||||||
|
"connect.appearance.connect": "Соединение",
|
||||||
"response": "Ответ",
|
"response": "Ответ",
|
||||||
"read-prompt": "Извлечь ключевые слова",
|
"refresh": "Обновить",
|
||||||
"execute-tool": "Запустить инструмент"
|
"read-prompt": "Чтение подсказки",
|
||||||
|
"execute-tool": "Запуск",
|
||||||
|
"save": "Сохранить"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "重置",
|
"reset": "重置",
|
||||||
"read-resource": "读取资源",
|
"read-resource": "读取资源",
|
||||||
"enter": "输入",
|
"enter": "输入",
|
||||||
"refresh": "刷新",
|
"blank-test": "空白测试",
|
||||||
"finish-refresh": "刷新完成",
|
"connect.appearance.reconnect": "重新连接",
|
||||||
|
"connect.appearance.connect": "连接",
|
||||||
"response": "响应",
|
"response": "响应",
|
||||||
"read-prompt": "提取提词",
|
"refresh": "刷新",
|
||||||
"execute-tool": "运行工具"
|
"read-prompt": "读取 prompt",
|
||||||
|
"execute-tool": "运行",
|
||||||
|
"save": "保存"
|
||||||
}
|
}
|
@ -109,9 +109,12 @@
|
|||||||
"reset": "重置",
|
"reset": "重置",
|
||||||
"read-resource": "讀取資源",
|
"read-resource": "讀取資源",
|
||||||
"enter": "輸入",
|
"enter": "輸入",
|
||||||
"refresh": "重新整理",
|
"blank-test": "空白測試",
|
||||||
"finish-refresh": "刷新完成",
|
"connect.appearance.reconnect": "重新連線",
|
||||||
|
"connect.appearance.connect": "連接",
|
||||||
"response": "響應",
|
"response": "響應",
|
||||||
"read-prompt": "提取關鍵詞",
|
"refresh": "重新整理",
|
||||||
"execute-tool": "執行工具"
|
"read-prompt": "讀取提示",
|
||||||
|
"execute-tool": "執行",
|
||||||
|
"save": "儲存"
|
||||||
}
|
}
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { debugModes, tabs } from '@/components/main-panel/panel';
|
import { debugModes, tabs } from '@/components/main-panel/panel';
|
||||||
import { defineComponent, markRaw } from 'vue';
|
import { defineComponent, markRaw, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { connectionResult } from '../connect/connection';
|
import { connectionResult } from '../connect/connection';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
@ -33,22 +33,22 @@ const { t } = useI18n();
|
|||||||
const debugOptions = [
|
const debugOptions = [
|
||||||
{
|
{
|
||||||
icon: 'icon-file',
|
icon: 'icon-file',
|
||||||
name: t("resources"),
|
name: computed(() => t("resources")),
|
||||||
ident: 'resources'
|
ident: 'resources'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon-chat',
|
icon: 'icon-chat',
|
||||||
name: t("prompts"),
|
name: computed(() => t("prompts")),
|
||||||
ident: 'prompts'
|
ident: 'prompts'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon-tool',
|
icon: 'icon-tool',
|
||||||
name: t("tools"),
|
name: computed(() => t("tools")),
|
||||||
ident: 'tool'
|
ident: 'tool'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon-robot',
|
icon: 'icon-robot',
|
||||||
name: t("interaction-test"),
|
name: computed(() => t("interaction-test")),
|
||||||
ident: 'interaction'
|
ident: 'interaction'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -60,7 +60,9 @@ function chooseDebugMode(index: number) {
|
|||||||
const activeTab = tabs.activeTab;
|
const activeTab = tabs.activeTab;
|
||||||
activeTab.component = markRaw(debugModes[index]);
|
activeTab.component = markRaw(debugModes[index]);
|
||||||
activeTab.icon = debugOptions[index].icon;
|
activeTab.icon = debugOptions[index].icon;
|
||||||
activeTab.name = debugOptions[index].name;
|
|
||||||
|
// 此处可以这么做是因为这个操作过后 activeTab 绑定的 tab 的 name 就不会再被进行赋值操作了
|
||||||
|
activeTab.name = debugOptions[index].name as any;
|
||||||
} else {
|
} else {
|
||||||
const message = t('warning.click-to-connect')
|
const message = t('warning.click-to-connect')
|
||||||
.replace('$1', t('connect'));
|
.replace('$1', t('connect'));
|
||||||
|
@ -34,7 +34,9 @@
|
|||||||
<span class="option-title">{{ t('model') }}</span>
|
<span class="option-title">{{ t('model') }}</span>
|
||||||
</span>
|
</span>
|
||||||
<div style="width: 160px;">
|
<div style="width: 160px;">
|
||||||
<el-select name="language-setting" class="language-setting"
|
<el-select
|
||||||
|
v-if="llms[llmManager.currentModelIndex]"
|
||||||
|
name="language-setting" class="language-setting"
|
||||||
v-model="llms[llmManager.currentModelIndex].userModel"
|
v-model="llms[llmManager.currentModelIndex].userModel"
|
||||||
@change="onmodelchange"
|
@change="onmodelchange"
|
||||||
>
|
>
|
||||||
@ -54,6 +56,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<div style="width: 240px;">
|
<div style="width: 240px;">
|
||||||
<el-input
|
<el-input
|
||||||
|
v-if="llms[llmManager.currentModelIndex]"
|
||||||
v-model="llms[llmManager.currentModelIndex].baseUrl"
|
v-model="llms[llmManager.currentModelIndex].baseUrl"
|
||||||
placeholder="https://"
|
placeholder="https://"
|
||||||
/>
|
/>
|
||||||
@ -67,12 +70,21 @@
|
|||||||
</span>
|
</span>
|
||||||
<div style="width: 240px;">
|
<div style="width: 240px;">
|
||||||
<el-input
|
<el-input
|
||||||
|
v-if="llms[llmManager.currentModelIndex]"
|
||||||
v-model="llms[llmManager.currentModelIndex].userToken"
|
v-model="llms[llmManager.currentModelIndex].userToken"
|
||||||
show-password
|
show-password
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="setting-save-container">
|
||||||
|
<el-button type="primary" @click="saveLlmSetting">
|
||||||
|
{{ t('save') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@ -81,14 +93,25 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { llmManager, llms, onmodelchange } from './llm';
|
import { llmManager, llms, onmodelchange } from './llm';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { saveSetting } from '@/hook/setting';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
defineComponent({ name: 'api' });
|
defineComponent({ name: 'api' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
function saveLlmSetting() {
|
||||||
|
saveSetting(() => {
|
||||||
|
ElMessage({
|
||||||
|
message: '成功保存',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.setting-save-container {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -21,6 +21,7 @@
|
|||||||
import { defineComponent, ref } from 'vue';
|
import { defineComponent, ref } from 'vue';
|
||||||
import { languageSetting } from './language';
|
import { languageSetting } from './language';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { saveSetting } from '@/hook/setting';
|
||||||
|
|
||||||
defineComponent({ name: 'appearance' });
|
defineComponent({ name: 'appearance' });
|
||||||
|
|
||||||
@ -34,6 +35,8 @@ function onlanguagechange(code: string) {
|
|||||||
currentLanguage.value = option.text;
|
currentLanguage.value = option.text;
|
||||||
}
|
}
|
||||||
// languageDialogShow.value = true;
|
// languageDialogShow.value = true;
|
||||||
|
|
||||||
|
saveSetting();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,104 +1,13 @@
|
|||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
import { pinkLog } from './util';
|
||||||
|
import { saveSetting } from '@/hook/setting';
|
||||||
|
|
||||||
export const llms = reactive([
|
export const llms = reactive<any[]>([]);
|
||||||
{
|
|
||||||
id: 'deepseek',
|
|
||||||
name: 'DeepSeek',
|
|
||||||
baseUrl: 'https://api.deepseek.com/v1',
|
|
||||||
models: ['deepseek-chat', 'deepseek-coder', 'deepseek-math'],
|
|
||||||
icon: '/images/deepseek.com.ico',
|
|
||||||
provider: 'DeepSeek',
|
|
||||||
isOpenAICompatible: true,
|
|
||||||
description: '深度求索推出的大模型,擅长中文和代码',
|
|
||||||
website: 'https://www.deepseek.com',
|
|
||||||
userToken: '',
|
|
||||||
userModel: 'deepseek-chat'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'openai',
|
|
||||||
name: 'OpenAI',
|
|
||||||
baseUrl: 'https://api.openai.com/v1',
|
|
||||||
models: ['gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'],
|
|
||||||
icon: '/images/openai.com.ico',
|
|
||||||
provider: 'OpenAI',
|
|
||||||
isOpenAICompatible: true,
|
|
||||||
description: 'OpenAI官方API',
|
|
||||||
website: 'https://openai.com',
|
|
||||||
userToken: '',
|
|
||||||
userModel: 'gpt-4-turbo'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'mistral',
|
|
||||||
name: 'Mistral',
|
|
||||||
baseUrl: 'https://api.mistral.ai/v1',
|
|
||||||
models: ['mistral-tiny', 'mistral-small', 'mistral-medium'],
|
|
||||||
icon: '/images/mistral.ai.ico',
|
|
||||||
provider: 'Mistral AI',
|
|
||||||
isOpenAICompatible: true,
|
|
||||||
description: '欧洲开源大模型代表',
|
|
||||||
website: 'https://mistral.ai',
|
|
||||||
userToken: '',
|
|
||||||
userModel: 'mistral-tiny'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ollama',
|
|
||||||
name: 'Ollama (Local)',
|
|
||||||
baseUrl: 'http://localhost:11434/v1',
|
|
||||||
models: ['llama2', 'mistral', 'codellama'],
|
|
||||||
icon: '/images/ollama.png',
|
|
||||||
provider: 'Ollama',
|
|
||||||
isOpenAICompatible: true,
|
|
||||||
description: '本地运行的大模型',
|
|
||||||
website: 'https://ollama.com',
|
|
||||||
userToken: '',
|
|
||||||
userModel: 'llama2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'groq',
|
|
||||||
name: 'Groq',
|
|
||||||
baseUrl: 'https://api.groq.com/openai/v1',
|
|
||||||
models: ['mixtral-8x7b-32768', 'llama2-70b-4096'],
|
|
||||||
icon: '/images/grok.com.png',
|
|
||||||
provider: 'Groq',
|
|
||||||
isOpenAICompatible: true,
|
|
||||||
description: '超高速推理API',
|
|
||||||
website: 'https://groq.com',
|
|
||||||
userToken: '',
|
|
||||||
userModel: 'mixtral-8x7b-32768'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'perplexity',
|
|
||||||
name: 'Perplexity',
|
|
||||||
baseUrl: 'https://api.perplexity.ai/v1',
|
|
||||||
models: ['pplx-7b-online', 'pplx-70b-online'],
|
|
||||||
icon: '/images/perplexity.ai.ico',
|
|
||||||
provider: 'Perplexity AI',
|
|
||||||
isOpenAICompatible: true,
|
|
||||||
description: '联网搜索增强的大模型',
|
|
||||||
website: 'https://www.perplexity.ai',
|
|
||||||
userToken: '',
|
|
||||||
userModel: 'pplx-7b-online'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'kimi',
|
|
||||||
name: 'Kimi Chat',
|
|
||||||
baseUrl: 'https://api.moonshot.cn/v1',
|
|
||||||
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
|
|
||||||
icon: '/images/kimichat.cn.png',
|
|
||||||
provider: '月之暗面 (Moonshot AI)',
|
|
||||||
isOpenAICompatible: true,
|
|
||||||
description: '支持超长上下文的中文大模型,上下文窗口高达128K',
|
|
||||||
website: 'https://kimi.moonshot.cn',
|
|
||||||
userToken: '',
|
|
||||||
userModel: 'moonshot-v1-8k'
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
export const llmManager = reactive({
|
export const llmManager = reactive({
|
||||||
currentModelIndex: 0,
|
currentModelIndex: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function onmodelchange() {
|
export function onmodelchange() {
|
||||||
console.log();
|
pinkLog('切换模型到:' + llms[llmManager.currentModelIndex].id);
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { reactive } from 'vue';
|
import { reactive, computed } from 'vue';
|
||||||
|
|
||||||
import I18n from '@/i18n/index';
|
import I18n from '@/i18n/index';
|
||||||
|
|
||||||
@ -13,11 +13,11 @@ export const settingSections = reactive({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'general',
|
value: 'general',
|
||||||
label: t('general-setting')
|
label: computed(() => t('general-setting'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'appearance',
|
value: 'appearance',
|
||||||
label: t('appearance-setting')
|
label: computed(() => t('appearance-setting'))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
93
test/src/llm.ts
Normal file
93
test/src/llm.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
export const llms = [
|
||||||
|
{
|
||||||
|
id: 'deepseek',
|
||||||
|
name: 'DeepSeek',
|
||||||
|
baseUrl: 'https://api.deepseek.com/v1',
|
||||||
|
models: ['deepseek-chat', 'deepseek-coder', 'deepseek-math'],
|
||||||
|
icon: '/images/deepseek.com.ico',
|
||||||
|
provider: 'DeepSeek',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: '深度求索推出的大模型,擅长中文和代码',
|
||||||
|
website: 'https://www.deepseek.com',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'deepseek-chat'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'openai',
|
||||||
|
name: 'OpenAI',
|
||||||
|
baseUrl: 'https://api.openai.com/v1',
|
||||||
|
models: ['gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'],
|
||||||
|
icon: '/images/openai.com.ico',
|
||||||
|
provider: 'OpenAI',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: 'OpenAI官方API',
|
||||||
|
website: 'https://openai.com',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'gpt-4-turbo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'mistral',
|
||||||
|
name: 'Mistral',
|
||||||
|
baseUrl: 'https://api.mistral.ai/v1',
|
||||||
|
models: ['mistral-tiny', 'mistral-small', 'mistral-medium'],
|
||||||
|
icon: '/images/mistral.ai.ico',
|
||||||
|
provider: 'Mistral AI',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: '欧洲开源大模型代表',
|
||||||
|
website: 'https://mistral.ai',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'mistral-tiny'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ollama',
|
||||||
|
name: 'Ollama (Local)',
|
||||||
|
baseUrl: 'http://localhost:11434/v1',
|
||||||
|
models: ['llama2', 'mistral', 'codellama'],
|
||||||
|
icon: '/images/ollama.png',
|
||||||
|
provider: 'Ollama',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: '本地运行的大模型',
|
||||||
|
website: 'https://ollama.com',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'llama2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'groq',
|
||||||
|
name: 'Groq',
|
||||||
|
baseUrl: 'https://api.groq.com/openai/v1',
|
||||||
|
models: ['mixtral-8x7b-32768', 'llama2-70b-4096'],
|
||||||
|
icon: '/images/grok.com.png',
|
||||||
|
provider: 'Groq',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: '超高速推理API',
|
||||||
|
website: 'https://groq.com',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'mixtral-8x7b-32768'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'perplexity',
|
||||||
|
name: 'Perplexity',
|
||||||
|
baseUrl: 'https://api.perplexity.ai/v1',
|
||||||
|
models: ['pplx-7b-online', 'pplx-70b-online'],
|
||||||
|
icon: '/images/perplexity.ai.ico',
|
||||||
|
provider: 'Perplexity AI',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: '联网搜索增强的大模型',
|
||||||
|
website: 'https://www.perplexity.ai',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'pplx-7b-online'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'kimi',
|
||||||
|
name: 'Kimi Chat',
|
||||||
|
baseUrl: 'https://api.moonshot.cn/v1',
|
||||||
|
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
|
||||||
|
icon: '/images/kimichat.cn.png',
|
||||||
|
provider: '月之暗面 (Moonshot AI)',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: '支持超长上下文的中文大模型,上下文窗口高达128K',
|
||||||
|
website: 'https://kimi.moonshot.cn',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'moonshot-v1-8k'
|
||||||
|
}
|
||||||
|
];
|
@ -1,6 +1,7 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
import { llms } from './llm';
|
||||||
|
|
||||||
function getConfigurationPath() {
|
function getConfigurationPath() {
|
||||||
// 如果是 vscode 插件下,则修改为 ~/.openmcp/config.json
|
// 如果是 vscode 插件下,则修改为 ~/.openmcp/config.json
|
||||||
@ -16,17 +17,23 @@ function getConfigurationPath() {
|
|||||||
return 'config.json';
|
return 'config.json';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDefaultLanguage() {
|
||||||
|
if (process.env.VSCODE_PID) {
|
||||||
|
// TODO: 获取 vscode 内部的语言
|
||||||
|
|
||||||
|
}
|
||||||
|
return 'zh';
|
||||||
|
}
|
||||||
|
|
||||||
interface IConfig {
|
interface IConfig {
|
||||||
MODEL_BASE_URL: string;
|
MODEL_INDEX: number;
|
||||||
MODEL_NAME: string;
|
|
||||||
API_TOKEN: string;
|
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_CONFIG: IConfig = {
|
const DEFAULT_CONFIG: IConfig = {
|
||||||
MODEL_BASE_URL: '',
|
MODEL_INDEX: 0,
|
||||||
MODEL_NAME: '',
|
LLM_INFO: llms,
|
||||||
API_TOKEN: ''
|
LANG: getDefaultLanguage()
|
||||||
};
|
};
|
||||||
|
|
||||||
function createConfig(): IConfig {
|
function createConfig(): IConfig {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user