From 8db214371a43268eb1283bf6eaddd45ce05f1c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=98=93?= <105188049+xiaoyiweb@users.noreply.github.com> Date: Sun, 28 Jan 2024 18:41:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Egpt-4V=E4=B8=8A=E4=BC=A0=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 10244 -> 14340 bytes admin/.env.example | 10 +- admin/package.json | 2 +- admin/src/constants/index.ts | 437 ++++++++++-------- admin/src/views/models/key.vue | 33 ++ chat/src/api/index.ts | 4 +- chat/src/assets/file.jpeg | Bin 0 -> 26293 bytes chat/src/layout/components/Login/Email.vue | 4 + chat/src/store/modules/chat/index.ts | 393 ++++++++-------- chat/src/views/chat/chatBase.vue | 346 +++++++++----- .../views/chat/components/Message/Text.vue | 48 +- .../views/chat/components/Message/index.vue | 22 +- service/.DS_Store | Bin 14340 -> 14340 bytes service/src/.DS_Store | Bin 10244 -> 10244 bytes service/src/main.ts | 2 +- service/src/modules/chatLog/chatLog.entity.ts | 3 + .../src/modules/chatLog/chatLog.service.ts | 4 +- .../src/modules/chatgpt/chatgpt.service.ts | 12 +- service/src/modules/chatgpt/openai.ts | 6 +- service/src/modules/chatgpt/store.ts | 241 ++++++---- .../modules/midjourney/midjourney.service.ts | 136 +++--- .../src/modules/models/dto/setModel.dto.ts | 2 + service/src/modules/models/models.entity.ts | 3 + service/src/modules/queue/queue.service.ts | 12 +- .../userBalance/userBalance.service.ts | 8 +- service/templates/.DS_Store | Bin 0 -> 6148 bytes 26 files changed, 1043 insertions(+), 685 deletions(-) create mode 100644 chat/src/assets/file.jpeg create mode 100644 service/templates/.DS_Store diff --git a/.DS_Store b/.DS_Store index 350aaf6ce1a39cea5a7b2c5b0564bd78b89606c6..8d3c13a8e7fbece35076dc8a5ec1edf2bc2bca3c 100644 GIT binary patch literal 14340 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 delta 456 zcmZoEXbF&DU|?W$DortDU{C-uIe-{M3-C-V6q~3gIoZI3MHI+qkO5*wpg2QLx?yl~ zes00Wi)QQ-9~5q8=V0Mrl$p$zz13ieu~d z`tXTBt0waZNU=dUlXV1Sm>D7hCVLC4n4BZwHrY~8G@cV;fH)r`v&6cl%@-wX**KclM_mTH>VurfWG#6vHi*DvD|tmG zwFQ%7<=1U|@ReDR8SE1V1#Tei3W|k|7r!%4<~Px0WSDHiqdYmmgq>3Zqy`uj29tA4 LCT{*E!ORQ*J@$Hu diff --git a/admin/.env.example b/admin/.env.example index c23da78..aeabaea 100644 --- a/admin/.env.example +++ b/admin/.env.example @@ -1,6 +1,6 @@ -# 本地链接生产# xxx填写你的后端服务地址后面/api勿删除 -VITE_GLOB_API_URL=https://xxx/api +# 页面标题 +VITE_APP_TITLE = YiAi-Admin +# 接口请求地址,会设置到 axios 的 baseURL 参数上 生产地址测试 - -VITE_GLOB_OPEN_LONG_REPLY=false -VITE_GLOB_APP_PWA=false +VITE_APP_API_BASEURL = https://xxxx/api +VITE_BASE_PATH=/ diff --git a/admin/package.json b/admin/package.json index e503f13..7768325 100644 --- a/admin/package.json +++ b/admin/package.json @@ -1,5 +1,5 @@ { - "version": "2.4.5", + "version": "2.4.0", "scripts": { "dev": "vite", "build:test": "vue-tsc --noEmit && vite build --mode test", diff --git a/admin/src/constants/index.ts b/admin/src/constants/index.ts index dfc7454..7fdc558 100644 --- a/admin/src/constants/index.ts +++ b/admin/src/constants/index.ts @@ -1,305 +1,350 @@ export const USER_STATUS_OPTIONS = [ - { value: 0, label: '待激活' }, - { value: 1, label: '正常' }, - { value: 2, label: '已封禁' }, - { value: 3, label: '黑名单' }, -] + { value: 0, label: "待激活" }, + { value: 1, label: "正常" }, + { value: 2, label: "已封禁" }, + { value: 3, label: "黑名单" }, +]; export const USER_STATUS_MAP = { - 0: '待激活', - 1: '正常', - 2: '已封禁', - 3: '黑名单', -} + 0: "待激活", + 1: "正常", + 2: "已封禁", + 3: "黑名单", +}; export const USER_STATUS_TYPE_MAP = { - 0: 'info', - 1: 'success', - 2: 'danger', - 3: 'danger', -} + 0: "info", + 1: "success", + 2: "danger", + 3: "danger", +}; // 充值类型map 1: 注册赠送 2: 受邀请赠送 3: 邀请人赠送 4: 购买套餐赠送 5: 管理员赠送 6:扫码支付 7: 绘画失败退款 8: 签到奖励 export const RECHARGE_TYPE_MAP = { - 1: '注册赠送', - 2: '受邀请赠送', - 3: '邀请人赠送', - 4: '购买套餐赠送', - 5: '管理员赠送', - 6: '扫码支付', - 7: '绘画失败退款', - 8: '签到奖励', -} + 1: "注册赠送", + 2: "受邀请赠送", + 3: "邀请人赠送", + 4: "购买套餐赠送", + 5: "管理员赠送", + 6: "扫码支付", + 7: "绘画失败退款", + 8: "签到奖励", +}; // 充值数组 export const RECHARGE_TYPE_OPTIONS = [ - { value: 1, label: '注册赠送' }, - { value: 2, label: '受邀请赠送' }, - { value: 3, label: '邀请人赠送' }, - { value: 4, label: '购买套餐赠送' }, - { value: 5, label: '管理员赠送' }, - { value: 6, label: '扫码支付' }, - { value: 7, label: '绘画失败退款' }, - { value: 8, label: '签到奖励' }, -] + { value: 1, label: "注册赠送" }, + { value: 2, label: "受邀请赠送" }, + { value: 3, label: "邀请人赠送" }, + { value: 4, label: "购买套餐赠送" }, + { value: 5, label: "管理员赠送" }, + { value: 6, label: "扫码支付" }, + { value: 7, label: "绘画失败退款" }, + { value: 8, label: "签到奖励" }, +]; -export type UserStatus = keyof typeof USER_STATUS_TYPE_MAP +export type UserStatus = keyof typeof USER_STATUS_TYPE_MAP; // 是否开启额外赠送 export const IS_OPTIONS = { - 0: '关闭', - 1: '开启', -} + 0: "关闭", + 1: "开启", +}; // 是否开启额外赠送类型 export const IS_TYPE_MAP = { - 0: 'danger', - 1: 'success', -} + 0: "danger", + 1: "success", +}; export const PACKAGE_TYPE_OPTIONS = [ - { value: 0, label: '禁用' }, - { value: 1, label: '启动' }, -] + { value: 0, label: "禁用" }, + { value: 1, label: "启动" }, +]; // 扣费形式 1: 按次数扣费 2:按Token扣费 export const DEDUCTION_TYPE_OPTIONS = [ - { value: 1, label: '按次数扣费' }, - { value: 2, label: '按Token扣费' }, -] + { value: 1, label: "按次数扣费" }, + { value: 2, label: "按Token扣费" }, +]; // 扣费形式 map export const DEDUCTION_TYPE_MAP = { - 1: '按次数扣费', - 2: '按Token扣费', -} + 1: "按次数扣费", + 2: "按Token扣费", +}; export const CRAMI_STATUS_OPTIONS = [ - { value: 0, label: '未使用' }, - { value: 1, label: '已使用' }, -] + { value: 0, label: "未使用" }, + { value: 1, label: "已使用" }, +]; // 图片推荐状态0未推荐1已推荐 export const RECOMMEND_STATUS_OPTIONS = [ - { value: 0, label: '未推荐' }, - { value: 1, label: '已推荐' }, -] + { value: 0, label: "未推荐" }, + { value: 1, label: "已推荐" }, +]; // 0 禁用 1 启用 export const ENABLE_STATUS_OPTIONS = [ - { value: 0, label: '禁用' }, - { value: 1, label: '启用' }, - { value: 3, label: '待审核' }, - { value: 4, label: '拒绝共享' }, - { value: 5, label: '通过共享' }, -] + { value: 0, label: "禁用" }, + { value: 1, label: "启用" }, + { value: 3, label: "待审核" }, + { value: 4, label: "拒绝共享" }, + { value: 5, label: "通过共享" }, +]; // 问题状态 0 未解决 1 已解决 export const QUESTION_STATUS_OPTIONS = [ - { value: '0', label: '未启用' }, - { value: '1', label: '已启用' }, -] + { value: "0", label: "未启用" }, + { value: "1", label: "已启用" }, +]; // 问题状态 0 未解决 1 已解决 export const ORDER_STATUS_OPTIONS = [ - { value: 0, label: '待审核' }, - { value: 1, label: '已通过' }, - { value: -1, label: '已拒绝' }, -] + { value: 0, label: "待审核" }, + { value: 1, label: "已通过" }, + { value: -1, label: "已拒绝" }, +]; // 0:未推荐 1:已推荐 数组 export const RECOMMEND_STATUS = [ - { value: 0, label: '未推荐' }, - { value: 1, label: '已推荐' }, -] + { value: 0, label: "未推荐" }, + { value: 1, label: "已推荐" }, +]; // 提现渠道 支付宝 微信 export const WITHDRAW_CHANNEL_OPTIONS = [ - { value: 1, label: '支付宝' }, - { value: 2, label: '微信' }, -] + { value: 1, label: "支付宝" }, + { value: 2, label: "微信" }, +]; // 1 排队中 2 处理中 3 已完成 4 失败 5 超时 export const WITHDRAW_STATUS_OPTIONS = [ - { value: 1, label: '正在排队' }, - { value: 2, label: '正在绘制' }, - { value: 3, label: '绘制完成' }, - { value: 4, label: '绘制失败' }, - { value: 5, label: '绘制超时' }, -] + { value: 1, label: "正在排队" }, + { value: 2, label: "正在绘制" }, + { value: 3, label: "绘制完成" }, + { value: 4, label: "绘制失败" }, + { value: 5, label: "绘制超时" }, +]; // 0 禁用 warning 1启用 状态 success export const ENABLE_STATUS_TYPE_MAP: QuestionStatusMap = { - 0: 'danger', - 1: 'success', -} + 0: "danger", + 1: "success", +}; interface QuestionStatusMap { - [key: number]: string + [key: number]: string; } // 问题状态 0 未解决 1 已解决 映射 export const QUESTION_STATUS_MAP: QuestionStatusMap = { - '-1': '欠费锁定', - '0': '未启用', - '1': '已启用', - '3': '待审核', - '4': '拒绝共享', - '5': '通过共享', -} + "-1": "欠费锁定", + "0": "未启用", + "1": "已启用", + "3": "待审核", + "4": "拒绝共享", + "5": "通过共享", +}; // 问题状态 0 被封号 1 正常 映射 export const KEY_STATUS_MAP: QuestionStatusMap = { - 0: '被封禁', - 1: '工作中', -} + 0: "被封禁", + 1: "工作中", +}; // 账号类型 5$ 18$ 120$ export const ACCOUNT_TYPE_MAP: QuestionStatus = [ - { value: '5$', label: '5$' }, - { value: '18$', label: '18$' }, - { value: '120$', label: '120$' }, - { value: '其他', label: '其他' }, -] + { value: "5$", label: "5$" }, + { value: "18$", label: "18$" }, + { value: "120$", label: "120$" }, + { value: "其他", label: "其他" }, +]; // 模型列表 export const MODEL_LIST = [ - 'gpt-3.5-turbo', - 'gpt-3.5-turbo-1106', - 'gpt-3.5-turbo-16k', - 'gpt-4', - 'gpt-4-0613', - 'gpt-4-32k', - 'gpt-4-32k-0613', - 'gpt-4-1106-preview', - 'gpt-4-vision-preview', - 'gpt-4-all', - 'gpt-4-0125-preview', -] + "gpt-3.5-turbo", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-16k", + "gpt-4", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0613", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4-all", + "gpt-4-0125-preview", + // claude + "claude-2.0", + "claude-2.1", + // gemini + "gemini-pro", + // 百度文心 + "ERNIE-Bot", + "ERNIE-Bot-4", + "ERNIE-Bot-turbo", + // 阿里通义 + "qwen-turbo", + "qwen-plus", + "qwen-max", + "qwen-max-lingcontext", + // 腾讯混元 + "hunyuan", + // 清华智谱 + "chatglm_turbo", + "chatglm_pro", + "chatglm_std", + "chatglm_lite", + // 360 智脑 + "360GPT_S2_V9", + // 讯飞星火 + "SparkDesk", +]; // 模型列表 0 mj 1 Dall-e export const DRAW_MODEL_LIST = [ - { value: 'mj', label: 'MidjourneyAi' }, - { value: 'DALL-E2', label: 'DALL-E' }, -] + { value: "mj", label: "MidjourneyAi" }, + { value: "DALL-E2", label: "DALL-E" }, +]; // 支付状态列表 status 0:未支付、1:已支付、2、支付失败、3:支付超时 export const PAY_STATUS_OPTIONS = [ - { value: 0, label: '未支付' }, - { value: 1, label: '已支付' }, - { value: 2, label: '支付失败' }, - { value: 3, label: '支付超时' }, -] + { value: 0, label: "未支付" }, + { value: 1, label: "已支付" }, + { value: 2, label: "支付失败" }, + { value: 3, label: "支付超时" }, +]; // 支付状态 status 0:未支付、1:已支付、2、支付失败、3:支付超时 export const PAY_STATUS_MAP: QuestionStatusMap = { - 0: '未支付', - 1: '已支付', - 2: '支付失败', - 3: '支付超时', -} + 0: "未支付", + 1: "已支付", + 2: "支付失败", + 3: "支付超时", +}; // 平台列表 epay: 易支付 hupi:虎皮椒 export const PAY_PLATFORM_LIST = [ - { value: 'epay', label: '易支付' }, - { value: 'hupi', label: '虎皮椒' }, - { value: 'wechat', label: '微信支付' }, - { value: 'mpay', label: '码支付' }, -] + { value: "epay", label: "易支付" }, + { value: "hupi", label: "虎皮椒" }, + { value: "wechat", label: "微信支付" }, + { value: "mpay", label: "码支付" }, +]; // 支付对应 export const PAY_PLATFORM_MAP = { - epay: '易支付', - hupi: '虎皮椒', - wechat: '微信支付', - mpay: '码支付', -} + epay: "易支付", + hupi: "虎皮椒", + wechat: "微信支付", + mpay: "码支付", +}; // 绘画状态 1: 等待中 2: 绘制中 3: 绘制完成 4: 绘制失败 5: 绘制超时 export const DRAW_MJ_STATUS_LIST = [ - { value: 1, label: '等待中' }, - { value: 2, label: '绘制中' }, - { value: 3, label: '绘制完成' }, - { value: 4, label: '绘制失败' }, - { value: 5, label: '绘制超时' }, -] + { value: 1, label: "等待中" }, + { value: 2, label: "绘制中" }, + { value: 3, label: "绘制完成" }, + { value: 4, label: "绘制失败" }, + { value: 5, label: "绘制超时" }, +]; // App角色 系统 system 用户 user export const APP_ROLE_LIST = [ - { value: 'system', label: '系统' }, - { value: 'user', label: '用户' }, -] + { value: "system", label: "系统" }, + { value: "user", label: "用户" }, +]; // 绘画状态 1:排队中 2:绘制中 3:绘制完成 4:绘制失败 5:绘制超时 export const DRAW_STATUS_MAP = { - 1: '排队中', - 2: '绘制中', - 3: '绘制完成', - 4: '绘制失败', - 5: '绘制超时', -} + 1: "排队中", + 2: "绘制中", + 3: "绘制完成", + 4: "绘制失败", + 5: "绘制超时", +}; export const TYPEORIGINLIST = [ - { value: '百度云检测', label: '百度云检测' }, - { value: '自定义检测', label: '自定义检测' }, - { value: 'NineAI检测', label: 'NineAI检测' }, -] + { value: "百度云检测", label: "百度云检测" }, + { value: "自定义检测", label: "自定义检测" }, + { value: "NineAI检测", label: "NineAI检测" }, +]; export const MODELTYPELIST = [ - { value: 1, label: 'OpenAi - [chatGpt]' }, - { value: 2, label: '百度 - [千帆大模型]' }, - { value: 3, label: '清华 - [智谱大模型]' }, -] + { value: 1, label: "OpenAi - [chatGpt]" }, + { value: 2, label: "百度 - [千帆大模型]" }, + { value: 3, label: "清华 - [智谱大模型]" }, +]; export const MODELSMAP = { - 1: 'OPENAI', - 2: '百度文心', - 3: '清华智谱', -} + 1: "OPENAI", + 2: "百度文心", + 3: "清华智谱", +}; export const MODELSMAPLIST = { 1: [ - 'gpt-3.5-turbo', - 'gpt-3.5-turbo-1106', - 'gpt-3.5-turbo-16k', - 'gpt-4', - 'gpt-4-0613', - 'gpt-4-32k', - 'gpt-4-32k-0613', - 'gpt-4-1106-preview', - 'gpt-4-vision-preview', - 'gpt-4-all', - 'gpt-4-0125-preview', + "gpt-3.5-turbo", + "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-16k", + "gpt-4", + "gpt-4-0613", + "gpt-4-32k", + "gpt-4-32k-0613", + "gpt-4-1106-preview", + "gpt-4-vision-preview", + "gpt-4-all", + "gpt-4-0125-preview", + // claude + "claude-2.0", + "claude-2.1", + // gemini + "gemini-pro", + // 百度文心 + "ERNIE-Bot", + "ERNIE-Bot-4", + "ERNIE-Bot-turbo", + // 阿里通义 + "qwen-turbo", + "qwen-plus", + "qwen-max", + "qwen-max-lingcontext", + // 腾讯混元 + "hunyuan", + // 清华智谱 + "chatglm_turbo", + "chatglm_pro", + "chatglm_std", + "chatglm_lite", + // 360 智脑 + "360GPT_S2_V9", + // 讯飞星火 + "SparkDesk", ], 2: [ - 'ERNIE-Bot', - 'ERNIE-Bot', - 'ERNIE-Bot-4', - 'ERNIE-Bot-turbo', - 'BLOOMZ-7B', - 'Llama-2-7b-chat', - 'Llama-2-13b-chat', + "ERNIE-Bot", + "ERNIE-Bot", + "ERNIE-Bot-4", + "ERNIE-Bot-turbo", + "BLOOMZ-7B", + "Llama-2-7b-chat", + "Llama-2-13b-chat", // 'Llama-2-70b-chat', // 'ChatGLM2-6B-32K', - 'Qianfan-BLOOMZ-7B-compressed', - 'Qianfan-Chinese-Llama-2-7B', - 'AquilaChat-7B', + "Qianfan-BLOOMZ-7B-compressed", + "Qianfan-Chinese-Llama-2-7B", + "AquilaChat-7B", ], - 3: [ - 'chatglm_pro', - 'chatglm_std', - 'chatglm_lite', - 'chatglm_lite_32k', - ], -} + 3: ["chatglm_pro", "chatglm_std", "chatglm_lite", "chatglm_lite_32k"], +}; /* 扣费类型 普通余额还是高级余额 */ export const DEDUCTTYPELIST = [ - { value: 1, label: '普通余额' }, - { value: 2, label: '高级余额' }, -] + { value: 1, label: "普通余额" }, + { value: 2, label: "高级余额" }, +]; /* 不同模型在填入key字段的时候 key代表的含义不同 */ export const ModelTypeLabelMap = { - 1: 'APIKey', - 2: 'client_id', - 3: 'AppKey', -} + 1: "APIKey", + 2: "client_id", + 3: "AppKey", +}; diff --git a/admin/src/views/models/key.vue b/admin/src/views/models/key.vue index 7a6f0d0..c09009a 100644 --- a/admin/src/views/models/key.vue +++ b/admin/src/views/models/key.vue @@ -54,6 +54,7 @@ const formPackage = reactive({ deductType: 1, maxRounds: 12, isTokenBased: false, + tokenFeeRatio: 1000, }) const rules = reactive({ @@ -84,6 +85,9 @@ const rules = reactive({ trigger: 'change', }, ], + tokenFeeRatio: [ + { required: true, message: 'token计费比例', trigger: 'change' }, + ], model: [ { required: true, @@ -192,6 +196,7 @@ function handleEditKey(row: any) { maxRounds, isDraw, isTokenBased, + tokenFeeRatio } = row nextTick(() => { Object.assign(formPackage, { @@ -211,6 +216,7 @@ function handleEditKey(row: any) { maxRounds, isDraw, isTokenBased, + tokenFeeRatio }) }) visible.value = true @@ -393,6 +399,18 @@ onMounted(() => { + + + { + + + + + + + ( prompt: string appId?: number options?: { conversationId?: string; parentMessageId?: string; temperature: number } + imageUrl?:string + model?:string signal?: GenericAbortSignal onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void }, ) { return post({ url: '/chatgpt/chat-process', - data: { prompt: params.prompt, appId: params?.appId, options: params.options }, + data: { prompt: params.prompt, appId: params?.appId, options: params.options,imageUrl: params.imageUrl,model: params.model}, signal: params.signal, onDownloadProgress: params.onDownloadProgress, }) diff --git a/chat/src/assets/file.jpeg b/chat/src/assets/file.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..11dc5a027f6e4842e4240368fc895daee73870b0 GIT binary patch literal 26293 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 literal 0 HcmV?d00001 diff --git a/chat/src/layout/components/Login/Email.vue b/chat/src/layout/components/Login/Email.vue index 9044907..d4c005a 100644 --- a/chat/src/layout/components/Login/Email.vue +++ b/chat/src/layout/components/Login/Email.vue @@ -230,6 +230,10 @@ onMounted(() => { +
+ 老用户密码统一重置为112233
+ 登录后请自行修改密码 +
getLocalState(), +export const useChatStore = defineStore("chat-store", { + state: (): Chat.ChatState => getLocalState(), - getters: { - /* 当前选用模型的配置 */ - activeConfig: (state) => { - const uuid = state.active - if (!uuid) - return {} - const config = state.groupList.find(item => item.uuid === uuid)?.config - return config ? JSON.parse(config) : state.baseConfig - }, + getters: { + /* 当前选用模型的配置 */ + activeConfig: (state) => { + const uuid = state.active; + if (!uuid) return {}; + const config = state.groupList.find((item) => item.uuid === uuid)?.config; + return config ? JSON.parse(config) : state.baseConfig; + }, - activeGroupAppId: (state) => { - const uuid = state.active - if (!uuid) - return null - return state.groupList.find(item => item.uuid === uuid)?.appId - }, + activeGroupAppId: (state) => { + const uuid = state.active; + if (!uuid) return null; + return state.groupList.find((item) => item.uuid === uuid)?.appId; + }, - /* 当前选用模型的扣费类型 */ - activeModelKeyDeductType(state) { - return this.activeConfig?.modelInfo?.deductType - }, + /* 当前选用模型的名称 */ + activeModelName(state) { + return this.activeConfig?.modelInfo?.model; + }, + /* 当前选用模型的扣费类型 */ + activeModelKeyDeductType(state) { + return this.activeConfig?.modelInfo?.deductType; + }, - /* 当前选用模型的模型类型 */ - activeModelKeyType(state) { - return this.activeConfig?.modelInfo?.keyType - }, + /* 当前选用模型的模型类型 */ + activeModelKeyType(state) { + return this.activeConfig?.modelInfo?.keyType; + }, - /* 当前选用模型的调用价格 */ - activeModelKeyPrice(state) { - return this.activeConfig?.modelInfo?.deduct - }, + /* 当前选用模型的调用价格 */ + activeModelKeyPrice(state) { + return this.activeConfig?.modelInfo?.deduct; + }, + }, - }, + actions: { + /* 对话组过滤 */ + setGroupKeyWord(keyWord: string) { + this.groupKeyWord = keyWord; + }, - actions: { - /* 对话组过滤 */ - setGroupKeyWord(keyWord: string) { - this.groupKeyWord = keyWord - }, + /* 计算拿到当前选择的对话组信息 */ + getChatByGroupInfo() { + if (this.active) + return this.groupList.find((item) => item.uuid === this.active) || {}; + }, - /* 计算拿到当前选择的对话组信息 */ - getChatByGroupInfo() { - if (this.active) - return this.groupList.find(item => item.uuid === this.active) || {} - }, + /* */ + getConfigFromUuid(uuid: any) { + return this.groupList.find((item) => item.uuid === uuid)?.config; + }, - /* */ - getConfigFromUuid(uuid: any) { - return this.groupList.find(item => item.uuid === uuid)?.config - }, + /* 新增新的对话组 */ + async addNewChatGroup(appId = 0) { + const res: any = await fetchCreateGroupAPI({ appId }); + const { id: uuid } = res.data; + await this.setActiveGroup(uuid); + this.recordState(); + }, - /* 新增新的对话组 */ - async addNewChatGroup(appId = 0) { - const res: any = await fetchCreateGroupAPI({ appId }) - const { id: uuid } = res.data - await this.setActiveGroup(uuid) - this.recordState() - }, + /* 查询基础模型配置 兼容老的chatgroup */ + async getBaseModelConfig() { + const res = await fetchModelBaseConfigAPI(); + this.baseConfig = res?.data; + }, - /* 查询基础模型配置 兼容老的chatgroup */ - async getBaseModelConfig() { - const res = await fetchModelBaseConfigAPI() - this.baseConfig = res?.data - }, + /* 查询我的对话组 */ + async queryMyGroup() { + const res: any = await fetchQueryGroupAPI(); + this.groupList = [ + ...res.data.map((item: any) => { + const { + id: uuid, + title, + isSticky, + createdAt, + updatedAt, + appId, + config, + appLogo, + } = item; + return { + uuid, + title, + isEdit: false, + appId, + config, + isSticky, + appLogo, + createdAt, + updatedAt: new Date(updatedAt).getTime(), + }; + }), + ]; + const isHasActive = this.groupList.some( + (item) => Number(item.uuid) === Number(this.active) + ); + if (!this.active || !isHasActive) + this.groupList.length && this.setActiveGroup(this.groupList[0].uuid); + }, - /* 查询我的对话组 */ - async queryMyGroup() { - const res: any = await fetchQueryGroupAPI() - this.groupList = [...res.data.map((item: any) => { - const { id: uuid, title, isSticky, createdAt, updatedAt, appId, config, appLogo } = item - return { uuid, title, isEdit: false, appId, config, isSticky, appLogo, createdAt, updatedAt: new Date(updatedAt).getTime() } - })] - const isHasActive = this.groupList.some(item => Number(item.uuid) === Number(this.active)) - if (!this.active || !isHasActive) - this.groupList.length && this.setActiveGroup(this.groupList[0].uuid) - }, + /* 修改对话组信息 */ + async updateGroupInfo(params: { + groupId: number; + title?: string; + isSticky?: boolean; + }) { + await fetchUpdateGroupAPI(params); + }, - /* 修改对话组信息 */ - async updateGroupInfo(params: { groupId: number; title?: string; isSticky?: boolean }) { - await fetchUpdateGroupAPI(params) - }, + /* 变更对话组 */ + async setActiveGroup(uuid: number) { + this.active = uuid; + if (this.active) await this.queryActiveChatLogList(); + else this.chatList = []; - /* 变更对话组 */ - async setActiveGroup(uuid: number) { - this.active = uuid - if (this.active) - await this.queryActiveChatLogList() + this.groupList.forEach((item) => (item.isEdit = false)); + this.recordState(); + }, - else - this.chatList = [] + /* 删除对话组 */ + async deleteGroup(params: Chat.History) { + const curIndex = this.groupList.findIndex( + (item) => item.uuid === params.uuid + ); + const { uuid: groupId } = params; + await fetchDelGroupAPI({ groupId }); + await this.queryMyGroup(); + if (this.groupList.length === 0) await this.setActiveGroup(0); - this.groupList.forEach(item => (item.isEdit = false)) - this.recordState() - }, + if (curIndex > 0 && curIndex < this.groupList.length) + await this.setActiveGroup(this.groupList[curIndex].uuid); - /* 删除对话组 */ - async deleteGroup(params: Chat.History) { - const curIndex = this.groupList.findIndex(item => item.uuid === params.uuid) - const { uuid: groupId } = params - await fetchDelGroupAPI({ groupId }) - await this.queryMyGroup() - if (this.groupList.length === 0) - await this.setActiveGroup(0) + if (curIndex === 0 && this.groupList.length > 0) + await this.setActiveGroup(this.groupList[0].uuid); - if (curIndex > 0 && curIndex < this.groupList.length) - await this.setActiveGroup(this.groupList[curIndex].uuid) + if ( + curIndex > this.groupList.length || + (curIndex === 0 && this.groupList.length === 0) + ) + await this.setActiveGroup(0); - if (curIndex === 0 && this.groupList.length > 0) - await this.setActiveGroup(this.groupList[0].uuid) + if (curIndex > 0 && curIndex === this.groupList.length) + await this.setActiveGroup(this.groupList[curIndex - 1].uuid); - if (curIndex > this.groupList.length || (curIndex === 0 && this.groupList.length === 0)) - await this.setActiveGroup(0) + this.recordState(); + }, - if (curIndex > 0 && curIndex === this.groupList.length) - await this.setActiveGroup(this.groupList[curIndex - 1].uuid) + /* 删除全部非置顶对话组 */ + async delAllGroup() { + if (!this.active || !this.groupList.length) return; + await fetchDelAllGroupAPI(); + await this.queryMyGroup(); + if (this.groupList.length === 0) await this.setActiveGroup(0); + else await this.setActiveGroup(this.groupList[0].uuid); + }, - this.recordState() - }, + /* 查询当前对话组的聊天记录 */ + async queryActiveChatLogList() { + if (!this.active || Number(this.active) === 0) return; + const res: any = await fetchQueryChatLogListAPI({ groupId: this.active }); + this.chatList = res.data; + }, - /* 删除全部非置顶对话组 */ - async delAllGroup() { - if (!this.active || !this.groupList.length) - return - await fetchDelAllGroupAPI() - await this.queryMyGroup() - if (this.groupList.length === 0) - await this.setActiveGroup(0) + /* 添加一条虚拟的对话记录 */ + addGroupChat(data) { + this.chatList = [...this.chatList, data]; + }, - else - await this.setActiveGroup(this.groupList[0].uuid) - }, + /* 动态修改对话记录 */ + updateGroupChat(index: number, data: Chat.Chat) { + this.chatList[index] = { ...this.chatList[index], ...data }; + }, - /* 查询当前对话组的聊天记录 */ - async queryActiveChatLogList() { - if (!this.active || Number(this.active) === 0) - return - const res: any = await fetchQueryChatLogListAPI({ groupId: this.active }) - this.chatList = res.data - }, + /* 修改其中部分内容 */ + updateGroupChatSome(index: number, data: Partial) { + this.chatList[index] = { ...this.chatList[index], ...data }; + }, - /* 添加一条虚拟的对话记录 */ - addGroupChat(data) { - this.chatList = [...this.chatList, data] - }, + /* 删除一条对话记录 */ + async deleteChatById(chatId: number | undefined) { + console.log(chatId); + if (!chatId) return; + await fetchDelChatLogAPI({ id: chatId }); + await this.queryActiveChatLogList(); + }, - /* 动态修改对话记录 */ - updateGroupChat(index: number, data: Chat.Chat) { - this.chatList[index] = { ...this.chatList[index], ...data } - }, + /* 查询快问预设 */ + async queryChatPre() { + const res: any = await fetchGetChatPreList(); + if (!res.data) return; + this.chatPreList = formatChatPre(res.data); + }, - /* 修改其中部分内容 */ - updateGroupChatSome(index: number, data: Partial) { - this.chatList[index] = { ...this.chatList[index], ...data } - }, + /* 设置使用上下文 */ + setUsingContext(context: boolean) { + this.usingContext = context; + this.recordState(); + }, - /* 删除一条对话记录 */ - async deleteChatById(chatId: number | undefined) { - console.log(chatId) - if (!chatId) - return - await fetchDelChatLogAPI({ id: chatId }) - await this.queryActiveChatLogList() - }, + /* 设置使用联网 */ + setUsingNetwork(context: boolean) { + this.usingNetwork = context; + this.recordState(); + }, - /* 查询快问预设 */ - async queryChatPre() { - const res: any = await fetchGetChatPreList() - if (!res.data) - return - this.chatPreList = formatChatPre(res.data) - }, + /* 删除当前对话组的全部内容 */ + async clearChatByGroupId() { + if (!this.active) return; - /* 设置使用上下文 */ - setUsingContext(context: boolean) { - this.usingContext = context - this.recordState() - }, + await fetchDelChatLogByGroupIdAPI({ groupId: this.active }); + await this.queryActiveChatLogList(); + }, - /* 设置使用联网 */ - setUsingNetwork(context: boolean) { - this.usingNetwork = context - this.recordState() - }, + recordState() { + setLocalState(this.$state); + }, - /* 删除当前对话组的全部内容 */ - async clearChatByGroupId() { - if (!this.active) - return - - await fetchDelChatLogByGroupIdAPI({ groupId: this.active }) - await this.queryActiveChatLogList() - }, - - recordState() { - setLocalState(this.$state) - }, - - clearChat() { - this.chatList = [] - this.groupList = [] - this.active = 0 - this.recordState() - }, - }, -}) + clearChat() { + this.chatList = []; + this.groupList = []; + this.active = 0; + this.recordState(); + }, + }, +}); diff --git a/chat/src/views/chat/chatBase.vue b/chat/src/views/chat/chatBase.vue index 5e7d45e..bc69e67 100644 --- a/chat/src/views/chat/chatBase.vue +++ b/chat/src/views/chat/chatBase.vue @@ -12,7 +12,9 @@ import { NTooltip, useDialog, useMessage, + NAlert } from 'naive-ui' +import type { MessageRenderMessage } from 'naive-ui' import html2canvas from 'html2canvas' import { useRoute } from 'vue-router' @@ -86,7 +88,7 @@ const theme = computed(() => appStore.theme) const globaelConfig = computed(() => authStore.globalConfig) const isSetBeian = computed( - () => globaelConfig.value?.companyName && globaelConfig.value?.filingNumber, + () => globaelConfig.value?.companyName && globaelConfig.value?.filingNumber ) const { addGroupChat, updateGroupChat, updateGroupChatSome } = useChat() const tradeStatus = computed(() => route.query.trade_status as string) @@ -101,13 +103,13 @@ const dataSources = computed(() => chatStore.chatList) /* 当前所有的ai回复信息列表 方便拿到上下文 */ const conversationList = computed(() => - dataSources.value.filter(item => !item.inversion && !item.error), + dataSources.value.filter((item) => !item.inversion && !item.error) ) /* 当前上下文有id的最后一条 防止停止回答的时候 上一条的id是空 接不上上下文 */ const lastContext = computed(() => { const hasIdCoversationList = conversationList.value.filter( - item => item.conversationOptions?.parentMessageId, + (item) => item.conversationOptions?.parentMessageId ) return hasIdCoversationList[hasIdCoversationList.length - 1] ?.conversationOptions @@ -120,17 +122,22 @@ const firstScroll = ref(true) const tipsRef = ref(null) const tipText = ref('') const tipsHeight = ref(null) +const dataBase64 = ref(null) +const fileName = ref('') +const isImageFile = ref(false) +const showDeleteIcon = ref(false) + /* 当前选中的对话组 */ const activeGroupId = computed(() => chatStore.active) /* 当前对话组的详细信息 */ const activeGroupInfo = computed(() => - chatStore.groupList.find((item: any) => item.uuid === chatStore.active), + chatStore.groupList.find((item: any) => item.uuid === chatStore.active) ) /* 当前选用的模型的类型 1: openai 2: 百度 */ const activeModelKeyType = computed(() => Number(chatStore?.activeModelKeyType)) /* 当前对话组是否是应用 */ const activeAppId = computed(() => - activeGroupInfo?.value ? activeGroupInfo.value.appId : 0, + activeGroupInfo?.value ? activeGroupInfo.value.appId : 0 ) /* 粘贴板的文字 */ const clipboardText = computed(() => useGlobalStore.clipboardText) @@ -144,43 +151,37 @@ watch(clipboardText, (val) => { watch( activeAppId, (val) => { - if (val) - queryAppDetail(val) + if (val) queryAppDetail(val) else appDetail.value = null }, - { immediate: true }, + { immediate: true } ) watch( activeGroupId, (val) => { - if (val) - firstScroll.value = true - if (inputRef.value && !isMobile.value) - inputRef.value?.focus() + if (val) firstScroll.value = true + if (inputRef.value && !isMobile.value) inputRef.value?.focus() }, - { immediate: true }, + { immediate: true } ) watch( dataSources, (val) => { - if (val.length === 0) - return + if (val.length === 0) return if (firstScroll.value) { firstScroll.value = false scrollToBottom() } }, - { immediate: true }, + { immediate: true } ) const modelName = computed(() => { - if (!chatStore.activeConfig) - return + if (!chatStore.activeConfig) return const { modelTypeInfo, modelInfo } = chatStore.activeConfig - if (!modelTypeInfo || !modelInfo) - return + if (!modelTypeInfo || !modelInfo) return return `${modelInfo.modelName}` }) function handleOpenModelDialog() { @@ -202,14 +203,52 @@ let curFile: File | null async function handleFileSelect(event: any) { const file = event?.target?.files[0] - if (file.size <= 5 * 1024 * 1024) + if (!file) return + if (file.size <= 10 * 1024 * 1024) { await handleSetFile(file) - else ms.error('上传文件失败,上传大小不能超过5M') + } else { + return ms.error('上传文件失败,上传大小不能超过10M') + } + let trimmedFileName = file.name + const maxLength = 8 // 最大长度限制 + const extension = trimmedFileName.split('.').pop() // 获取文件扩展名 + + if (trimmedFileName.length > maxLength) { + // 截取文件名并添加省略号,同时保留扩展名 + trimmedFileName = + trimmedFileName.substring(0, maxLength - extension.length - 1) + + '….' + + extension + } + + fileName.value = trimmedFileName // 更新文件名 + console.log(file.type) + // 检查文件类型 + if (file.type.startsWith('image/')) { + // 处理图像文件 + isImageFile.value = true + handleSetFile(file) + } else if ( + file.type.startsWith('application/') || + file.type.startsWith('text/') + ) { + // 处理文件类型 + isImageFile.value = false + handleSetFile(file) + } else { + // 处理其他类型的文件或显示错误消息 + ms.error('上传文件失败,不支持此类型文件') + console.log('不支持的文件类型') + } } async function handleSetFile(file: File) { curFile = file - uploadFile() + const reader = new FileReader() + reader.onload = (event: any) => { + dataBase64.value = event.target?.result as string + } + reader.readAsDataURL(file) } function uploadBtn() { @@ -233,11 +272,13 @@ async function uploadFile() { } }, }) - prompt.value = `请分析一下上传的这个文件:${res?.data?.data}` - ms.success('上传成功,输入内容后发送', { duration: 5000, closable: true }) - } - catch (error) { - ms.error('网络异常,上传失败') + return res?.data?.data + } catch (error) { + ms.error('网络异常,发送失败') + return null + } finally { + dataBase64.value = null + curFile = null } } @@ -271,9 +312,9 @@ function handleScrollBtm() { /* 发送消息 */ async function handleSubmit(index?: number) { if ( - chatStore.groupList.length === 0 - || loading.value - || !typingStatusEnd.value + chatStore.groupList.length === 0 || + loading.value || + !typingStatusEnd.value ) return let message = '' @@ -287,12 +328,10 @@ async function handleSubmit(index?: number) { function parseTextToJSON(input: string) { const startIndex = input.indexOf(',"text":"') + 10 - if (startIndex === -1) - return { text: '' } + if (startIndex === -1) return { text: '' } let endIndex = input.indexOf('","delta"', startIndex) - if (endIndex === -1) - endIndex = input.length - 1 + if (endIndex === -1) endIndex = input.length - 1 else endIndex = endIndex - 10 const text = input.substring(startIndex, endIndex) @@ -301,15 +340,17 @@ function parseTextToJSON(input: string) { /* 按钮发送消息 */ async function onConversation(msg?: string) { + let imageUrl = null + if (dataBase64.value || curFile) { + imageUrl = await uploadFile() + } let message = msg || prompt.value if (tipText.value && !message.includes(tipText.value)) message = `${tipText.value}\n${message}` - if (loading.value) - return + if (loading.value) return - if (!message || message.trim() === '') - return + if (!message || message.trim() === '') return controller = new AbortController() @@ -319,6 +360,7 @@ async function onConversation(msg?: string) { text: message, inversion: true, error: false, + imageUrl, conversationOptions: null, requestOptions: { prompt: message, options: null }, }) @@ -369,12 +411,10 @@ async function onConversation(msg?: string) { if (cacheResText.length - i > 150) { currentText += cacheResText.substring(i, i + 10) i += 10 - } - else if (cacheResText.length - i > 200) { + } else if (cacheResText.length - i > 200) { currentText += cacheResText.substring(i) i += cacheResText.length - i - } - else { + } else { currentText += cacheResText[i] i++ } @@ -396,8 +436,8 @@ async function onConversation(msg?: string) { const curLen = currentText ? currentText.length : 0 const cacheResLen = cacheResText ? cacheResText.length : 0 if ( - !isStreamIn.value - && (curLen === cacheResLen || curLen > cacheResLen) + !isStreamIn.value && + (curLen === cacheResLen || curLen > cacheResLen) ) { typingStatusEnd.value = true updateGroupChatSome(dataSources.value.length - 1, { @@ -413,12 +453,12 @@ async function onConversation(msg?: string) { authStore.updateUserBanance(userBanance) if ( - dataSources.value.length === 2 - && !activeGroupInfo?.value?.appId + dataSources.value.length === 2 && + !activeGroupInfo?.value?.appId ) { const lengthStr = isMobile.value ? 10 : 20 - const title - = dataSources.value[1].text.length > lengthStr + const title = + dataSources.value[1].text.length > lengthStr ? dataSources.value[1].text.slice(0, lengthStr) : dataSources.value[1].text chatStore @@ -433,8 +473,7 @@ async function onConversation(msg?: string) { /* 有多余的再请求下一帧 */ if (cacheResText.length && cacheResText.length > currentText.length) { requestAnimationFrame(update) - } - else { + } else { setTimeout(() => { requestAnimationFrame(update) }, 1000) @@ -447,6 +486,8 @@ async function onConversation(msg?: string) { prompt: message, appId: activeGroupInfo.value ? activeGroupInfo.value.appId : 0, options, + imageUrl, + model: chatStore?.activeModelName, signal: controller.signal, onDownloadProgress: ({ event }) => { const xhr = event.target @@ -456,16 +497,14 @@ async function onConversation(msg?: string) { if ([1].includes(activeModelKeyType.value)) { const lastIndex = responseText.lastIndexOf( '\n', - responseText.length - 2, + responseText.length - 2 ) let chunk = responseText - if (lastIndex !== -1) - chunk = responseText.substring(lastIndex) + if (lastIndex !== -1) chunk = responseText.substring(lastIndex) try { data = JSON.parse(chunk) - } - catch (error) { + } catch (error) { /* 二次解析 */ // const parseData = parseTextToJSON(responseText) // TODO 如果出现类似超时错误 会连接上次的内容一起发出来导致无法解析 后端需要处理 下 @@ -489,8 +528,7 @@ async function onConversation(msg?: string) { const parseData = JSON.parse(line) cacheResult += parseData.result tem = parseData - } - catch (error) { + } catch (error) { console.log('Json parse 2 3 type error: ') } } @@ -502,8 +540,7 @@ async function onConversation(msg?: string) { /* 如果出现输出内容不一致就需要处理了 */ if (activeModelKeyType.value === 1) { cacheResText = data.text - if (data?.userBanance) - userBanance = data?.userBanance + if (data?.userBanance) userBanance = data?.userBanance } if ([2, 3].includes(activeModelKeyType.value)) { @@ -512,24 +549,21 @@ async function onConversation(msg?: string) { isStreamIn.value = !is_end data?.userBanance && (userBanance = data?.userBanance) } - } - catch (error) {} + } catch (error) {} }, }) } await fetchChatAPIOnce() - } - catch (error: any) { + } catch (error: any) { useGlobalStore.updateIsChatIn(false) clearInterval(timer) isStreamIn.value = false if ( - error.code === 402 - || error?.message.includes('余额不足') - || error?.message.includes('免费额度已经使用完毕') + error.code === 402 || + error?.message.includes('余额不足') || + error?.message.includes('免费额度已经使用完毕') ) { - if (isLogin.value) - useGlobalStore.updateGoodsDialog(true) + if (isLogin.value) useGlobalStore.updateGoodsDialog(true) else authStore.setLoginDialog(true) } @@ -568,10 +602,10 @@ async function onConversation(msg?: string) { requestOptions: { prompt: message, options: { ...options } }, }) scrollToBottomIfAtBottom() - } - finally { + } finally { loading.value = false isStreamIn.value = false + imageUrl = null } } @@ -589,16 +623,14 @@ function handleRefresh() { ms.success('感谢你的购买、祝您使用愉快~', { duration: 5000 }) authStore.getUserInfo() router.replace({ name: 'Chat', query: {} }) - } - else { + } else { ms.error('您还没有购买成功哦~') } } /* 导出 */ function handleExport() { - if (loading.value) - return + if (loading.value) return const d = dialog.warning({ title: t('chat.exportImage'), @@ -627,11 +659,9 @@ function handleExport() { d.loading = false ms.success(t('chat.exportSuccess')) Promise.resolve() - } - catch (error: any) { + } catch (error: any) { ms.error(t('chat.exportFailed')) - } - finally { + } finally { d.loading = false } }, @@ -640,8 +670,7 @@ function handleExport() { /* 删除 */ function handleDelete({ chatId }: Chat.Chat) { - if (loading.value) - return + if (loading.value) return dialog.warning({ title: t('chat.deleteMessage'), @@ -655,8 +684,7 @@ function handleDelete({ chatId }: Chat.Chat) { } function handleClear() { - if (loading.value) - return + if (loading.value) return dialog.warning({ title: t('chat.clearChat'), @@ -676,8 +704,7 @@ function handleEnter(event: KeyboardEvent) { event.preventDefault() handleSubmit() } - } - else { + } else { if (event.key === 'Enter' && event.ctrlKey) { event.preventDefault() handleSubmit() @@ -695,17 +722,16 @@ function handleStop() { } const placeholder = computed(() => { - if (isMobile.value) - return t('chat.placeholderMobile') + if (isMobile.value) return t('chat.placeholderMobile') return t('chat.placeholder') }) const buttonDisabled = computed(() => { return ( - loading.value - || !prompt.value - || prompt.value.trim() === '' - || !typingStatusEnd.value + loading.value || + !prompt.value || + prompt.value.trim() === '' || + !typingStatusEnd.value ) }) // 改动:发送后添加loading圈圈 @@ -719,8 +745,7 @@ function getTipsRefHeight() { function onInputeTip() { tipsHeight.value = 'auto' - if (!tipText.value) - tipsHeight.value = 0 + if (!tipText.value) tipsHeight.value = 0 nextTick(() => getTipsRefHeight()) } @@ -728,24 +753,20 @@ function onInputeTip() { onMounted(async () => { chatStore.queryChatPre() - if (token.value) - otherLoginByToken(token.value) + if (token.value) otherLoginByToken(token.value) - if (tradeStatus.value) - handleRefresh() + if (tradeStatus.value) handleRefresh() nextTick(async () => { await chatStore.queryActiveChatLogList() scrollToBottom() - if (inputRef.value && !isMobile.value) - inputRef.value?.focus() + if (inputRef.value && !isMobile.value) inputRef.value?.focus() }) }) const darkMode = computed(() => appStore.theme === 'dark') onUnmounted(() => { - if (loading.value) - controller.abort() + if (loading.value) controller.abort() }) @@ -793,6 +814,7 @@ onUnmounted(() => { :inversion="item.inversion" :error="item.error" :loading="item.loading" + :imageUrl="item.imageUrl" @regenerate="handleSubmit(index)" @delete="handleDelete(item)" /> @@ -825,10 +847,10 @@ onUnmounted(() => { 'text-[#3076fd]': usingContext, 'text-[#a8071a]': !usingContext, }" - > @@ -852,10 +874,11 @@ onUnmounted(() => { class="shrink0 flex h-8 w-8 items-center justify-center rounded border transition hover:bg-[#eef0f3] dark:border-neutral-700 dark:hover:bg-[#33373c]" @click="openChatPre" > - @@ -950,7 +973,7 @@ onUnmounted(() => { {{ modelName }} @@ -1007,7 +1030,10 @@ onUnmounted(() => {
{ :multiple="false" type="file" style="display: none" - accept="text/plain,image/*, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/pdf" - @change="handleFileSelect($event)" - > - + :accept=" + chatStore.activeConfig.modelInfo.model === + 'gpt-4-vision-preview' + ? 'image/*' + : 'text/plain,image/*, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/pdf' + " + @change="handleFileSelect($event)" /> + 上传 + +
+
+ + + +
+
- {{ usingNetwork ? '关闭' : '开启' }}联网访问 + {{ usingNetwork ? '关闭' : '开启' }}联网访问 @@ -1137,4 +1210,31 @@ onUnmounted(() => { .shrink0 { flex-shrink: 0 !important; } + +.close-icon { + position: absolute; + top: -0; + right: 0; + color: #ff6347; + font-size: 1rem; + width: 1rem; + height: 1rem; + animation: scaleAnim 2s infinite ease-in-out; + cursor: pointer; + &:hover { + font-weight: 800; + color: red; + } +} + +@keyframes scaleAnim { + 0%, + 100% { + transform: scale(1); + } + + 50% { + transform: scale(1.2); + } +} diff --git a/chat/src/views/chat/components/Message/Text.vue b/chat/src/views/chat/components/Message/Text.vue index af51a5e..dda33bf 100644 --- a/chat/src/views/chat/components/Message/Text.vue +++ b/chat/src/views/chat/components/Message/Text.vue @@ -15,6 +15,7 @@ interface Props { text?: string loading?: boolean asRawText?: boolean + imageUrl?: string } interface Emit { @@ -83,6 +84,12 @@ const text = computed(() => { if (!props.asRawText) return mdi.render(value) return value }) +const imageUrl = computed(() => props.imageUrl) + +const isImageUrl = computed(() => { + if (!imageUrl.value) return false + return /\.(jpg|jpeg|png|gif)$/i.test(imageUrl.value) +}) function highlightBlock(str: string, lang?: string) { return `
           
-
@@ -170,6 +181,28 @@ defineExpose({ textRef })