Spaces:
Sleeping
Sleeping
Commit ·
fa81e4d
1
Parent(s): 4afa792
feat: add frontend WebSocket integration with episode progress tracking
Browse files
frontend/src/hooks/useEpisodeProgress.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useEffect, useState } from 'react';
|
| 2 |
+
import { useWebSocket } from '@/hooks/useWebSocket';
|
| 3 |
+
import type { WebSocketMessage } from '@/types';
|
| 4 |
+
|
| 5 |
+
interface EpisodeProgressProps {
|
| 6 |
+
episodeId: string | null;
|
| 7 |
+
onProgressUpdate?: (data: WebSocketMessage) => void;
|
| 8 |
+
onCompletion?: (data: WebSocketMessage) => void;
|
| 9 |
+
onError?: (error: string) => void;
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
export function useEpisodeProgress({
|
| 13 |
+
episodeId,
|
| 14 |
+
onProgressUpdate,
|
| 15 |
+
onCompletion,
|
| 16 |
+
onError,
|
| 17 |
+
}: EpisodeProgressProps) {
|
| 18 |
+
const [currentStep, setCurrentStep] = useState(0);
|
| 19 |
+
const [totalReward, setTotalReward] = useState(0);
|
| 20 |
+
const [progress, setProgress] = useState(0);
|
| 21 |
+
const [lastAction, setLastAction] = useState<string>('');
|
| 22 |
+
const [isCompleted, setIsCompleted] = useState(false);
|
| 23 |
+
const [error, setError] = useState<string | null>(null);
|
| 24 |
+
|
| 25 |
+
const { isConnected, lastMessage } = useWebSocket(
|
| 26 |
+
episodeId ? `/ws/episode/${episodeId}` : '',
|
| 27 |
+
{
|
| 28 |
+
autoConnect: !!episodeId,
|
| 29 |
+
onMessage: (message: WebSocketMessage) => {
|
| 30 |
+
console.log('WebSocket message:', message);
|
| 31 |
+
|
| 32 |
+
switch (message.type) {
|
| 33 |
+
case 'connected':
|
| 34 |
+
console.log('Connected to episode:', message.episode_id);
|
| 35 |
+
break;
|
| 36 |
+
|
| 37 |
+
case 'progress':
|
| 38 |
+
if (message.step !== undefined) setCurrentStep(message.step);
|
| 39 |
+
if (message.reward !== undefined) setTotalReward(prev => prev + message.reward!);
|
| 40 |
+
if (message.progress !== undefined) setProgress(message.progress);
|
| 41 |
+
if (message.action_type) setLastAction(message.action_type);
|
| 42 |
+
onProgressUpdate?.(message);
|
| 43 |
+
break;
|
| 44 |
+
|
| 45 |
+
case 'completion':
|
| 46 |
+
setIsCompleted(true);
|
| 47 |
+
if (message.total_reward !== undefined) setTotalReward(message.total_reward);
|
| 48 |
+
setProgress(100);
|
| 49 |
+
onCompletion?.(message);
|
| 50 |
+
break;
|
| 51 |
+
|
| 52 |
+
case 'error':
|
| 53 |
+
const errorMsg = message.error || 'Unknown error occurred';
|
| 54 |
+
setError(errorMsg);
|
| 55 |
+
onError?.(errorMsg);
|
| 56 |
+
break;
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
}
|
| 60 |
+
);
|
| 61 |
+
|
| 62 |
+
// Reset state when episode changes
|
| 63 |
+
useEffect(() => {
|
| 64 |
+
if (episodeId) {
|
| 65 |
+
setCurrentStep(0);
|
| 66 |
+
setTotalReward(0);
|
| 67 |
+
setProgress(0);
|
| 68 |
+
setLastAction('');
|
| 69 |
+
setIsCompleted(false);
|
| 70 |
+
setError(null);
|
| 71 |
+
}
|
| 72 |
+
}, [episodeId]);
|
| 73 |
+
|
| 74 |
+
return {
|
| 75 |
+
isConnected,
|
| 76 |
+
currentStep,
|
| 77 |
+
totalReward,
|
| 78 |
+
progress,
|
| 79 |
+
lastAction,
|
| 80 |
+
isCompleted,
|
| 81 |
+
error,
|
| 82 |
+
lastMessage,
|
| 83 |
+
};
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
export default useEpisodeProgress;
|
frontend/src/types/index.ts
CHANGED
|
@@ -205,10 +205,24 @@ export interface SystemSettings {
|
|
| 205 |
}
|
| 206 |
|
| 207 |
export interface WebSocketMessage {
|
| 208 |
-
type: '
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
}
|
| 213 |
|
| 214 |
export interface APIResponse<T> {
|
|
|
|
| 205 |
}
|
| 206 |
|
| 207 |
export interface WebSocketMessage {
|
| 208 |
+
type: 'connected' | 'ping' | 'pong' | 'progress' | 'error' | 'completion';
|
| 209 |
+
episode_id?: string;
|
| 210 |
+
message?: string;
|
| 211 |
+
// Progress update fields
|
| 212 |
+
step?: number;
|
| 213 |
+
action_type?: string;
|
| 214 |
+
reward?: number;
|
| 215 |
+
progress?: number;
|
| 216 |
+
// Error fields
|
| 217 |
+
error?: string;
|
| 218 |
+
details?: Record<string, unknown>;
|
| 219 |
+
// Completion fields
|
| 220 |
+
success?: boolean;
|
| 221 |
+
total_reward?: number;
|
| 222 |
+
extracted_data?: Record<string, unknown>;
|
| 223 |
+
// Metadata
|
| 224 |
+
timestamp?: number;
|
| 225 |
+
payload?: unknown;
|
| 226 |
}
|
| 227 |
|
| 228 |
export interface APIResponse<T> {
|