@mosaicoo/svg-engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ const E="0.1.0";export{E as SVG_ENGINE_VERSION};
package/package.json ADDED
@@ -0,0 +1,105 @@
1
+ {
2
+ "name": "@mosaicoo/svg-engine",
3
+ "version": "0.1.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Headless-first, plugin-extensible SVG editor library for Angular v21+. Render, manipulate and optimize SVG inside any Angular app — 9 secondary entry points (core/render/io/optimize/edit/ui + ai/nlu + ai/nlu-ui + ai/nlu-voice-wasm), Material UI is opt-in and local Whisper voice is opt-in.",
8
+ "keywords": [
9
+ "svg",
10
+ "svg-editor",
11
+ "svg-renderer",
12
+ "svg-optimizer",
13
+ "vector",
14
+ "vector-graphics",
15
+ "angular",
16
+ "angular-library",
17
+ "ng-packagr",
18
+ "headless",
19
+ "plugin",
20
+ "pathfinder",
21
+ "anchor-editor"
22
+ ],
23
+ "author": "Mosaicoo",
24
+ "license": "Apache-2.0",
25
+ "homepage": "https://github.com/mosaicoo/svg-engine#readme",
26
+ "bugs": {
27
+ "url": "https://github.com/mosaicoo/svg-engine/issues"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/mosaicoo/svg-engine.git",
32
+ "directory": "projects/svg-engine"
33
+ },
34
+ "peerDependencies": {
35
+ "@angular/common": "^21.2.0",
36
+ "@angular/core": "^21.2.0",
37
+ "@angular/material": "^21.2.0",
38
+ "@angular/cdk": "^21.2.0",
39
+ "@huggingface/transformers": "^4.2.0"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "@angular/material": {
43
+ "optional": true
44
+ },
45
+ "@angular/cdk": {
46
+ "optional": true
47
+ },
48
+ "@huggingface/transformers": {
49
+ "optional": true
50
+ }
51
+ },
52
+ "dependencies": {
53
+ "polygon-clipping": "^0.15.7",
54
+ "tslib": "^2.3.0"
55
+ },
56
+ "sideEffects": false,
57
+ "module": "fesm2022/mosaicoo-svg-engine.mjs",
58
+ "typings": "types/mosaicoo-svg-engine.d.ts",
59
+ "exports": {
60
+ "./package.json": {
61
+ "default": "./package.json"
62
+ },
63
+ ".": {
64
+ "types": "./types/mosaicoo-svg-engine.d.ts",
65
+ "default": "./fesm2022/mosaicoo-svg-engine.mjs"
66
+ },
67
+ "./ai/nlu": {
68
+ "types": "./types/mosaicoo-svg-engine-ai-nlu.d.ts",
69
+ "default": "./fesm2022/mosaicoo-svg-engine-ai-nlu.mjs"
70
+ },
71
+ "./ai/nlu-ui": {
72
+ "types": "./types/mosaicoo-svg-engine-ai-nlu-ui.d.ts",
73
+ "default": "./fesm2022/mosaicoo-svg-engine-ai-nlu-ui.mjs"
74
+ },
75
+ "./ai/nlu-voice-wasm": {
76
+ "types": "./types/mosaicoo-svg-engine-ai-nlu-voice-wasm.d.ts",
77
+ "default": "./fesm2022/mosaicoo-svg-engine-ai-nlu-voice-wasm.mjs"
78
+ },
79
+ "./core": {
80
+ "types": "./types/mosaicoo-svg-engine-core.d.ts",
81
+ "default": "./fesm2022/mosaicoo-svg-engine-core.mjs"
82
+ },
83
+ "./edit": {
84
+ "types": "./types/mosaicoo-svg-engine-edit.d.ts",
85
+ "default": "./fesm2022/mosaicoo-svg-engine-edit.mjs"
86
+ },
87
+ "./io": {
88
+ "types": "./types/mosaicoo-svg-engine-io.d.ts",
89
+ "default": "./fesm2022/mosaicoo-svg-engine-io.mjs"
90
+ },
91
+ "./optimize": {
92
+ "types": "./types/mosaicoo-svg-engine-optimize.d.ts",
93
+ "default": "./fesm2022/mosaicoo-svg-engine-optimize.mjs"
94
+ },
95
+ "./render": {
96
+ "types": "./types/mosaicoo-svg-engine-render.d.ts",
97
+ "default": "./fesm2022/mosaicoo-svg-engine-render.mjs"
98
+ },
99
+ "./ui": {
100
+ "types": "./types/mosaicoo-svg-engine-ui.d.ts",
101
+ "default": "./fesm2022/mosaicoo-svg-engine-ui.mjs"
102
+ }
103
+ },
104
+ "type": "module"
105
+ }
@@ -0,0 +1,416 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { Signal } from '@angular/core';
3
+ import { VoiceEngine, NluCandidate, NluExecuteResult, NaturalLanguageService, LlmIntentResolverService } from '@mosaicoo/svg-engine/ai/nlu';
4
+
5
+ /**
6
+ * **`VoiceEngineService`** — orquestrador de voz com engine
7
+ * **selecionável pelo usuário** (D-046 voz híbrida).
8
+ *
9
+ * Expõe a MESMA surface de um {@link VoiceProvider}
10
+ * (`isSupported`/`listening`/`lastError`/`listen`/`stop`) para o
11
+ * `<svge-nlu-input>` consumir de forma transparente, mas internamente
12
+ * delega para:
13
+ * - **Web Speech** ({@link VoiceRecognitionService}) — sempre presente.
14
+ * - **Whisper local** (via {@link VOICE_WHISPER_PROVIDER}) — opcional,
15
+ * só quando o app chamou `provideWhisperVoiceEngine()`.
16
+ *
17
+ * **Modos** ({@link VoiceEngine}):
18
+ * - `'web-speech'`: usa só a Web Speech API.
19
+ * - `'whisper'`: usa só o Whisper local (offline).
20
+ * - `'auto'`: tenta Web Speech e, em **falha** (ex.: `network`),
21
+ * cai automaticamente para o Whisper. Só fica disponível quando as
22
+ * duas engines existem.
23
+ *
24
+ * O `lastError` é **próprio** do orquestrador (não espelha os providers
25
+ * diretamente): zera no início de cada `listen()` e só é setado quando
26
+ * a tentativa realmente falha — assim um erro `network` do Web Speech
27
+ * não fica "preso" na UI após um fallback Whisper bem-sucedido.
28
+ */
29
+ declare class VoiceEngineService {
30
+ private readonly webSpeech;
31
+ /** Provider Whisper, se o app registrou; senão `null`. */
32
+ private readonly whisper;
33
+ private readonly _engine;
34
+ /** Engine atualmente selecionada. */
35
+ readonly engine: Signal<VoiceEngine>;
36
+ /** `true` se a voz local (Whisper) está registrada. */
37
+ readonly whisperAvailable: Signal<boolean>;
38
+ /**
39
+ * Engines disponíveis (suportadas no ambiente atual). `'auto'` só
40
+ * aparece quando as duas engines básicas existem. A UI mostra o
41
+ * seletor apenas quando há mais de uma opção.
42
+ */
43
+ readonly availableEngines: Signal<readonly VoiceEngine[]>;
44
+ /** `false` quando nenhuma engine está disponível (UI esconde o mic). */
45
+ readonly isSupported: Signal<boolean>;
46
+ /** `true` enquanto qualquer provider está capturando/processando. */
47
+ readonly listening: Signal<boolean>;
48
+ /** `true` durante o carregamento do modelo Whisper (primeira vez). */
49
+ readonly modelLoading: Signal<boolean>;
50
+ private readonly _lastError;
51
+ /** Último erro do orquestrador (limpo a cada `listen` bem-sucedido). */
52
+ readonly lastError: Signal<string | null>;
53
+ constructor();
54
+ /** Troca a engine ativa. Ignora valores não disponíveis no ambiente. */
55
+ setEngine(engine: VoiceEngine): void;
56
+ /**
57
+ * Inicia a captura na engine selecionada e resolve com a transcrição.
58
+ * Em `'auto'`, tenta Web Speech e cai para o Whisper se falhar.
59
+ */
60
+ listen(lang?: string, options?: {
61
+ readonly timeoutMs?: number;
62
+ }): Promise<string>;
63
+ /** Encerra a captura ativa em ambos os providers (seguro se inativos). */
64
+ stop(): void;
65
+ /** Executa um provider único, propagando o erro para `_lastError`. */
66
+ private runProvider;
67
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<VoiceEngineService, never>;
68
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<VoiceEngineService>;
69
+ }
70
+
71
+ /** Opção de idioma de voz exibida no seletor. */
72
+ interface VoiceLanguageOption {
73
+ /** BCP-47 (Web Speech usa direto; Whisper mapeia p/ nome do idioma). */
74
+ readonly code: string;
75
+ /** Rótulo completo no menu. */
76
+ readonly label: string;
77
+ /** Rótulo curto (chip/tooltip). */
78
+ readonly short: string;
79
+ }
80
+ /**
81
+ * **`<svge-nlu-input>`** — D-046 Fase 1 UI surface.
82
+ *
83
+ * Input textual + voice button para enviar comandos em linguagem
84
+ * natural ao {@link NaturalLanguageService}. Mostra:
85
+ *
86
+ * - Campo de texto Material outlined + prefix icon (smart_toy)
87
+ * - **Mic button** (Web Speech API) com pulse animation enquanto grava
88
+ * - **Run button** (Enter também dispara)
89
+ * - **Live preview** do top candidate (label + confidence% + bar colorida)
90
+ * - **Status** do último execute (success / rejeição com motivo humano)
91
+ * - **Botão "Confirmar"** quando rejection é destructive ou low-confidence
92
+ * — usuário aprova explicitamente em vez de ficar travado
93
+ * - **Lista de alternativas** clicável (cada click respeita threshold +
94
+ * destructive via `nlu.executeCandidate`)
95
+ *
96
+ * **Por que `window.confirm` default e não Material dialog**: zero
97
+ * dependência circular `nlu-ui → ui` (D-017-style isolation entre
98
+ * camadas AI e dialogs Material). Consumer pode override via input
99
+ * `confirmGate` se quiser dialog próprio.
100
+ *
101
+ * **Multi-editor (D-042/D-043)**: passa `{ injector: this.hostInjector }`
102
+ * para `executeCandidate`/`execute` — handlers resolvem services do
103
+ * scope ativo automaticamente.
104
+ *
105
+ * **Acessibilidade**:
106
+ * - Input ARIA-described com hint do top candidate
107
+ * - Mic button: `aria-pressed` reativo
108
+ * - Lista de alternatives: `role="listbox"` + `role="option"` + `aria-selected="false"`
109
+ * - Status com `aria-live="polite"`
110
+ */
111
+ declare class SvgeNluInput {
112
+ /** Label do input (Material outline). Default em PT. */
113
+ readonly label: _angular_core.InputSignal<string>;
114
+ /** Placeholder textual. Default exemplo PT. */
115
+ readonly placeholder: _angular_core.InputSignal<string>;
116
+ /**
117
+ * BCP-47 language tag pra voice recognition. Default `pt-BR`.
118
+ *
119
+ * **D-046 review-10 (M14)**: quando `autoDetectLanguage = true`,
120
+ * o componente sobreescreve esse default usando `detectLanguage(text)`
121
+ * (PT/EN). Override manual deste input sempre tem prioridade.
122
+ */
123
+ readonly voiceLang: _angular_core.InputSignal<string>;
124
+ /**
125
+ * **D-046 review-10 (M14)**: auto-detecta idioma do input via
126
+ * dicionários PT/EN (hits count). Quando `true`, passa o resultado
127
+ * pra `voice.listen()` em vez de `voiceLang()` estático.
128
+ *
129
+ * Útil pra apps que aceitam PT E EN sem o user trocar config manual.
130
+ */
131
+ readonly autoDetectLanguage: _angular_core.InputSignal<boolean>;
132
+ /**
133
+ * **D-046 review-10 (M5)**: debounce em ms antes de rodar `parse()`.
134
+ * Default 0 (sem debounce — mantém comportamento Fase 1).
135
+ * Recomendado `150` pra voice input rápido (~6 keystrokes/s).
136
+ * Acima de 300 fica perceptível pro user.
137
+ */
138
+ readonly parseDebounceMs: _angular_core.InputSignal<number>;
139
+ /**
140
+ * Confidence mínima pra auto-execute. Abaixo disso, o componente
141
+ * **não** dispara automaticamente — mostra "Confirmar" pra usuário
142
+ * aprovar explicitamente, OU rejeita se gate não aprovar.
143
+ */
144
+ readonly autoExecuteThreshold: _angular_core.InputSignal<number>;
145
+ /**
146
+ * Gate de confirmação customizado. Quando ausente (default), usa
147
+ * **`window.confirm`** nativo — funciona sem dependência extra, é
148
+ * universal, e dispensa abrir Material dialog (privacy + zero
149
+ * coupling com `svg-engine/ui`).
150
+ *
151
+ * Override pra integrar com Material dialog próprio ou tela custom:
152
+ * ```ts
153
+ * <svge-nlu-input [confirmGate]="myDialogGate" />
154
+ * ```
155
+ *
156
+ * O gate recebe o candidate (com `intent.id`, `intent.destructive`,
157
+ * `confidence`, `slots`) e retorna `boolean | Promise<boolean>`.
158
+ */
159
+ readonly confirmGate: _angular_core.InputSignal<((candidate: NluCandidate) => boolean | Promise<boolean>) | null>;
160
+ /**
161
+ * **D-093** — habilita o **fallback LLM**: quando o NLU rule-based não
162
+ * reconhece o pedido (`no-match`), escala para o
163
+ * {@link LlmIntentResolverService}, que pede um plano de comandos ao LLM
164
+ * e o executa pelo mesmo pipeline seguro. Só dispara se um provider LLM
165
+ * estiver registrado (`AI_CHAT_PROVIDER`); senão é no-op. Default `true`.
166
+ */
167
+ readonly enableLlmFallback: _angular_core.InputSignal<boolean>;
168
+ /**
169
+ * **D-093** — modelo a usar no fallback LLM (roteamento por
170
+ * complexidade). `null` = usa o default do provider. O consumer pode
171
+ * passar `qwen2.5:7b` para pedidos pesados, por exemplo.
172
+ */
173
+ readonly llmModel: _angular_core.InputSignal<string | null>;
174
+ /** Evento emitido após cada execute (sucesso ou rejeição). */
175
+ readonly executed: _angular_core.OutputEmitterRef<NluExecuteResult>;
176
+ protected readonly nlu: NaturalLanguageService;
177
+ protected readonly llm: LlmIntentResolverService;
178
+ protected readonly voice: VoiceEngineService;
179
+ private readonly hostInjector;
180
+ private readonly textInputRef;
181
+ protected readonly text: _angular_core.WritableSignal<string>;
182
+ /**
183
+ * **D-046 review-10 (M5)**: signal debouncado pra reduzir parse rate.
184
+ * Quando `parseDebounceMs=0`, sempre igual a `text()`. Caso contrário,
185
+ * só atualiza após o delay sem mudanças (typing burst absorve).
186
+ */
187
+ protected readonly debouncedText: _angular_core.WritableSignal<string>;
188
+ private debounceHandle;
189
+ protected readonly lastResult: _angular_core.WritableSignal<NluExecuteResult | null>;
190
+ /** **D-093** — `true` enquanto o fallback LLM está interpretando (spinner). */
191
+ protected readonly llmThinking: _angular_core.WritableSignal<boolean>;
192
+ /** **D-093** — mensagem de erro do fallback LLM (rede / JSON inválido / sem comandos). */
193
+ protected readonly llmError: _angular_core.WritableSignal<string | null>;
194
+ /**
195
+ * **D-094 — modo de geração do LLM.** `'catalog'` (default) escala para o
196
+ * resolver de **intents** (o LLM devolve um plano de comandos já
197
+ * registrados); `'raw-svg'` pede um **SVG completo** e o desenha no canvas
198
+ * (sem catálogo). Trocável pelo usuário no menu de configuração da IA.
199
+ */
200
+ protected readonly llmMode: _angular_core.WritableSignal<"catalog" | "raw-svg">;
201
+ /**
202
+ * **D-094 — modelo escolhido pelo usuário** no seletor (`null` = usa o
203
+ * default do provider). Tem prioridade sobre o input {@link llmModel}.
204
+ */
205
+ protected readonly selectedModel: _angular_core.WritableSignal<string | null>;
206
+ /** **D-094 — modelos disponíveis** descobertos no backend (Ollama /api/tags). */
207
+ protected readonly availableModels: _angular_core.WritableSignal<readonly string[]>;
208
+ /**
209
+ * **D-094/D-095** — opções do seletor de modelo: funde os modelos
210
+ * **descobertos** ao vivo (`/api/tags`, instalados de fato) com os
211
+ * **curados** ({@link LlmIntentResolverService.suggestedModels} — ex.: os
212
+ * `qwen2.5-coder`) e garante o default do provider na lista, tudo
213
+ * deduplicado. Os curados servem de fallback quando a descoberta falha.
214
+ */
215
+ protected readonly modelOptions: _angular_core.Signal<readonly string[]>;
216
+ /**
217
+ * **D-094** — modelo que **de fato** será usado na próxima chamada:
218
+ * seleção do usuário › input `llmModel` › default do provider. Usado no
219
+ * seletor (checkmark) e como rótulo no tooltip.
220
+ */
221
+ protected readonly effectiveModel: _angular_core.Signal<string | null>;
222
+ constructor();
223
+ /**
224
+ * **D-094** — carrega a lista de modelos do backend (Ollama `/api/tags`)
225
+ * para o seletor. Best-effort: backend offline ou sem suporte a listagem
226
+ * mantém a lista vazia (o seletor cai no default do provider).
227
+ */
228
+ private loadModels;
229
+ /** **D-094** — troca o modo de geração do LLM (catálogo ↔ SVG livre). */
230
+ protected setLlmMode(mode: 'catalog' | 'raw-svg'): void;
231
+ /** **D-094** — seleciona o modelo do seletor (override do default). */
232
+ protected selectModel(model: string): void;
233
+ /**
234
+ * **D-094** — modelo a enviar na próxima chamada LLM: seleção do usuário ›
235
+ * input `llmModel` › `undefined` (provider usa seu default).
236
+ */
237
+ private requestModel;
238
+ /**
239
+ * Candidates ordenados por confidence — recomputa quando
240
+ * `debouncedText` muda OU quando o registry de intents muda.
241
+ */
242
+ protected readonly candidates: _angular_core.Signal<readonly NluCandidate[]>;
243
+ /**
244
+ * **D-046 review-10 (M14)**: idioma detectado do input (PT/EN/unknown).
245
+ * Quando `autoDetectLanguage = true`, este valor sobreescreve `voiceLang()`
246
+ * default pra escolher o engine STT do browser correto.
247
+ */
248
+ protected readonly detectedLanguage: _angular_core.Signal<"unknown" | "pt" | "en">;
249
+ /**
250
+ * Idioma de voz selecionado (BCP-47). Default = **locale do navegador**
251
+ * (normalizado p/ PT-BR/EN-US/ES-ES), trocável pelo usuário no seletor
252
+ * de idioma. Serve às duas engines: a Web Speech usa o BCP-47 direto; o
253
+ * Whisper mapeia para o nome do idioma (pt-BR → "portuguese").
254
+ */
255
+ protected readonly selectedLanguage: _angular_core.WritableSignal<string>;
256
+ /** Opções do seletor de idioma. */
257
+ protected readonly languages: readonly VoiceLanguageOption[];
258
+ /**
259
+ * Resolve BCP-47 efetivo pro `voice.listen(lang)`: o idioma do seletor.
260
+ * Quando `autoDetectLanguage = true`, o idioma detectado do **texto
261
+ * digitado** (PT/EN) tem prioridade sobre a seleção manual.
262
+ */
263
+ protected readonly effectiveVoiceLang: _angular_core.Signal<string>;
264
+ protected readonly topCandidate: _angular_core.Signal<NluCandidate | null>;
265
+ protected readonly alternatives: _angular_core.Signal<readonly NluCandidate[]>;
266
+ /**
267
+ * Mensagem **acionável** pra erro do Web Speech API. Mapeia os codes
268
+ * crus (`'network'`, `'not-allowed'`, `'no-speech'`, `'audio-capture'`,
269
+ * `'service-not-allowed'`) pra texto humano em PT com o passo concreto
270
+ * que o usuário pode tomar pra resolver. Retorna `null` quando não
271
+ * deve mostrar nada (sem erro OU erro `'aborted'` que é silencioso).
272
+ *
273
+ * **Por que `'network'` é comum no Chrome**: o Web Speech API delega
274
+ * o reconhecimento a servidores Google STT — sem internet, com
275
+ * firewall corporativo ou com bloqueador (uBlock/Brave Shields)
276
+ * filtrando `*.google.com`, o handshake falha e o navegador dispara
277
+ * esse erro. Não é bug do app — é dependência arquitetural do
278
+ * Web Speech API spec ao backend STT do vendor.
279
+ */
280
+ protected readonly voiceErrorMessage: _angular_core.Signal<string | null>;
281
+ /** Troca o idioma de voz (seletor) e persiste a escolha. */
282
+ protected setLanguage(code: string): void;
283
+ /** Rótulo curto do idioma atual (chip do seletor). */
284
+ protected languageShort(code: string): string;
285
+ /** Rótulo humano para cada engine de voz. */
286
+ protected engineLabel(engine: VoiceEngine): string;
287
+ /** Ícone Material para cada engine de voz. */
288
+ protected engineIcon(engine: VoiceEngine): string;
289
+ /** Tooltip do botão de microfone (reflete carregamento/gravação). */
290
+ protected micTooltip(): string;
291
+ /**
292
+ * Input handler — atualiza o signal a partir do valor nativo. Não
293
+ * usamos `[value]` binding (que conflita com o controle interno do
294
+ * MatInput em digitação rápida); em vez disso lemos do input direto
295
+ * e setamos programaticamente via `setTextProgrammatically` quando
296
+ * preciso (voice transcript, limpar pós-execute).
297
+ */
298
+ protected onInput(value: string): void;
299
+ /**
300
+ * Seta o valor do input programaticamente (voice transcript, clear
301
+ * pós-execute). Atualiza o signal E o input element value — o input
302
+ * nativo não escuta mudanças de signal sozinho.
303
+ *
304
+ * **D-046 review-10**: também atualiza `debouncedText` IMEDIATO
305
+ * (sem debounce) — caller programático sabe que o valor é final.
306
+ */
307
+ private setTextProgrammatically;
308
+ protected runNow(): Promise<void>;
309
+ /**
310
+ * **D-093** — fallback LLM. Pede um plano de comandos ao
311
+ * {@link LlmIntentResolverService} e o executa pelo mesmo pipeline
312
+ * seguro. Mostra spinner enquanto interpreta (pode levar segundos no
313
+ * hardware local) e mensagem amigável em caso de erro/sem-comandos.
314
+ * Não limpa o input em falha (o usuário pode reformular).
315
+ */
316
+ private escalateToLlm;
317
+ /**
318
+ * **D-094 — modo SEM catálogo.** Pede um SVG completo ao
319
+ * {@link LlmIntentResolverService.generateAndInsertSvg}, que o parseia,
320
+ * saneia e desenha no canvas. Em sucesso limpa o input; em falha mostra o
321
+ * erro amigável do resolver. Erros de rede sobem para o `catch` de
322
+ * {@link escalateToLlm}.
323
+ */
324
+ private escalateRawSvg;
325
+ /**
326
+ * **D-093 Fase 3** — escape hatch explícito: manda o texto **direto**
327
+ * ao LLM, ignorando o rule-based. Útil quando o usuário sabe que quer a
328
+ * IA (ex.: composição complexa) independente do que o rule-based acharia.
329
+ */
330
+ protected askAi(): Promise<void>;
331
+ /**
332
+ * Executa um candidate específico (clique na lista de alternativas)
333
+ * — usa `nlu.executeCandidate` que aplica gate + threshold +
334
+ * destructive check, em vez de chamar `intent.execute` direto
335
+ * (que bypassaria toda a defesa).
336
+ */
337
+ protected execCandidate(cand: NluCandidate): Promise<void>;
338
+ /**
339
+ * Força a execução do top candidate **após** o usuário clicar
340
+ * "Confirmar" — passa um gate `() => true` overridand a rejeição
341
+ * `'destructive-no-gate'` / `'below-threshold'` anterior.
342
+ */
343
+ protected forceExecute(rejected: NluExecuteResult): Promise<void>;
344
+ /**
345
+ * `true` quando o último resultado merece um botão "Confirmar" na
346
+ * UI: usuário escolheu rodar e bateu numa proteção (destrutivo sem
347
+ * gate, ou confidence baixa sem gate), mas há candidate concreto
348
+ * pra forçar execução manualmente.
349
+ */
350
+ protected canForceExecute(result: NluExecuteResult): boolean;
351
+ protected toggleVoice(): Promise<void>;
352
+ /**
353
+ * Texto humano pra exibir do candidate. Prioridade:
354
+ * 1. `intent.description` (quando explícita)
355
+ * 2. Keywords joined (mais legível que reverse-DNS id)
356
+ * 3. `intent.id` (último recurso)
357
+ */
358
+ protected describeIntent(c: NluCandidate): string;
359
+ protected confidencePercent(c: NluCandidate): number;
360
+ protected describeRejection(result: NluExecuteResult): string;
361
+ /**
362
+ * Monta as `NluExecuteOptions` consolidadas: thresholds + gate.
363
+ * Quando o consumer não passou `confirmGate` via input, usa
364
+ * `window.confirm` como default — universal, zero dep.
365
+ */
366
+ private executeOptions;
367
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SvgeNluInput, never>;
368
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SvgeNluInput, "svge-nlu-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "voiceLang": { "alias": "voiceLang"; "required": false; "isSignal": true; }; "autoDetectLanguage": { "alias": "autoDetectLanguage"; "required": false; "isSignal": true; }; "parseDebounceMs": { "alias": "parseDebounceMs"; "required": false; "isSignal": true; }; "autoExecuteThreshold": { "alias": "autoExecuteThreshold"; "required": false; "isSignal": true; }; "confirmGate": { "alias": "confirmGate"; "required": false; "isSignal": true; }; "enableLlmFallback": { "alias": "enableLlmFallback"; "required": false; "isSignal": true; }; "llmModel": { "alias": "llmModel"; "required": false; "isSignal": true; }; }, { "executed": "executed"; }, never, never, true, never>;
369
+ }
370
+
371
+ declare class VoiceRecognitionService {
372
+ /** Quando `false`, a UI deve esconder/desabilitar o botão de voz. */
373
+ readonly isSupported: Signal<boolean>;
374
+ private readonly _listening;
375
+ /** `true` enquanto o microfone está capturando. */
376
+ readonly listening: Signal<boolean>;
377
+ private readonly _lastError;
378
+ /**
379
+ * Último erro do recognizer (`'no-speech'`, `'aborted'`,
380
+ * `'not-allowed'`, etc.). Reseta no próximo `start()`.
381
+ */
382
+ readonly lastError: Signal<string | null>;
383
+ private activeRec;
384
+ /**
385
+ * Default timeout pra `listen()` (D-046 review-10).
386
+ * 30 segundos cobre comandos longos sem deixar Promise pendurada
387
+ * indefinidamente quando o recognizer entra em estado patológico
388
+ * (tab em background, perda de conexão, browser sem disparar onend).
389
+ */
390
+ static readonly DEFAULT_LISTEN_TIMEOUT_MS = 30000;
391
+ /**
392
+ * Default do **watchdog de silêncio** (VAD) — encerra a captura
393
+ * `DEFAULT_SILENCE_MS` ms após a última palavra reconhecida, espelhando
394
+ * o auto-stop do provider Whisper local. A Web Speech API não tem
395
+ * config nativa de endpointing; emulamos via `interimResults`.
396
+ */
397
+ static readonly DEFAULT_SILENCE_MS = 1000;
398
+ /**
399
+ * Inicia a captura. Resolve com a transcrição final quando o
400
+ * recognizer terminar. Rejeita em erro, em timeout ou se chamado sem suporte.
401
+ *
402
+ * @param lang BCP-47 language tag (default `pt-BR`)
403
+ * @param options.timeoutMs timeout em ms (default 30000). Após
404
+ * expirar, aborta o recognizer e rejeita com `'timeout'`.
405
+ */
406
+ listen(lang?: string, options?: {
407
+ readonly timeoutMs?: number;
408
+ readonly silenceMs?: number;
409
+ }): Promise<string>;
410
+ /** Aborta a captura ativa, se houver. */
411
+ stop(): void;
412
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<VoiceRecognitionService, never>;
413
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<VoiceRecognitionService>;
414
+ }
415
+
416
+ export { SvgeNluInput, VoiceEngineService, VoiceRecognitionService };