Initial commit

This commit is contained in:
2025-12-02 02:06:51 +08:00
commit eb6c0c51fa
37 changed files with 7454 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
import type {
ModelListResponse,
StreamAnalyzeRequest,
StreamAnalyzeResponse,
Step1Result,
CausalChain
} from '../types';
// 自動使用當前瀏覽器的 hostname支援遠端存取
const API_BASE_URL = `http://${window.location.hostname}:8000/api`;
export interface SSECallbacks {
onStep1Start?: () => void;
onStep1Complete?: (result: Step1Result) => void;
onChainStart?: (index: number, total: number) => void;
onChainComplete?: (index: number, chain: CausalChain) => void;
onChainError?: (index: number, error: string) => void;
onDone?: (response: StreamAnalyzeResponse) => void;
onError?: (error: string) => void;
}
export async function analyzeAttributesStream(
request: StreamAnalyzeRequest,
callbacks: SSECallbacks
): Promise<void> {
const response = await fetch(`${API_BASE_URL}/analyze`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
});
if (!response.ok) {
throw new Error(`API error: ${response.statusText}`);
}
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) break;
buffer += decoder.decode(value, { stream: true });
// 解析 SSE 事件
const lines = buffer.split('\n\n');
buffer = lines.pop() || ''; // 保留未完成的部分
for (const chunk of lines) {
if (!chunk.trim()) continue;
const eventMatch = chunk.match(/event: (\w+)/);
const dataMatch = chunk.match(/data: (.+)/s);
if (eventMatch && dataMatch) {
const eventType = eventMatch[1];
try {
const eventData = JSON.parse(dataMatch[1]);
switch (eventType) {
case 'step1_start':
callbacks.onStep1Start?.();
break;
case 'step1_complete':
callbacks.onStep1Complete?.(eventData.result);
break;
case 'chain_start':
callbacks.onChainStart?.(eventData.index, eventData.total);
break;
case 'chain_complete':
callbacks.onChainComplete?.(eventData.index, eventData.chain);
break;
case 'chain_error':
callbacks.onChainError?.(eventData.index, eventData.error);
break;
case 'done':
callbacks.onDone?.(eventData);
break;
case 'error':
callbacks.onError?.(eventData.error);
break;
}
} catch (e) {
console.error('Failed to parse SSE event:', e, chunk);
}
}
}
}
}
export async function getModels(): Promise<ModelListResponse> {
const response = await fetch(`${API_BASE_URL}/models`);
if (!response.ok) {
throw new Error(`API error: ${response.statusText}`);
}
return response.json();
}