正在显示
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 | } |
-
请 注册 或 登录 后发表评论