完成全部配置的保存

This commit is contained in:
huangzhelong.byte 2025-04-05 17:34:22 +08:00
parent 05080e2b72
commit 3d372dafae
22 changed files with 335 additions and 203 deletions

View File

@ -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);
} }

View File

@ -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);

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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,

View File

@ -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
});
} }

View File

@ -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": "حفظ"
} }

View File

@ -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"
} }

View File

@ -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"
} }

View File

@ -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"
} }

View File

@ -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": "保存"
} }

View File

@ -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": "저장"
} }

View File

@ -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": "Сохранить"
} }

View File

@ -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": "保存"
} }

View File

@ -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": "儲存"
} }

View File

@ -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'));

View File

@ -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>

View File

@ -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>

View File

@ -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);
} }

View File

@ -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
View 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'
}
];

View File

@ -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 {