Spaces:
Sleeping
Sleeping
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>知识提炼与资产化智能体 | Knowledge Refinery Agent</title> | |
| <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet"> | |
| <style> | |
| body { font-family: 'Inter', sans-serif; background-color: #f8fafc; color: #1e293b; } | |
| .card { background: white; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; } | |
| .btn-primary { background-color: #0f172a; color: white; transition: all 0.2s; } | |
| .btn-primary:hover { background-color: #334155; } | |
| .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; } | |
| .tag { @apply px-2 py-1 rounded-full text-xs font-medium; } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="app" class="min-h-screen flex flex-col"> | |
| <!-- Header --> | |
| <header class="bg-white border-b border-gray-200 sticky top-0 z-50"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between"> | |
| <div class="flex items-center gap-2"> | |
| <div class="w-8 h-8 bg-slate-900 rounded-lg flex items-center justify-center text-white font-bold">K</div> | |
| <h1 class="text-xl font-semibold text-slate-900 tracking-tight">知识提炼与资产化智能体</h1> | |
| </div> | |
| <div class="text-sm text-slate-500 hidden sm:block">v1.0.0 | Powered by Mock AI</div> | |
| </div> | |
| </header> | |
| <main class="flex-1 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 w-full grid grid-cols-1 lg:grid-cols-12 gap-8"> | |
| <!-- Left Column: Input & Controls --> | |
| <div class="lg:col-span-4 space-y-6"> | |
| <!-- Input Card --> | |
| <div class="card p-6"> | |
| <h2 class="text-lg font-medium mb-4 flex items-center gap-2"> | |
| <svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path></svg> | |
| 输入源挖掘 | |
| </h2> | |
| <div class="flex gap-2 mb-4 bg-slate-100 p-1 rounded-lg"> | |
| <button @click="inputType = 'text'" :class="{'bg-white shadow text-slate-900': inputType === 'text', 'text-slate-500': inputType !== 'text'}" class="flex-1 py-1.5 px-3 rounded-md text-sm font-medium transition-all">文本内容</button> | |
| <button @click="inputType = 'url'" :class="{'bg-white shadow text-slate-900': inputType === 'url', 'text-slate-500': inputType !== 'url'}" class="flex-1 py-1.5 px-3 rounded-md text-sm font-medium transition-all">URL 链接</button> | |
| <button @click="inputType = 'file'" :class="{'bg-white shadow text-slate-900': inputType === 'file', 'text-slate-500': inputType !== 'file'}" class="flex-1 py-1.5 px-3 rounded-md text-sm font-medium transition-all">文件上传</button> | |
| </div> | |
| <div class="space-y-4"> | |
| <div v-if="inputType === 'text'"> | |
| <label class="block text-sm font-medium text-slate-700 mb-1">原始文本</label> | |
| <textarea v-model="inputText" rows="6" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-slate-500 focus:ring-slate-500 text-sm p-3 border" placeholder="输入需要分析的文本..."></textarea> | |
| </div> | |
| <div v-else-if="inputType === 'url'"> | |
| <label class="block text-sm font-medium text-slate-700 mb-1">目标 URL</label> | |
| <input v-model="inputUrl" type="text" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-slate-500 focus:ring-slate-500 text-sm p-3 border" placeholder="https://example.com/article"> | |
| </div> | |
| <div v-else> | |
| <label class="block text-sm font-medium text-slate-700 mb-1">上传文件 (支持 .txt, .md)</label> | |
| <div @click="triggerUpload" class="border-2 border-dashed border-slate-300 rounded-lg p-6 text-center hover:border-slate-500 cursor-pointer transition-colors bg-slate-50"> | |
| <input type="file" ref="fileInput" @change="handleFileChange" class="hidden"> | |
| <div v-if="selectedFile" class="text-sm text-slate-900 font-medium flex items-center justify-center gap-2"> | |
| <svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg> | |
| ${ selectedFile.name } | |
| </div> | |
| <div v-else class="text-slate-500 text-sm"> | |
| <p>点击选择文件或拖拽至此处</p> | |
| <p class="text-xs mt-1 text-slate-400">最大支持 50MB</p> | |
| </div> | |
| </div> | |
| </div> | |
| <button @click="startMining" :disabled="isProcessing" class="w-full btn-primary py-2.5 rounded-lg font-medium flex items-center justify-center gap-2"> | |
| <span v-if="isProcessing"> | |
| <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> | |
| 深度挖掘中... | |
| </span> | |
| <span v-else>开始提炼资产</span> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- History / Vault Preview --> | |
| <div class="card p-6"> | |
| <h2 class="text-lg font-medium mb-4">资产库</h2> | |
| <div v-if="vault.length === 0" class="text-center text-slate-400 py-8 text-sm"> | |
| 暂无提炼资产 | |
| </div> | |
| <ul v-else class="space-y-3"> | |
| <li v-for="item in vault" :key="item.id" @click="loadItem(item)" class="p-3 hover:bg-slate-50 rounded-lg cursor-pointer border border-transparent hover:border-slate-200 transition-all"> | |
| <div class="flex justify-between items-start mb-1"> | |
| <span class="text-xs font-mono text-slate-400">${ item.timestamp.split(' ')[1] }</span> | |
| <span class="tag bg-blue-100 text-blue-700">${ item.metrics.commercial_value }分</span> | |
| </div> | |
| <div class="text-sm text-slate-700 line-clamp-2">${ item.summary }</div> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| <!-- Right Column: Results & Visualization --> | |
| <div class="lg:col-span-8 space-y-6"> | |
| <!-- Welcome State --> | |
| <div v-if="!currentAnalysis" class="h-full flex flex-col items-center justify-center text-center p-12 border-2 border-dashed border-slate-200 rounded-xl bg-slate-50/50"> | |
| <div class="w-16 h-16 bg-slate-100 rounded-full flex items-center justify-center mb-4"> | |
| <svg class="w-8 h-8 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg> | |
| </div> | |
| <h3 class="text-lg font-medium text-slate-900">准备就绪</h3> | |
| <p class="text-slate-500 max-w-md mt-2">输入文本或 URL,智能体将自动提炼关键信息、评估商业价值并生成结构化知识资产。</p> | |
| </div> | |
| <!-- Analysis Result --> | |
| <div v-else class="space-y-6"> | |
| <!-- Metrics & Summary --> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div class="card p-4 flex flex-col items-center justify-center text-center"> | |
| <div class="text-sm text-slate-500 mb-1">商业价值评分</div> | |
| <div class="text-3xl font-bold text-slate-900">${ currentAnalysis.metrics.commercial_value }</div> | |
| <div class="w-full bg-gray-200 rounded-full h-1.5 mt-3"> | |
| <div class="bg-slate-900 h-1.5 rounded-full" :style="{ width: currentAnalysis.metrics.commercial_value + '%' }"></div> | |
| </div> | |
| </div> | |
| <div class="card p-4 flex flex-col items-center justify-center text-center"> | |
| <div class="text-sm text-slate-500 mb-1">信息复杂度</div> | |
| <div class="text-3xl font-bold text-slate-900">${ currentAnalysis.metrics.complexity }</div> | |
| <div class="text-xs text-slate-400 mt-1">Mock Analysis</div> | |
| </div> | |
| <div class="card p-4 flex flex-col items-center justify-center text-center"> | |
| <div class="text-sm text-slate-500 mb-1">情感倾向</div> | |
| <div class="text-3xl font-bold text-green-600" v-if="currentAnalysis.metrics.sentiment > 0.6">积极</div> | |
| <div class="text-3xl font-bold text-yellow-600" v-else-if="currentAnalysis.metrics.sentiment > 0.4">中性</div> | |
| <div class="text-3xl font-bold text-red-600" v-else>消极</div> | |
| </div> | |
| </div> | |
| <!-- Main Report --> | |
| <div class="card p-6"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-xl font-bold text-slate-900">提炼报告</h2> | |
| <div class="flex gap-2"> | |
| <button @click="generateAsset('report')" class="text-sm border border-slate-300 px-3 py-1.5 rounded hover:bg-slate-50">下载 PDF</button> | |
| <button @click="generateAsset('mindmap')" class="text-sm border border-slate-300 px-3 py-1.5 rounded hover:bg-slate-50">导出脑图</button> | |
| </div> | |
| </div> | |
| <div class="bg-slate-50 p-4 rounded-lg border border-slate-100 mb-6"> | |
| <h3 class="text-sm font-semibold text-slate-700 uppercase tracking-wider mb-2">摘要</h3> | |
| <p class="text-slate-600 leading-relaxed">${ currentAnalysis.summary }</p> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="text-sm font-semibold text-slate-700 uppercase tracking-wider mb-3">关键洞察</h3> | |
| <ul class="space-y-2"> | |
| <li v-for="(insight, index) in currentAnalysis.insights" :key="index" class="flex items-start gap-3"> | |
| <span class="flex-shrink-0 w-6 h-6 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center text-xs font-bold">${ index + 1 }</span> | |
| <span class="text-slate-700">${ insight }</span> | |
| </li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h3 class="text-sm font-semibold text-slate-700 uppercase tracking-wider mb-3">关联标签</h3> | |
| <div class="flex flex-wrap gap-2"> | |
| <span v-for="tag in currentAnalysis.tags" :key="tag" class="tag bg-slate-100 text-slate-600 border border-slate-200">#${ tag }</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Chart --> | |
| <div class="card p-6"> | |
| <h2 class="text-lg font-medium mb-4">趋势雷达</h2> | |
| <div ref="radarChart" class="w-full h-64"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| <script> | |
| const { createApp, ref, onMounted, nextTick } = Vue; | |
| createApp({ | |
| delimiters: ['${', '}'], | |
| setup() { | |
| const inputType = ref('text'); | |
| const inputText = ref('2024年 AI 代理(AI Agents)市场正迎来爆发式增长。企业不再仅仅满足于聊天机器人,而是寻求能够执行复杂任务、自主决策的智能体。从软件开发到市场营销,Agent 正在重塑工作流程。然而,数据安全和幻觉问题依然是主要挑战。预计到 2025 年,Agent 市场规模将突破 500 亿美元。'); | |
| const inputUrl = ref(''); | |
| const isProcessing = ref(false); | |
| const currentAnalysis = ref(null); | |
| const vault = ref([]); | |
| const radarChart = ref(null); | |
| const fileInput = ref(null); | |
| const selectedFile = ref(null); | |
| let chartInstance = null; | |
| const triggerUpload = () => { | |
| fileInput.value.click(); | |
| }; | |
| const handleFileChange = (event) => { | |
| const file = event.target.files[0]; | |
| if (file) { | |
| if (file.size > 50 * 1024 * 1024) { | |
| alert('文件大小超过 50MB 限制'); | |
| event.target.value = ''; | |
| return; | |
| } | |
| selectedFile.value = file; | |
| } | |
| }; | |
| const startMining = async () => { | |
| isProcessing.value = true; | |
| try { | |
| let response; | |
| if (inputType.value === 'file') { | |
| if (!selectedFile.value) { | |
| alert('请先选择文件'); | |
| isProcessing.value = false; | |
| return; | |
| } | |
| const formData = new FormData(); | |
| formData.append('file', selectedFile.value); | |
| formData.append('type', 'file'); | |
| response = await fetch('/api/mine', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| } else { | |
| const content = inputType.value === 'text' ? inputText.value : inputUrl.value; | |
| if (!content) { | |
| alert('请输入内容'); | |
| isProcessing.value = false; | |
| return; | |
| } | |
| response = await fetch('/api/mine', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ content, type: inputType.value }) | |
| }); | |
| } | |
| if (!response.ok) { | |
| const errorData = await response.json(); | |
| throw new Error(errorData.error || 'Request failed'); | |
| } | |
| const data = await response.json(); | |
| currentAnalysis.value = data; | |
| vault.value.unshift(data); | |
| await nextTick(); | |
| initChart(); | |
| } catch (error) { | |
| console.error("Mining failed", error); | |
| alert("分析失败: " + error.message); | |
| } finally { | |
| isProcessing.value = false; | |
| } | |
| }; | |
| const loadItem = async (item) => { | |
| currentAnalysis.value = item; | |
| await nextTick(); | |
| initChart(); | |
| }; | |
| const generateAsset = async (type) => { | |
| alert(`正在生成 ${type === 'report' ? 'PDF 报告' : '思维导图'}... \n(Mock Function: Asset Generated)`); | |
| }; | |
| const initChart = () => { | |
| if (!radarChart.value) return; | |
| if (chartInstance) { | |
| chartInstance.dispose(); | |
| } | |
| chartInstance = echarts.init(radarChart.value); | |
| const metrics = currentAnalysis.value.metrics; | |
| const option = { | |
| radar: { | |
| indicator: [ | |
| { name: '商业价值', max: 100 }, | |
| { name: '技术可行性', max: 100 }, | |
| { name: '市场热度', max: 100 }, | |
| { name: '合规风险', max: 100 }, | |
| { name: '创新度', max: 100 } | |
| ], | |
| radius: '70%' | |
| }, | |
| series: [{ | |
| name: 'Asset Analysis', | |
| type: 'radar', | |
| data: [{ | |
| value: [ | |
| metrics.commercial_value, | |
| Math.random() * 40 + 60, | |
| Math.random() * 40 + 60, | |
| 100 - metrics.complexity, | |
| Math.random() * 50 + 50 | |
| ], | |
| name: '当前项目', | |
| itemStyle: { color: '#0f172a' }, | |
| areaStyle: { opacity: 0.2 } | |
| }] | |
| }] | |
| }; | |
| chartInstance.setOption(option); | |
| window.addEventListener('resize', () => chartInstance.resize()); | |
| }; | |
| onMounted(() => { | |
| // Optional: Fetch initial history | |
| // fetch('/api/vault').then(r => r.json()).then(d => vault.value = d); | |
| }); | |
| return { | |
| inputType, | |
| inputText, | |
| inputUrl, | |
| isProcessing, | |
| currentAnalysis, | |
| vault, | |
| radarChart, | |
| fileInput, | |
| selectedFile, | |
| triggerUpload, | |
| handleFileChange, | |
| startMining, | |
| loadItem, | |
| generateAsset | |
| }; | |
| } | |
| }).mount('#app'); | |
| </script> | |
| </body> | |
| </html> | |