From f62e8d4ceab2038d71d396e5863094a5b5543eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E8=B0=A2=E9=9B=A8?= <554737215@qq.com> Date: Tue, 18 Feb 2025 11:32:36 +0800 Subject: [PATCH 01/18] =?UTF-8?q?fetch:=20=E9=A1=B5=E9=9D=A2=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 会话模型、向量模型、文生图模型、向量数据库 --- .../ai/model/chatModel/composables/columns.ts | 85 +++++ .../ai/model/chatModel/composables/consts.ts | 198 ++++++++++++ .../model/chatModel/composables/provider.ts | 37 +++ src/views/ai/model/chatModel/edit.vue | 11 + src/views/ai/model/chatModel/index.vue | 298 +++++++----------- .../ai/model/embedStore/composables/index.ts | 116 +++++++ src/views/ai/model/embedStore/index.vue | 26 ++ .../ai/model/embedding/composables/index.ts | 102 ++++++ src/views/ai/model/embedding/index.vue | 26 ++ src/views/ai/model/image/composables/index.ts | 110 +++++++ src/views/ai/model/image/index.vue | 26 ++ 11 files changed, 856 insertions(+), 179 deletions(-) create mode 100644 src/views/ai/model/chatModel/composables/columns.ts create mode 100644 src/views/ai/model/chatModel/composables/consts.ts create mode 100644 src/views/ai/model/chatModel/composables/provider.ts create mode 100644 src/views/ai/model/chatModel/edit.vue create mode 100644 src/views/ai/model/embedStore/composables/index.ts create mode 100644 src/views/ai/model/embedStore/index.vue create mode 100644 src/views/ai/model/embedding/composables/index.ts create mode 100644 src/views/ai/model/embedding/index.vue create mode 100644 src/views/ai/model/image/composables/index.ts create mode 100644 src/views/ai/model/image/index.vue diff --git a/src/views/ai/model/chatModel/composables/columns.ts b/src/views/ai/model/chatModel/composables/columns.ts new file mode 100644 index 0000000..5a8f68f --- /dev/null +++ b/src/views/ai/model/chatModel/composables/columns.ts @@ -0,0 +1,85 @@ +import {ProviderEnum} from './provider'; + +export const baseColumns = [ + { + label: '模型别名', + field: 'name', + }, + { + label: '模型版本', + field: 'model', + width: '140', + }, + { + label: '回复上限', + field: 'responseLimit', + width: '100', + }, + { + label: '生成随机性', + field: 'temperature', + width: '100', + }, + { + label: 'Top P', + field: 'topP', + width: '100', + }, +]; + +export const openaiColumns = [ + ...baseColumns, + { + label: 'Api Key', + field: 'apiKey', + }, +]; + +export const ollamaColumns = [ + ...baseColumns, + { + label: 'Base Url', + field: 'baseUrl', + }, +]; + +export const qfanColumns = [ + ...baseColumns, + { + label: 'Api Key', + field: 'apiKey', + }, +]; + +export const qwenColumns = [ + ...baseColumns, + { + label: 'Api Key', + field: 'apiKey', + }, +]; +export const zhipuColumns = [ + ...baseColumns, + { + label: 'Api Key', + field: 'apiKey', + }, +]; + +export function getColumns(provider: string) { + switch (provider) { + case ProviderEnum.OLLAMA: { + return ollamaColumns; + } + case ProviderEnum.Q_FAN: { + return qfanColumns; + } + case ProviderEnum.Q_WEN: { + return qwenColumns; + } + case ProviderEnum.ZHIPU: { + return zhipuColumns; + } + } + return openaiColumns; +} diff --git a/src/views/ai/model/chatModel/composables/consts.ts b/src/views/ai/model/chatModel/composables/consts.ts new file mode 100644 index 0000000..0b003f5 --- /dev/null +++ b/src/views/ai/model/chatModel/composables/consts.ts @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ProviderEnum } from './provider'; + +export const LLMProviders: any[] = [ + { + model: ProviderEnum.OPENAI, + name: 'OpenAI', + models: ['gpt-3.5-turbo', 'gpt-4', 'gpt-4-32k', 'gpt-4-turbo', 'gpt-4o'], + }, + { + model: ProviderEnum.Q_FAN, + name: '百度千帆', + models: [ + 'ERNIE-Bot', + 'ERNIE-Bot 4.0', + 'ERNIE-Bot-8K', + 'ERNIE-Bot-turbo', + 'ERNIE-Speed-128K', + 'EB-turbo-AppBuilder', + 'Yi-34B-Chat', + 'BLOOMZ-7B', + 'Qianfan-BLOOMZ-7B-compressed', + 'Mixtral-8x7B-Instruct', + 'Llama-2-7b-chat', + 'Llama-2-13b-chat', + 'Llama-2-70b-chat', + 'Qianfan-Chinese-Llama-2-7B', + 'ChatGLM2-6B-32K', + 'AquilaChat-7B', + ], + }, + { + model: ProviderEnum.Q_WEN, + name: '阿里百炼', + models: [ + 'qwen-turbo', + 'qwen-plus', + 'qwen-max', + 'qwen-max-longcontext', + 'qwen-7b-chat', + 'qwen-14b-chat', + 'qwen-72b-chat', + ], + }, + { + model: ProviderEnum.ZHIPU, + name: '智谱清言', + models: [ + 'glm-4', + 'glm-4v', + 'glm-4-air', + 'glm-4-airx', + 'glm-4-flash', + 'glm-3-turbo', + 'chatglm_turbo', + ], + }, + { + model: ProviderEnum.GITEEAI, + name: 'Gitee AI', + models: [ + 'Qwen2-72B-Instruct', + 'Qwen2-7B-Instruct', + 'Qwen2.5-72B-Instruct', + 'glm-4-9b-chat', + 'deepseek-coder-33B-instruct', + 'codegeex4-all-9b', + 'Yi-34B-Chat', + 'code-raccoon-v1', + 'Qwen2.5-Coder-32B-Instruct', + ], + }, + { + model: ProviderEnum.DEEPSEEK, + name: 'DeepSeek', + models: ['deepseek-chat', 'deepseek-coder'], + }, + { + model: ProviderEnum.DOUYIN, + name: '抖音豆包', + models: [], + }, + { + model: ProviderEnum.SILICON, + name: '硅基流动', + models: [ + 'deepseek-ai/DeepSeek-V2-Chat', + 'deepseek-ai/DeepSeek-Coder-V2-Instruct', + 'deepseek-ai/DeepSeek-V2.5', + 'Qwen/Qwen2.5-72B-Instruct-128K', + 'Qwen/Qwen2.5-72B-Instruct', + 'Qwen/Qwen2-VL-72B-Instruct', + 'Qwen/Qwen2.5-32B-Instruct', + 'Qwen/Qwen2.5-14B-Instruct', + 'Qwen/Qwen2.5-7B-Instruct', + 'Qwen/Qwen2.5-Math-72B-Instruct', + 'Qwen/Qwen2.5-Coder-7B-Instruct', + 'Qwen/Qwen2-72B-Instruct', + 'Qwen/Qwen2-7B-Instruct', + 'Qwen/Qwen2-1.5B-Instruct', + 'Qwen/Qwen2-57B-A14B-Instruct', + 'TeleAI/TeleChat2', + '01-ai/Yi-1.5-34B-Chat-16K', + '01-ai/Yi-1.5-9B-Chat-16K', + '01-ai/Yi-1.5-6B-Chat', + 'THUDM/chatglm3-6b', + 'THUDM/glm-4-9b-chat', + 'Vendor-A/Qwen/Qwen2-72B-Instruct', + 'Vendor-A/Qwen/Qwen2.5-72B-Instruct', + 'internlm/internlm2_5-7b-chat', + 'internlm/internlm2_5-20b-chat', + 'OpenGVLab/InternVL2-Llama3-76B', + 'OpenGVLab/InternVL2-26B', + 'nvidia/Llama-3.1-Nemotron-70B-Instruct', + 'meta-llama/Meta-Llama-3.1-405B-Instruct', + 'meta-llama/Meta-Llama-3.1-70B-Instruct', + 'meta-llama/Meta-Llama-3.1-8B-Instruct', + 'meta-llama/Meta-Llama-3-8B-Instruct', + 'meta-llama/Meta-Llama-3-70B-Instruct', + 'google/gemma-2-27b-it', + 'google/gemma-2-9b-it', + 'Pro/Qwen/Qwen2.5-7B-Instruct', + 'Pro/Qwen/Qwen2-7B-Instruct', + 'Pro/Qwen/Qwen2-1.5B-Instruct', + 'Pro/Qwen/Qwen2-VL-7B-Instruct', + 'Pro/01-ai/Yi-1.5-9B-Chat-16K', + 'Pro/01-ai/Yi-1.5-6B-Chat', + 'Pro/THUDM/chatglm3-6b', + 'Pro/THUDM/glm-4-9b-chat', + 'Pro/internlm/internlm2_5-7b-chat', + 'Pro/OpenGVLab/InternVL2-8B', + 'Pro/meta-llama/Meta-Llama-3-8B-Instruct', + 'Pro/meta-llama/Meta-Llama-3.1-8B-Instruct', + 'Pro/google/gemma-2-9b-it', + ], + }, + { + model: ProviderEnum.YI, + name: '零一万物', + models: [ + 'yi-lightning', + 'yi-large', + 'yi-medium', + 'yi-medium-200k', + 'yi-spark', + 'yi-large-rag', + 'yi-large-turbo', + ], + }, + { + model: ProviderEnum.SPARK, + name: '讯飞星火', + // models: ['lite', 'generalv3', 'pro-128k', 'generalv3.5', 'max-32k', '4.0Ultra'], + models: [ + { label: 'Spark Lite', value: 'lite' }, + { label: 'Spark Pro', value: 'generalv3' }, + { label: 'Spark Pro-128K', value: 'pro-128k' }, + { label: 'Spark Max', value: 'generalv3.5' }, + { label: 'Spark Max-32K', value: 'max-32k' }, + { label: 'Spark4.0 Ultra', value: '4.0Ultra' }, + ], + }, + { + model: ProviderEnum.OLLAMA, + name: 'Ollama', + models: [], + }, + { + model: ProviderEnum.AZURE_OPENAI, + name: 'Azure OpenAI', + models: ['gpt-3.5-turbo', 'gpt-4', 'gpt-4-32k', 'gpt-4-turbo', 'gpt-4o'], + }, + { + model: ProviderEnum.GEMINI, + name: 'Gemini', + models: ['gemini-1.5-pro'], + }, + { + model: ProviderEnum.CLAUDE, + name: 'Claude', + models: ['claude-3-opus', 'claude-3-opus-20240229', 'claude-3-sonnet', 'claude-3-haiku'], + }, +]; diff --git a/src/views/ai/model/chatModel/composables/provider.ts b/src/views/ai/model/chatModel/composables/provider.ts new file mode 100644 index 0000000..b956cdf --- /dev/null +++ b/src/views/ai/model/chatModel/composables/provider.ts @@ -0,0 +1,37 @@ +export enum ProviderEnum { + OPENAI = 'OPENAI', + AZURE_OPENAI = 'AZURE_OPENAI', + GEMINI = 'GEMINI', + OLLAMA = 'OLLAMA', + CLAUDE = 'CLAUDE', + Q_FAN = 'Q_FAN', + Q_WEN = 'Q_WEN', + ZHIPU = 'ZHIPU', + GITEEAI = 'GITEEAI', + DEEPSEEK = 'DEEPSEEK', + DOUYIN = 'DOUYIN', + SILICON = 'SILICON', + YI = 'YI', + SPARK = 'SPARK', +} + +export function getModels(provider: string, providers: Array) { + const arr = providers.filter((i) => i.model === provider); + if (arr.length === 0) { + return []; + } + if (typeof arr[0].models[0] === 'string') { + return arr[0].models.map((i) => { + return { + label: i, + value: i, + }; + }); + } else { + return arr[0].models; + } +} + +export function getTitle(provider: string, providers: Array) { + return providers.filter((i) => i.model === provider)[0].name; +} diff --git a/src/views/ai/model/chatModel/edit.vue b/src/views/ai/model/chatModel/edit.vue new file mode 100644 index 0000000..eb92e45 --- /dev/null +++ b/src/views/ai/model/chatModel/edit.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/src/views/ai/model/chatModel/index.vue b/src/views/ai/model/chatModel/index.vue index c550674..541dcf3 100644 --- a/src/views/ai/model/chatModel/index.vue +++ b/src/views/ai/model/chatModel/index.vue @@ -1,185 +1,125 @@ + + + - + diff --git a/src/views/ai/model/embedStore/composables/index.ts b/src/views/ai/model/embedStore/composables/index.ts new file mode 100644 index 0000000..1d5a2eb --- /dev/null +++ b/src/views/ai/model/embedStore/composables/index.ts @@ -0,0 +1,116 @@ +import {ref} from "vue"; +import {FormSchema} from "@/types/form"; +import {ElTag} from "element-plus"; + +export enum ProviderEnum { + Redis = 'REDIS', + PgVector = 'PGVECTOR', + Milvus = 'MILVUS', +} + + +export default function () { + const ProviderConst = [ + { label: 'Redis', value: ProviderEnum.Redis }, + { label: 'PgVector', value: ProviderEnum.PgVector }, + { label: 'Milvus', value: ProviderEnum.Milvus }, + ]; + function getProviderLabel(value: any) { + const arr = ProviderConst.filter((i) => i.value === value); + if (arr === undefined || arr.length === 0) { + return value; + } + return arr[0].label; + } + const shema = ref([ + { + label: '模型名称', + field: 'name', + component: 'Input', + colProps: { + span: 6 + }, + } + ]) + const columns = ref([ + { + label: '数据库别名', + field: 'name', + align: 'center', + }, + { + label: '供应商', + field: 'provider', + align: 'center', + width: '120', + render(row) { + return h( + ElTag, + { + type: 'success', + }, + { + default: () => getProviderLabel(row.provider), + } + ); + }, + }, + { + label: '向量纬度', + field: 'dimension', + align: 'center', + width: '80', + render(row) { + return h( + ElTag, + { + size: 'small', + }, + { + default: () => row.dimension, + } + ); + }, + }, + { + label: '数据库地址', + field: 'host', + align: 'center', + width: '110', + }, + { + label: '数据库端口', + field: 'port', + align: 'center', + width: '100', + }, + { + label: '数据库用户名', + field: 'username', + align: 'center', + }, + { + label: '数据库密码', + field: 'password', + align: 'center', + }, + { + label: '数据库名', + field: 'databaseName', + align: 'center', + }, + { + label: '表名称', + field: 'tableName', + align: 'center', + }, + ]) + const tableData = ref([]) + return { + ProviderConst, + getProviderLabel, + shema, + columns, + tableData + } +} diff --git a/src/views/ai/model/embedStore/index.vue b/src/views/ai/model/embedStore/index.vue new file mode 100644 index 0000000..aedef94 --- /dev/null +++ b/src/views/ai/model/embedStore/index.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/views/ai/model/embedding/composables/index.ts b/src/views/ai/model/embedding/composables/index.ts new file mode 100644 index 0000000..e7c73f5 --- /dev/null +++ b/src/views/ai/model/embedding/composables/index.ts @@ -0,0 +1,102 @@ +import {ElTag} from "element-plus"; +import {ref} from "vue"; +import {ProviderEnum} from "@/views/ai/model/chatModel/composables/provider"; +import {FormSchema} from "@/types/form"; + +export default function () { + const LLMProviders: any[] = [ + { + model: ProviderEnum.OPENAI, + name: 'OpenAI', + models: ['text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002'], + }, + { + model: ProviderEnum.Q_FAN, + name: '百度千帆', + models: ['bge-large-zh', 'bge-large-en', 'tao-8k'], + }, + { + model: ProviderEnum.Q_WEN, + name: '阿里百炼', + models: ['text-embedding-v3'], + }, + { + model: ProviderEnum.ZHIPU, + name: '智谱清言', + models: ['embedding-2', 'embedding-3'], + }, + { + model: ProviderEnum.DOUYIN, + name: '抖音豆包', + models: ['text-240715', 'text-240515'], + }, + { + model: ProviderEnum.OLLAMA, + name: 'Ollama', + models: ['text2vec-bge-large-chinese:latest'], + }, + ]; + const baseColumns = [ + { + label: '模型别名', + field: 'name', + }, + { + label: '模型版本', + field: 'model', + width: '160', + }, + { + label: '向量纬度', + field: 'dimension', + align: 'center', + width: '100', + render(row) { + return h( + ElTag, + { + size: 'small', + }, + { + default: () => row.dimension, + } + ); + }, + }, + { + label: 'Api Key', + field: 'apiKey', + }, + { + label: 'Base Url', + field: 'baseUrl', + }, + ]; + const tableData = ref([ + ]) + const shema = ref([ + { + label: '模型名称', + field: 'name', + component: 'Select', + colProps: { + span: 6 + }, + componentProps: { + style: { + width: '150px', + }, + options: LLMProviders.map((item) => ({ + label: item.name, + value: item.model, + })), + }, + + } + ]) + return { + baseColumns, + shema, + tableData + } +} diff --git a/src/views/ai/model/embedding/index.vue b/src/views/ai/model/embedding/index.vue new file mode 100644 index 0000000..8f7ae8f --- /dev/null +++ b/src/views/ai/model/embedding/index.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/views/ai/model/image/composables/index.ts b/src/views/ai/model/image/composables/index.ts new file mode 100644 index 0000000..063e97d --- /dev/null +++ b/src/views/ai/model/image/composables/index.ts @@ -0,0 +1,110 @@ +export default function () { + enum ProviderEnum { + OPENAI = 'OPENAI', + AZURE_OPENAI = 'AZURE_OPENAI', + ZHIPU = 'ZHIPU', + } + + const LLMProviders: any[] = [ + { + model: ProviderEnum.OPENAI, + name: 'OpenAI', + models: ['dall-e-2', 'dall-e-3'], + }, + { + model: ProviderEnum.AZURE_OPENAI, + name: 'Azure OpenAI', + models: ['dall-e-2', 'dall-e-3'], + }, + { + model: ProviderEnum.ZHIPU, + name: '智谱清言', + models: ['cogview-3'], + }, + ] + const formData = ref({ + provider: ProviderEnum.OPENAI, + }); + const tableData = ref([]) + const shema = ref([ + { + field: 'provider', + label: '模型别名', + component: 'Select', + required: true, + componentProps: { + placeholder: '请输入模型别名', + style: { + width: '180px', + }, + options: LLMProviders.map((item) => ({ + label: item.name, + value: item.model, + })), + }, + }, + ]) + + const baseColumns = [ + { + label: '模型别名', + field: 'name', + }, + { + label: '模型版本', + field: 'model', + }, + ]; + + const openaiColumns = [ + ...baseColumns, + { + label: 'Api Key', + field: 'apiKey', + }, + ]; + + const azureOpenaiColumns = [ + ...baseColumns, + { + label: 'Api Key', + field: 'apiKey', + }, + { + label: 'Endpoint', + field: 'endpoint', + }, + { + label: 'Deployment Name', + field: 'azureDeploymentName', + }, + ]; + + const zhipuColumns = [...baseColumns]; + function getColumns(provider: string) { + console.log(provider); + switch (provider) { + case ProviderEnum.OPENAI: { + return openaiColumns; + } + case ProviderEnum.AZURE_OPENAI: { + return azureOpenaiColumns; + } + case ProviderEnum.ZHIPU: { + return zhipuColumns; + } + } + return []; + } + const columns = computed(() => { + nextTick(); + return getColumns(formData.value.provider) + }); + return { + LLMProviders, + columns, + tableData, + shema, + formData + } +} diff --git a/src/views/ai/model/image/index.vue b/src/views/ai/model/image/index.vue new file mode 100644 index 0000000..2ee54bc --- /dev/null +++ b/src/views/ai/model/image/index.vue @@ -0,0 +1,26 @@ + + + + + From eb5af0eec6f9dd1a6ad3688fabaec6aea7bf375f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E8=B0=A2=E9=9B=A8?= <554737215@qq.com> Date: Tue, 18 Feb 2025 16:51:11 +0800 Subject: [PATCH 02/18] =?UTF-8?q?fetch:=20=E9=A1=B5=E9=9D=A2=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 会话模型、向量模型、文生图模型、向量数据库 --- src/components/Form/src/Form.vue | 8 +- src/utils/is.ts | 6 + .../ai/model/chatModel/composables/schemas.ts | 204 ++++++++++++ src/views/ai/model/chatModel/edit.vue | 32 +- src/views/ai/model/chatModel/index.vue | 198 +++++++----- .../ai/model/embedding/composables/consts.ts | 34 ++ .../ai/model/embedding/composables/index.ts | 77 +---- .../ai/model/embedding/composables/schemas.ts | 138 ++++++++ src/views/ai/model/embedding/edit.vue | 41 +++ src/views/ai/model/embedding/index.vue | 67 +++- .../ai/model/image/composables/consts.ts | 22 ++ src/views/ai/model/image/composables/index.ts | 54 +--- .../ai/model/image/composables/schemas.ts | 294 ++++++++++++++++++ src/views/ai/model/image/edit.vue | 41 +++ src/views/ai/model/image/index.vue | 69 +++- 15 files changed, 1081 insertions(+), 204 deletions(-) create mode 100644 src/views/ai/model/chatModel/composables/schemas.ts create mode 100644 src/views/ai/model/embedding/composables/consts.ts create mode 100644 src/views/ai/model/embedding/composables/schemas.ts create mode 100644 src/views/ai/model/embedding/edit.vue create mode 100644 src/views/ai/model/image/composables/consts.ts create mode 100644 src/views/ai/model/image/composables/schemas.ts create mode 100644 src/views/ai/model/image/edit.vue diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index 3acc10a..c7d22dc 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -117,7 +117,10 @@ export default defineComponent({ const getElFormRef = (): ComponentRef => { return unref(elFormRef) as ComponentRef } - + const clearForm = () => { + formModel.value = {} + getElFormRef().resetFields() + } expose({ setValues, formModel, @@ -125,7 +128,8 @@ export default defineComponent({ delSchema, addSchema, setSchema, - getElFormRef + getElFormRef, + clearForm }) // 监听表单结构化数组,重新生成formModel diff --git a/src/utils/is.ts b/src/utils/is.ts index 24d7191..b825013 100644 --- a/src/utils/is.ts +++ b/src/utils/is.ts @@ -116,3 +116,9 @@ export const isImgPath = (path: string): boolean => { export const isEmptyVal = (val: any): boolean => { return val === '' || val === null || val === undefined } +export function isWhitespace(val: unknown) { + return val === ''; +} +export function isNullOrWhitespace(val: unknown) { + return isNullOrUnDef(val) || isWhitespace(val); +} diff --git a/src/views/ai/model/chatModel/composables/schemas.ts b/src/views/ai/model/chatModel/composables/schemas.ts new file mode 100644 index 0000000..c0aab8d --- /dev/null +++ b/src/views/ai/model/chatModel/composables/schemas.ts @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// import { FormSchema } from '@/components/Form'; +import { LLMProviders } from './consts'; +import { getModels, ProviderEnum } from './provider'; +// import { ModelTypeEnum } from '@/api/models'; +import {FormSchema} from "@/types/form"; +import { isNullOrWhitespace } from '@/utils/is'; + +const baseSchemas: FormSchema[] = [ + // { + // field: 'id', + // label: 'ID', + // component: 'Input', + // }, + // { + // field: 'type', + // label: 'type', + // component: 'Input', + // // value: ModelTypeEnum.CHAT, + // }, + { + field: 'provider', + label: 'LLM供应商', + component: 'Select', + // isHidden: true, + componentProps: { + placeholder: 'LLM供应商', + options: LLMProviders, + labelField: 'name', + valueField: 'model', + }, + // rules: [{ required: true, message: '请选择LLM供应商', trigger: ['blur'] }], + }, + { + field: 'name', + label: '模型别名', + component: 'Input', + formItemProps: { + rules: [{ required: true, message: '请输入模型别名', trigger: ['blur'] }] + }, + componentProps: { + placeholder: '请输入模型别名', + }, + }, + { + field: 'apiKey', + label: 'Api Key', + labelMessage: '模型的ApiKey', + component: 'Input', + // rules: [{ required: true, message: '请输入API Key', trigger: ['blur'] }], + componentProps: { + placeholder: '请输入Api Key', + }, + }, + { + field: 'responseLimit', + label: '回复上限', + labelMessage: '控制模型输出的Tokens长度上限。通常 100 Tokens 约等于150个中文汉字', + component: 'Slider', + formItemProps:{ + rules: [{ type: 'number', required: true, message: '请输入回复上限', trigger: ['blur'] }] + }, + componentProps: { + showTooltip: true, + value: 2000, + step: 1, + min: 1, + max: 8192, + }, + }, + { + field: 'temperature', + label: '生成随机性', + labelMessage: '调高参数会使得模型的输出更多样性和创新性,反之降低参数将会减少多样性', + component: 'Slider', + formItemProps: { + rules: [{ type: 'number', required: true, message: '请输入生成随机性', trigger: ['blur'] }] + }, + value:0.2, + componentProps: { + showTooltip: true, + step: 0.05, + min: 0, + max: 2, + }, + }, + { + field: 'topP', + label: 'Top P', + labelMessage: + '模型在生成输出时会从概率最高的词汇开始选择,直到这些词汇的总概率累积达到Top p值。这样可以限制模型只选择这些高概率的词汇,从而控制输出内容的多样性。建议不要与“生成随机性“同时调整', + component: 'Slider', + formItemProps: { + rules: [{ type: 'number', required: true, message: '请输入', trigger: ['blur'] }] + }, + componentProps: { + showTooltip: true, + value: 0.8, + step: 0.1, + min: 0, + max: 1, + }, + }, +]; + +export function getSchemas(provider: string) { + const list = JSON.parse(JSON.stringify(baseSchemas)); + console.log(provider); + const modelSchema: any = { + field: 'model', + label: '模型版本', + labelMessage: '该LLM供应商对应的模型版本号', + component: 'Select', + rules: [{ required: true, message: '请选择模型', trigger: ['blur'] }], + componentProps: { + placeholder: '请选择模型版本(可以手动输入)', + filterable: true, + tag: true, + options: getModels(provider, LLMProviders), + }, + }; + list.splice(1, 0, modelSchema); + + let value: any = undefined; + let labelMessage: any = '模型的基础请求URL地址(或中转地址)'; + let disabled = false; + switch (provider) { + case ProviderEnum.GITEEAI: + disabled = true; + value = 'https://ai.gitee.com/v1'; + labelMessage = '对于Gitee AI,此Url固定不可修改'; + break; + case ProviderEnum.DEEPSEEK: + disabled = true; + value = 'https://api.deepseek.com/v1'; + labelMessage = '对于DeepSeek模型,此Url固定不可修改'; + break; + case ProviderEnum.SILICON: + disabled = true; + value = 'https://api.siliconflow.cn/v1'; + labelMessage = '对于硅基流动模型,此Url固定不可修改'; + break; + case ProviderEnum.DOUYIN: + disabled = true; + value = 'https://ark.cn-beijing.volces.com/api/v3'; + labelMessage = '对于抖音豆包模型,此Url固定不可修改'; + break; + case ProviderEnum.YI: + disabled = true; + value = 'https://api.lingyiwanwu.com/v1'; + labelMessage = '对于零一模型,此Url固定不可修改'; + break; + case ProviderEnum.SPARK: + disabled = true; + value = 'https://spark-api-open.xf-yun.com/v1'; + labelMessage = '对于讯飞星火大模型,此Url固定不可修改'; + break; + } + const baseUlrSchema: any = { + field: 'baseUrl', + label: 'Base Url', + labelMessage, + component: 'Input', + value, + componentProps: { + disabled, + placeholder: '请输入BaseUrl', + }, + rules: [ + { + required: false, + trigger: ['blur'], + validator: (_, value: string) => { + if (!value) { + return; + } + const urlRegex = + /^(https?:\/\/)?((([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|localhost|(\d{1,3}\.){3}\d{1,3})(:\d{1,5})?(\/.*)?)$/; + if (isNullOrWhitespace(value) || urlRegex.test(value)) { + return true; + } + return new Error('URL格式错误'); + }, + }, + ], + }; + list.splice(3, 0, baseUlrSchema); + return list; +} diff --git a/src/views/ai/model/chatModel/edit.vue b/src/views/ai/model/chatModel/edit.vue index eb92e45..603c534 100644 --- a/src/views/ai/model/chatModel/edit.vue +++ b/src/views/ai/model/chatModel/edit.vue @@ -1,9 +1,39 @@ + diff --git a/src/views/ai/model/embedding/composables/consts.ts b/src/views/ai/model/embedding/composables/consts.ts new file mode 100644 index 0000000..a5fc69f --- /dev/null +++ b/src/views/ai/model/embedding/composables/consts.ts @@ -0,0 +1,34 @@ +import {ProviderEnum} from "@/views/ai/model/chatModel/composables/provider"; + +export const LLMProviders: any[] = [ + { + model: ProviderEnum.OPENAI, + name: 'OpenAI', + models: ['text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002'], + }, + { + model: ProviderEnum.Q_FAN, + name: '百度千帆', + models: ['bge-large-zh', 'bge-large-en', 'tao-8k'], + }, + { + model: ProviderEnum.Q_WEN, + name: '阿里百炼', + models: ['text-embedding-v3'], + }, + { + model: ProviderEnum.ZHIPU, + name: '智谱清言', + models: ['embedding-2', 'embedding-3'], + }, + { + model: ProviderEnum.DOUYIN, + name: '抖音豆包', + models: ['text-240715', 'text-240515'], + }, + { + model: ProviderEnum.OLLAMA, + name: 'Ollama', + models: ['text2vec-bge-large-chinese:latest'], + }, +]; diff --git a/src/views/ai/model/embedding/composables/index.ts b/src/views/ai/model/embedding/composables/index.ts index e7c73f5..23a9d75 100644 --- a/src/views/ai/model/embedding/composables/index.ts +++ b/src/views/ai/model/embedding/composables/index.ts @@ -1,49 +1,20 @@ import {ElTag} from "element-plus"; import {ref} from "vue"; import {ProviderEnum} from "@/views/ai/model/chatModel/composables/provider"; -import {FormSchema} from "@/types/form"; export default function () { - const LLMProviders: any[] = [ - { - model: ProviderEnum.OPENAI, - name: 'OpenAI', - models: ['text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002'], - }, - { - model: ProviderEnum.Q_FAN, - name: '百度千帆', - models: ['bge-large-zh', 'bge-large-en', 'tao-8k'], - }, - { - model: ProviderEnum.Q_WEN, - name: '阿里百炼', - models: ['text-embedding-v3'], - }, - { - model: ProviderEnum.ZHIPU, - name: '智谱清言', - models: ['embedding-2', 'embedding-3'], - }, - { - model: ProviderEnum.DOUYIN, - name: '抖音豆包', - models: ['text-240715', 'text-240515'], - }, - { - model: ProviderEnum.OLLAMA, - name: 'Ollama', - models: ['text2vec-bge-large-chinese:latest'], - }, - ]; + const formData = ref({ + provider: ProviderEnum.OPENAI + }) + const editRef = ref() const baseColumns = [ { label: '模型别名', - field: 'name', + field: 'name', }, { label: '模型版本', - field: 'model', + field: 'model', width: '160', }, { @@ -65,38 +36,22 @@ export default function () { }, { label: 'Api Key', - field: 'apiKey', + field: 'apiKey', }, { label: 'Base Url', - field: 'baseUrl', + field: 'baseUrl', }, ]; - const tableData = ref([ - ]) - const shema = ref([ - { - label: '模型名称', - field: 'name', - component: 'Select', - colProps: { - span: 6 - }, - componentProps: { - style: { - width: '150px', - }, - options: LLMProviders.map((item) => ({ - label: item.name, - value: item.model, - })), - }, - - } - ]) + const tableData = ref([]) + const open = () => { + editRef.value.show({provider: formData.value.provider}); + } return { baseColumns, - shema, - tableData + tableData, + formData, + editRef, + open } } diff --git a/src/views/ai/model/embedding/composables/schemas.ts b/src/views/ai/model/embedding/composables/schemas.ts new file mode 100644 index 0000000..3e186ca --- /dev/null +++ b/src/views/ai/model/embedding/composables/schemas.ts @@ -0,0 +1,138 @@ + + + import {FormSchema} from "@/types/form"; +// import { ModelTypeEnum } from '@/api/models'; + import {getModels, ProviderEnum} from "@/views/ai/model/chatModel/composables/provider"; + import {LLMProviders} from "@/views/ai/model/embedding/composables/consts"; +// import { LLMProviders } from './consts'; +const baseSchemas: FormSchema[] = [ + // { + // field: 'id', + // label: 'ID', + // component: 'Input', + // isHidden: true, + // }, + // { + // field: 'type', + // label: 'type', + // component: 'Input', + // isHidden: true, + // value: ModelTypeEnum.EMBEDDING, + // }, + { + field: 'provider', + label: 'LLM供应商', + component: 'Select', + componentProps: { + placeholder: '请选择LLM供应商', + options: LLMProviders, + }, + }, + { + field: 'name', + label: '模型别名', + component: 'Input', + formItemProps: { + rules: [{ required: true, message: '请输入模型别名', trigger: ['blur'] }] + }, + componentProps: { + placeholder: '请输入模型别名', + }, + }, + { + field: 'apiKey', + label: 'Api Key', + labelMessage: '模型的ApiKey', + component: 'Input', + // rules: [{ required: true, message: '请输入ApiKey', trigger: ['blur'] }], + componentProps: { + placeholder: '请输入ApiKey', + }, + }, + { + field: 'dimension', + label: '向量纬度', + component: 'Select', + value: 1024, + labelMessage: '慎重修改此参数,纬度高会消耗更多的算力,但纬度高并不代表搜索更精确', + componentProps: { + placeholder: '请输入向量纬度', + options: [ + { + label: '512', + value: 512, + }, + { + label: '768', + value: 768, + }, + { + label: '1024', + value: 1024, + }, + { + label: '1536', + value: 1536, + }, + ], + }, + formItemProps:{ + rules: [{ type: 'number', required: true, message: '请输入向量纬度', trigger: ['blur'] }] + }, + }, +]; + +export function getSchemas(provider: string) { + const list = JSON.parse(JSON.stringify(baseSchemas)); + + const modelSchema: any = { + field: 'model', + label: '模型版本', + labelMessage: '该LLM供应商对应的模型版本号', + component: 'Select', + rules: [{ required: true, message: '请选择模型', trigger: ['blur'] }], + componentProps: { + placeholder: '请选择模型版本', + filterable: true, + tag: true, + options: getModels(provider, LLMProviders), + }, + }; + list.splice(list.length, 0, modelSchema); + + let value: any = undefined; + let labelMessage: any = '模型的基础请求URL地址(或中转地址)'; + let disabled = false; + switch (provider) { + case ProviderEnum.DOUYIN: + disabled = true; + value = 'https://ark.cn-beijing.volces.com/api/v3'; + labelMessage = '对于抖音豆包模型,此Url固定不可修改'; + break; + case ProviderEnum.Q_FAN: + disabled = true; + labelMessage = '对于百度千帆模型,此Url固定不可修改'; + break; + case ProviderEnum.Q_WEN: + disabled = true; + labelMessage = '对于阿里千问模型,此Url固定不可修改'; + break; + case ProviderEnum.ZHIPU: + disabled = true; + labelMessage = '对于智谱清言模型,此Url固定不可修改'; + break; + } + const baseUlrSchema: any = { + field: 'baseUrl', + label: 'Base Url', + labelMessage, + component: 'Input', + value, + componentProps: { + disabled, + placeholder: '请输入BaseUrl', + }, + }; + list.splice(list.length, 0, baseUlrSchema); + return list; +} diff --git a/src/views/ai/model/embedding/edit.vue b/src/views/ai/model/embedding/edit.vue new file mode 100644 index 0000000..c9c3be4 --- /dev/null +++ b/src/views/ai/model/embedding/edit.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/views/ai/model/embedding/index.vue b/src/views/ai/model/embedding/index.vue index 8f7ae8f..8a0e5f6 100644 --- a/src/views/ai/model/embedding/index.vue +++ b/src/views/ai/model/embedding/index.vue @@ -2,25 +2,68 @@ import {Plus} from "@element-plus/icons-vue"; import usePage from './composables/index' -const {shema, baseColumns: columns, tableData} = usePage() +import Edit from "@/views/ai/model/embedding/edit.vue"; +import {LLMProviders} from "@/views/ai/model/embedding/composables/consts"; +import {Table} from "@/components/Table"; +const { baseColumns: columns, tableData, formData, editRef, open} = usePage() diff --git a/src/views/ai/model/image/composables/consts.ts b/src/views/ai/model/image/composables/consts.ts new file mode 100644 index 0000000..56a95fa --- /dev/null +++ b/src/views/ai/model/image/composables/consts.ts @@ -0,0 +1,22 @@ +export enum ProviderEnum { + OPENAI = 'OPENAI', + AZURE_OPENAI = 'AZURE_OPENAI', + ZHIPU = 'ZHIPU', +} +export const LLMProviders: any[] = [ + { + model: ProviderEnum.OPENAI, + name: 'OpenAI', + models: ['dall-e-2', 'dall-e-3'], + }, + { + model: ProviderEnum.AZURE_OPENAI, + name: 'Azure OpenAI', + models: ['dall-e-2', 'dall-e-3'], + }, + { + model: ProviderEnum.ZHIPU, + name: '智谱清言', + models: ['cogview-3'], + }, +] diff --git a/src/views/ai/model/image/composables/index.ts b/src/views/ai/model/image/composables/index.ts index 063e97d..4d4689e 100644 --- a/src/views/ai/model/image/composables/index.ts +++ b/src/views/ai/model/image/composables/index.ts @@ -1,49 +1,12 @@ -export default function () { - enum ProviderEnum { - OPENAI = 'OPENAI', - AZURE_OPENAI = 'AZURE_OPENAI', - ZHIPU = 'ZHIPU', - } +import {ProviderEnum} from "@/views/ai/model/image/composables/consts"; - const LLMProviders: any[] = [ - { - model: ProviderEnum.OPENAI, - name: 'OpenAI', - models: ['dall-e-2', 'dall-e-3'], - }, - { - model: ProviderEnum.AZURE_OPENAI, - name: 'Azure OpenAI', - models: ['dall-e-2', 'dall-e-3'], - }, - { - model: ProviderEnum.ZHIPU, - name: '智谱清言', - models: ['cogview-3'], - }, - ] +export default function () { + + const editRef= ref() const formData = ref({ provider: ProviderEnum.OPENAI, }); const tableData = ref([]) - const shema = ref([ - { - field: 'provider', - label: '模型别名', - component: 'Select', - required: true, - componentProps: { - placeholder: '请输入模型别名', - style: { - width: '180px', - }, - options: LLMProviders.map((item) => ({ - label: item.name, - value: item.model, - })), - }, - }, - ]) const baseColumns = [ { @@ -100,11 +63,14 @@ export default function () { nextTick(); return getColumns(formData.value.provider) }); + const open = () => { + editRef.value.show({provider: formData.value.provider}); + } return { - LLMProviders, columns, tableData, - shema, - formData + formData, + editRef, + open } } diff --git a/src/views/ai/model/image/composables/schemas.ts b/src/views/ai/model/image/composables/schemas.ts new file mode 100644 index 0000000..7079885 --- /dev/null +++ b/src/views/ai/model/image/composables/schemas.ts @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {FormSchema} from '@/types/form'; +// import { LLMProviders, ProviderEnum } from './data'; +// import { ModelTypeEnum } from '@/api/models'; +import {isNullOrWhitespace} from '@/utils/is'; +import {LLMProviders, ProviderEnum} from "@/views/ai/model/image/composables/consts"; + +const baseHeadSchemas: FormSchema[] = [ + // { + // field: 'id', + // label: 'ID', + // component: 'Input', + // isHidden: true, + // }, + // { + // field: 'type', + // label: 'type', + // component: 'Input', + // isHidden: true, + // defaultValue: ModelTypeEnum.TEXT_IMAGE, + // }, + { + field: 'provider', + label: 'LLM供应商', + component: 'Select', + componentProps: { + options: LLMProviders, + labelField: 'name', + valueField: 'model', + }, + formItemProps: {rules: [{required: true, message: '请选择LLM供应商', trigger: ['blur']}]}, + }, + { + field: 'name', + label: '模型别名', + component: 'Input', + formItemProps: {rules: [{required: true, message: '请输入模型别名', trigger: ['blur']}]}, + }, +]; +const keySchemas: FormSchema[] = [ + { + field: 'apiKey', + label: 'Api Key', + labelMessage: '模型链接的秘钥,注意有些模型例如Gemini是本地认证方式,则不是通过这种方式', + component: 'Input', + formItemProps: {rules: [{required: true, message: '请输入API Key', trigger: ['blur']}]}, + }, + { + field: 'baseUrl', + label: 'Base Url', + labelMessage: '注意对于大多数模型此参数仅代表中转地址,但是对于Ollama这类本地模型则是必填的', + component: 'Input', + formItemProps: { + rules: [ + { + required: false, + trigger: ['blur'], + validator: (_, value: string) => { + const urlRegex = /^(https?:\/\/)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(\/.*)?$/; + if (isNullOrWhitespace(value) || urlRegex.test(value)) { + return true; + } + return new Error('URL格式错误'); + }, + }, + ] + }, + }, +]; + +export const openaiSchemas: FormSchema[] = [ + ...baseHeadSchemas, + { + field: 'model', + label: '模型', + labelMessage: '该LLM供应商对应的模型版本号', + component: 'Select', + formItemProps: { + rules: [{required: true, message: '请选择模型', trigger: ['blur']}] + }, + componentProps: { + filterable: true, + options: getModels(ProviderEnum.OPENAI), + }, + }, + { + field: 'imageSize', + label: '图片大小', + labelMessage: '生成图片的大小尺寸', + component: 'Select', + formItemProps: { + rules: [{required: true, message: '请选择图片大小', trigger: ['blur']}] + }, + componentProps: { + options: [ + { + label: '1024x1024', + value: '1024x1024', + }, + { + label: '1024x1792', + value: '1024x1792', + }, + { + label: '1792x1024', + value: '1792x1024', + }, + ], + }, + }, + { + field: 'imageQuality', + label: '图片质量', + labelMessage: '生成图片的质量', + component: 'Select', + formItemProps: { + rules: [{required: true, message: '请选择图片的质量', trigger: ['blur']}] + }, + componentProps: { + options: [ + { + label: 'standard', + value: 'standard', + }, + { + label: 'hd', + value: 'hd', + }, + ], + }, + }, + { + field: 'imageStyle', + label: '图片风格', + labelMessage: '生成图片的风格', + component: 'Select', + formItemProps: { + rules: [{required: true, message: '请选择图片的风格', trigger: ['blur']}] + }, + componentProps: { + options: [ + { + label: 'vivid', + value: 'vivid', + }, + { + label: 'natural', + value: 'natural', + }, + ], + }, + }, + ...keySchemas, +]; + +export const azureOpenaiSchemas: FormSchema[] = [ + ...baseHeadSchemas, + { + field: 'model', + label: '模型', + labelMessage: '该LLM供应商对应的模型版本号', + component: 'Select', + formItemProps: { + rules: [{required: true, message: '请选择模型', trigger: ['blur']}] + }, + componentProps: { + filterable: true, + options: getModels(ProviderEnum.AZURE_OPENAI), + }, + }, + { + field: 'imageSize', + label: '图片大小', + labelMessage: '生成图片的大小尺寸', + component: 'Select', + formItemProps: { + rules: [{required: true, message: '请选择图片大小', trigger: ['blur']}] + }, + componentProps: { + options: [ + { + label: '1024x1024', + value: '1024x1024', + }, + { + label: '1024x1792', + value: '1024x1792', + }, + { + label: '1792x1024', + value: '1792x1024', + }, + ], + }, + }, + { + field: 'imageQuality', + label: '图片质量', + labelMessage: '生成图片的质量', + component: 'Select', + formItemProps: {rules: [{required: true, message: '请选择图片的质量', trigger: ['blur']}]}, + componentProps: { + options: [ + { + label: 'standard', + value: 'standard', + }, + { + label: 'hd', + value: 'hd', + }, + ], + }, + }, + { + field: 'imageStyle', + label: '图片风格', + labelMessage: '生成图片的风格', + component: 'Select', + formItemProps: {rules: [{required: true, message: '请选择图片的风格', trigger: ['blur']}]}, + componentProps: { + options: [ + { + label: 'vivid', + value: 'vivid', + }, + { + label: 'natural', + value: 'natural', + }, + ], + }, + }, + ...keySchemas, +]; + +export const zhipuSchemas: FormSchema[] = [ + ...baseHeadSchemas, + { + field: 'model', + label: '模型', + labelMessage: '该LLM供应商对应的模型版本号', + component: 'Select', + formItemProps: {rules: [{required: true, message: '请选择模型', trigger: ['blur']}]}, + componentProps: { + filterable: true, + options: getModels(ProviderEnum.ZHIPU), + }, + }, + ...keySchemas, +]; + +export function getSchemas(provider: string) { + switch (provider) { + case ProviderEnum.OPENAI: { + return openaiSchemas; + } + case ProviderEnum.AZURE_OPENAI: { + return azureOpenaiSchemas; + } + case ProviderEnum.ZHIPU: { + return zhipuSchemas; + } + } + return []; +} + +export function getModels(provider: string) { + const arr = LLMProviders.filter((i) => i.model === provider); + if (arr.length === 0) { + return []; + } + return arr[0].models.map((i) => { + return { + label: i, + value: i, + }; + }); +} diff --git a/src/views/ai/model/image/edit.vue b/src/views/ai/model/image/edit.vue new file mode 100644 index 0000000..d3b9744 --- /dev/null +++ b/src/views/ai/model/image/edit.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/views/ai/model/image/index.vue b/src/views/ai/model/image/index.vue index 2ee54bc..0c09ebb 100644 --- a/src/views/ai/model/image/index.vue +++ b/src/views/ai/model/image/index.vue @@ -2,25 +2,70 @@ import {Plus} from "@element-plus/icons-vue"; import usePage from './composables/index' -const {shema, columns, tableData, formData} = usePage() +import {LLMProviders} from "@/views/ai/model/image/composables/consts"; +import Edit from './edit.vue' + +const {columns, tableData, formData, editRef, open} = usePage() From cbc3f3296a99daac4f4bf08cc48e821dbc9aafc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E8=B0=A2=E9=9B=A8?= <554737215@qq.com> Date: Tue, 18 Feb 2025 18:04:21 +0800 Subject: [PATCH 03/18] =?UTF-8?q?fetch:=20=E9=A1=B5=E9=9D=A2=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 会话模型、向量模型、文生图模型、向量数据库 --- src/views/ai/model/chatModel/index.vue | 2 +- src/views/ai/model/embedding/index.vue | 2 +- src/views/ai/model/image/index.vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/ai/model/chatModel/index.vue b/src/views/ai/model/chatModel/index.vue index 9ef6a32..dacbec3 100644 --- a/src/views/ai/model/chatModel/index.vue +++ b/src/views/ai/model/chatModel/index.vue @@ -167,7 +167,7 @@ function handleDel(record: any) { margin-bottom: 20px; &.active { color: #ffffff; - background-color: var(--el-color-primary-light-3); + background-color: var(--el-color-primary); } &:hover { diff --git a/src/views/ai/model/embedding/index.vue b/src/views/ai/model/embedding/index.vue index 8a0e5f6..f510bca 100644 --- a/src/views/ai/model/embedding/index.vue +++ b/src/views/ai/model/embedding/index.vue @@ -57,7 +57,7 @@ const { baseColumns: columns, tableData, formData, editRef, open} = usePage() &.active { color: #ffffff; - background-color: var(--el-color-primary-light-3); + background-color: var(--el-color-primary); } &:hover { diff --git a/src/views/ai/model/image/index.vue b/src/views/ai/model/image/index.vue index 0c09ebb..f402948 100644 --- a/src/views/ai/model/image/index.vue +++ b/src/views/ai/model/image/index.vue @@ -59,7 +59,7 @@ const {columns, tableData, formData, editRef, open} = usePage() &.active { color: #ffffff; - background-color: var(--el-color-primary-light-3); + background-color: var(--el-color-primary); } &:hover { From a92e21767b490332e9b2b99df6392e84f426956d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E8=B0=A2=E9=9B=A8?= <554737215@qq.com> Date: Wed, 19 Feb 2025 15:25:35 +0800 Subject: [PATCH 04/18] =?UTF-8?q?fetch:=20=E9=A1=B5=E9=9D=A2=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 知识库列表,知识库数据页面 --- src/components/UploadFile/src/UploadFile.vue | 6 +- .../dataset-form/components/data-cut.vue | 78 ++++++++ .../dataset-form/components/data-document.vue | 84 +++++++++ .../components/data-embedding.vue | 48 +++++ .../dataset-form/components/data-import.vue | 11 ++ .../knowledge/dataset-form/form-step1.vue | 151 ---------------- .../knowledge/dataset-form/form-step2.vue | 168 ------------------ src/views/knowledge/dataset-form/index.vue | 104 +++++++++++ src/views/knowledge/dataset.vue | 16 +- 9 files changed, 340 insertions(+), 326 deletions(-) create mode 100644 src/views/knowledge/dataset-form/components/data-cut.vue create mode 100644 src/views/knowledge/dataset-form/components/data-document.vue create mode 100644 src/views/knowledge/dataset-form/components/data-embedding.vue create mode 100644 src/views/knowledge/dataset-form/components/data-import.vue delete mode 100644 src/views/knowledge/dataset-form/form-step1.vue delete mode 100644 src/views/knowledge/dataset-form/form-step2.vue create mode 100644 src/views/knowledge/dataset-form/index.vue diff --git a/src/components/UploadFile/src/UploadFile.vue b/src/components/UploadFile/src/UploadFile.vue index 9d0a904..10cfda8 100644 --- a/src/components/UploadFile/src/UploadFile.vue +++ b/src/components/UploadFile/src/UploadFile.vue @@ -22,13 +22,13 @@ > - 选取文件 + {{ props.drag ? '拖拽或' : ''}}选取文件 diff --git a/src/views/knowledge/dataset-form/components/data-cut.vue b/src/views/knowledge/dataset-form/components/data-cut.vue new file mode 100644 index 0000000..6dc7be6 --- /dev/null +++ b/src/views/knowledge/dataset-form/components/data-cut.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/views/knowledge/dataset-form/components/data-document.vue b/src/views/knowledge/dataset-form/components/data-document.vue new file mode 100644 index 0000000..2a41c1b --- /dev/null +++ b/src/views/knowledge/dataset-form/components/data-document.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/src/views/knowledge/dataset-form/components/data-embedding.vue b/src/views/knowledge/dataset-form/components/data-embedding.vue new file mode 100644 index 0000000..9dfc8f8 --- /dev/null +++ b/src/views/knowledge/dataset-form/components/data-embedding.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/views/knowledge/dataset-form/components/data-import.vue b/src/views/knowledge/dataset-form/components/data-import.vue new file mode 100644 index 0000000..18b9fde --- /dev/null +++ b/src/views/knowledge/dataset-form/components/data-import.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/src/views/knowledge/dataset-form/form-step1.vue b/src/views/knowledge/dataset-form/form-step1.vue deleted file mode 100644 index ef3579e..0000000 --- a/src/views/knowledge/dataset-form/form-step1.vue +++ /dev/null @@ -1,151 +0,0 @@ - - - - - diff --git a/src/views/knowledge/dataset-form/form-step2.vue b/src/views/knowledge/dataset-form/form-step2.vue deleted file mode 100644 index f8ca571..0000000 --- a/src/views/knowledge/dataset-form/form-step2.vue +++ /dev/null @@ -1,168 +0,0 @@ - - - - - diff --git a/src/views/knowledge/dataset-form/index.vue b/src/views/knowledge/dataset-form/index.vue new file mode 100644 index 0000000..73084e0 --- /dev/null +++ b/src/views/knowledge/dataset-form/index.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/views/knowledge/dataset.vue b/src/views/knowledge/dataset.vue index 4636a91..4614cf3 100644 --- a/src/views/knowledge/dataset.vue +++ b/src/views/knowledge/dataset.vue @@ -11,9 +11,12 @@ - +
- + + + 接口鉴权示例代码.md
@@ -45,9 +48,11 @@ From 2fd76aa5b9c398b970665b4d460b1c43662b02ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E8=B0=A2=E9=9B=A8?= <554737215@qq.com> Date: Thu, 27 Feb 2025 17:16:12 +0800 Subject: [PATCH 06/18] =?UTF-8?q?fetch:=20=E9=A1=B5=E9=9D=A2=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 会话模型、向量模型、文生图模型接口对接 --- src/api/new-ai/docs.ts | 61 ++++++ src/api/new-ai/embed-store.ts | 101 ++++++++++ src/api/new-ai/embedding.ts | 81 ++++++++ src/api/new-ai/knowledge.ts | 40 ++++ src/api/new-ai/model.ts | 40 ++++ src/api/new-ai/slice.ts | 56 ++++++ src/components/Form/src/Form.vue | 5 +- .../ai/model/chatModel/composables/columns.ts | 6 +- .../ai/model/chatModel/composables/consts.ts | 6 + src/views/ai/model/chatModel/edit.vue | 49 ++++- src/views/ai/model/chatModel/index.vue | 176 ++++++++---------- .../ai/model/embedStore/composables/index.ts | 70 ++++--- src/views/ai/model/embedStore/edit.vue | 146 +++++++++++++++ src/views/ai/model/embedStore/index.vue | 17 +- .../ai/model/embedding/composables/index.ts | 69 ++++++- src/views/ai/model/embedding/edit.vue | 47 ++++- src/views/ai/model/embedding/index.vue | 21 ++- src/views/ai/model/image/composables/index.ts | 97 +++++++--- src/views/ai/model/image/edit.vue | 52 ++++-- src/views/ai/model/image/index.vue | 48 +++-- .../dataset-form/components/data-cut.vue | 63 ++++++- .../dataset-form/components/data-document.vue | 100 +++++++--- src/views/knowledge/dataset-form/index.vue | 51 +++-- src/views/knowledge/dataset.vue | 141 ++++++++------ 24 files changed, 1226 insertions(+), 317 deletions(-) create mode 100644 src/api/new-ai/docs.ts create mode 100644 src/api/new-ai/embed-store.ts create mode 100644 src/api/new-ai/embedding.ts create mode 100644 src/api/new-ai/knowledge.ts create mode 100644 src/api/new-ai/model.ts create mode 100644 src/api/new-ai/slice.ts create mode 100644 src/views/ai/model/embedStore/edit.vue diff --git a/src/api/new-ai/docs.ts b/src/api/new-ai/docs.ts new file mode 100644 index 0000000..d42e777 --- /dev/null +++ b/src/api/new-ai/docs.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import request from '@/config/axios' + +// AI 文档 VO +export interface DocsVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 文档 API +export const DocsApi = { + // 获得文档分页 + async getDocsPage(params: any) { + return await request.get({ url: '/aigc/docs/page', params }) + }, + + // 获得文档列表 + async getDocsList(params: any) { + return await request.get({ url: '/aigc/docs/list', params }) + }, + + // 获得文档详情 + async getDocsById(id: string) { + return await request.get({ url: `/aigc/docs/${id}` }) + }, + + // 创建文档 + async addDocs(data: any) { + return await request.post({ url: '/aigc/docs', data }) + }, + + // 更新文档 + async updateDocs(data: any) { + return await request.put({ url: '/aigc/docs', data }) + }, + + // 删除文档 + async deleteDocs(id: string) { + return await request.delete({ url: `/aigc/docs/${id}` }) + }, + + // 重新向量化 + async reEmbedDocs(id: string) { + return await request.get({ url: `/aigc/embedding/re-embed/${id}` }) + } +} diff --git a/src/api/new-ai/embed-store.ts b/src/api/new-ai/embed-store.ts new file mode 100644 index 0000000..a67e929 --- /dev/null +++ b/src/api/new-ai/embed-store.ts @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import request from '@/config/axios' + +// AI 嵌入存储 VO +export interface EmbedStoreVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 嵌入存储 API +export const EmbedStoreApi = { + // 获得嵌入存储列表 + getEmbedStoreList: async (params: any) => { + return await request.get({ url: '/aigc/embed-store/list', params }) + }, + + // 获得嵌入存储分页 + getEmbedStorePage: async (params: any) => { + return await request.get({ url: '/aigc/embed-store/page', params }) + }, + + // 获得嵌入存储详情 + getEmbedStore: async (id: string) => { + return await request.get({ url: `/aigc/embed-store/${id}` }) + }, + + // 创建嵌入存储 + createEmbedStore: async (data: any) => { + return await request.post({ url: '/aigc/embed-store', data }) + }, + + // 更新嵌入存储 + updateEmbedStore: async (data: any) => { + return await request.put({ url: '/aigc/embed-store', data }) + }, + + // 删除嵌入存储 + deleteEmbedStore: async (id: string) => { + return await request.delete({ url: `/aigc/embed-store/${id}` }) + } +} +// export function list(params: any) { +// return http.request({ +// url: '/aigc/embed-store/list', +// method: 'get', +// params, +// }); +// } + +// export function page(params: any) { +// return http.request({ +// url: '/aigc/embed-store/page', +// method: 'get', +// params, +// }); +// } + +// export function getById(id: string) { +// return http.request({ +// url: `/aigc/embed-store/${id}`, +// method: 'get', +// }); +// } + +// export function add(params: any) { +// return http.request({ +// url: '/aigc/embed-store', +// method: 'post', +// params, +// }); +// } + +// export function update(params: any) { +// return http.request({ +// url: '/aigc/embed-store', +// method: 'put', +// params, +// }); +// } + +// export function del(id?: string) { +// return http.request({ +// url: `/aigc/embed-store/${id}`, +// method: 'delete', +// }); +// } diff --git a/src/api/new-ai/embedding.ts b/src/api/new-ai/embedding.ts new file mode 100644 index 0000000..4a8326a --- /dev/null +++ b/src/api/new-ai/embedding.ts @@ -0,0 +1,81 @@ +import request from '@/config/axios' +import { AxiosProgressEvent } from 'axios' + +// AI 嵌入 API +export const EmbeddingApi = { + // 文本嵌入 + embeddingText: async (params: any) => { + return await request.post({ url: '/aigc/embedding/text', params }) + }, + + // 嵌入搜索 + embeddingSearch: async (data: any) => { + return await request.post({ url: '/aigc/embedding/search', data }) + }, + + // 文档嵌入 + embeddingDocs: async ( + knowledgeId: string, + data: any, + onUploadProgress?: (progressEvent: AxiosProgressEvent) => void + ) => { + return await request.post({ + url: `/aigc/embedding/docs/${knowledgeId}`, + data, + headers: { + 'Content-Type': 'multipart/form-data' + }, + onUploadProgress + }) + } +} +// /* +// * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. +// * +// * Licensed under the GNU Affero General Public License, Version 3 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * https://www.gnu.org/licenses/agpl-3.0.html +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ + +// import { http } from '@/utils/http/axios'; +// import { AxiosProgressEvent } from 'axios'; + +// export function embeddingText(params: any) { +// return http.request({ +// url: '/aigc/embedding/text', +// method: 'post', +// params, +// }); +// } + +// export function embeddingSearch(data: any) { +// return http.request({ +// url: '/aigc/embedding/search', +// method: 'post', +// data, +// }); +// } + +// export function embeddingDocs( +// knowledgeId: string, +// data: any, +// onUploadProgress?: (progressEvent: AxiosProgressEvent) => void +// ) { +// return http.request({ +// url: `/aigc/embedding/docs/${knowledgeId}`, +// method: 'post', +// data, +// headers: { +// 'Content-Type': 'multipart/form-data', +// }, +// onUploadProgress, +// }); +// } diff --git a/src/api/new-ai/knowledge.ts b/src/api/new-ai/knowledge.ts new file mode 100644 index 0000000..755f834 --- /dev/null +++ b/src/api/new-ai/knowledge.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +// AI 知识库 VO +export interface KnowledgeVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 知识库 API +export const KnowledgeApi = { + // 获得知识库列表 + getKnowledgeList: async (params: any) => { + return await request.get({ url: '/aigc/knowledge/list', params }) + }, + + // 获得知识库分页 + getKnowledgePage: async (params: any) => { + return await request.get({ url: '/aigc/knowledge/page', params }) + }, + + // 获得知识库详情 + getKnowledge: async (id: string) => { + return await request.get({ url: `/aigc/knowledge/${id}` }) + }, + + // 创建知识库 + createKnowledge: async (data: any) => { + return await request.post({ url: '/aigc/knowledge', data }) + }, + + // 更新知识库 + updateKnowledge: async (data: any) => { + return await request.put({ url: '/aigc/knowledge', data }) + }, + + // 删除知识库 + deleteKnowledge: async (id: string) => { + return await request.delete({ url: `/aigc/knowledge/${id}` }) + } +} \ No newline at end of file diff --git a/src/api/new-ai/model.ts b/src/api/new-ai/model.ts new file mode 100644 index 0000000..2aefc33 --- /dev/null +++ b/src/api/new-ai/model.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +// AI 模型 VO +export interface ModelVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 模型 API +export const ModelApi = { + // 获得模型分页 + getModelPage: async (params: any) => { + return await request.get({ url: '/chat/aigc/model/page', params }) + }, + + // 获得模型列表 + getModelList: async (params: any) => { + return await request.get({ url: '/chat/aigc/model/list', params }) + }, + + // 获得模型详情 + getModel: async (id: string) => { + return await request.get({ url: `/chat/aigc/model/${id}` }) + }, + + // 创建模型 + createModel: async (data: any) => { + return await request.post({ url: '/chat/aigc/model', data }) + }, + + // 更新模型 + updateModel: async (data: any) => { + return await request.put({ url: '/chat/aigc/model', data }) + }, + + // 删除模型 + deleteModel: async (id: string) => { + return await request.delete({ url: `/chat/aigc/model/${id}` }) + } +} \ No newline at end of file diff --git a/src/api/new-ai/slice.ts b/src/api/new-ai/slice.ts new file mode 100644 index 0000000..bd7947e --- /dev/null +++ b/src/api/new-ai/slice.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import request from '@/config/axios' + +// AI 文档切片 VO +export interface SliceVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 文档切片 API +export const SliceApi = { + // 获得切片分页 + getSlicePage: async (params: any) => { + return await request.get({ url: '/aigc/docs/slice/page', params }) + }, + + // 获得切片列表 + getSliceList: async (params: any) => { + return await request.get({ url: '/aigc/docs/slice/list', params }) + }, + + // 获得切片详情 + getSlice: async (id: string) => { + return await request.get({ url: `/aigc/docs/slice/${id}` }) + }, + + // 创建切片 + createSlice: async (data: any) => { + return await request.post({ url: '/aigc/docs/slice', data }) + }, + + // 更新切片 + updateSlice: async (data: any) => { + return await request.put({ url: '/aigc/docs/slice', data }) + }, + + // 删除切片 + deleteSlice: async (id: string) => { + return await request.delete({ url: `/aigc/docs/slice/${id}` }) + } +} diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index c7d22dc..4d59f03 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -191,7 +191,7 @@ export default defineComponent({ ) { slotsMap.default = () => renderOptions(item) } - + const formItemSlots: Recordable = setFormItemSlots(slots, item.field) // 如果有 labelMessage,自动使用插槽渲染 if (item?.labelMessage) { @@ -230,6 +230,7 @@ export default defineComponent({ return slots[item.field] ? ( getSlot(slots, item.field, formModel.value) ) : ( + <> {{ ...slotsMap }} + + ) } }} diff --git a/src/views/ai/model/chatModel/composables/columns.ts b/src/views/ai/model/chatModel/composables/columns.ts index 5a8f68f..d6d18f4 100644 --- a/src/views/ai/model/chatModel/composables/columns.ts +++ b/src/views/ai/model/chatModel/composables/columns.ts @@ -81,5 +81,9 @@ export function getColumns(provider: string) { return zhipuColumns; } } - return openaiColumns; + return [...openaiColumns, { + label: '操作', + field: 'action', + width: '150', + }]; } diff --git a/src/views/ai/model/chatModel/composables/consts.ts b/src/views/ai/model/chatModel/composables/consts.ts index 0b003f5..3b11bc0 100644 --- a/src/views/ai/model/chatModel/composables/consts.ts +++ b/src/views/ai/model/chatModel/composables/consts.ts @@ -196,3 +196,9 @@ export const LLMProviders: any[] = [ models: ['claude-3-opus', 'claude-3-opus-20240229', 'claude-3-sonnet', 'claude-3-haiku'], }, ]; +export enum ModelTypeEnum { + CHAT = 'CHAT', + EMBEDDING = 'EMBEDDING', + TEXT_IMAGE = 'TEXT_IMAGE', + WEB_SEARCH = 'WEB_SEARCH', +} \ No newline at end of file diff --git a/src/views/ai/model/chatModel/edit.vue b/src/views/ai/model/chatModel/edit.vue index 603c534..6a74c4f 100644 --- a/src/views/ai/model/chatModel/edit.vue +++ b/src/views/ai/model/chatModel/edit.vue @@ -1,25 +1,55 @@ diff --git a/src/views/ai/model/chatModel/index.vue b/src/views/ai/model/chatModel/index.vue index dacbec3..aac7055 100644 --- a/src/views/ai/model/chatModel/index.vue +++ b/src/views/ai/model/chatModel/index.vue @@ -3,14 +3,12 @@ import {Table} from '@/components/Table'; import {Delete, Edit, Plus} from '@element-plus/icons-vue'; import editCom from './edit.vue'; -import {computed, h, nextTick, reactive, ref} from 'vue'; -import {getColumns} from './composables/columns.ts'; -import {LLMProviders} from './composables/consts.ts'; -// import { del, list as getModels } from '@/api/aigc/model'; +import {computed, h, nextTick, reactive, ref, watch, onMounted} from 'vue'; +import {getColumns} from './composables/columns'; +import {LLMProviders, ModelTypeEnum} from './composables/consts'; +import {ModelApi} from '@/api/new-ai/model'; import {ElMessage, ElMessageBox} from 'element-plus'; -import {FormSchema} from "@/types/form"; -// import { ModelTypeEnum } from '@/api/models'; -import {getModels, ProviderEnum} from './composables/provider.ts'; +import {getModels, ProviderEnum} from './composables/provider'; const formData = ref({ provider: ProviderEnum.OPENAI @@ -19,129 +17,101 @@ const message = ElMessage; const dialog = ElMessageBox; const actionRef = ref(); const editRef = ref(); -const tableData = ref([ - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, { - name: '1111' - }, - { - name: '1111' +const tableData = ref([]); +const loading = ref(false); +// 获取模型列表 +const loadData = async () => { + loading.value = true; + try { + const res = await ModelApi.getModelList({ + provider: formData.value.provider, + type: ModelTypeEnum.CHAT + }).finally(() => { + loading.value = false; + }); + console.log(res) + tableData.value = res; + } catch (error) { + console.error('Failed to load models:', error); + message.error('获取模型列表失败'); } -]) -// const actionColumn = reactive({ -// width: 100, -// title: '操作', -// key: 'action', -// fixed: 'right', -// align: 'center', -// render(record: any) { -// return h(TableAction as any, { -// style: 'text', -// actions: [ -// { -// type: 'info', -// icon: Edit, -// onClick: handleEdit.bind(null, record), -// }, -// { -// type: 'error', -// icon: Delete, -// onClick: handleDel.bind(null, record), -// }, -// ], -// }); -// }, -// }); +}; + +// 监听 provider 变化重新加载数据 +watch(() => formData.value.provider, () => { + loadData(); +}); + +// 初始加载 +onMounted(() => { + loadData(); +}); const columns = computed(() => { nextTick(); return getColumns(formData.value.provider); }); -// const loadDataTable = async (params: any) => { -// if (formData.value.provider === '') { -// formData.value.provider = LLMProviders[0].model; -// } -// return await getModels({ ...params, provider: formData.value.provider, type: ModelTypeEnum.CHAT }); -// }; async function addModel() { console.log(formData.value.provider); - editRef.value.show({provider: formData.value.provider}); + editRef.value.show({provider: formData.value.provider, type: ModelTypeEnum.CHAT }); } function handleEdit(record: any) { editRef.value.show(record); } -function reloadTable() { - actionRef.value.reload(); +async function reloadTable() { + await loadData(); } -function handleDel(record: any) { - dialog.warning({ - title: '警告', - message: `你确定删除 [${record.name}] 模型吗?删除之后不可再用该模型对话`, +async function handleDel(record: any) { + dialog.confirm('确定要删除该模型吗?', '警告', { confirmButtonText: '确定', - cancelButtonText: '不确定', + cancelButtonText: '取消', type: 'warning', }).then(async () => { - await del(record.id); - reloadTable(); - message.success('模型删除成功'); + try { + await ModelApi.deleteModel(record.id); + await reloadTable(); + message.success('模型删除成功'); + } catch (error) { + console.error('Failed to delete model:', error); + message.error('删除模型失败'); + } }).catch(() => { - // 取消删除 }); } diff --git a/src/views/ai/model/embedStore/composables/index.ts b/src/views/ai/model/embedStore/composables/index.ts index 1d5a2eb..90c66f8 100644 --- a/src/views/ai/model/embedStore/composables/index.ts +++ b/src/views/ai/model/embedStore/composables/index.ts @@ -1,20 +1,25 @@ import {ref} from "vue"; import {FormSchema} from "@/types/form"; import {ElTag} from "element-plus"; +import {EmbedStoreApi} from "@/api/new-ai/embed-store"; export enum ProviderEnum { Redis = 'REDIS', PgVector = 'PGVECTOR', Milvus = 'MILVUS', } - - +export const ProviderConst = [ + { label: 'Redis', value: ProviderEnum.Redis }, + { label: 'PgVector', value: ProviderEnum.PgVector }, + { label: 'Milvus', value: ProviderEnum.Milvus }, +]; export default function () { const ProviderConst = [ { label: 'Redis', value: ProviderEnum.Redis }, { label: 'PgVector', value: ProviderEnum.PgVector }, { label: 'Milvus', value: ProviderEnum.Milvus }, ]; + function getProviderLabel(value: any) { const arr = ProviderConst.filter((i) => i.value === value); if (arr === undefined || arr.length === 0) { @@ -22,6 +27,7 @@ export default function () { } return arr[0].label; } + const shema = ref([ { label: '模型名称', @@ -32,6 +38,7 @@ export default function () { }, } ]) + const columns = ref([ { label: '数据库别名', @@ -59,7 +66,7 @@ export default function () { label: '向量纬度', field: 'dimension', align: 'center', - width: '80', + width: '100', render(row) { return h( ElTag, @@ -76,7 +83,6 @@ export default function () { label: '数据库地址', field: 'host', align: 'center', - width: '110', }, { label: '数据库端口', @@ -85,32 +91,46 @@ export default function () { width: '100', }, { - label: '数据库用户名', - field: 'username', + label: '数据库名称', + field: 'database', align: 'center', }, - { - label: '数据库密码', - field: 'password', - align: 'center', - }, - { - label: '数据库名', - field: 'databaseName', - align: 'center', - }, - { - label: '表名称', - field: 'tableName', - align: 'center', - }, - ]) + ]); + const tableData = ref([]) + const editRef = ref() + const searchParams = ref({}) + + // 加载数据 + const loadData = async () => { + try { + const res = await EmbedStoreApi.getEmbedStorePage(searchParams.value); + tableData.value = res.data.list; + } catch (error) { + console.error('Failed to load embed stores:', error); + } + } + + // 打开编辑对话框 + const open = () => { + editRef.value.show({}); + } + + // 处理搜索 + const handleSearch = (values: any) => { + searchParams.value = values; + loadData(); + } + return { - ProviderConst, - getProviderLabel, shema, columns, - tableData + tableData, + editRef, + open, + loadData, + handleSearch, + ProviderConst, + getProviderLabel } } diff --git a/src/views/ai/model/embedStore/edit.vue b/src/views/ai/model/embedStore/edit.vue new file mode 100644 index 0000000..e0abcc8 --- /dev/null +++ b/src/views/ai/model/embedStore/edit.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/src/views/ai/model/embedStore/index.vue b/src/views/ai/model/embedStore/index.vue index aedef94..1cb17e9 100644 --- a/src/views/ai/model/embedStore/index.vue +++ b/src/views/ai/model/embedStore/index.vue @@ -1,13 +1,21 @@ diff --git a/src/views/ai/model/embedding/composables/index.ts b/src/views/ai/model/embedding/composables/index.ts index 23a9d75..a6b14dd 100644 --- a/src/views/ai/model/embedding/composables/index.ts +++ b/src/views/ai/model/embedding/composables/index.ts @@ -1,12 +1,18 @@ -import {ElTag} from "element-plus"; -import {ref} from "vue"; +import {ref, watch} from "vue"; import {ProviderEnum} from "@/views/ai/model/chatModel/composables/provider"; +import {ModelApi} from "@/api/new-ai/model"; +import {ElTag, ElMessageBox as dialog, ElMessage as message} from "element-plus"; +import { ModelTypeEnum } from "../../chatModel/composables/consts"; + export default function () { - const formData = ref({ - provider: ProviderEnum.OPENAI - }) const editRef = ref() + const formData = ref({ + provider: ProviderEnum.OPENAI, + type: ModelTypeEnum.EMBEDDING + }); + const tableData = ref([]) + const baseColumns = [ { label: '模型别名', @@ -19,7 +25,7 @@ export default function () { }, { label: '向量纬度', - field: 'dimension', + field: 'dimension', align: 'center', width: '100', render(row) { @@ -41,17 +47,60 @@ export default function () { { label: 'Base Url', field: 'baseUrl', - }, + }, {label: '操作', field: 'action', width: 150} ]; - const tableData = ref([]) + + // 加载数据 + const loadData = async () => { + try { + const res = await ModelApi.getModelList({ provider: formData.value.provider, type: ModelTypeEnum.EMBEDDING }); + tableData.value = res; + } catch (error) { + console.error('Failed to load embedding models:', error); + } + } + + // 监听供应商变化 + watch(() => formData.value.provider, () => { + loadData(); + }, { immediate: true }); + const open = () => { - editRef.value.show({provider: formData.value.provider}); + editRef.value.show({provider: formData.value.provider, type: ModelTypeEnum.EMBEDDING}); + } + function handleEdit(record: any) { + editRef.value.show(record); + } + + async function reloadTable() { + await loadData(); + } + + async function handleDel(record: any) { + dialog.confirm('确定要删除该模型吗?', '警告', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + }).then(async () => { + try { + await ModelApi.deleteModel(record.id); + await reloadTable(); + message.success('模型删除成功'); + } catch (error) { + console.error('Failed to delete model:', error); + message.error('删除模型失败'); + } + }).catch(() => { + }); } return { baseColumns, tableData, formData, editRef, - open + open, + loadData, + handleDel, + handleEdit } } diff --git a/src/views/ai/model/embedding/edit.vue b/src/views/ai/model/embedding/edit.vue index c9c3be4..853b827 100644 --- a/src/views/ai/model/embedding/edit.vue +++ b/src/views/ai/model/embedding/edit.vue @@ -1,25 +1,59 @@ diff --git a/src/views/ai/model/embedding/index.vue b/src/views/ai/model/embedding/index.vue index f510bca..aaed469 100644 --- a/src/views/ai/model/embedding/index.vue +++ b/src/views/ai/model/embedding/index.vue @@ -1,11 +1,15 @@ diff --git a/src/views/ai/model/image/composables/index.ts b/src/views/ai/model/image/composables/index.ts index 4d4689e..d7550e1 100644 --- a/src/views/ai/model/image/composables/index.ts +++ b/src/views/ai/model/image/composables/index.ts @@ -1,51 +1,55 @@ +import {computed, nextTick, ref, watch} from "vue"; import {ProviderEnum} from "@/views/ai/model/image/composables/consts"; +import {ModelApi} from "@/api/new-ai/model"; +import { ModelTypeEnum } from "../../chatModel/composables/consts"; +import {ElTag, ElMessageBox as dialog, ElMessage as message} from "element-plus"; export default function () { - - const editRef= ref() + const editRef = ref() const formData = ref({ provider: ProviderEnum.OPENAI, + type: ModelTypeEnum.TEXT_IMAGE }); const tableData = ref([]) - const baseColumns = [ + const baseColumns = [ { - label: '模型别名', - field: 'name', + label: '模型别名', + field: 'name', }, { - label: '模型版本', - field: 'model', + label: '模型版本', + field: 'model', }, ]; - const openaiColumns = [ + const openaiColumns = [ ...baseColumns, { - label: 'Api Key', - field: 'apiKey', + label: 'Api Key', + field: 'apiKey', }, ]; - const azureOpenaiColumns = [ + const azureOpenaiColumns = [ ...baseColumns, { - label: 'Api Key', - field: 'apiKey', + label: 'Api Key', + field: 'apiKey', }, { - label: 'Endpoint', - field: 'endpoint', + label: 'Endpoint', + field: 'endpoint', }, { - label: 'Deployment Name', - field: 'azureDeploymentName', + label: 'Deployment Name', + field: 'azureDeploymentName', }, ]; - const zhipuColumns = [...baseColumns]; + const zhipuColumns = [...baseColumns]; + function getColumns(provider: string) { - console.log(provider); switch (provider) { case ProviderEnum.OPENAI: { return openaiColumns; @@ -56,21 +60,68 @@ export default function () { case ProviderEnum.ZHIPU: { return zhipuColumns; } + default: { + return baseColumns; + } } - return []; } + const columns = computed(() => { nextTick(); - return getColumns(formData.value.provider) + return [...getColumns(formData.value.provider), {label: '操作', field: 'action', width: 150}] }); + + // 加载数据 + const loadData = async () => { + try { + const res = await ModelApi.getModelList({ provider: formData.value.provider, type: ModelTypeEnum.TEXT_IMAGE }); + tableData.value = res; + } catch (error) { + console.error('Failed to load image models:', error); + } + } + + // 监听供应商变化 + watch(() => formData.value.provider, () => { + loadData(); + }, { immediate: true }); + const open = () => { - editRef.value.show({provider: formData.value.provider}); + editRef.value.show({provider: formData.value.provider, type: ModelTypeEnum.TEXT_IMAGE}); + } + function handleEdit(record: any) { + editRef.value.show(record); + } + + async function reloadTable() { + await loadData(); + } + + async function handleDel(record: any) { + dialog.confirm('确定要删除该模型吗?', '警告', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + }).then(async () => { + try { + await ModelApi.deleteModel(record.id); + await reloadTable(); + message.success('模型删除成功'); + } catch (error) { + console.error('Failed to delete model:', error); + message.error('删除模型失败'); + } + }).catch(() => { + }); } return { columns, tableData, formData, editRef, - open + open, + loadData, + handleDel, + handleEdit } } diff --git a/src/views/ai/model/image/edit.vue b/src/views/ai/model/image/edit.vue index d3b9744..ee9a6ab 100644 --- a/src/views/ai/model/image/edit.vue +++ b/src/views/ai/model/image/edit.vue @@ -1,25 +1,55 @@ - diff --git a/src/views/ai/model/image/index.vue b/src/views/ai/model/image/index.vue index f402948..c55649e 100644 --- a/src/views/ai/model/image/index.vue +++ b/src/views/ai/model/image/index.vue @@ -1,11 +1,16 @@ @@ -51,21 +62,18 @@ const {columns, tableData, formData, editRef, open} = usePage() } .menu { - transition: all .15s; + padding: 10px; + margin-bottom: 10px; + border-radius: 6px; cursor: pointer; - padding: 12px 10px; - border-radius: 5px; - margin-bottom: 20px; - - &.active { - color: #ffffff; - background-color: var(--el-color-primary); - } &:hover { - &:not(&.active) { - background-color: var(--el-color-info-light-7); - } + background: var(--el-fill-color-light); + } + + &.active { + background: var(--el-color-primary-light-9); + color: var(--el-color-primary); } } diff --git a/src/views/knowledge/dataset-form/components/data-cut.vue b/src/views/knowledge/dataset-form/components/data-cut.vue index 6dc7be6..c4c4957 100644 --- a/src/views/knowledge/dataset-form/components/data-cut.vue +++ b/src/views/knowledge/dataset-form/components/data-cut.vue @@ -1,6 +1,17 @@ diff --git a/src/views/knowledge/dataset-form/index.vue b/src/views/knowledge/dataset-form/index.vue index 3938fc3..9bfb21b 100644 --- a/src/views/knowledge/dataset-form/index.vue +++ b/src/views/knowledge/dataset-form/index.vue @@ -1,13 +1,19 @@ - diff --git a/src/views/knowledge/dataset.vue b/src/views/knowledge/dataset.vue index 4614cf3..5cf915a 100644 --- a/src/views/knowledge/dataset.vue +++ b/src/views/knowledge/dataset.vue @@ -1,7 +1,7 @@ - + diff --git a/src/views/knowledge/dataset-form/components/data-document.vue b/src/views/knowledge/dataset-form/components/data-document.vue index ca6f8a2..b3cd144 100644 --- a/src/views/knowledge/dataset-form/components/data-document.vue +++ b/src/views/knowledge/dataset-form/components/data-document.vue @@ -1,84 +1,93 @@ - + diff --git a/src/views/knowledge/dataset-form/components/data-embedding.vue b/src/views/knowledge/dataset-form/components/data-embedding.vue index 9dfc8f8..30a420d 100644 --- a/src/views/knowledge/dataset-form/components/data-embedding.vue +++ b/src/views/knowledge/dataset-form/components/data-embedding.vue @@ -1,48 +1,79 @@ -