新增总结功能
This commit is contained in:
115
src/App.vue
115
src/App.vue
@@ -119,6 +119,9 @@ const focusedNodeId = ref<string | null>(null)
|
|||||||
const draggingNodeId = ref<string | null>(null)
|
const draggingNodeId = ref<string | null>(null)
|
||||||
const previewImageUrl = ref<string | null>(null)
|
const previewImageUrl = ref<string | null>(null)
|
||||||
const showResetConfirm = ref(false)
|
const showResetConfirm = ref(false)
|
||||||
|
const showSummaryModal = ref(false)
|
||||||
|
const isSummarizing = ref(false)
|
||||||
|
const summaryContent = ref('')
|
||||||
|
|
||||||
// 画布控制状态
|
// 画布控制状态
|
||||||
const panOnDrag = ref(true)
|
const panOnDrag = ref(true)
|
||||||
@@ -352,6 +355,58 @@ const exportMarkdown = () => {
|
|||||||
URL.revokeObjectURL(url)
|
URL.revokeObjectURL(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成全篇总结
|
||||||
|
*/
|
||||||
|
const generateSummary = async () => {
|
||||||
|
if (flowNodes.value.length === 0) return
|
||||||
|
|
||||||
|
showSummaryModal.value = true
|
||||||
|
isSummarizing.value = true
|
||||||
|
summaryContent.value = ''
|
||||||
|
|
||||||
|
// 收集所有节点信息
|
||||||
|
const nodesInfo = flowNodes.value.map(n => ({
|
||||||
|
label: n.data.label,
|
||||||
|
description: n.data.description,
|
||||||
|
type: n.data.type
|
||||||
|
}))
|
||||||
|
|
||||||
|
const useConfig = apiConfig.mode === 'default' ? DEFAULT_CONFIG.chat : apiConfig.chat
|
||||||
|
const finalApiKey = apiConfig.mode === 'default' ? useConfig.apiKey || API_KEY : useConfig.apiKey
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(useConfig.baseUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${finalApiKey}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: useConfig.model,
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: t('prompts.summaryPrompt', {
|
||||||
|
nodes: JSON.stringify(nodesInfo, null, 2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error('Summary request failed')
|
||||||
|
|
||||||
|
const data = await response.json()
|
||||||
|
summaryContent.value = data.choices[0].message.content
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Summary Generation Error:', error)
|
||||||
|
summaryContent.value = t('common.error.unknown')
|
||||||
|
} finally {
|
||||||
|
isSummarizing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用智谱AI生成图片
|
* 调用智谱AI生成图片
|
||||||
*/
|
*/
|
||||||
@@ -720,6 +775,12 @@ const startNewSession = () => {
|
|||||||
|
|
||||||
<div class="h-4 w-[1px] bg-slate-100 mx-1 flex-shrink-0"></div>
|
<div class="h-4 w-[1px] bg-slate-100 mx-1 flex-shrink-0"></div>
|
||||||
|
|
||||||
|
<!-- 总结功能 -->
|
||||||
|
<button @click="generateSummary" class="toolbar-btn text-orange-600 hover:bg-orange-50 border-orange-100 flex-shrink-0" :title="t('nav.summary')">
|
||||||
|
<Sparkles class="w-3.5 h-3.5 md:w-4 h-4" />
|
||||||
|
<span>{{ t('nav.summary') }}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- 导出选项 -->
|
<!-- 导出选项 -->
|
||||||
<button @click="exportMarkdown" class="toolbar-btn text-indigo-600 hover:bg-indigo-50 border-indigo-100 flex-shrink-0" :title="t('nav.export')">
|
<button @click="exportMarkdown" class="toolbar-btn text-indigo-600 hover:bg-indigo-50 border-indigo-100 flex-shrink-0" :title="t('nav.export')">
|
||||||
<Download class="w-3.5 h-3.5 md:w-4 h-4" />
|
<Download class="w-3.5 h-3.5 md:w-4 h-4" />
|
||||||
@@ -821,6 +882,12 @@ const startNewSession = () => {
|
|||||||
<span>{{ t('nav.map') }}</span>
|
<span>{{ t('nav.map') }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- 总结功能 -->
|
||||||
|
<button @click="generateSummary(); isToolsExpanded = false" class="toolbar-btn text-orange-600 hover:bg-orange-50 border-orange-100" :title="t('nav.summary')">
|
||||||
|
<Sparkles class="w-4 h-4" />
|
||||||
|
<span>{{ t('nav.summary') }}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- 导出选项 -->
|
<!-- 导出选项 -->
|
||||||
<button @click="exportMarkdown(); isToolsExpanded = false" class="toolbar-btn text-indigo-600 hover:bg-indigo-50 border-indigo-100" :title="t('nav.export')">
|
<button @click="exportMarkdown(); isToolsExpanded = false" class="toolbar-btn text-indigo-600 hover:bg-indigo-50 border-indigo-100" :title="t('nav.export')">
|
||||||
<Download class="w-4 h-4" />
|
<Download class="w-4 h-4" />
|
||||||
@@ -1246,6 +1313,54 @@ const startNewSession = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
|
<!-- 全篇总结弹窗 -->
|
||||||
|
<Transition name="fade">
|
||||||
|
<div v-if="showSummaryModal" class="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
||||||
|
<div class="absolute inset-0 bg-slate-900/40 backdrop-blur-sm" @click="showSummaryModal = false"></div>
|
||||||
|
<div class="relative bg-white rounded-3xl shadow-2xl border border-slate-100 w-full max-w-2xl overflow-hidden animate-in zoom-in duration-300">
|
||||||
|
<div class="absolute top-0 left-0 right-0 h-2 bg-gradient-to-r from-orange-400 to-rose-400"></div>
|
||||||
|
|
||||||
|
<div class="p-6 md:p-8">
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-10 h-10 bg-orange-50 rounded-xl flex items-center justify-center text-orange-500">
|
||||||
|
<Sparkles class="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-black text-slate-800 tracking-tight">{{ t('common.summaryTitle') }}</h3>
|
||||||
|
<p class="text-xs text-slate-400 font-medium uppercase tracking-wider">{{ t('common.aiGenerated') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button @click="showSummaryModal = false" class="p-2 hover:bg-slate-50 rounded-full text-slate-400 transition-colors">
|
||||||
|
<X class="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative min-h-[200px] max-h-[60vh] overflow-y-auto pr-2 custom-scrollbar">
|
||||||
|
<div v-if="isSummarizing" class="absolute inset-0 flex flex-col items-center justify-center space-y-4">
|
||||||
|
<RefreshCw class="w-8 h-8 text-orange-500 animate-spin" />
|
||||||
|
<p class="text-sm font-bold text-slate-400 animate-pulse">{{ t('common.summarizing') }}</p>
|
||||||
|
</div>
|
||||||
|
<div v-else class="prose prose-slate max-w-none">
|
||||||
|
<div class="whitespace-pre-wrap text-slate-600 leading-relaxed text-sm md:text-base font-medium">
|
||||||
|
{{ summaryContent }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8 flex justify-end">
|
||||||
|
<button
|
||||||
|
@click="showSummaryModal = false"
|
||||||
|
class="px-8 py-3 bg-slate-900 text-white rounded-2xl text-xs font-black tracking-widest hover:bg-slate-800 transition-all shadow-xl shadow-slate-200 active:scale-95"
|
||||||
|
>
|
||||||
|
{{ t('common.close') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部全局操作栏 -->
|
<!-- 底部全局操作栏 -->
|
||||||
|
|||||||
@@ -6,8 +6,12 @@
|
|||||||
"save": "Save & Close",
|
"save": "Save & Close",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
|
"close": "Close",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
"generating": "Generating...",
|
"generating": "Generating...",
|
||||||
|
"summarizing": "Generating session summary...",
|
||||||
|
"summaryTitle": "Session Summary",
|
||||||
|
"aiGenerated": "AI Generated",
|
||||||
"expanding": "Expanding Idea...",
|
"expanding": "Expanding Idea...",
|
||||||
"active": "Active",
|
"active": "Active",
|
||||||
"signin": "SIGN IN",
|
"signin": "SIGN IN",
|
||||||
@@ -36,6 +40,7 @@
|
|||||||
"lines": "LINES",
|
"lines": "LINES",
|
||||||
"dots": "DOTS",
|
"dots": "DOTS",
|
||||||
"map": "MAP",
|
"map": "MAP",
|
||||||
|
"summary": "SUMMARY",
|
||||||
"export": "EXPORT"
|
"export": "EXPORT"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@@ -71,6 +76,7 @@
|
|||||||
"contextPath": "Thinking Context Path",
|
"contextPath": "Thinking Context Path",
|
||||||
"selectedNode": "Current Selected Node",
|
"selectedNode": "Current Selected Node",
|
||||||
"newRequirement": "User Follow-up/New Requirement",
|
"newRequirement": "User Follow-up/New Requirement",
|
||||||
"deepDivePrompt": "Please provide a deep and detailed analysis of 【{topic}】. Requirements:\n1. Clear structure, including background, core principles, key elements, and practical applications.\n2. Professional yet easy-to-understand language.\n3. Total length around 300-500 words.\n4. Output the body text directly, do not use JSON format, and do not include any opening or closing remarks."
|
"deepDivePrompt": "Please provide a deep and detailed analysis of 【{topic}】. Requirements:\n1. Clear structure, including background, core principles, key elements, and practical applications.\n2. Professional yet easy-to-understand language.\n3. Total length around 300-500 words.\n4. Output the body text directly, do not use JSON format, and do not include any opening or closing remarks.",
|
||||||
|
"summaryPrompt": "You are a thinking summary expert. Please generate a structured summary based on the provided mind map node information (including the core idea and all branched sub-ideas).\n\nNode data:\n{nodes}\n\nRequirements:\n1. Extract the core theme and its underlying logic.\n2. Summarize several main dimensions or branch directions.\n3. Conclude with final insights or conclusions.\n4. Language should be concise, professional, and inspiring.\n5. Output the summary content directly, do not use JSON format, and do not include any opening remarks."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,9 +6,13 @@
|
|||||||
"save": "保存并关闭",
|
"save": "保存并关闭",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"confirm": "确定",
|
"confirm": "确定",
|
||||||
|
"close": "关闭",
|
||||||
"loading": "加载中...",
|
"loading": "加载中...",
|
||||||
"generating": "生成中...",
|
"generating": "生成中...",
|
||||||
"expanding": "发散中...",
|
"summarizing": "正在生成全篇总结...",
|
||||||
|
"summaryTitle": "思维全篇总结",
|
||||||
|
"aiGenerated": "AI 智能生成",
|
||||||
|
"expanding": "思考中...",
|
||||||
"active": "激活",
|
"active": "激活",
|
||||||
"signin": "登录",
|
"signin": "登录",
|
||||||
"tools": "工具箱",
|
"tools": "工具箱",
|
||||||
@@ -36,6 +40,7 @@
|
|||||||
"lines": "网格",
|
"lines": "网格",
|
||||||
"dots": "点阵",
|
"dots": "点阵",
|
||||||
"map": "地图",
|
"map": "地图",
|
||||||
|
"summary": "总结",
|
||||||
"export": "导出"
|
"export": "导出"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@@ -71,6 +76,7 @@
|
|||||||
"contextPath": "思考上下文路径",
|
"contextPath": "思考上下文路径",
|
||||||
"selectedNode": "当前选择节点",
|
"selectedNode": "当前选择节点",
|
||||||
"newRequirement": "用户追问/新要求",
|
"newRequirement": "用户追问/新要求",
|
||||||
"deepDivePrompt": "请针对【{topic}】提供一个深度且详细的解析。要求:\n1. 结构清晰,包含背景、核心原理、关键要素和实际应用。\n2. 语言专业且易懂。\n3. 总字数控制在 300-500 字左右。\n4. 直接输出正文内容,不要包含 JSON 格式,也不要包含任何开场白或结束语。"
|
"deepDivePrompt": "请针对【{topic}】提供一个深度且详细的解析。要求:\n1. 结构清晰,包含背景、核心原理、关键要素和实际应用。\n2. 语言专业且易懂。\n3. 总字数控制在 300-500 字左右。\n4. 直接输出正文内容,不要包含 JSON 格式,也不要包含任何开场白或结束语。",
|
||||||
|
"summaryPrompt": "你是一个思维总结专家。请根据以下提供的思维导图节点信息(包含核心想法及其发散出的所有子想法),生成一份结构化的全篇总结。\n\n节点数据如下:\n{nodes}\n\n要求:\n1. 提炼出核心主题及其背后的核心逻辑。\n2. 归纳出几个主要的维度或分支方向。\n3. 总结最终达成的洞察或结论。\n4. 语言要精炼、专业,富有启发性。\n5. 直接输出总结内容,不要包含 JSON 格式,不要有任何开场白。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user