73 lines
2.2 KiB
TypeScript
73 lines
2.2 KiB
TypeScript
|
|
import { useState, useEffect, useCallback } from 'react';
|
||
|
|
import { apiClient } from '@/api/client';
|
||
|
|
|
||
|
|
export interface Suggestion {
|
||
|
|
id: string;
|
||
|
|
entity_type: string;
|
||
|
|
entity_id: string | null;
|
||
|
|
suggestion_type: 'info' | 'warning' | 'action' | 'insight';
|
||
|
|
title: string;
|
||
|
|
content: string;
|
||
|
|
confidence: number;
|
||
|
|
actions: Array<{ method: string; path: string; body: any; description: string }>;
|
||
|
|
created_at: string;
|
||
|
|
is_dismissed: boolean;
|
||
|
|
is_acted_upon: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useSuggestions() {
|
||
|
|
const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
|
||
|
|
const [connected, setConnected] = useState(false);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
// Initial load
|
||
|
|
apiClient.get('/api/v1/ai-proactive/suggestions').then(r => {
|
||
|
|
setSuggestions(r.data.items);
|
||
|
|
}).catch(() => {});
|
||
|
|
|
||
|
|
// SSE Stream
|
||
|
|
const eventSource = new EventSource('/api/v1/ai-proactive/suggestions/stream');
|
||
|
|
eventSource.onopen = () => setConnected(true);
|
||
|
|
eventSource.onerror = () => setConnected(false);
|
||
|
|
eventSource.onmessage = (e) => {
|
||
|
|
try {
|
||
|
|
const suggestion = JSON.parse(e.data);
|
||
|
|
setSuggestions(prev => [suggestion, ...prev].slice(0, 50));
|
||
|
|
} catch {}
|
||
|
|
};
|
||
|
|
|
||
|
|
return () => eventSource.close();
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const dismiss = useCallback(async (id: string) => {
|
||
|
|
setSuggestions(prev => prev.filter(s => s.id !== id));
|
||
|
|
await apiClient.post(`/api/v1/ai-proactive/suggestions/${id}/dismiss`).catch(() => {});
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const act = useCallback(async (id: string, actionIndex: number) => {
|
||
|
|
const result = await apiClient.post(`/api/v1/ai-proactive/suggestions/${id}/act`, {
|
||
|
|
action_index: actionIndex
|
||
|
|
});
|
||
|
|
setSuggestions(prev => prev.map(s => s.id === id ? { ...s, is_acted_upon: true } : s));
|
||
|
|
return result.data;
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return { suggestions, connected, dismiss, act };
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useProactiveSettings() {
|
||
|
|
const [settings, setSettings] = useState<any>(null);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
apiClient.get('/api/v1/ai-proactive/settings').then(r => setSettings(r.data));
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const update = useCallback(async (updates: any) => {
|
||
|
|
const r = await apiClient.put('/api/v1/ai-proactive/settings', updates);
|
||
|
|
setSettings(r.data);
|
||
|
|
return r.data;
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return { settings, update };
|
||
|
|
}
|