feat: 添加万川AI平台对接功能
- 新增万川AI平台API接口层,支持登录、获取知识库列表、上传文件等操作 - 实现万川平台配置界面,支持平台地址、账号密码配置和知识库绑定 - 在知识库页面添加上传功能,支持单个或批量上传售后报告到万川知识库 - 提供检查配置的工具脚本便于调试
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Plus, Trash2, Sparkles, RefreshCw, ChevronRight, Loader, Settings2, X, Download } from 'lucide-react'
|
||||
import { Plus, Trash2, Sparkles, RefreshCw, ChevronRight, Loader, Settings2, X, Download, Upload } from 'lucide-react'
|
||||
import dayjs from 'dayjs'
|
||||
import {
|
||||
getGroups,
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
import MessageBubble from '../components/MessageBubble'
|
||||
import ReportDocumentView from '../components/ReportDocumentView'
|
||||
import { exportWordDoc } from '../utils/wordExport'
|
||||
import { uploadToKnowledgeBase, getWanchuanKnowledgeBases } from '../api/wanchuan'
|
||||
|
||||
const TYPE_MAP = {
|
||||
1: 0,
|
||||
@@ -139,6 +140,8 @@ export default function TopicsPage({ sessions = [], onToast }) {
|
||||
const [groupPromptDraft, setGroupPromptDraft] = useState('')
|
||||
const [savingGroupPrompt, setSavingGroupPrompt] = useState(false)
|
||||
|
||||
|
||||
const [uploadingToKb, setUploadingToKb] = useState(false)
|
||||
const loadGroups = useCallback(async () => {
|
||||
try {
|
||||
const data = await getGroups()
|
||||
@@ -550,6 +553,7 @@ export default function TopicsPage({ sessions = [], onToast }) {
|
||||
|
||||
const handleSummarize = async () => {
|
||||
if (!selectedTopic) return
|
||||
if (uploadingToKb) return
|
||||
setSummarizing(true)
|
||||
setSummarizeProgress(null)
|
||||
try {
|
||||
@@ -566,7 +570,9 @@ export default function TopicsPage({ sessions = [], onToast }) {
|
||||
}
|
||||
|
||||
let tries = 0
|
||||
let handled = false
|
||||
const poll = setInterval(async () => {
|
||||
if (handled) return
|
||||
tries += 1
|
||||
try {
|
||||
const task = await getTask(taskId)
|
||||
@@ -578,14 +584,26 @@ export default function TopicsPage({ sessions = [], onToast }) {
|
||||
// Ignore malformed progress payloads.
|
||||
}
|
||||
if (taskData.status === 'done') {
|
||||
handled = true
|
||||
clearInterval(poll)
|
||||
setSummarizeProgress(null)
|
||||
setSummarizing(false)
|
||||
handleSelectTopic(selectedTopic)
|
||||
onToast?.('AI 报告生成完成')
|
||||
// 报告生成成功后,如果已绑定知识库则自动上传
|
||||
try {
|
||||
const freshDetail = await getTopic(selectedTopic.id)
|
||||
const reportContent = freshDetail?.knowledge_doc?.content
|
||||
if (reportContent) {
|
||||
await uploadToKnowledgeBaseIfBound(selectedTopic.title, reportContent)
|
||||
}
|
||||
} catch {
|
||||
// 获取报告详情失败不影响主流程
|
||||
}
|
||||
setSummarizeProgress(null)
|
||||
setSummarizing(false)
|
||||
return
|
||||
}
|
||||
if (taskData.status === 'error') {
|
||||
handled = true
|
||||
clearInterval(poll)
|
||||
setSummarizeProgress(null)
|
||||
setSummarizing(false)
|
||||
@@ -594,6 +612,7 @@ export default function TopicsPage({ sessions = [], onToast }) {
|
||||
return
|
||||
}
|
||||
if (tries > 60) {
|
||||
handled = true
|
||||
clearInterval(poll)
|
||||
setSummarizeProgress(null)
|
||||
setSummarizing(false)
|
||||
@@ -602,6 +621,7 @@ export default function TopicsPage({ sessions = [], onToast }) {
|
||||
}
|
||||
} catch (e) {
|
||||
if (tries > 60) {
|
||||
handled = true
|
||||
clearInterval(poll)
|
||||
setSummarizeProgress(null)
|
||||
setSummarizing(false)
|
||||
@@ -631,6 +651,37 @@ export default function TopicsPage({ sessions = [], onToast }) {
|
||||
}
|
||||
}
|
||||
|
||||
// 上传报告到已绑定的万川知识库
|
||||
const uploadToKnowledgeBaseIfBound = async (reportTitle, content) => {
|
||||
if (uploadingToKb) return
|
||||
setUploadingToKb(true)
|
||||
try {
|
||||
const raw = localStorage.getItem('chatlab_wanchuan_config')
|
||||
if (!raw) return
|
||||
const bound = JSON.parse(raw)
|
||||
const kbInfo = bound?.selectedKbInfo
|
||||
// 上传接口必须使用 datasetId。selectedKbId 现已统一存为 datasetId,
|
||||
// selectedKbInfo.kbDatasetId 为冗余备份,两者任一可用。
|
||||
const datasetId = kbInfo?.kbDatasetId || bound?.selectedKbId
|
||||
if (!bound?.platformUrl || !datasetId) return
|
||||
|
||||
const safeTitle = (reportTitle || 'report').replace(/[^a-zA-Z0-9\u4e00-\u9fa5_-]/g, '_').slice(0, 50)
|
||||
// 上传接口必须使用 datasetId,而不是知识库对象的 id
|
||||
console.log('[上传KB] datasetId:', datasetId, 'kbName:', kbInfo?.kbName || 'N/A')
|
||||
const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' })
|
||||
const file = new File([blob], `${safeTitle}.md`, { type: 'text/markdown' })
|
||||
|
||||
// 上传接口使用 datasetId
|
||||
await uploadToKnowledgeBase(bound.platformUrl, datasetId, file)
|
||||
onToast?.('报告已同步上传到知识库')
|
||||
} catch (e) {
|
||||
console.error('[上传知识库失败]', e?.message || e)
|
||||
onToast?.(`报告生成成功,但上传到知识库失败: ${e.message}`, 'error')
|
||||
} finally {
|
||||
setUploadingToKb(false)
|
||||
}
|
||||
}
|
||||
|
||||
const selectedInitState = selectedGroup ? initStateByGroup[selectedGroup.id] : null
|
||||
const analyzing = selectedInitState?.status === 'running'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user