Spaces:
Sleeping
Sleeping
File size: 2,887 Bytes
0d37119 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | import { useState, useCallback } from 'react';
const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || (import.meta.env.DEV ? 'http://localhost:8000' : '');
export default function useOperatorSSE() {
const [toolCalls, setToolCalls] = useState([]);
const [projectStatuses, setProjectStatuses] = useState({});
const [briefText, setBriefText] = useState(null);
const [isScanning, setIsScanning] = useState(false);
const [isLive, setIsLive] = useState(false);
const startScan = useCallback(() => {
setToolCalls([]);
setProjectStatuses({});
setBriefText(null);
setIsScanning(true);
setIsLive(false);
const source = new EventSource(`${BACKEND_URL}/api/run`);
source.addEventListener('mode', (e) => {
const data = JSON.parse(e.data);
setIsLive(data.live);
});
source.addEventListener('tool_call', (e) => {
const data = JSON.parse(e.data);
setToolCalls(prev => [...prev, { tool: data.tool, project: data.project, status: 'running' }]);
});
source.addEventListener('tool_result', (e) => {
const data = JSON.parse(e.data);
setToolCalls(prev => {
const updated = [...prev];
const idx = updated.findLastIndex(t => t.tool === data.tool && t.project === data.project);
if (idx >= 0) updated[idx] = { ...updated[idx], status: 'done' };
return updated;
});
});
source.addEventListener('initiative', (e) => {
const data = JSON.parse(e.data);
setProjectStatuses(prev => ({ ...prev, [data.project]: data }));
});
source.addEventListener('brief', (e) => {
const data = JSON.parse(e.data);
setBriefText(data.text);
setIsScanning(false);
source.close();
});
source.onerror = () => {
setIsScanning(false);
source.close();
};
}, []);
const sendChat = useCallback(async (message) => {
const res = await fetch(`${BACKEND_URL}/api/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message }),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let replyText = '';
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data:') || line.startsWith('data: ')) {
try {
const data = JSON.parse(line.replace(/^data:\s*/, ''));
if (data.type === 'chat_reply') {
replyText = data.text;
}
} catch { /* skip */ }
}
}
}
return replyText;
}, []);
return { toolCalls, projectStatuses, briefText, isScanning, isLive, startScan, sendChat };
}
|