[AC-AISVC-02, AC-AISVC-16] 多个需求合并 #1
|
|
@ -0,0 +1,50 @@
|
|||
import request from '@/utils/request'
|
||||
import type {
|
||||
LLMProviderInfo,
|
||||
LLMConfig,
|
||||
LLMConfigUpdate,
|
||||
LLMTestResult,
|
||||
LLMTestRequest,
|
||||
LLMProvidersResponse,
|
||||
LLMConfigUpdateResponse
|
||||
} from '@/types/llm'
|
||||
|
||||
export function getLLMProviders(): Promise<LLMProvidersResponse> {
|
||||
return request({
|
||||
url: '/llm/providers',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getLLMConfig(): Promise<LLMConfig> {
|
||||
return request({
|
||||
url: '/llm/config',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function saveLLMConfig(data: LLMConfigUpdate): Promise<LLMConfigUpdateResponse> {
|
||||
return request({
|
||||
url: '/llm/config',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function testLLM(data: LLMTestRequest): Promise<LLMTestResult> {
|
||||
return request({
|
||||
url: '/llm/test',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export type {
|
||||
LLMProviderInfo,
|
||||
LLMConfig,
|
||||
LLMConfigUpdate,
|
||||
LLMTestResult,
|
||||
LLMTestRequest,
|
||||
LLMProvidersResponse,
|
||||
LLMConfigUpdateResponse
|
||||
}
|
||||
|
|
@ -1,9 +1,131 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
export function runRagExperiment(data: { query: string, kbIds?: string[], params?: any }) {
|
||||
export interface AIResponse {
|
||||
content: string
|
||||
prompt_tokens?: number
|
||||
completion_tokens?: number
|
||||
total_tokens?: number
|
||||
latency_ms?: number
|
||||
model?: string
|
||||
}
|
||||
|
||||
export interface RetrievalResult {
|
||||
content: string
|
||||
score: number
|
||||
source: string
|
||||
metadata?: Record<string, any>
|
||||
}
|
||||
|
||||
export interface RagExperimentRequest {
|
||||
query: string
|
||||
kb_ids?: string[]
|
||||
top_k?: number
|
||||
score_threshold?: number
|
||||
llm_provider?: string
|
||||
generate_response?: boolean
|
||||
}
|
||||
|
||||
export interface RagExperimentResult {
|
||||
query: string
|
||||
retrieval_results?: RetrievalResult[]
|
||||
final_prompt?: string
|
||||
ai_response?: AIResponse
|
||||
total_latency_ms?: number
|
||||
}
|
||||
|
||||
export function runRagExperiment(data: RagExperimentRequest): Promise<RagExperimentResult> {
|
||||
return request({
|
||||
url: '/admin/rag/experiments/run',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function runRagExperimentStream(
|
||||
data: RagExperimentRequest,
|
||||
onMessage: (event: MessageEvent) => void,
|
||||
onError?: (error: Event) => void,
|
||||
onComplete?: () => void
|
||||
): EventSource {
|
||||
const baseUrl = import.meta.env.VITE_APP_BASE_API || '/api'
|
||||
const url = `${baseUrl}/admin/rag/experiments/stream`
|
||||
|
||||
const eventSource = new EventSource(url, {
|
||||
withCredentials: true
|
||||
})
|
||||
|
||||
eventSource.onmessage = onMessage
|
||||
eventSource.onerror = (error) => {
|
||||
eventSource.close()
|
||||
onError?.(error)
|
||||
}
|
||||
|
||||
return eventSource
|
||||
}
|
||||
|
||||
export function createSSEConnection(
|
||||
url: string,
|
||||
body: RagExperimentRequest,
|
||||
onMessage: (data: string) => void,
|
||||
onError?: (error: Error) => void,
|
||||
onComplete?: () => void
|
||||
): () => void {
|
||||
const baseUrl = import.meta.env.VITE_APP_BASE_API || '/api'
|
||||
const fullUrl = `${baseUrl}${url}`
|
||||
|
||||
const controller = new AbortController()
|
||||
|
||||
fetch(fullUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'text/event-stream',
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
signal: controller.signal
|
||||
})
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
|
||||
const reader = response.body?.getReader()
|
||||
if (!reader) {
|
||||
throw new Error('No response body')
|
||||
}
|
||||
|
||||
const decoder = new TextDecoder()
|
||||
let buffer = ''
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
|
||||
if (done) {
|
||||
onComplete?.()
|
||||
break
|
||||
}
|
||||
|
||||
buffer += decoder.decode(value, { stream: true })
|
||||
const lines = buffer.split('\n')
|
||||
buffer = lines.pop() || ''
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('data: ')) {
|
||||
const data = line.slice(6)
|
||||
if (data === '[DONE]') {
|
||||
onComplete?.()
|
||||
return
|
||||
}
|
||||
onMessage(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name !== 'AbortError') {
|
||||
onError?.(error)
|
||||
}
|
||||
})
|
||||
|
||||
return () => controller.abort()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
export interface LLMProviderInfo {
|
||||
name: string
|
||||
display_name: string
|
||||
description?: string
|
||||
config_schema: Record<string, any>
|
||||
}
|
||||
|
||||
export interface LLMConfig {
|
||||
provider: string
|
||||
config: Record<string, any>
|
||||
updated_at?: string
|
||||
}
|
||||
|
||||
export interface LLMConfigUpdate {
|
||||
provider: string
|
||||
config?: Record<string, any>
|
||||
}
|
||||
|
||||
export interface LLMTestResult {
|
||||
success: boolean
|
||||
response?: string
|
||||
latency_ms?: number
|
||||
prompt_tokens?: number
|
||||
completion_tokens?: number
|
||||
total_tokens?: number
|
||||
message?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface LLMTestRequest {
|
||||
test_prompt?: string
|
||||
config?: LLMConfigUpdate
|
||||
}
|
||||
|
||||
export interface LLMProvidersResponse {
|
||||
providers: LLMProviderInfo[]
|
||||
}
|
||||
|
||||
export interface LLMConfigUpdateResponse {
|
||||
success: boolean
|
||||
message: string
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ version: "0.3.0"
|
|||
- [x] (P5-01~P5-06) 后端管理接口实现
|
||||
|
||||
#### Phase 6: 嵌入模型管理(待处理)
|
||||
- [ ] (P5-01) API 服务层与类型定义 [AC-ASA-08, AC-ASA-09]
|
||||
- [x] (P5-01) API 服务层与类型定义 [AC-ASA-08, AC-ASA-09]
|
||||
- [ ] (P5-02) 提供者选择组件 [AC-ASA-09]
|
||||
- [ ] (P5-03) 动态配置表单 [AC-ASA-09, AC-ASA-10]
|
||||
- [ ] (P5-04) 测试连接组件 [AC-ASA-11, AC-ASA-12]
|
||||
|
|
@ -60,7 +60,7 @@ version: "0.3.0"
|
|||
- [ ] (P5-08) 组件整合与测试 [AC-ASA-08~AC-ASA-13]
|
||||
|
||||
#### Phase 7: LLM 配置与 RAG 调试输出(当前)
|
||||
- [ ] (P6-01) LLM API 服务层与类型定义:创建 src/api/llm.ts 和 src/types/llm.ts [AC-ASA-14, AC-ASA-15]
|
||||
- [x] (P6-01) LLM API 服务层与类型定义:创建 src/api/llm.ts 和 src/types/llm.ts [AC-ASA-14, AC-ASA-15]
|
||||
- [ ] (P6-02) LLM 提供者选择组件:创建 LLMProviderSelect.vue [AC-ASA-15]
|
||||
- [ ] (P6-03) LLM 动态配置表单:创建 LLMConfigForm.vue [AC-ASA-15, AC-ASA-16]
|
||||
- [ ] (P6-04) LLM 测试连接组件:创建 LLMTestPanel.vue [AC-ASA-17, AC-ASA-18]
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ principles:
|
|||
|
||||
> 页面导向:嵌入模型配置页面,支持提供者切换、参数配置、连接测试。
|
||||
|
||||
- [ ] (P5-01) API 服务层与类型定义:创建 src/api/embedding.ts 和 src/types/embedding.ts
|
||||
- [x] (P5-01) API 服务层与类型定义:创建 src/api/embedding.ts 和 src/types/embedding.ts
|
||||
- AC: [AC-ASA-08, AC-ASA-09]
|
||||
|
||||
- [ ] (P5-02) 提供者选择组件:实现 `EmbeddingProviderSelect` 下拉组件,对接 `/admin/embedding/providers`
|
||||
|
|
@ -153,7 +153,7 @@ principles:
|
|||
|
||||
| 任务 | 描述 | 状态 |
|
||||
|------|------|------|
|
||||
| P5-01 | API 服务层与类型定义 | ⏳ 待处理 |
|
||||
| P5-01 | API 服务层与类型定义 | ✅ 已完成 |
|
||||
| P5-02 | 提供者选择组件 | ⏳ 待处理 |
|
||||
| P5-03 | 动态配置表单 | ⏳ 待处理 |
|
||||
| P5-04 | 测试连接组件 | ⏳ 待处理 |
|
||||
|
|
@ -170,7 +170,7 @@ principles:
|
|||
|
||||
### 6.1 LLM 模型配置
|
||||
|
||||
- [ ] (P6-01) LLM API 服务层与类型定义:创建 src/api/llm.ts 和 src/types/llm.ts
|
||||
- [x] (P6-01) LLM API 服务层与类型定义:创建 src/api/llm.ts 和 src/types/llm.ts
|
||||
- AC: [AC-ASA-14, AC-ASA-15]
|
||||
|
||||
- [ ] (P6-02) LLM 提供者选择组件:实现 `LLMProviderSelect` 下拉组件
|
||||
|
|
@ -208,7 +208,7 @@ principles:
|
|||
|
||||
| 任务 | 描述 | 状态 |
|
||||
|------|------|------|
|
||||
| P6-01 | LLM API 服务层与类型定义 | ⏳ 待处理 |
|
||||
| P6-01 | LLM API 服务层与类型定义 | ✅ 已完成 |
|
||||
| P6-02 | LLM 提供者选择组件 | ⏳ 待处理 |
|
||||
| P6-03 | LLM 动态配置表单 | ⏳ 待处理 |
|
||||
| P6-04 | LLM 测试连接组件 | ⏳ 待处理 |
|
||||
|
|
|
|||
Loading…
Reference in New Issue