From 0deb3113b5d054cd13a59ce7d95c46c0ace049af Mon Sep 17 00:00:00 2001 From: kuaifan Date: Sat, 8 Nov 2025 20:42:21 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=95=E5=85=A5=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E6=8F=90=E5=8F=96=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?AI=E5=86=85=E5=AE=B9=E8=A7=A3=E6=9E=90=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E7=A7=BB=E9=99=A4=E5=86=97=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/assets/js/pages/manage.vue | 35 +------------- .../manage/components/ChatInput/index.vue | 23 ++-------- .../js/pages/manage/components/TaskAdd.vue | 46 +++---------------- resources/assets/js/utils/ai.js | 32 +++++++++++++ resources/assets/js/utils/text.js | 13 ++++++ 5 files changed, 56 insertions(+), 93 deletions(-) create mode 100644 resources/assets/js/utils/text.js diff --git a/resources/assets/js/pages/manage.vue b/resources/assets/js/pages/manage.vue index a84baea8a..c40c3094b 100644 --- a/resources/assets/js/pages/manage.vue +++ b/resources/assets/js/pages/manage.vue @@ -457,7 +457,7 @@ import SearchBox from "../components/SearchBox.vue"; import AIAssistant from "../components/AIAssistant.vue"; import transformEmojiToHtml from "../utils/emoji"; import {languageName} from "../language"; -import {PROJECT_AI_SYSTEM_PROMPT} from "../utils/ai"; +import {AINormalizeJsonContent, PROJECT_AI_SYSTEM_PROMPT} from "../utils/ai"; import Draggable from 'vuedraggable' export default { @@ -1197,39 +1197,8 @@ export default { return []; }, - normalizeAIJsonContent(content) { - if (!content) { - return null; - } - const raw = String(content).trim(); - if (!raw) { - return null; - } - const candidates = [raw]; - const block = raw.match(/```(?:json)?\s*([\s\S]*?)```/i); - if (block && block[1]) { - candidates.push(block[1].trim()); - } - const start = raw.indexOf('{'); - const end = raw.lastIndexOf('}'); - if (start !== -1 && end !== -1 && end > start) { - candidates.push(raw.slice(start, end + 1)); - } - for (const candidate of candidates) { - if (!candidate) { - continue; - } - try { - return JSON.parse(candidate); - } catch (e) { - continue; - } - } - return null; - }, - parseProjectAIContent(content) { - const payload = this.normalizeAIJsonContent(content); + const payload = AINormalizeJsonContent(content); if (!payload || typeof payload !== 'object') { return null; } diff --git a/resources/assets/js/pages/manage/components/ChatInput/index.vue b/resources/assets/js/pages/manage/components/ChatInput/index.vue index 3bce20d8c..b841bedb4 100755 --- a/resources/assets/js/pages/manage/components/ChatInput/index.vue +++ b/resources/assets/js/pages/manage/components/ChatInput/index.vue @@ -343,6 +343,7 @@ import longpress from "../../../../directives/longpress"; import {inputLoadAdd, inputLoadIsLast, inputLoadRemove} from "./one"; import {languageList, languageName} from "../../../../language"; import {isMarkdownFormat, MarkdownConver} from "../../../../utils/markdown"; +import {extractPlainText} from "../../../../utils/text"; import {MESSAGE_AI_SYSTEM_PROMPT} from "../../../../utils/ai"; import emitter from "../../../../store/events"; import historyMixin from "./history"; @@ -1911,7 +1912,6 @@ export default { emitter.emit('openAIAssistant', { placeholder: this.$L('请简要描述消息的主题、语气或要点,AI 将生成完整消息'), onBeforeSend: this.handleMessageAIBeforeSend, - onRender: this.handleMessageAIRender, onApply: this.handleMessageAIApply, }); }, @@ -1933,10 +1933,6 @@ export default { return prepared; }, - handleMessageAIRender({rawOutput}) { - return rawOutput || ''; - }, - handleMessageAIApply({rawOutput}) { if (!rawOutput) { $A.messageWarning('AI 未生成内容'); @@ -1991,7 +1987,7 @@ export default { } } - const draftText = this.extractPlainText(this.value); + const draftText = extractPlainText(this.value); if (draftText) { sections.push('## 当前草稿'); sections.push(this.cutText(draftText, 200)); @@ -2062,26 +2058,13 @@ export default { } try { const preview = $A.getMsgSimpleDesc(message); - const plain = this.extractPlainText(preview || ''); + const plain = extractPlainText(preview || ''); return this.cutText(plain, 160); } catch (error) { return ''; } }, - extractPlainText(content) { - if (!content) { - return ''; - } - const value = typeof content === 'string' ? content : JSON.stringify(content); - if (typeof window === 'undefined' || !window.document) { - return value.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim(); - } - const div = document.createElement('div'); - div.innerHTML = value; - return (div.textContent || div.innerText || '').replace(/\s+/g, ' ').trim(); - }, - cutText(text, limit = 60) { const value = (text || '').trim(); if (!value) { diff --git a/resources/assets/js/pages/manage/components/TaskAdd.vue b/resources/assets/js/pages/manage/components/TaskAdd.vue index 6d1fa756a..fe75de499 100644 --- a/resources/assets/js/pages/manage/components/TaskAdd.vue +++ b/resources/assets/js/pages/manage/components/TaskAdd.vue @@ -201,7 +201,8 @@ import TaskExistTips from "./TaskExistTips.vue"; import TEditorTask from "../../../components/TEditorTask.vue"; import nostyle from "../../../components/VMEditor/engine/nostyle"; import {MarkdownConver} from "../../../utils/markdown"; -import {TASK_AI_SYSTEM_PROMPT} from "../../../utils/ai"; +import {extractPlainText} from "../../../utils/text"; +import {AINormalizeJsonContent, TASK_AI_SYSTEM_PROMPT} from "../../../utils/ai"; export default { name: "TaskAdd", @@ -639,15 +640,11 @@ export default { buildTaskAIContextData() { const prompts = []; const plainText = (value, limit = 600) => { - if (!value || typeof value !== 'string') { + const text = extractPlainText(value || ''); + if (!text) { return ''; } - return value - .replace(/<[^>]+>/g, ' ') - .replace(/ /gi, ' ') - .replace(/\s+/g, ' ') - .slice(0, limit) - .trim(); + return text.slice(0, limit).trim(); }; const currentTitle = (this.addData.name || '').trim(); @@ -778,7 +775,7 @@ export default { }, parseTaskAIContent(content) { - const payload = this.normalizeAIJsonContent(content); + const payload = AINormalizeJsonContent(content); if (!payload || typeof payload !== 'object') { return null; } @@ -802,37 +799,6 @@ export default { }; }, - normalizeAIJsonContent(content) { - if (!content) { - return null; - } - const raw = String(content).trim(); - if (!raw) { - return null; - } - const candidates = [raw]; - const block = raw.match(/```(?:json)?\s*([\s\S]*?)```/i); - if (block && block[1]) { - candidates.push(block[1].trim()); - } - const start = raw.indexOf('{'); - const end = raw.lastIndexOf('}'); - if (start !== -1 && end !== -1 && end > start) { - candidates.push(raw.slice(start, end + 1)); - } - for (const candidate of candidates) { - if (!candidate) { - continue; - } - try { - return JSON.parse(candidate); - } catch (e) { - continue; - } - } - return null; - }, - normalizeAISubtasks(value) { let raw = []; if (Array.isArray(value)) { diff --git a/resources/assets/js/utils/ai.js b/resources/assets/js/utils/ai.js index d27a3de72..2c5d27193 100644 --- a/resources/assets/js/utils/ai.js +++ b/resources/assets/js/utils/ai.js @@ -11,6 +11,37 @@ const AIModelNames = (str) => { }, []).filter(item => item.value); } +const AINormalizeJsonContent = (content) => { + if (!content) { + return null; + } + const raw = String(content).trim(); + if (!raw) { + return null; + } + const candidates = [raw]; + const block = raw.match(/```(?:json)?\s*([\s\S]*?)```/i); + if (block && block[1]) { + candidates.push(block[1].trim()); + } + const start = raw.indexOf('{'); + const end = raw.lastIndexOf('}'); + if (start !== -1 && end !== -1 && end > start) { + candidates.push(raw.slice(start, end + 1)); + } + for (const candidate of candidates) { + if (!candidate) { + continue; + } + try { + return JSON.parse(candidate); + } catch (e) { + // continue + } + } + return null; +} + const AIBotList = [] const AIBotMap = { @@ -295,6 +326,7 @@ const PROJECT_AI_SYSTEM_PROMPT = `你是一名资深的项目规划顾问,帮 export { AIModelNames, + AINormalizeJsonContent, AIBotList, AIBotMap, AISystemConfig, diff --git a/resources/assets/js/utils/text.js b/resources/assets/js/utils/text.js new file mode 100644 index 000000000..23b49fe91 --- /dev/null +++ b/resources/assets/js/utils/text.js @@ -0,0 +1,13 @@ +export function extractPlainText(content) { + if (!content) { + return ''; + } + const value = typeof content === 'string' ? content : JSON.stringify(content); + if (typeof window === 'undefined' || !window.document) { + return value.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim(); + } + const div = document.createElement('div'); + div.innerHTML = value; + return (div.textContent || div.innerText || '').replace(/\s+/g, ' ').trim(); +} +