Spaces:
Sleeping
Sleeping
| /** | |
| * browserLLM.ts | |
| * Infrastruttura per AI locale browser-side (WebGPU / transformers.js). | |
| * | |
| * STATO: nessun modello locale è integrato (WebLLM/transformers.js richiedono | |
| * ~3–4 GB di download, non adatti a iPhone). browserGenerate() ora lancia un | |
| * errore esplicito (Gap 1 fix S483) invece di simulare una risposta falsa. | |
| * providerChain.ts cattura l'errore (non-AbortError) e cade sull'esaurimento | |
| * provider, mostrando un messaggio onesto all'utente. | |
| * | |
| * Compatibile con: ProviderIndicator · consensusMode · providerChain | |
| */ | |
| import type { ChatMessage } from "./types"; | |
| export type BrowserLLMPhase = | |
| | { phase: "idle" } | |
| | { phase: "loading"; progress: number; text: string } | |
| | { phase: "ready"; model: string } | |
| | { phase: "generating"; model: string } | |
| | { phase: "error"; message: string } | |
| | { phase: "unsupported"; reason: string }; | |
| export interface BrowserModel { | |
| id: string; | |
| name: string; | |
| desc: string; | |
| } | |
| export const BROWSER_MODELS: BrowserModel[] = [ | |
| { | |
| id: "local-small", | |
| name: "Locale piccolo", | |
| desc: "Fallback offline leggero", | |
| }, | |
| ]; | |
| let currentPhase: BrowserLLMPhase = { phase: "idle" }; | |
| const listeners = new Set<(s: BrowserLLMPhase) => void>(); | |
| function emit(status: BrowserLLMPhase) { | |
| currentPhase = status; | |
| listeners.forEach(fn => fn(status)); | |
| } | |
| export function onBrowserLLMStatus( | |
| cb: (status: BrowserLLMPhase) => void, | |
| ): () => void { | |
| listeners.add(cb); | |
| cb(currentPhase); | |
| return () => { | |
| listeners.delete(cb); | |
| }; | |
| } | |
| export function isWebGPUSupported(): boolean { | |
| return typeof navigator !== "undefined" && "gpu" in navigator; | |
| } | |
| let ready = false; | |
| export async function loadBrowserModel( | |
| _modelId = "local-small", | |
| ): Promise<void> { | |
| // Nessun modello locale integrato — segnala unsupported senza simulare loading. | |
| emit({ | |
| phase: "unsupported", | |
| reason: "Nessun modello locale disponibile. Usa i provider cloud.", | |
| }); | |
| } | |
| export function isModelReady(): boolean { | |
| return ready; | |
| } | |
| /** | |
| * Gap 1 fix (S483): invece di restituire un echo formattato della domanda | |
| * dell'utente (che sembrava una risposta AI ma non lo era), lancia un errore | |
| * esplicito. providerChain.ts cattura questo errore (non-AbortError) e | |
| * prosegue verso il messaggio di esaurimento provider, che è onesto e utile. | |
| */ | |
| export async function browserGenerate( | |
| _messages: ChatMessage[], | |
| _onChunk?: (chunk: string) => void, | |
| signal?: AbortSignal, | |
| ): Promise<string> { | |
| if (signal?.aborted) { | |
| throw new DOMException("Operazione interrotta", "AbortError"); | |
| } | |
| emit({ phase: "unsupported", reason: "Nessun modello LLM locale integrato." }); | |
| throw new Error( | |
| "BrowserLLM_UNAVAILABLE: nessun modello LLM locale è integrato. " + | |
| "Tutti i provider cloud sono temporaneamente esauriti.", | |
| ); | |
| } | |
| export function unloadBrowserModel(): void { | |
| ready = false; | |
| emit({ | |
| phase: "idle", | |
| }); | |
| } | |