160 lines
4.5 KiB
TypeScript
160 lines
4.5 KiB
TypeScript
import { useMemo, useCallback } from 'react'
|
||
import { request } from '@/http/request'
|
||
import type { TaskArtifact } from '../types'
|
||
import type { PlatformConfig } from './useNovaEvents'
|
||
|
||
export interface ConversationInfo {
|
||
conversation_id: string
|
||
title?: string
|
||
task_status?: string
|
||
is_read?: boolean
|
||
is_favourite?: boolean
|
||
}
|
||
|
||
interface UseNovaServiceProps {
|
||
platformConfig?: PlatformConfig
|
||
getToken?: () => string | undefined
|
||
getTenantId?: () => string | undefined
|
||
conversationId?: string
|
||
}
|
||
|
||
interface DirFileItem {
|
||
desc?: string
|
||
file_name?: string
|
||
file_type?: string
|
||
last_modified?: number
|
||
path?: string
|
||
}
|
||
|
||
const toAbsoluteHttpUrl = (value: unknown): string | null => {
|
||
if (typeof value !== 'string' || !value) return null
|
||
if (value.startsWith('http://') || value.startsWith('https://')) return value
|
||
return null
|
||
}
|
||
|
||
const extractDirFileList = (payload: unknown): DirFileItem[] => {
|
||
if (Array.isArray(payload)) return payload
|
||
if (!payload || typeof payload !== 'object') return []
|
||
const obj = payload as Record<string, unknown>
|
||
if (Array.isArray(obj.data)) return obj.data as DirFileItem[]
|
||
return []
|
||
}
|
||
|
||
const normalizeFileName = (name: string): string => {
|
||
const raw = name.trim()
|
||
if (!raw) return ''
|
||
const withoutPrefix = raw.startsWith('/upload/') ? raw.slice('/upload/'.length) : raw
|
||
return withoutPrefix
|
||
}
|
||
|
||
const resolvePathByName = (files: DirFileItem[], fileName?: string): string | null => {
|
||
if (!fileName) return null
|
||
const normalizedName = normalizeFileName(fileName)
|
||
if (!normalizedName) return null
|
||
|
||
const expectedSegment = `upload/${normalizedName}`
|
||
const matched = files.find(item => {
|
||
if (typeof item.file_name !== 'string' || !item.file_name) return false
|
||
return item.file_name.includes(expectedSegment)
|
||
})
|
||
|
||
return matched?.path || null
|
||
}
|
||
|
||
export function useNovaService({
|
||
platformConfig,
|
||
conversationId,
|
||
}: UseNovaServiceProps) {
|
||
// API Client Singleton
|
||
const apiClient = useMemo(() => {
|
||
if (!platformConfig?.apiBaseUrl) {
|
||
return null
|
||
}
|
||
|
||
return request
|
||
}, [platformConfig])
|
||
|
||
// Get Artifact URL Method
|
||
const getArtifactUrl = useCallback(
|
||
async (
|
||
artifact: TaskArtifact,
|
||
params?: Record<string, string>
|
||
): Promise<{ data: string }> => {
|
||
try {
|
||
if (!apiClient) {
|
||
throw new Error('API client is not initialized')
|
||
}
|
||
|
||
const taskId = artifact.task_id || conversationId
|
||
let resolvedPath = artifact.path
|
||
|
||
if (taskId) {
|
||
const dirFilesResponse = await apiClient.post<unknown>(
|
||
'/v1/super_agent/chat/get_dir_file',
|
||
{ task_id: taskId }
|
||
)
|
||
const dirFiles = extractDirFileList(dirFilesResponse)
|
||
const matchedPath = resolvePathByName(dirFiles, artifact.file_name)
|
||
if (matchedPath) {
|
||
resolvedPath = matchedPath
|
||
}
|
||
}
|
||
|
||
// Call OSS URL interface
|
||
const response = await apiClient.post<string>('/chat/oss_url', {
|
||
file_path: resolvedPath,
|
||
task_id: taskId,
|
||
params
|
||
})
|
||
const signedUrl = toAbsoluteHttpUrl(response) || ''
|
||
const fallback = toAbsoluteHttpUrl(artifact.path) || ''
|
||
return { data: signedUrl || fallback }
|
||
} catch (error) {
|
||
console.error('Failed to fetch artifact URL:', error)
|
||
return { data: toAbsoluteHttpUrl(artifact.path) || '' }
|
||
}
|
||
},
|
||
[conversationId, apiClient]
|
||
)
|
||
|
||
const stopChat = useCallback(async () => {
|
||
try {
|
||
if (!apiClient) {
|
||
throw new Error('API client is not initialized')
|
||
}
|
||
|
||
if (!conversationId) {
|
||
throw new Error('Conversation ID is required')
|
||
}
|
||
|
||
await apiClient.get('/chat/stop', { conversation_id: conversationId })
|
||
} catch (error) {
|
||
console.error('Failed to stop chat:', error)
|
||
throw error
|
||
}
|
||
}, [conversationId, apiClient])
|
||
|
||
/** 获取会话信息列表(用于轮询 task_status),使用 novaRequest */
|
||
const getConversationInfoList = useCallback(
|
||
async (conversationIds: string[]) => {
|
||
if (conversationIds.length === 0) {
|
||
return { data: [] as ConversationInfo[] }
|
||
}
|
||
const res = await request.post<{ data?: ConversationInfo[] } | ConversationInfo[]>(
|
||
'/conversation/info',
|
||
{ conversation_ids: conversationIds }
|
||
)
|
||
const list = Array.isArray(res) ? res : (res?.data ?? [])
|
||
return { data: list }
|
||
},
|
||
[]
|
||
)
|
||
|
||
return {
|
||
apiClient,
|
||
getArtifactUrl,
|
||
stopChat,
|
||
getConversationInfoList,
|
||
}
|
||
}
|