Repository navigation
Expand file tree
/
Copy pathshared.js
More file actions
98 lines (91 loc) · 5.08 KB
/
Copy pathshared.js
File metadata and controls
98 lines (91 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Shared catalog + defaults used by the service worker, content script and
// options/popup pages. Declared with `var` so each becomes a global in both
// the worker scope (via importScripts) and the page/content-script world.
// ── Global, provider-agnostic settings ───────────────────────────────────────
var DEFAULT_SETTINGS = {
speed: 1.0,
instructions: '',
responseFormat: 'mp3', // applies fully to OpenAI; other providers map/override
streamingMode: 'complete',
autoRead: false, // auto-start reading each new answer (no click)
cleanCitations: true,
skipCodeBlocks: true,
skipRelated: true,
cleanMarkdown: true,
};
// ── OpenAI voice set (shared by OpenAI + OpenRouter openai-family models) ─────
var OPENAI_VOICES = [
{ id: 'alloy', desc: 'Neutral, balanced' },
{ id: 'ash', desc: 'Warm, conversational' },
{ id: 'ballad', desc: 'Melodic, expressive' },
{ id: 'coral', desc: 'Bright, friendly' },
{ id: 'echo', desc: 'Clean, precise' },
{ id: 'fable', desc: 'Narrative, engaging' },
{ id: 'nova', desc: 'Modern, crisp' },
{ id: 'onyx', desc: 'Deep, authoritative' },
{ id: 'sage', desc: 'Calm, reflective' },
{ id: 'shimmer', desc: 'Light, lively' },
{ id: 'verse', desc: 'Versatile, expressive' },
];
var OPENAI_VOICE_IDS = OPENAI_VOICES.map((v) => v.id);
// Per-model voice namespaces for OpenRouter providers (verified working).
var GEMINI_VOICES = ['Zephyr', 'Puck', 'Charon', 'Kore', 'Fenrir', 'Leda', 'Orus', 'Aoede', 'Callirrhoe', 'Autonoe', 'Enceladus', 'Iapetus', 'Umbriel', 'Algieba', 'Despina', 'Erinome', 'Algenib', 'Rasalgethi', 'Laomedeia', 'Achernar', 'Alnilam', 'Schedar', 'Gacrux', 'Pulcherrima', 'Achird', 'Zubenelgenubi', 'Vindemiatrix', 'Sadachbia', 'Sadaltager', 'Sulafat'];
var KOKORO_VOICES = ['af_heart', 'af_alloy', 'af_aoede', 'af_bella', 'af_jessica', 'af_kore', 'af_nicole', 'af_nova', 'af_river', 'af_sarah', 'af_sky', 'am_adam', 'am_echo', 'am_eric', 'am_fenrir', 'am_liam', 'am_michael', 'am_onyx', 'am_puck', 'am_santa', 'bf_alice', 'bf_emma', 'bf_isabella', 'bf_lily', 'bm_daniel', 'bm_fable', 'bm_george', 'bm_lewis'];
var ORPHEUS_VOICES = ['tara', 'leah', 'jess', 'leo', 'dan', 'mia', 'zac'];
var GROK_VOICES = ['Eve', 'Rex', 'Gork', 'Ara', 'Sal', 'Leo', 'Una'];
// Map an OpenRouter model id to its voice set (by family substring).
function openrouterVoicesFor(modelId) {
const m = (modelId || '').toLowerCase();
if (m.includes('gemini')) return GEMINI_VOICES;
if (m.includes('kokoro')) return KOKORO_VOICES;
if (m.includes('orpheus')) return ORPHEUS_VOICES;
if (m.includes('grok')) return GROK_VOICES;
return OPENAI_VOICE_IDS; // openai, sesame, and unknown → OpenAI voice names
}
// ── Provider catalog ──────────────────────────────────────────────────────────
// Each model lists its own voices (voices can be model-dependent).
// ElevenLabs voices are fetched dynamically (dynamicVoices: true).
var PROVIDERS = {
openai: {
label: 'OpenAI',
keyPlaceholder: 'sk-...',
keyHint: 'OpenAI key (platform.openai.com).',
models: [
{ id: 'gpt-4o-mini-tts', label: 'gpt-4o-mini-tts (instructions)', voices: OPENAI_VOICE_IDS },
{ id: 'tts-1', label: 'tts-1 (fast)', voices: OPENAI_VOICE_IDS },
{ id: 'tts-1-hd', label: 'tts-1-hd (high quality)', voices: OPENAI_VOICE_IDS },
],
},
openrouter: {
label: 'OpenRouter',
keyPlaceholder: 'sk-or-...',
keyHint: 'OpenRouter key (openrouter.ai/keys). Routes TTS models from several providers.',
models: [
{ id: 'openai/gpt-4o-mini-tts', label: 'OpenAI gpt-4o-mini-tts' },
{ id: 'google/gemini-3.1-flash-tts-preview', label: 'Google Gemini Flash TTS' },
{ id: 'hexgrad/kokoro-82m', label: 'Kokoro 82M' },
{ id: 'canopylabs/orpheus-3b-0.1-ft', label: 'Orpheus 3B' },
{ id: 'x-ai/grok-voice-tts-1.0', label: 'xAI Grok Voice' },
{ id: 'sesame/csm-1b', label: 'Sesame CSM-1b' },
],
},
elevenlabs: {
label: 'ElevenLabs',
keyPlaceholder: 'xi-api-key',
keyHint: 'ElevenLabs key (elevenlabs.io → Profile → API key).',
dynamicVoices: true,
models: [
{ id: 'eleven_multilingual_v2', label: 'Multilingual v2' },
{ id: 'eleven_flash_v2_5', label: 'Flash v2.5 (fast)' },
{ id: 'eleven_turbo_v2_5', label: 'Turbo v2.5' },
{ id: 'eleven_v3', label: 'v3' },
],
},
};
var PROVIDER_ORDER = ['openai', 'openrouter', 'elevenlabs'];
// ── Default per-provider configuration ────────────────────────────────────────
var DEFAULT_PROVIDER_CONFIG = {
openai: { model: 'gpt-4o-mini-tts', voice: 'nova' },
openrouter: { model: 'openai/gpt-4o-mini-tts', voice: 'nova' },
elevenlabs: { model: 'eleven_multilingual_v2', voiceId: '' },
};