正在显示
8 个修改的文件
包含
302 行增加
和
58 行删除
@@ -52,7 +52,7 @@ import HeadphoneIcon from "../icons/headphone.svg"; | @@ -52,7 +52,7 @@ import HeadphoneIcon from "../icons/headphone.svg"; | ||
52 | //20250317新增word excel图标 | 52 | //20250317新增word excel图标 |
53 | import ExcelIcon from "../icons/excel.svg"; | 53 | import ExcelIcon from "../icons/excel.svg"; |
54 | import WordIcon from "../icons/word.svg"; | 54 | import WordIcon from "../icons/word.svg"; |
55 | -import MindIcon from "../icons/mind.svg" | 55 | +import MindIcon from "../icons/mind.svg"; |
56 | 56 | ||
57 | import { | 57 | import { |
58 | BOT_HELLO, | 58 | BOT_HELLO, |
@@ -66,6 +66,7 @@ import { | @@ -66,6 +66,7 @@ import { | ||
66 | useAppConfig, | 66 | useAppConfig, |
67 | useChatStore, | 67 | useChatStore, |
68 | usePluginStore, | 68 | usePluginStore, |
69 | + useMindMapStore, //新增消息仓库用于存储上下文至思维导图页面 | ||
69 | } from "../store"; | 70 | } from "../store"; |
70 | 71 | ||
71 | import { | 72 | import { |
@@ -134,7 +135,8 @@ import { getAvailableClientsCount, isMcpEnabled } from "../mcp/actions"; | @@ -134,7 +135,8 @@ import { getAvailableClientsCount, isMcpEnabled } from "../mcp/actions"; | ||
134 | 135 | ||
135 | //20250317新增 | 136 | //20250317新增 |
136 | import { toExcel } from "../utils/excelAndWordUtils/export2Excel"; | 137 | import { toExcel } from "../utils/excelAndWordUtils/export2Excel"; |
137 | -import {exportWord} from "../utils/excelAndWordUtils/word"; | 138 | +import { exportWord } from "../utils/excelAndWordUtils/word"; |
139 | +import { getMindPrompt } from "../utils/prompt"; | ||
138 | const localStorage = safeLocalStorage(); | 140 | const localStorage = safeLocalStorage(); |
139 | 141 | ||
140 | const ttsPlayer = createTTSPlayer(); | 142 | const ttsPlayer = createTTSPlayer(); |
@@ -181,7 +183,9 @@ function isTableContent(content: string): boolean { | @@ -181,7 +183,9 @@ function isTableContent(content: string): boolean { | ||
181 | const hasTableSeparator = tablePattern.test(content); | 183 | const hasTableSeparator = tablePattern.test(content); |
182 | 184 | ||
183 | // 检查是否包含至少一行表格内容 | 185 | // 检查是否包含至少一行表格内容 |
184 | - const hasTableRows = content.split("\n").some((line) => rowPattern.test(line)); | 186 | + const hasTableRows = content |
187 | + .split("\n") | ||
188 | + .some((line) => rowPattern.test(line)); | ||
185 | 189 | ||
186 | // 如果同时包含分隔符行和表格内容行,则认为是表格 | 190 | // 如果同时包含分隔符行和表格内容行,则认为是表格 |
187 | return hasTableSeparator && hasTableRows; | 191 | return hasTableSeparator && hasTableRows; |
@@ -709,10 +713,11 @@ export function ChatActions(props: { | @@ -709,10 +713,11 @@ export function ChatActions(props: { | ||
709 | <Selector | 713 | <Selector |
710 | defaultSelectedValue={`${currentModel}@${currentProviderName}`} | 714 | defaultSelectedValue={`${currentModel}@${currentProviderName}`} |
711 | items={models.map((m) => ({ | 715 | items={models.map((m) => ({ |
712 | - title: `${m.displayName}${m?.provider?.providerName | ||
713 | - ? " (" + m?.provider?.providerName + ")" | ||
714 | - : "" | ||
715 | - }`, | 716 | + title: `${m.displayName}${ |
717 | + m?.provider?.providerName | ||
718 | + ? " (" + m?.provider?.providerName + ")" | ||
719 | + : "" | ||
720 | + }`, | ||
716 | value: `${m.name}@${m?.provider?.providerName}`, | 721 | value: `${m.name}@${m?.provider?.providerName}`, |
717 | }))} | 722 | }))} |
718 | onClose={() => setShowModelSelector(false)} | 723 | onClose={() => setShowModelSelector(false)} |
@@ -1029,9 +1034,9 @@ function _Chat() { | @@ -1029,9 +1034,9 @@ function _Chat() { | ||
1029 | const scrollRef = useRef<HTMLDivElement>(null); | 1034 | const scrollRef = useRef<HTMLDivElement>(null); |
1030 | const isScrolledToBottom = scrollRef?.current | 1035 | const isScrolledToBottom = scrollRef?.current |
1031 | ? Math.abs( | 1036 | ? Math.abs( |
1032 | - scrollRef.current.scrollHeight - | ||
1033 | - (scrollRef.current.scrollTop + scrollRef.current.clientHeight), | ||
1034 | - ) <= 1 | 1037 | + scrollRef.current.scrollHeight - |
1038 | + (scrollRef.current.scrollTop + scrollRef.current.clientHeight), | ||
1039 | + ) <= 1 | ||
1035 | : false; | 1040 | : false; |
1036 | const isAttachWithTop = useMemo(() => { | 1041 | const isAttachWithTop = useMemo(() => { |
1037 | const lastMessage = scrollRef.current?.lastElementChild as HTMLElement; | 1042 | const lastMessage = scrollRef.current?.lastElementChild as HTMLElement; |
@@ -1377,27 +1382,27 @@ function _Chat() { | @@ -1377,27 +1382,27 @@ function _Chat() { | ||
1377 | .concat( | 1382 | .concat( |
1378 | isLoading | 1383 | isLoading |
1379 | ? [ | 1384 | ? [ |
1380 | - { | ||
1381 | - ...createMessage({ | ||
1382 | - role: "assistant", | ||
1383 | - content: "……", | ||
1384 | - }), | ||
1385 | - preview: true, | ||
1386 | - }, | ||
1387 | - ] | 1385 | + { |
1386 | + ...createMessage({ | ||
1387 | + role: "assistant", | ||
1388 | + content: "……", | ||
1389 | + }), | ||
1390 | + preview: true, | ||
1391 | + }, | ||
1392 | + ] | ||
1388 | : [], | 1393 | : [], |
1389 | ) | 1394 | ) |
1390 | .concat( | 1395 | .concat( |
1391 | userInput.length > 0 && config.sendPreviewBubble | 1396 | userInput.length > 0 && config.sendPreviewBubble |
1392 | ? [ | 1397 | ? [ |
1393 | - { | ||
1394 | - ...createMessage({ | ||
1395 | - role: "user", | ||
1396 | - content: userInput, | ||
1397 | - }), | ||
1398 | - preview: true, | ||
1399 | - }, | ||
1400 | - ] | 1398 | + { |
1399 | + ...createMessage({ | ||
1400 | + role: "user", | ||
1401 | + content: userInput, | ||
1402 | + }), | ||
1403 | + preview: true, | ||
1404 | + }, | ||
1405 | + ] | ||
1401 | : [], | 1406 | : [], |
1402 | ); | 1407 | ); |
1403 | }, [ | 1408 | }, [ |
@@ -1494,7 +1499,7 @@ function _Chat() { | @@ -1494,7 +1499,7 @@ function _Chat() { | ||
1494 | if (payload.key || payload.url) { | 1499 | if (payload.key || payload.url) { |
1495 | showConfirm( | 1500 | showConfirm( |
1496 | Locale.URLCommand.Settings + | 1501 | Locale.URLCommand.Settings + |
1497 | - `\n${JSON.stringify(payload, null, 4)}`, | 1502 | + `\n${JSON.stringify(payload, null, 4)}`, |
1498 | ).then((res) => { | 1503 | ).then((res) => { |
1499 | if (!res) return; | 1504 | if (!res) return; |
1500 | if (payload.key) { | 1505 | if (payload.key) { |
@@ -1704,6 +1709,36 @@ function _Chat() { | @@ -1704,6 +1709,36 @@ function _Chat() { | ||
1704 | 1709 | ||
1705 | const [showChatSidePanel, setShowChatSidePanel] = useState(false); | 1710 | const [showChatSidePanel, setShowChatSidePanel] = useState(false); |
1706 | 1711 | ||
1712 | + // 20250327新增思维导图导出 | ||
1713 | + function toMind(messages: RenderMessage[], content: string) { | ||
1714 | + const newMessages = []; | ||
1715 | + const { setMindMapData } = useMindMapStore.getState(); | ||
1716 | + // 遍历 messages 数组 | ||
1717 | + for (const message of messages) { | ||
1718 | + // 检查 content 类型并正确存储 | ||
1719 | + if (typeof message.content === "string") { | ||
1720 | + newMessages.push({ | ||
1721 | + role: message.role, | ||
1722 | + content: message.content, | ||
1723 | + }); | ||
1724 | + } else { | ||
1725 | + newMessages.push({ | ||
1726 | + role: message.role, | ||
1727 | + content: JSON.stringify(message.content), | ||
1728 | + }); | ||
1729 | + } | ||
1730 | + if (message.content === content) { | ||
1731 | + newMessages.push({ | ||
1732 | + role: "user", | ||
1733 | + content: getMindPrompt(content, true), | ||
1734 | + }); | ||
1735 | + break; | ||
1736 | + } | ||
1737 | + } | ||
1738 | + setMindMapData(newMessages, content); | ||
1739 | + navigate("/mind", { state: { msg: true } }); | ||
1740 | + } | ||
1741 | + | ||
1707 | return ( | 1742 | return ( |
1708 | <> | 1743 | <> |
1709 | <div className={styles.chat} key={session.id}> | 1744 | <div className={styles.chat} key={session.id}> |
@@ -1939,7 +1974,7 @@ function _Chat() { | @@ -1939,7 +1974,7 @@ function _Chat() { | ||
1939 | } | 1974 | } |
1940 | /> | 1975 | /> |
1941 | {/* 以下 20250317 新增Word excel导出按钮 */} | 1976 | {/* 以下 20250317 新增Word excel导出按钮 */} |
1942 | - {isTableContent(getMessageTextContent(message)) && ( | 1977 | + {/* {isTableContent(getMessageTextContent(message)) && ( |
1943 | <> | 1978 | <> |
1944 | <ChatAction | 1979 | <ChatAction |
1945 | text={Locale.Chat.Actions.Excel} | 1980 | text={Locale.Chat.Actions.Excel} |
@@ -1949,23 +1984,38 @@ function _Chat() { | @@ -1949,23 +1984,38 @@ function _Chat() { | ||
1949 | } | 1984 | } |
1950 | /> | 1985 | /> |
1951 | </> | 1986 | </> |
1952 | - )} | ||
1953 | - | ||
1954 | - {!isTableContent(getMessageTextContent(message)) && ( | 1987 | + )} */} |
1988 | + <ChatAction | ||
1989 | + text={Locale.Chat.Actions.Excel} | ||
1990 | + icon={<ExcelIcon />} | ||
1991 | + onClick={() => | ||
1992 | + toExcel( | ||
1993 | + getMessageTextContent(message), | ||
1994 | + ) | ||
1995 | + } | ||
1996 | + /> | ||
1997 | + {!isTableContent( | ||
1998 | + getMessageTextContent(message), | ||
1999 | + ) && ( | ||
1955 | <> | 2000 | <> |
1956 | <ChatAction | 2001 | <ChatAction |
1957 | text={Locale.Chat.Actions.Word} | 2002 | text={Locale.Chat.Actions.Word} |
1958 | icon={<WordIcon />} | 2003 | icon={<WordIcon />} |
1959 | - onClick={() => exportWord( | ||
1960 | - getMessageTextContent(message), | ||
1961 | - )} | 2004 | + onClick={() => |
2005 | + exportWord( | ||
2006 | + getMessageTextContent(message), | ||
2007 | + ) | ||
2008 | + } | ||
1962 | /> | 2009 | /> |
1963 | <ChatAction | 2010 | <ChatAction |
1964 | text={Locale.Chat.Actions.Mind} | 2011 | text={Locale.Chat.Actions.Mind} |
1965 | icon={<MindIcon />} | 2012 | icon={<MindIcon />} |
1966 | - onClick={() => exportWord( | ||
1967 | - getMessageTextContent(message), | ||
1968 | - )} | 2013 | + onClick={() => { |
2014 | + toMind( | ||
2015 | + messages, | ||
2016 | + getMessageTextContent(message), | ||
2017 | + ); | ||
2018 | + }} | ||
1969 | /> | 2019 | /> |
1970 | </> | 2020 | </> |
1971 | )} | 2021 | )} |
@@ -2065,7 +2115,7 @@ function _Chat() { | @@ -2065,7 +2115,7 @@ function _Chat() { | ||
2065 | <img | 2115 | <img |
2066 | className={ | 2116 | className={ |
2067 | styles[ | 2117 | styles[ |
2068 | - "chat-message-item-image-multi" | 2118 | + "chat-message-item-image-multi" |
2069 | ] | 2119 | ] |
2070 | } | 2120 | } |
2071 | key={index} | 2121 | key={index} |
@@ -22,9 +22,15 @@ export function MindPanel(props: MindPanelProps) { | @@ -22,9 +22,15 @@ export function MindPanel(props: MindPanelProps) { | ||
22 | if (!inputValue.trim()) return message.error("请输入提示词!"); | 22 | if (!inputValue.trim()) return message.error("请输入提示词!"); |
23 | setIsLoading(true); | 23 | setIsLoading(true); |
24 | try { | 24 | try { |
25 | - const prompt = getMindPrompt(inputValue); | 25 | + const prompt = getMindPrompt(inputValue, false); |
26 | const response = await chatStore.directLlmInvoke(prompt, "gpt-4o-mini"); | 26 | const response = await chatStore.directLlmInvoke(prompt, "gpt-4o-mini"); |
27 | console.log("原始响应:", response); | 27 | console.log("原始响应:", response); |
28 | + let cleanedContent = response.startsWith("```json") | ||
29 | + ? response.substring(8) | ||
30 | + : response; | ||
31 | + if (cleanedContent.endsWith("```")) { | ||
32 | + cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4); | ||
33 | + } | ||
28 | const parsedData: MindElixirData = JSON.parse(response); | 34 | const parsedData: MindElixirData = JSON.parse(response); |
29 | console.log("解析后响应:", parsedData); | 35 | console.log("解析后响应:", parsedData); |
30 | // 增强校验逻辑 | 36 | // 增强校验逻辑 |
@@ -8,7 +8,7 @@ import { useMobileScreen } from "@/app/utils"; | @@ -8,7 +8,7 @@ import { useMobileScreen } from "@/app/utils"; | ||
8 | import { IconButton } from "../button"; | 8 | import { IconButton } from "../button"; |
9 | import Locale from "@/app/locales"; | 9 | import Locale from "@/app/locales"; |
10 | import { Path } from "@/app/constant"; | 10 | import { Path } from "@/app/constant"; |
11 | -import { useNavigate } from "react-router-dom"; | 11 | +import { useNavigate, useLocation } from "react-router-dom"; |
12 | import clsx from "clsx"; | 12 | import clsx from "clsx"; |
13 | import { getClientConfig } from "@/app/config/client"; | 13 | import { getClientConfig } from "@/app/config/client"; |
14 | import React, { useEffect, useMemo, useRef, useState } from "react"; | 14 | import React, { useEffect, useMemo, useRef, useState } from "react"; |
@@ -18,6 +18,8 @@ import ReturnIcon from "@/app/icons/return.svg"; | @@ -18,6 +18,8 @@ import ReturnIcon from "@/app/icons/return.svg"; | ||
18 | import MinIcon from "@/app/icons/min.svg"; | 18 | import MinIcon from "@/app/icons/min.svg"; |
19 | import MaxIcon from "@/app/icons/max.svg"; | 19 | import MaxIcon from "@/app/icons/max.svg"; |
20 | import SDIcon from "@/app/icons/sd.svg"; | 20 | import SDIcon from "@/app/icons/sd.svg"; |
21 | +import { useChatStore, useMindMapStore } from "@/app/store"; | ||
22 | +import { message } from "antd"; | ||
21 | 23 | ||
22 | export function MindPage() { | 24 | export function MindPage() { |
23 | const isMobileScreen = useMobileScreen(); | 25 | const isMobileScreen = useMobileScreen(); |
@@ -26,10 +28,14 @@ export function MindPage() { | @@ -26,10 +28,14 @@ export function MindPage() { | ||
26 | const showMaxIcon = !isMobileScreen && !clientConfig?.isApp; | 28 | const showMaxIcon = !isMobileScreen && !clientConfig?.isApp; |
27 | const config = useAppConfig(); | 29 | const config = useAppConfig(); |
28 | const scrollRef = useRef<HTMLDivElement>(null); | 30 | const scrollRef = useRef<HTMLDivElement>(null); |
29 | - const isWriting = location.pathname === Path.Writing; | 31 | + const isMind = location.pathname === Path.Mind; |
30 | const [isLoading, setIsLoading] = useState(false); | 32 | const [isLoading, setIsLoading] = useState(false); |
31 | const containerRef = useRef<HTMLDivElement>(null); | 33 | const containerRef = useRef<HTMLDivElement>(null); |
32 | const mindInstance = useRef<InstanceType<typeof MindElixir> | null>(null); | 34 | const mindInstance = useRef<InstanceType<typeof MindElixir> | null>(null); |
35 | + const chatStore = useChatStore(); | ||
36 | + const { newMessages, content } = useMindMapStore.getState(); | ||
37 | + const query = useLocation(); | ||
38 | + const { msg } = query.state || {}; | ||
33 | const [data, setData] = useState<MindElixirData>({ | 39 | const [data, setData] = useState<MindElixirData>({ |
34 | nodeData: { | 40 | nodeData: { |
35 | id: "root", | 41 | id: "root", |
@@ -51,6 +57,46 @@ export function MindPage() { | @@ -51,6 +57,46 @@ export function MindPage() { | ||
51 | mindInstance.current = new MindElixir(options); | 57 | mindInstance.current = new MindElixir(options); |
52 | mindInstance.current.init(data); | 58 | mindInstance.current.init(data); |
53 | 59 | ||
60 | + const fetchData = async () => { | ||
61 | + if (msg) { | ||
62 | + if (content) { | ||
63 | + setIsLoading(true); | ||
64 | + try { | ||
65 | + const response = await chatStore.getMindData( | ||
66 | + newMessages, | ||
67 | + "gpt-4o-mini", | ||
68 | + ); | ||
69 | + console.log("原始响应:", response); | ||
70 | + let cleanedContent = response.startsWith("```json") | ||
71 | + ? response.substring(8) | ||
72 | + : response; | ||
73 | + if (cleanedContent.endsWith("```")) { | ||
74 | + cleanedContent = cleanedContent.substring( | ||
75 | + 0, | ||
76 | + cleanedContent.length - 4, | ||
77 | + ); | ||
78 | + } | ||
79 | + const parsedData: MindElixirData = JSON.parse(cleanedContent); | ||
80 | + console.log("解析后响应:", parsedData); | ||
81 | + // 增强校验逻辑 | ||
82 | + if ( | ||
83 | + !parsedData?.nodeData?.id || | ||
84 | + !Array.isArray(parsedData.nodeData.children) | ||
85 | + ) { | ||
86 | + throw new Error("数据结构不完整"); | ||
87 | + } | ||
88 | + setData(parsedData); | ||
89 | + } catch (error) { | ||
90 | + console.log(error); | ||
91 | + message.error("请求失败,请重试"); | ||
92 | + } finally { | ||
93 | + setIsLoading(false); // 确保关闭加载状态 | ||
94 | + } | ||
95 | + } | ||
96 | + } | ||
97 | + }; | ||
98 | + fetchData(); | ||
99 | + | ||
54 | return () => { | 100 | return () => { |
55 | if (mindInstance.current) { | 101 | if (mindInstance.current) { |
56 | mindInstance.current.destroy(); | 102 | mindInstance.current.destroy(); |
@@ -73,6 +119,13 @@ export function MindPage() { | @@ -73,6 +119,13 @@ export function MindPage() { | ||
73 | topic: "生成中....", | 119 | topic: "生成中....", |
74 | }, | 120 | }, |
75 | }); | 121 | }); |
122 | + } else { | ||
123 | + mindInstance.current?.refresh({ | ||
124 | + nodeData: { | ||
125 | + id: "root", | ||
126 | + topic: "中心主题", | ||
127 | + }, | ||
128 | + }); | ||
76 | } | 129 | } |
77 | }, [isLoading]); | 130 | }, [isLoading]); |
78 | 131 | ||
@@ -133,7 +186,7 @@ export function MindPage() { | @@ -133,7 +186,7 @@ export function MindPage() { | ||
133 | return ( | 186 | return ( |
134 | <> | 187 | <> |
135 | <MindSiderBar | 188 | <MindSiderBar |
136 | - className={clsx({ [homeStyles["sidebar-show"]]: isWriting })} | 189 | + className={clsx({ [homeStyles["sidebar-show"]]: isMind })} |
137 | setData={setData} | 190 | setData={setData} |
138 | isLoading={isLoading} | 191 | isLoading={isLoading} |
139 | setIsLoading={setIsLoading} | 192 | setIsLoading={setIsLoading} |
@@ -855,31 +855,31 @@ export const useChatStore = createPersistStore( | @@ -855,31 +855,31 @@ export const useChatStore = createPersistStore( | ||
855 | } | 855 | } |
856 | }, | 856 | }, |
857 | 857 | ||
858 | - async directLlmInvoke(content: string,model:string): Promise<string> { | 858 | + async directLlmInvoke(content: string, model: string): Promise<string> { |
859 | return new Promise((resolve, reject) => { | 859 | return new Promise((resolve, reject) => { |
860 | const config = useAppConfig.getState(); | 860 | const config = useAppConfig.getState(); |
861 | const accessStore = useAccessStore.getState(); | 861 | const accessStore = useAccessStore.getState(); |
862 | - | 862 | + |
863 | // 使用默认模型配置 | 863 | // 使用默认模型配置 |
864 | const modelConfig = { | 864 | const modelConfig = { |
865 | ...config.modelConfig, | 865 | ...config.modelConfig, |
866 | - model: model, | ||
867 | - providerName: accessStore.provider | 866 | + model: model, |
867 | + providerName: accessStore.provider, | ||
868 | }; | 868 | }; |
869 | - | 869 | + |
870 | // 直接构造消息 | 870 | // 直接构造消息 |
871 | const messages: ChatMessage[] = [ | 871 | const messages: ChatMessage[] = [ |
872 | createMessage({ | 872 | createMessage({ |
873 | role: "user", | 873 | role: "user", |
874 | content: fillTemplateWith(content, modelConfig), | 874 | content: fillTemplateWith(content, modelConfig), |
875 | - }) | 875 | + }), |
876 | ]; | 876 | ]; |
877 | - | 877 | + |
878 | const api: ClientApi = getClientApi(modelConfig.providerName); | 878 | const api: ClientApi = getClientApi(modelConfig.providerName); |
879 | - | 879 | + |
880 | api.llm.chat({ | 880 | api.llm.chat({ |
881 | messages, | 881 | messages, |
882 | - config: { | 882 | + config: { |
883 | ...modelConfig, | 883 | ...modelConfig, |
884 | stream: false, // 关闭流式响应 | 884 | stream: false, // 关闭流式响应 |
885 | }, | 885 | }, |
@@ -887,13 +887,94 @@ export const useChatStore = createPersistStore( | @@ -887,13 +887,94 @@ export const useChatStore = createPersistStore( | ||
887 | resolve(message); | 887 | resolve(message); |
888 | }, | 888 | }, |
889 | onError(error) { | 889 | onError(error) { |
890 | - reject(error instanceof Error ? error : new Error(prettyObject(error))); | ||
891 | - } | 890 | + reject( |
891 | + error instanceof Error ? error : new Error(prettyObject(error)), | ||
892 | + ); | ||
893 | + }, | ||
892 | }); | 894 | }); |
893 | }); | 895 | }); |
894 | - } | ||
895 | - | 896 | + }, |
897 | + | ||
898 | + async getMindData( | ||
899 | + messages: Array<{ role: string; content: string }>, | ||
900 | + model: string, | ||
901 | + ): Promise<string> { | ||
902 | + return new Promise(async (resolve, reject) => { | ||
903 | + try { | ||
904 | + const config = useAppConfig.getState(); | ||
905 | + const accessStore = useAccessStore.getState(); | ||
906 | + | ||
907 | + // 1. 构建模型配置 | ||
908 | + const modelConfig = { | ||
909 | + ...config.modelConfig, | ||
910 | + model: model, | ||
911 | + providerName: accessStore.provider, | ||
912 | + enableInjectSystemPrompts: | ||
913 | + config.modelConfig.enableInjectSystemPrompts, | ||
914 | + }; | ||
915 | + | ||
916 | + // 2. 处理系统提示 | ||
917 | + let systemPrompts: ChatMessage[] = []; | ||
918 | + const shouldInjectSystem = | ||
919 | + modelConfig.enableInjectSystemPrompts && | ||
920 | + (model.startsWith("gpt-") || model.startsWith("chatgpt-")); | ||
921 | + | ||
922 | + const mcpEnabled = await isMcpEnabled(); | ||
923 | + let systemContent = ""; | ||
924 | + | ||
925 | + // 3. 添加基础系统提示 | ||
926 | + if (shouldInjectSystem) { | ||
927 | + systemContent += fillTemplateWith("", { | ||
928 | + ...modelConfig, | ||
929 | + template: DEFAULT_SYSTEM_TEMPLATE, | ||
930 | + }); | ||
931 | + } | ||
932 | + | ||
933 | + // 4. 添加MCP系统提示 | ||
934 | + if (mcpEnabled) { | ||
935 | + systemContent += await getMcpSystemPrompt(); | ||
936 | + } | ||
896 | 937 | ||
938 | + if (systemContent) { | ||
939 | + systemPrompts.push( | ||
940 | + createMessage({ | ||
941 | + role: "system", | ||
942 | + content: systemContent, | ||
943 | + }), | ||
944 | + ); | ||
945 | + } | ||
946 | + | ||
947 | + // 5. 处理消息模板 | ||
948 | + const processedMessages = messages.map((msg) => { | ||
949 | + if (msg.role === "user") { | ||
950 | + return { | ||
951 | + ...msg, | ||
952 | + content: fillTemplateWith(msg.content, modelConfig), | ||
953 | + } as ChatMessage; | ||
954 | + } | ||
955 | + return msg as ChatMessage; | ||
956 | + }); | ||
957 | + | ||
958 | + // 6. 组合最终消息(系统提示 + 处理后的消息) | ||
959 | + const finalMessages = [...systemPrompts, ...processedMessages]; | ||
960 | + | ||
961 | + // 7. 创建API客户端并调用 | ||
962 | + const api = getClientApi(modelConfig.providerName); | ||
963 | + api.llm.chat({ | ||
964 | + messages: finalMessages, | ||
965 | + config: { | ||
966 | + ...modelConfig, | ||
967 | + stream: false, | ||
968 | + }, | ||
969 | + onFinish: resolve, | ||
970 | + onError: (err) => | ||
971 | + reject(err instanceof Error ? err : new Error(err)), | ||
972 | + }); | ||
973 | + } catch (err) { | ||
974 | + reject(err instanceof Error ? err : new Error(String(err))); | ||
975 | + } | ||
976 | + }); | ||
977 | + }, | ||
897 | }; | 978 | }; |
898 | 979 | ||
899 | return methods; | 980 | return methods; |
app/store/message.ts
0 → 100644
1 | +import { createPersistStore } from "../utils/store"; | ||
2 | + | ||
3 | +export const useMindMapStore = createPersistStore< | ||
4 | + { newMessages: { role: string; content: string }[]; content: string }, | ||
5 | + { | ||
6 | + setMindMapData: ( | ||
7 | + newMessages: { role: string; content: string }[], | ||
8 | + content: string, | ||
9 | + ) => void; | ||
10 | + clearMindMapData: () => void; | ||
11 | + } | ||
12 | +>( | ||
13 | + { | ||
14 | + newMessages: [], | ||
15 | + content: "", | ||
16 | + }, | ||
17 | + (set, get) => ({ | ||
18 | + setMindMapData: (newMessages, content) => { | ||
19 | + set(() => ({ | ||
20 | + newMessages, | ||
21 | + content, | ||
22 | + })); | ||
23 | + }, | ||
24 | + | ||
25 | + clearMindMapData: () => { | ||
26 | + set(() => ({ | ||
27 | + newMessages: [], | ||
28 | + content: "", | ||
29 | + })); | ||
30 | + }, | ||
31 | + }), | ||
32 | + { | ||
33 | + name: "mind-map-store", | ||
34 | + version: 1, | ||
35 | + }, | ||
36 | +); |
app/types/message.d.ts
0 → 100644
1 | +import type { ChatMessage } from "../store"; | ||
2 | + | ||
3 | +export type RenderMessage = ChatMessage & { preview?: boolean }; | ||
4 | + | ||
5 | +export interface MindMapStore { | ||
6 | + newMessages: { role: string; content: string }[]; | ||
7 | + content: string; | ||
8 | + setMindMapData: ( | ||
9 | + newMessages: { role: string; content: string }[], | ||
10 | + content: string, | ||
11 | + ) => void; | ||
12 | + clearMindMapData: () => void; | ||
13 | +} |
1 | import type { writePromptParam } from "@/app/types/prompt"; | 1 | import type { writePromptParam } from "@/app/types/prompt"; |
2 | - | ||
3 | export function getWrtingPrompt(param: writePromptParam) { | 2 | export function getWrtingPrompt(param: writePromptParam) { |
4 | const isImg = `文案要配上图片,实现图文混排,要美观,要符合${param.writingPurposeName}的排版标准和写作风格,写作风格要${param.writingStyleName}, | 3 | const isImg = `文案要配上图片,实现图文混排,要美观,要符合${param.writingPurposeName}的排版标准和写作风格,写作风格要${param.writingStyleName}, |
5 | 你没有图片没关系,把图文混排的效果实现,并在你认为要插入图片的地方将图片的Prompt用英文输出给:,记得图片地址后面的?nologo=true一定不能去掉了, | 4 | 你没有图片没关系,把图文混排的效果实现,并在你认为要插入图片的地方将图片的Prompt用英文输出给:,记得图片地址后面的?nologo=true一定不能去掉了, |
@@ -19,8 +18,9 @@ export function getBgPrompt(content: string) { | @@ -19,8 +18,9 @@ export function getBgPrompt(content: string) { | ||
19 | return input; | 18 | return input; |
20 | } | 19 | } |
21 | 20 | ||
22 | -export function getMindPrompt(content: string) { | ||
23 | - return `请你帮我生成一份以"${content}"为主题的思维导图数据,请严格遵循以下要求生成思维导图数据: | 21 | +export function getMindPrompt(content: string, isContext: boolean) { |
22 | + const context = `联系上下文`; | ||
23 | + let prompt = `请你帮我生成一份以"${content}"为主题的思维导图数据,请严格遵循以下要求生成思维导图数据: | ||
24 | 1. 所有键名必须使用双引号 | 24 | 1. 所有键名必须使用双引号 |
25 | 2. 所有字符串值必须使用双引号 | 25 | 2. 所有字符串值必须使用双引号 |
26 | 3. 确保没有尾随逗号 | 26 | 3. 确保没有尾随逗号 |
@@ -42,4 +42,8 @@ export function getMindPrompt(content: string) { | @@ -42,4 +42,8 @@ export function getMindPrompt(content: string) { | ||
42 | },} | 42 | },} |
43 | 只需要返回数据,不要做任何解释 | 43 | 只需要返回数据,不要做任何解释 |
44 | `; | 44 | `; |
45 | + if (isContext) { | ||
46 | + prompt = context + prompt; | ||
47 | + } | ||
48 | + return prompt; | ||
45 | } | 49 | } |
-
请 注册 或 登录 后发表评论