Files
Claude 32551ccc0d feat: voix Edge neuronales, Supertonic 3 en local et genre respecté par tous les moteurs (v2.5.0)
- Nouveau moteur « Microsoft Edge » (voix neuronales gratuites, sans clé) : Henri / Denise
  par défaut selon le genre, liste des voix fr-FR / fr-CA / fr-CH / fr-BE, WebSocket signé
  (Sec-MS-GEC) dans le processus principal, MP3 24 kHz. Moteur par défaut des nouvelles
  installations.
- Supertonic 3 ajouté au catalogue local (31 langues, 5 voix masculines + 5 féminines,
  44 kHz, 129 Mo) : langue transmise au worker, genres des voix vérifiés par mesure de F0.
- Kokoro déclassé pour le français (une seule voix féminine, accent) ; le choix
  masculin/féminin bascule sur le meilleur modèle installé et conserve le genre quand on
  change de modèle ; Google Translate signalé comme voix féminine uniquement.
- Deux préréglages JARVIS : en ligne (Edge Henri) et hors ligne (Supertonic 3).
- Traitement du micro par Chromium (écho, bruit, gain) débrayable pour de meilleures
  transcriptions au casque.
- Tests : protocole Edge (jeton, SSML, trames), sélection de voix ; README et feuille de
  route (mesures Supertonic, Parakeet vs Qwen3-ASR).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMpgFriwxiBgurUVb21oCE
2026-09-04 15:37:00 +00:00

155 lines
3.7 KiB
TypeScript

/** Local voice engine contract (sherpa-onnx in a utility process). Shared by main and renderer. */
export type VoiceModelKind = 'stt' | 'tts' | 'kws' | 'vad';
export type VoiceEngineKind = 'whisper' | 'sense-voice' | 'nemo-transducer' | 'kokoro' | 'piper' | 'supertonic' | 'kws-transducer' | 'silero';
export interface VoiceSpeaker {
id: number;
name: string;
lang: string;
/** m = masculine, f = feminine (from the catalog label). */
gender?: 'm' | 'f';
}
export interface VoiceModelSpec {
id: string;
kind: VoiceModelKind;
engine: VoiceEngineKind;
name: string;
description: string;
languages: string[];
sizeMb: number;
url: string;
/** Folder created by the archive (files are referenced relative to it). */
dir: string;
/** Files that must exist once installed. */
files: string[];
speakers?: VoiceSpeaker[];
sampleRate?: number;
recommended?: boolean;
}
export interface VoiceModelStatus extends VoiceModelSpec {
installed: boolean;
downloading: boolean;
installedBytes: number;
}
export interface VoiceDownloadProgress {
id: string;
phase: 'download' | 'extract' | 'done' | 'error' | 'cancelled';
received: number;
total: number;
percent: number;
message?: string;
}
export interface TranscribeRequest {
modelId: string;
wav: Uint8Array;
language: string; // 'fr', 'en', 'auto'
}
export interface TranscribeResult {
text: string;
language?: string;
durationMs: number;
audioSec: number;
}
export interface SynthesizeRequest {
modelId: string;
text: string;
speaker: number;
speed: number;
/** BCP-47 tag or 2-letter code of the text (multilingual engines such as Supertonic need it). */
language?: string;
}
/** Microsoft Edge "Read aloud" neural voices (online, no key). */
export interface EdgeVoice {
/** e.g. fr-FR-HenriNeural */
shortName: string;
/** Display name, e.g. Henri */
name: string;
locale: string;
gender: 'm' | 'f';
}
export interface EdgeSynthesizeRequest {
text: string;
voice: string;
/** Playback speed multiplier (0.5 .. 2). */
speed: number;
}
export interface EdgeSynthesizeResult {
/** MP3, 24 kHz mono 48 kbit/s. */
mp3: Uint8Array;
durationMs: number;
}
export interface SynthesizeResult {
wav: Uint8Array;
sampleRate: number;
durationMs: number;
audioSec: number;
}
export interface KwsStartRequest {
modelId: string;
/** Wake phrases in plain text (e.g. "jarvis", "hey jarvis"). */
keywords: string[];
/** 1 (strict) .. 5 (eager) */
sensitivity: number;
}
export interface KwsDetection {
keyword: string;
at: number;
}
export interface VadStartRequest {
modelId: string;
/** Silence that ends an utterance, in ms. */
silenceMs: number;
/** Detection threshold 0..1 (0.5 default). */
threshold: number;
maxUtteranceSec: number;
}
export type VadEvent =
| { type: 'speech-start' }
| { type: 'segment'; wav: Uint8Array; durationSec: number }
| { type: 'error'; message: string };
export interface VoiceEngineStatus {
available: boolean;
error?: string;
version?: string;
loaded: string[];
modelsDir: string;
}
export const VOICE_IPC = {
status: 'voice:status',
modelsList: 'voice:models:list',
modelsDownload: 'voice:models:download',
modelsCancel: 'voice:models:cancel',
modelsRemove: 'voice:models:remove',
modelsProgress: 'voice:models:progress',
transcribe: 'voice:transcribe',
synthesize: 'voice:synthesize',
edgeSynthesize: 'voice:edge:synthesize',
edgeVoices: 'voice:edge:voices',
unload: 'voice:unload',
kwsStart: 'voice:kws:start',
kwsStop: 'voice:kws:stop',
kwsAudio: 'voice:kws:audio',
kwsDetected: 'voice:kws:detected',
vadStart: 'voice:vad:start',
vadStop: 'voice:vad:stop',
vadAudio: 'voice:vad:audio',
vadEvent: 'voice:vad:event'
} as const;