@@ -180,7 +168,7 @@ export function ClonePage() {
size="sm"
onClick={() => {
setLibraryTab('takes');
- setLibraryOpen(true);
+ setWorkspace({ libraryOpen: true });
}}
>
diff --git a/electron/src/renderer/src/features/home/home-page.tsx b/electron/src/renderer/src/features/home/home-page.tsx
index 0f95f16e..ea8b6f33 100644
--- a/electron/src/renderer/src/features/home/home-page.tsx
+++ b/electron/src/renderer/src/features/home/home-page.tsx
@@ -1,3 +1,4 @@
+import { isMac } from '@/components/bridge';
import { WorkspaceHeader } from '@/components/app-shell/workspace-header';
import { ProfileAvatar } from '@/components/profile-avatar';
import { Button } from '@/components/ui/button';
@@ -181,18 +182,19 @@ export function HomePage() {
return (
- {libraryOpen ? (
-
- ) : (
-
- )}
+ {isMac() &&
+ (libraryOpen ? (
+
+ ) : (
+
+ ))}
{t('app.name')}
Promise.all(
- [
- 'model-install-jobs',
- 'model-catalogue',
- 'model-recommendations',
- 'performance-profile',
- ].map((key) => client.invalidateQueries({ queryKey: [key] })),
+ ['model-install-jobs', 'model-catalogue', 'model-recommendations', 'performance-profile'].map(
+ (key) => client.invalidateQueries({ queryKey: [key] }),
+ ),
);
const installPack = async () => {
@@ -175,7 +172,18 @@ export function PerformanceModelPacks() {
}
};
- if (!catalogue.data || !profile.data || pack.models.length === 0) return null;
+ if (!catalogue.data || !profile.data)
+ return (
+
+
{t(catalogue.isError || profile.isError ? 'common.error' : 'common.loading')}
+ {(catalogue.isError || profile.isError) && (
+
+ )}
+
+ );
+ if (pack.models.length === 0) return null;
return (
@@ -214,10 +222,13 @@ export function PerformanceModelPacks() {
- {model.label}
+ {compact ? t('engineSidebar.' + family) : model.label}
- {t('engineSidebar.' + family)} · {model.size_gb} GB
+ {t(
+ model.installed ? 'modelMaintenance.installed' : 'modelMaintenance.download',
+ )}{' '}
+ · {model.size_gb} GB
{active ? (
@@ -259,7 +270,13 @@ export function PerformanceModelPacks() {
{t('models.pack_total', { count: pack.models.length, size: pack.totalGb.toFixed(1) })}
0:00.0
{overlaps.size > 0 && (
-
+ {
+ const id = [...overlaps][0];
+ setZoom(16);
+ selectAndFocus(id);
+ requestAnimationFrame(() => segmentRefs.current.get(id)?.scrollIntoView({ block: 'nearest', inline: 'center' }));
+ }}>
{t('segmentEditing.overlap')}
-
+
)}
{formatTime(duration)}
diff --git a/electron/src/renderer/src/features/projects/project-format.test.ts b/electron/src/renderer/src/features/projects/project-format.test.ts
index 43f86da3..c433d8df 100644
--- a/electron/src/renderer/src/features/projects/project-format.test.ts
+++ b/electron/src/renderer/src/features/projects/project-format.test.ts
@@ -27,6 +27,7 @@ it('opens legacy projects and preserves unexposed options when saving edits', ()
dubFilename: 'clip.mp4',
dubLang: 'French',
translateQuality: 'cinematic',
+ translationInstructions: 'Preserve humor.',
fitOptions: { allow_video_retime: false, audio_rate_cap: 1.3 },
dubStep: 'generating',
dubSegments: [{ id: 7, start: 0, end: 2, text: 'Bonjour', translations: { fr: 'Bonjour' } }],
@@ -37,12 +38,14 @@ it('opens legacy projects and preserves unexposed options when saving edits', ()
};
const session = projectSession(project, defaults);
expect(session.quality).toBe('cinematic');
+ expect(session.translationInstructions).toBe('Preserve humor.');
expect(session.exportOptions).toMatchObject({ preserveBg: false, excluded: ['original'] });
expect(session.fitOptions).toEqual({ allow_video_retime: false, audio_rate_cap: 1.3 });
expect(session.phase).toBe('editing');
expect(session.taskId).toBeNull();
expect(session.segments[0]).toMatchObject({ id: '7', text_original: 'Bonjour' });
const payload = projectPayload({ ...session, target: 'Spanish' }, ' Renamed ');
+ expect(payload.state.translationInstructions).toBe('Preserve humor.');
expect(payload).toMatchObject({
name: 'Renamed',
audio_path: '/audio.wav',
diff --git a/electron/src/renderer/src/features/projects/project-format.ts b/electron/src/renderer/src/features/projects/project-format.ts
index fb2b0cab..09ba313c 100644
--- a/electron/src/renderer/src/features/projects/project-format.ts
+++ b/electron/src/renderer/src/features/projects/project-format.ts
@@ -33,6 +33,7 @@ export function projectSession(project: DubProject, defaults: DubSession): DubSe
reflectPass: s.reflectPass,
condenseSuggest: s.condenseSuggest,
dialect: s.dubDialect,
+ translationInstructions: s.translationInstructions,
exportOptions: {
...(typeof s.exportOptions === 'object' && s.exportOptions ? s.exportOptions : {}),
preserveBg: s.preserveBg,
@@ -86,6 +87,7 @@ export function projectPayload(session: DubSession, name: string) {
reflectPass: session.reflectPass,
condenseSuggest: session.condenseSuggest,
dubDialect: session.dialect,
+ translationInstructions: session.translationInstructions,
exportOptions: session.exportOptions,
...(session.exportOptions
? {
diff --git a/frontend/src/utils/timeline.js b/frontend/src/utils/timeline.js
index 198dfd04..3a16dd13 100644
--- a/frontend/src/utils/timeline.js
+++ b/frontend/src/utils/timeline.js
@@ -282,13 +282,14 @@ export function detectOverlaps(segments, epsilon = 1e-6) {
const flagged = new Set();
if (segments.length < 2) return flagged;
const sorted = [...segments].sort((x, y) => x.start - y.start || x.end - y.end);
- for (let i = 1; i < sorted.length; i++) {
- const prev = sorted[i - 1];
- const cur = sorted[i];
- if (cur.start < prev.end - epsilon) {
- flagged.add(String(prev.id));
+ let active = [];
+ for (const cur of sorted) {
+ active = active.filter((previous) => previous.end > cur.start + epsilon);
+ for (const previous of active) {
+ flagged.add(String(previous.id));
flagged.add(String(cur.id));
}
+ active.push(cur);
}
return flagged;
}
diff --git a/frontend/src/utils/timeline.test.js b/frontend/src/utils/timeline.test.js
index 9167d478..7a5f7ebe 100644
--- a/frontend/src/utils/timeline.test.js
+++ b/frontend/src/utils/timeline.test.js
@@ -318,3 +318,11 @@ describe('REGION_COLORS — opaque JS-pre-blended paint guard (#373, #963)', ()
expect(blendRegionColor([255, 255, 255], [0, 0, 0])).toBe('rgb(115, 115, 115)'); // 0.45·255 = 114.75
});
});
+
+it('flags every nested overlap, not just consecutive intervals', () => {
+ expect([...detectOverlaps([
+ { id: 'long', start: 0, end: 10 },
+ { id: 'a', start: 1, end: 2 },
+ { id: 'b', start: 3, end: 4 },
+ ])].sort()).toEqual(['a', 'b', 'long']);
+});
diff --git a/tests/test_dub_chunk_duplicates.py b/tests/test_dub_chunk_duplicates.py
new file mode 100644
index 00000000..685319e0
--- /dev/null
+++ b/tests/test_dub_chunk_duplicates.py
@@ -0,0 +1,54 @@
+from services.segmentation import deduplicate_chunk_segments
+
+
+def segment(id, words, speaker='Speaker 1'):
+ return {'id':id, 'start':words[0]['start'], 'end':words[-1]['end'], 'words':words,
+ 'text':' '.join(w['text'] for w in words), 'speaker_id':speaker}
+
+
+def words(text, start):
+ return [{'text':w,'start':start+i*.4,'end':start+(i+1)*.4} for i,w in enumerate(text.split())]
+
+
+def test_repeated_chunk_context_is_removed_without_losing_the_new_tail():
+ a=segment('a',words('Thank you very much',10))
+ b=segment('b',words('Thank you very much Welcome everyone',10))
+ result=deduplicate_chunk_segments([a,b])
+ assert result[1]['text']=='Welcome everyone'
+ assert result[1]['start']==11.6
+ assert a['text']=='Thank you very much'
+
+
+def test_exact_duplicate_removed_but_other_speaker_preserved():
+ a=segment('a',words('Thank you very much',10))
+ b={**a,'id':'b'}
+ assert len(deduplicate_chunk_segments([a,b]))==1
+ assert len(deduplicate_chunk_segments([a,{**b,'speaker_id':'Speaker 2'}]))==2
+
+
+def test_repeated_phrase_at_different_time_is_not_a_duplicate():
+ a=segment('a',words('Thank you very much',10))
+ b=segment('b',words('Thank you very much',12))
+ assert deduplicate_chunk_segments([a,b])==[a,b]
+
+
+def test_fix_bounds_only_when_words_prove_speech_is_disjoint():
+ a=segment('a',words('Good morning everyone',10))
+ b=segment('b',words('Nice to meet you',12))
+ a['end']=13
+ result=deduplicate_chunk_segments([a,b])
+ assert result[0]['end']==11.2
+ assert a['end']==13
+ c=segment('c',words('Other simultaneous words',10.5),'Speaker 2')
+ assert deduplicate_chunk_segments([a,c])==[a,c]
+
+
+def test_out_of_order_stitched_word_cannot_invert_or_delete_a_line():
+ a=segment('a',words('You are so young',10))
+ a['end']=12.2
+ a['words'].append({'text':'Earlier?','start':8,'end':9})
+ b=segment('b',words('How old are you',12))
+ result=deduplicate_chunk_segments([a,b])
+ assert len(result)==2
+ assert result[0]['start']==10
+ assert result[0]['end']==11.6
From 1d5d3d873e9ba7700bb34843773b7c74163e51fe Mon Sep 17 00:00:00 2001
From: Palash Debnath <4178343+debpalash@users.noreply.github.com>
Date: Wed, 16 Sep 2026 12:38:16 +0530
Subject: [PATCH 11/15] feat: refresh support and integrations experience
---
CHANGELOG.md | 8 +
README.md | 511 ++-----------
README_CN.md | 717 ++----------------
docs/integration-directory.md | 20 +
docs/media/electron/README.md | 19 +
docs/media/electron/dubbing.png | Bin 0 -> 161926 bytes
docs/media/electron/models.png | Bin 0 -> 117004 bytes
docs/media/electron/voice-cloning.png | Bin 0 -> 101065 bytes
docs/media/electron/voice-design.png | Bin 0 -> 127490 bytes
docs/media/electron/voicestudio.gif | Bin 0 -> 3215648 bytes
docs/support-page.md | 19 +
electron/src/renderer/index.html | 2 +-
.../components/app-shell/agent-dock-frame.tsx | 2 +-
.../src/components/app-shell/app-shell.tsx | 2 +
.../app-shell/repair-agent-dock.tsx | 10 +-
.../components/app-shell/sponsor-footer.css | 478 ++++++++++++
.../app-shell/sponsor-footer.test.tsx | 155 ++++
.../components/app-shell/sponsor-footer.tsx | 331 ++++++++
.../components/app-shell/sponsor-inquiry.css | 84 ++
.../components/app-shell/sponsor-inquiry.tsx | 236 ++++++
.../components/app-shell/support-shortcut.tsx | 28 +
.../app-shell/translation-agent-dock.tsx | 2 +-
.../components/app-shell/workspace-header.tsx | 26 +-
.../components/app-shell/workspace-menu.tsx | 6 +-
.../app-shell/workspace-sidebar.tsx | 10 +-
.../src/features/clone/clone-page.tsx | 2 +
.../src/features/dub/dub-timeline.test.tsx | 2 +-
.../renderer/src/features/home/home-page.tsx | 15 +-
.../integrations/integration-detail-page.tsx | 72 ++
.../integrations/integrations-page.css | 316 ++++++++
.../integrations/integrations-page.tsx | 175 +++++
.../src/features/settings/donation-goal.tsx | 19 +-
.../features/settings/support-settings.css | 368 +++++++++
.../settings/support-settings.test.tsx | 40 +-
.../features/settings/support-settings.tsx | 290 ++++---
.../src/renderer/src/i18n/locales/ar.json | 51 +-
.../src/renderer/src/i18n/locales/de.json | 51 +-
.../src/renderer/src/i18n/locales/en.json | 53 +-
.../src/renderer/src/i18n/locales/es.json | 51 +-
.../src/renderer/src/i18n/locales/fr.json | 51 +-
.../src/renderer/src/i18n/locales/hi.json | 51 +-
.../src/renderer/src/i18n/locales/id.json | 51 +-
.../src/renderer/src/i18n/locales/it.json | 51 +-
.../src/renderer/src/i18n/locales/ja.json | 51 +-
.../src/renderer/src/i18n/locales/ko.json | 51 +-
.../src/renderer/src/i18n/locales/nl.json | 51 +-
.../src/renderer/src/i18n/locales/pl.json | 51 +-
.../src/renderer/src/i18n/locales/pt.json | 51 +-
.../src/renderer/src/i18n/locales/ru.json | 51 +-
.../src/renderer/src/i18n/locales/sv.json | 51 +-
.../src/renderer/src/i18n/locales/th.json | 51 +-
.../src/renderer/src/i18n/locales/tr.json | 51 +-
.../src/renderer/src/i18n/locales/uk.json | 51 +-
.../src/renderer/src/i18n/locales/vi.json | 51 +-
.../src/renderer/src/i18n/locales/zh-CN.json | 51 +-
.../src/renderer/src/i18n/locales/zh-TW.json | 51 +-
electron/src/renderer/src/routes/index.ts | 23 +
electron/src/renderer/src/styles/globals.css | 1 +
frontend/src/api/donation.ts | 2 +-
.../src/assets/integrations/anthropic.png | Bin 0 -> 1359 bytes
.../src/assets/integrations/assemblyai.ico | Bin 0 -> 16958 bytes
frontend/src/assets/integrations/cartesia.png | Bin 0 -> 472 bytes
frontend/src/assets/integrations/codex.png | Bin 0 -> 33270 bytes
frontend/src/assets/integrations/deepgram.ico | Bin 0 -> 34494 bytes
frontend/src/assets/integrations/docker.png | Bin 0 -> 751 bytes
.../src/assets/integrations/elevenlabs.ico | Bin 0 -> 15086 bytes
frontend/src/assets/integrations/ghcr.png | Bin 0 -> 33270 bytes
frontend/src/assets/integrations/github.png | Bin 0 -> 33270 bytes
frontend/src/assets/integrations/hume.ico | Bin 0 -> 10990 bytes
.../integrations/integration-generic.svg | 5 +
frontend/src/assets/integrations/inworld.ico | Bin 0 -> 2455 bytes
frontend/src/assets/integrations/mcp.png | Bin 0 -> 3055 bytes
frontend/src/assets/integrations/murf.ico | Bin 0 -> 4286 bytes
frontend/src/assets/integrations/n8n.ico | Bin 0 -> 15086 bytes
frontend/src/assets/integrations/plivo.svg | 5 +
frontend/src/assets/integrations/resemble.png | Bin 0 -> 1284 bytes
.../src/assets/integrations/speechify.ico | Bin 0 -> 94254 bytes
frontend/src/assets/integrations/telnyx.ico | Bin 0 -> 26467 bytes
frontend/src/assets/integrations/twilio.png | Bin 0 -> 8103 bytes
.../src/assets/integrations/voicestudio.png | Bin 0 -> 33270 bytes
frontend/src/assets/integrations/wellsaid.png | Bin 0 -> 825 bytes
frontend/src/assets/integrations/zapier.ico | Bin 0 -> 57638 bytes
frontend/src/components/donate/GoalBar.jsx | 4 +-
frontend/src/config/integration-catalog.d.ts | 12 +
frontend/src/config/integration-catalog.js | 40 +
frontend/src/config/voice-ai-directory.d.ts | 1 +
frontend/src/config/voice-ai-directory.js | 29 +
frontend/src/i18n/locales/ar.json | 38 +-
frontend/src/i18n/locales/de.json | 38 +-
frontend/src/i18n/locales/en.json | 38 +-
frontend/src/i18n/locales/es.json | 38 +-
frontend/src/i18n/locales/fr.json | 38 +-
frontend/src/i18n/locales/hi.json | 38 +-
frontend/src/i18n/locales/id.json | 38 +-
frontend/src/i18n/locales/it.json | 38 +-
frontend/src/i18n/locales/ja.json | 38 +-
frontend/src/i18n/locales/ko.json | 38 +-
frontend/src/i18n/locales/nl.json | 38 +-
frontend/src/i18n/locales/pl.json | 38 +-
frontend/src/i18n/locales/pt.json | 38 +-
frontend/src/i18n/locales/ru.json | 38 +-
frontend/src/i18n/locales/sv.json | 38 +-
frontend/src/i18n/locales/th.json | 38 +-
frontend/src/i18n/locales/tr.json | 38 +-
frontend/src/i18n/locales/uk.json | 38 +-
frontend/src/i18n/locales/vi.json | 38 +-
frontend/src/i18n/locales/zh-CN.json | 38 +-
frontend/src/i18n/locales/zh-TW.json | 38 +-
frontend/src/index.css | 4 +-
frontend/src/pages/SupportPage.jsx | 30 +-
frontend/src/store/donationSlice.ts | 2 +-
scripts/capture-readme-electron.mjs | 50 ++
112 files changed, 4650 insertions(+), 1394 deletions(-)
create mode 100644 docs/integration-directory.md
create mode 100644 docs/media/electron/README.md
create mode 100644 docs/media/electron/dubbing.png
create mode 100644 docs/media/electron/models.png
create mode 100644 docs/media/electron/voice-cloning.png
create mode 100644 docs/media/electron/voice-design.png
create mode 100644 docs/media/electron/voicestudio.gif
create mode 100644 docs/support-page.md
create mode 100644 electron/src/renderer/src/components/app-shell/sponsor-footer.css
create mode 100644 electron/src/renderer/src/components/app-shell/sponsor-footer.test.tsx
create mode 100644 electron/src/renderer/src/components/app-shell/sponsor-footer.tsx
create mode 100644 electron/src/renderer/src/components/app-shell/sponsor-inquiry.css
create mode 100644 electron/src/renderer/src/components/app-shell/sponsor-inquiry.tsx
create mode 100644 electron/src/renderer/src/components/app-shell/support-shortcut.tsx
create mode 100644 electron/src/renderer/src/features/integrations/integration-detail-page.tsx
create mode 100644 electron/src/renderer/src/features/integrations/integrations-page.css
create mode 100644 electron/src/renderer/src/features/integrations/integrations-page.tsx
create mode 100644 electron/src/renderer/src/features/settings/support-settings.css
create mode 100644 frontend/src/assets/integrations/anthropic.png
create mode 100644 frontend/src/assets/integrations/assemblyai.ico
create mode 100644 frontend/src/assets/integrations/cartesia.png
create mode 100644 frontend/src/assets/integrations/codex.png
create mode 100644 frontend/src/assets/integrations/deepgram.ico
create mode 100644 frontend/src/assets/integrations/docker.png
create mode 100644 frontend/src/assets/integrations/elevenlabs.ico
create mode 100644 frontend/src/assets/integrations/ghcr.png
create mode 100644 frontend/src/assets/integrations/github.png
create mode 100644 frontend/src/assets/integrations/hume.ico
create mode 100644 frontend/src/assets/integrations/integration-generic.svg
create mode 100644 frontend/src/assets/integrations/inworld.ico
create mode 100644 frontend/src/assets/integrations/mcp.png
create mode 100644 frontend/src/assets/integrations/murf.ico
create mode 100644 frontend/src/assets/integrations/n8n.ico
create mode 100644 frontend/src/assets/integrations/plivo.svg
create mode 100644 frontend/src/assets/integrations/resemble.png
create mode 100644 frontend/src/assets/integrations/speechify.ico
create mode 100644 frontend/src/assets/integrations/telnyx.ico
create mode 100644 frontend/src/assets/integrations/twilio.png
create mode 100644 frontend/src/assets/integrations/voicestudio.png
create mode 100644 frontend/src/assets/integrations/wellsaid.png
create mode 100644 frontend/src/assets/integrations/zapier.ico
create mode 100644 frontend/src/config/integration-catalog.d.ts
create mode 100644 frontend/src/config/integration-catalog.js
create mode 100644 frontend/src/config/voice-ai-directory.d.ts
create mode 100644 frontend/src/config/voice-ai-directory.js
create mode 100644 scripts/capture-readme-electron.mjs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9eaecf9..25f87054 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,14 @@ the frozen-backend fallback mirror it for their toolchains.
**Highlights**
+- The README is shorter, with a new Electron UI tour and refreshed screenshots (#2129)
+
+- Support pages feature cleaner donation cards, with a workspace support shortcut and sponsor footer with hover cards and email inquiries (#2129)
+
+- Integrations has a dedicated sidebar workspace with featured sponsors, searchable AI providers, and smooth sponsor-strip scrolling (#2129)
+
+- Integrations now covers 100+ automation, communications, MCP, agent, developer, data, and productivity tools with config-driven detail pages (#2129)
+
- Electron now ships as a complete cross-platform VoiceStudio desktop app with local-first cloning, production workspaces, model packs, repair agents, native integrations, updates, parity checks, and the shared backend contracts required by those workflows (#1823)
- The Model Catalogue is one page: what you use now on top, then each family's engines and weights (#2013)
diff --git a/README.md b/README.md
index cb8d6cdf..b1ad3a4b 100644
--- a/README.md
+++ b/README.md
@@ -1,502 +1,81 @@
-
-
NOTE: Electron Rewrite Ongoing: Please dont't create desktop app related issues and pr
-
-

+
VoiceStudio
+
Your voices. Your stories. Your machine.
+
Clone voices, dub videos, dictate, and create audiobooks with local AI.
-
-
-
Previously OmniVoice-Studio
-
Clone voices, dub video, dictate, and produce long-form audio on your own hardware.
-
16 TTS engines · 11 ASR engines · 646-language catalogue · macOS, Windows, Linux, and Docker
-
No account, API key, subscription, or usage meter for the local workflow.
-
-
- Install ·
- Features ·
- Compare ·
- Requirements ·
- Hardware ·
- Engines ·
- Architecture ·
- API ·
+ Download ·
+ Get started ·
Docs ·
- FAQ ·
- 简体中文
+ Discord ·
+ 简体中文
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-

-
+
-> [!WARNING]
-> **Active beta.** Use the [latest release](https://github.com/debpalash/VoiceStudio/releases/latest) for stable work. `main` contains the newest fixes and may change between releases. Report problems through [GitHub Issues](https://github.com/debpalash/VoiceStudio/issues).
+
The new Electron desktop UI, captured from this branch with the bundled demo voice. Release builds may look different.
-## At a glance
+## Create with VoiceStudio
-| | VoiceStudio |
-|---|---|
-| **Workflows** | Voice cloning and design, video dubbing, dictation, stories, audiobooks, batch generation |
-| **Language catalogue** | 646 TTS languages; actual coverage and quality depend on the selected engine |
-| **Engines** | 16 TTS · 11 ASR · switch in Model Catalogue or with
Ctrl/
Cmd+
E |
-| **Platforms** | macOS 13.3+ on Apple Silicon · Windows 10/11 x64 · Linux x86_64 with glibc 2.39+ |
-| **Compute** | CUDA · Apple Silicon MPS/MLX · ROCm on Linux · CPU · optional remote workers |
-| **Interfaces** | Desktop app · local REST/SSE/WebSocket API · OpenAI-compatible audio API · MCP Server |
-| **Storage** | Voices, projects, settings, and outputs stay on the machine by default |
-| **License** | AGPL-3.0 application; downloaded models keep their upstream terms |
+- **Clone & design voices** — use a reference recording or describe the voice you imagine.
+- **Dub video** — transcribe, translate, assign speakers, and edit timed speech.
+- **Dictate anywhere** — record, transcribe, and copy text with a floating recording widget.
+- **Tell longer stories** — create multi-voice scripts, audiobooks, and batch jobs.
+- **Choose your models** — manage speech and transcription engines, languages, and compute devices.
-The Voice workspace starts with three tabs: **From audio** for cloning, **By design** for creating a voice, and **Convert** for speech-to-speech conversion. Each tab displays its own workflow, with Synthesize Audio or Convert pinned below the scrolling form. The top-bar **Engines** panel combines engine selection, loaded models, and unload/flush controls;
Ctrl/
Cmd+
E opens it. The searchable language picker shares Dubbing’s flags and language list layout, selects one output language, and retains Auto and the full cloning catalogue. Language options flow into multiple columns when space allows. Expand **Workspaces** in the sidebar to reveal navigation labels; Escape collapses it.
+Start with **VoiceStudio** (default, powered by k2-fsa/OmniVoice), or choose another engine.
-Dubbing starts with file upload or URL import and nearby language choices. Its **Projects** panel lists previous dubs so they can be reopened by clicking anywhere on a card; action buttons operate independently. Advanced import options include captions and optional YouTube sign-in. Dubbing places playback controls over the video with background blur and combines the waveform and timed transcript in one compact editing surface. Drag the zoomed waveform left or right to pan; click to seek. Translation language and ISO-code controls stay synchronized; Auto clears any previous language code and dialect. Transcript items group editable text, timing and status, and voice controls into three readable rows that wrap with the panel width. Output Options stays compact with the active settings shown in its summary; expand it to change output, timing, or voice matching. Transcript, glossary, and paste controls share a toolbar above the segment editor. Project details, workflow steps, and Generate/Verify/Export actions use an unfilled header.
+Local workflows run on your hardware. Remote services are optional; usage analytics requires consent.
-The Audiobook Script editor fills the available workspace beneath its markup toolbar; Voices and Book settings stay in their own tabs.
+
+
+  |
+  |
+
+ | Voice cloning | Video dubbing |
+
-Output settings use aligned rows; review status appears before the collapsible transcript and glossary. Glossary terms have labelled entry fields and an explicit edit action. Launchpad arranges recent files and saved voices side by side when space allows, with responsive card grids and visible Open actions.
+## Get started
-The casting board shows icon-based voice cards and searchable selectors for each speaker. Drag a card onto a speaker or choose a voice from that speaker’s menu.
+Download from [Releases](https://github.com/debpalash/VoiceStudio/releases/latest), then follow your platform guide:
-
+**[macOS](docs/install/macos.md) · [Windows](docs/install/windows.md) · [Linux](docs/install/linux.md) · [Docker](docs/install/docker.md)**
-## Install
+Open **Voice cloning**, choose a voice or add a clean reference recording, enter your text, and generate. Install the required model when prompted. Hardware needs vary by engine; see [performance](docs/performance.md).
-Download a package from the [latest release](https://github.com/debpalash/VoiceStudio/releases/latest), then follow the platform guide.
-
-| Platform | Package | Guide |
-|---|---|---|
-| macOS 13.3+ | Apple Silicon DMG | [Install on macOS](docs/install/macos.md) |
-| Windows 10/11 | x64 MSI; choose the current-user build when listed to install without admin access | [Install on Windows](docs/install/windows.md#install-pre-built-msi) |
-| Linux | AppImage, x86_64 with glibc 2.39+ | [Install on Linux](docs/install/linux.md) |
-| Docker | Linux/AMD64 images; CUDA, ROCm, CPU, and worker-only GPU profiles | [Run with Docker](docs/install/docker.md) |
-
-First launch creates a managed Python environment and downloads the default model. Later launches reuse both.
-
-> [!NOTE]
-> On macOS, first launch needs a one-time right-click, then **Open** approval. Intel Macs cannot run the local Python backend; use a [remote backend](docs/install/macos.md) instead.
-
-### Quick Docker run
-
-The published images are **`linux/amd64` only**. On Apple Silicon, use the
-[native macOS app](docs/install/macos.md) for GPU acceleration. ARM64 hosts
-should read the [architecture requirements](docs/install/docker.md#architecture)
-before pulling an image.
-
-```bash
-docker run -d -p 127.0.0.1:3900:3900 -v omnivoice-data:/app/omnivoice_data --name voicestudio palashdeb/omnivoice-studio:stable
-```
-
-### First voice
-
-1. Launch VoiceStudio and open **Voice Cloning**.
-2. Add a clean voice sample. Three seconds works; 5 to 15 seconds usually gives a better prompt.
-3. Enter text, choose a language, then select **Generate**.
-
-> [!TIP]
-> **Try without installing:** Run VoiceStudio in the cloud via the [Google Colab notebook](https://colab.research.google.com/github/debpalash/VoiceStudio/blob/main/notebooks/OmniVoice_Studio_Colab.ipynb). Explore audio quality comparisons in [benchmarks](docs/benchmarks.md) and prompt design tips in [expressive speech](docs/expressive-speech.md).
-
-### Audio samples
-
-Listen to sample outputs produced locally with VoiceStudio:
-
-| Workflow | Prompt / Reference Audio | Generated Audio |
-|---|---|---|
-| **Voice Cloning** | [demo_voice.wav](backend/assets/samples/demo_voice.wav) | [demo_clone_output.wav](backend/assets/samples/demo_clone_output.wav) |
-| **Voice Design** (US News Anchor) | *"Clear, authoritative American broadcast tone"* | [demo_voice_design_us_news_anchor.wav](backend/assets/samples/voice_design/demo_voice_design_us_news_anchor.wav) |
-| **Voice Design** (UK Audiobook) | *"Warm, expressive British storytelling voice"* | [demo_voice_design_audiobook_uk_narrator.wav](backend/assets/samples/voice_design/demo_voice_design_audiobook_uk_narrator.wav) |
-| **Video Dubbing** (Multilingual) | [source.src.wav](backend/assets/samples/demo/dubbing/source.src.wav) | [Spanish](backend/assets/samples/demo/dubbing/dubbed_es.src.wav) · [French](backend/assets/samples/demo/dubbing/dubbed_fr.src.wav) · [Japanese](backend/assets/samples/demo/dubbing/dubbed_ja.src.wav) · [Chinese](backend/assets/samples/demo/dubbing/dubbed_zh.src.wav) |
-
-### Run from source
-
-Install the [development prerequisites](.github/CONTRIBUTING.md#development-setup) (Node 20+/Bun and Python 3.11+), then:
+**Run the Electron preview from source:**
```bash
git clone https://github.com/debpalash/VoiceStudio.git
cd VoiceStudio
bun install
-bun run desktop
+cd electron
+bun run dev
```
-The desktop launcher configures Python dependencies on first run via `uv` automatically. Use `bun run dev` for the browser UI. See [Contributing](.github/CONTRIBUTING.md) for services, tests, and platform packages.
-
-### If setup fails
-
-- Run **Settings → About → Run self-check** or `uv run python backend/main.py --diagnose --deep`.
-- Check [install troubleshooting](docs/install/troubleshooting.md).
-- Save a scrubbed diagnostic bundle from the app when opening an issue.
-- For slow generation, compare [measured benchmarks](docs/benchmarks.md) and [performance settings](docs/performance.md).
-
-
-
-## Features
-
-| Area | Included |
-|---|---|
-| **Voice Cloning** | Zero-shot synthesis from a short reference clip ([guide](docs/engines/README.md)) |
-| **Voice Design** | Create a voice from age, accent, pitch, style, and delivery instructions ([expressive speech](docs/expressive-speech.md)) |
-| **Video Dubbing** | Transcribe, translate, preserve speakers, synthesize, and export video; compact translation settings include track selection, and completed dubs flag timing issues for review ([export guide](docs/dubbing/export.md)) |
-| **Stories and audiobooks** | Multi-voice scripts · EPUB/PDF import · chapter rendering · `.m4b` export |
-| **[Dictation Widget](docs/features/dictation.md)** | System-wide shortcut, live transcription, optional local-LLM cleanup |
-| **Vocal Isolation** | Demucs speech/background separation |
-| **Speaker Diarization** | Pyannote and WhisperX speaker assignment ([guide](docs/features/diarization.md)) |
-| **Batch Queue** | Queue large sets of audio and video jobs with per-job progress, or watch a local folder for new videos |
-| **Model Catalogue** | Install, remove, select, and route TTS, ASR, and LLM models ([catalogue](docs/engines/README.md)) |
-| **Remote Model Downloads** | Install models on enrolled remote workers with live progress ([guide](docs/downloading-models.md)) |
-| **GPU Auto-Detect** | CUDA, MPS, ROCm, and CPU routing with per-engine checks ([performance](docs/performance.md)) |
-| **AI Watermark** | AudioSeal embedding and detection |
-| **MCP Server** | Synthesis and transcription tools for MCP clients ([guide](docs/mcp.md)) |
-| **Diagnostics** | Self-checks, error journal, logs, and scrubbed support bundles ([troubleshooting](docs/install/troubleshooting.md)) |
-| **Local-first** | Core creation stays local; network-backed features are explicit opt-ins |
-| **Extensible** | Registry-based TTS, ASR, and plugin interfaces ([acceptance](docs/engine-acceptance.md)) |
-
-
-
-  |
-  |
-
-
- | Model Catalogue: engine, device, and install state |
- Gallery: save a shared voice as a local profile |
-
-
-
-
-
-## Comparison
-
-VoiceStudio trades managed cloud compute for local control. This is the practical difference:
-
-| | **VoiceStudio** | **Typical hosted voice service** |
-|---|---|---|
-| **Best fit** | Private, offline, self-hosted, or high-volume work | Fast setup without local model management |
-| **Data path** | Local by default; remote features are opt-in | Audio and text are processed by the provider |
-| **Cost model** | Free software; you supply the hardware | Subscription, credits, or metered API use |
-| **Setup** | Install the app and model weights | Create an account and use the web app or API |
-| **Performance** | Depends on your engine and hardware | Provider manages compute and scaling |
-| **Offline use** | Yes, after required models are installed | Usually requires a network connection |
-| **Customization** | Source, engines, models, API, and routing are open | Limited to provider options |
-| **Maintenance** | You manage updates, disk, and compute | Provider manages infrastructure |
-
-
-
-## Requirements
-
-Requirements vary by engine. These values cover the default local workflow.
-
-| | **Minimum** | **Recommended** |
-|---|---|---|
-| **OS** | Windows 10 x64 · macOS 13.3 Apple Silicon · Linux x86_64 with glibc 2.39+ | Current supported OS release |
-| **RAM** | 8 GB | 16 GB+ |
-| **Disk** | 10 GB free | 20 GB+ SSD |
-| **GPU** | Optional; CPU mode is supported | NVIDIA CUDA or Apple Silicon |
-| **VRAM** | 4 GB when using a GPU | 8 GB+; large optional engines need more |
-| **Python from source** | 3.11+ | 3.11 or 3.12 |
-
-ROCm is Linux-only and opt-in. Windows AMD/Ryzen AI uses CPU. Systems with limited VRAM offload work to CPU when required. See [performance](docs/performance.md), [benchmarks](docs/benchmarks.md), and [engine disk usage](docs/engines/disk-usage.md).
-
-
-
-### Recommended stack by hardware
-
-| Hardware | Recommended TTS | Recommended ASR | Why |
-|---|---|---|---|
-| **Apple Silicon (M1–M4)** | [MLX-Audio](docs/engines/mlx-audio.md) · [OmniVoice](docs/engines/omnivoice.md) (MPS) | [MLX Whisper](docs/engines/mlx-whisper.md) · [Parakeet MLX](docs/engines/parakeet-mlx.md) | Native unified memory, lowest latency on macOS |
-| **NVIDIA GPU (8 GB+ VRAM)** | [OmniVoice](docs/engines/omnivoice.md) · [CosyVoice 3](docs/engines/cosyvoice.md) | [WhisperX](docs/engines/whisperx.md) | High-fidelity zero-shot cloning, word timestamps, diarization |
-| **Low VRAM / CPU-only** | [PocketTTS](docs/engines/pockettts.md) · [Sherpa-ONNX](docs/engines/sherpa-onnx.md) · [KittenTTS](docs/engines/kittentts.md) | [Moonshine](docs/engines/moonshine.md) · [Faster-Whisper](docs/engines/faster-whisper.md) (`int8`) | Low memory footprint, optimized CPU inference |
-
-
-
-## Engines
-
-Engine support is capability-specific. Check cloning, language, platform, memory, and license before choosing one. Full setup guides: [docs/engines](docs/engines/README.md).
-
-
-
-### Text to speech
-
-| Engine | Languages | Clone | Instruct | Linux | macOS ARM | Windows | License |
-|---|:---:|:---:|:---:|:---:|:---:|:---:|---|
-| [**VoiceStudio** (default, powered by k2-fsa/OmniVoice)](docs/engines/omnivoice.md) | 600+ | Yes | Yes | CUDA/CPU | MPS | CUDA/CPU | [AGPL-3.0](LICENSE) app · [Apache-2.0 code, CC-BY-NC weights](https://huggingface.co/k2-fsa/OmniVoice#license)³ |
-| [**CosyVoice 3**](docs/engines/cosyvoice.md) | 9 + 18 dialects | Yes | Yes | CUDA/CPU | CPU | CUDA/CPU | Apache-2.0 |
-| [**GPT-SoVITS**](docs/engines/gpt-sovits.md) | 5 | Yes | No | CUDA/CPU | No | CUDA/CPU | MIT |
-| [**VoxCPM2**](docs/engines/voxcpm2.md) | 30 | Yes | Yes | CUDA/CPU | MPS | CUDA/CPU | Apache-2.0 |
-| [**MOSS-TTS-Nano**](docs/engines/moss-tts-nano.md) | 20 | Yes | No | CUDA/CPU | CPU | CUDA/CPU | Apache-2.0 |
-| [**KittenTTS**](docs/engines/kittentts.md) | English | No | No | CPU | CPU | CPU | MIT |
-| [**MLX-Audio**](docs/engines/mlx-audio.md) | Model-dependent | Varies | Varies | No | MLX | No | Varies |
-| [**Sherpa-ONNX**](docs/engines/sherpa-onnx.md) | 20+ | No | No | CUDA/CPU | CPU | CUDA/CPU | Apache-2.0 |
-| [**IndexTTS 2.5** ⚡](docs/engines/indextts.md) | ZH · EN · JA · ES · AR | Yes | No | CUDA/CPU | CPU | CUDA/CPU | Bilibili model license¹ |
-| [**OmniVoice GGUF** ⚡](docs/engines/omnivoice-gguf.md) | 600+ | Yes | Yes | CUDA/CPU | MPS/CPU | CUDA/CPU | [AGPL-3.0](LICENSE) app · [review the derivative model terms](https://huggingface.co/Serveurperso/OmniVoice-GGUF#license)³ |
-| [**OmniVoice (subprocess; opt-in off MPS)** ⚡](docs/engines/omnivoice-subprocess.md) | 600+ | Yes | Yes | CUDA/CPU | MPS via default OmniVoice | CUDA/CPU | [AGPL-3.0](LICENSE) app · [Apache-2.0 code, CC-BY-NC weights](https://huggingface.co/k2-fsa/OmniVoice#license)³ |
-| [**PocketTTS** ⚡](docs/engines/pockettts.md) | EN · FR · DE · PT · IT · ES | Yes | No | CPU | CPU | CPU | CC-BY-4.0, gated² |
-| [**Supertonic 3** ⚡](docs/engines/supertonic3.md) | 31 | No | No | CPU | CPU | CPU | OpenRAIL-M |
-| [**MOSS-TTS-v1.5** ⚡](docs/engines/moss-tts-v15.md) | 31 | Yes | No | CUDA/CPU | CPU | CUDA/CPU | Apache-2.0 |
-| [**dots.tts** ⚡](docs/engines/dots-tts.md) | 24 | Yes | No | CUDA/CPU | CPU | No | Apache-2.0 |
-| [**Confucius4-TTS** ⚡](docs/engines/confucius4-tts.md) | 14 | Yes | No | CUDA/CPU | CPU | CUDA/CPU | Apache-2.0 |
-
-⚡ Installed or registered on demand.
-
-¹ IndexTTS 2.5 requires a separate written Bilibili license above 100 million monthly active users or RMB 1 billion annual revenue. Review the [model license](https://huggingface.co/IndexTeam/IndexTTS-2.5/blob/main/LICENSE).
-
-² PocketTTS shows its gated-access and CC-BY-4.0 terms before first use.
-
-³ The OmniVoice snapshot also includes an audio tokenizer under separate [Boson Higgs Audio 2 and Meta Llama community terms](https://huggingface.co/k2-fsa/OmniVoice/blob/main/audio_tokenizer/LICENSE). VoiceStudio's application license does not replace model or tokenizer terms.
-
-Clone-less engines cannot preserve a reference speaker in dubbing or pinned-voice batch jobs. VoiceStudio rejects those jobs instead of silently changing engines. Heavy engines have separate memory and platform limits; check their engine guide first.
-
-
-
-### Speech to text
-
-| Engine | ID | Languages | Best fit |
-|---|---|:---:|---|
-| [**WhisperX** (default)](docs/engines/whisperx.md) | `whisperx` | ~100 | Dubbing, subtitles, word-level timing |
-| [**Faster-Whisper**](docs/engines/faster-whisper.md) | `faster-whisper` | ~100 | General cross-platform transcription |
-| [**Faster-Whisper (isolated)**](docs/engines/faster-whisper-isolated.md) | `faster-whisper-isolated` | ~100 | Crash-isolated batch transcription |
-| [**MLX Whisper**](docs/engines/mlx-whisper.md) | `mlx-whisper` | ~100 | Apple Silicon |
-| [**PyTorch Whisper**](docs/engines/pytorch-whisper.md) | `pytorch-whisper` | ~100 | CUDA, MPS, and CPU fallback |
-| [**Parakeet TDT**](docs/engines/nemo-parakeet.md) | `nemo-parakeet` | English + 25 EU | Fast CPU/CUDA transcription |
-| [**Parakeet TDT v3 (MLX)**](docs/engines/parakeet-mlx.md) | `parakeet-mlx` | 25 EU | Apple Silicon dictation and word timestamps |
-| [**Moonshine**](docs/engines/moonshine.md) | `moonshine` | English | Low-power, low-latency ONNX |
-| [**FunASR**](docs/engines/funasr.md) | `funasr` | 50+ | VAD and inline diarization |
-| [**sherpa-onnx** (live dictation)](docs/engines/sherpa-onnx-asr.md) | `sherpa-onnx-asr` | Model-dependent | Streaming CPU dictation |
-| [**OpenAI-compatible** ⚠️ configured server](docs/engines/openai-compatible-asr.md) | `openai-compat-asr` | Server-dependent | Local gigastt/Qwen3-ASR or a remote endpoint; audio goes only to that server |
-
-WhisperX and Faster-Whisper retry with `int8` when efficient `float16` is unavailable. Pin `ASR_COMPUTE_TYPE=int8` or `float32` only if automatic selection still fails.
-
-
-
-## Architecture
-
-```text
-Tauri v2 desktop shell (Rust)
- │ IPC
-React + Vite UI
- │ HTTP · SSE · WebSocket on localhost:3900
-FastAPI backend
- ├── TTS / ASR engine registries
- ├── dubbing / audio / long-form pipelines
- ├── OpenAI-compatible API and MCP server
- └── SQLite + Alembic → omnivoice_data/
-```
-
-| Layer | Path | Responsibility |
-|---|---|---|
-| Desktop shell | `frontend/src-tauri/` | Window lifecycle, tray, shortcuts, updater, sidecar bootstrap |
-| Frontend | `frontend/src/` | React UI, Zustand state, API and event clients, i18n |
-| API | `backend/api/` | REST routes, schemas, auth boundaries, streaming |
-| Core services | `backend/services/` | Generation, dubbing, audio processing, persistence |
-| Engines | `backend/engines/` | Isolated and optional engine adapters |
-| Worker system | `backend/worker/` | Authenticated remote compute and job transport |
-| Data | `omnivoice_data/` | Projects, voices, settings, logs, and SQLite state |
-| Delivery | `scripts/`, `deploy/`, `.github/workflows/` | Development, packaging, containers, releases, CI |
-
-### Network boundary
-
-- The desktop talks to a loopback-only backend on `localhost:3900`.
-- Loopback API calls need no server key. Remote access requires a share PIN or API key.
-- Remote workers and OpenAI-compatible ASR are opt-in. Loopback ASR may use HTTP and keeps audio on the machine; non-loopback endpoints require HTTPS, and redirects are not followed.
-- Analytics is off until consent. If enabled, it sends allowlisted, content-free usage metadata. It never sends text, audio, file names, or projects.
-
-
-
-## Local speech platform and OpenAI-compatible API
-
-Point an OpenAI-compatible audio client at the local backend:
-
-```diff
-- base_url="https://api.openai.com/v1"
-+ base_url="http://localhost:3900/v1"
-```
-
-| Endpoint | Purpose |
-|---|---|
-| `POST /v1/audio/speech` | TTS to `mp3`, `opus`, `aac`, `flac`, `wav`, or `pcm`; select a profile with `voice` and an engine with `model` |
-| `POST /v1/audio/transcriptions` | STT to `json`, `text`, `verbose_json`, `srt`, or `vtt` |
-| `WS /v1/audio/transcriptions/stream` | Live PCM/WebM transcription with partial, utterance, and session-final events |
-| `GET /.well-known/voicestudio-speech` | Discover HTTP, WebSocket, MCP, and native dictation-control transports |
-| `GET /v1/audio/voices` | List local voice profiles and engines |
-
-```python
-from openai import OpenAI
-
-client = OpenAI(base_url="http://localhost:3900/v1", api_key="local")
-
-with client.audio.speech.with_streaming_response.create(
- model="tts-1",
- voice="
",
- input="Made on my own hardware.",
- response_format="wav",
-) as response:
- response.stream_to_file("speech.wav")
-```
-
-```bash
-# Quick test via cURL
-curl http://localhost:3900/v1/audio/speech \
- -H "Content-Type: application/json" \
- -d '{"model": "tts-1", "input": "Made on my own hardware.", "voice": "default", "response_format": "wav"}' \
- --output speech.wav
-```
-
-The bundled Rust control sidecar lets Herdr, coding agents, VS Code, desktop apps,
-and TUIs trigger the system-wide dictation flow or reuse its native text
-insertion. See the [speech platform guide](docs/speech-platform.md). The full API
-reference is in **Settings → OpenAPI Reference**. For LAN, Tailscale, or proxy
-access, read [API authentication](docs/api-auth.md) before exposing the backend.
-
-### Agent skills
-
-Install the VoiceStudio skills for Claude Code, Codex, Cursor, and other [skills.sh](https://skills.sh)-compatible agents:
-
-```bash
-npx skills add debpalash/VoiceStudio
-```
-
-- `omnivoice`: synthesize speech and transcribe audio through local VoiceStudio.
-- `oss-maintainer`: the repository's open-source maintenance workflow.
-
-### Model Context Protocol (MCP)
-
-VoiceStudio mounts an MCP server at `http://localhost:3900/mcp` for Claude Desktop, Cursor, and AI agents:
-
-```json
-{
- "mcpServers": {
- "voicestudio": {
- "url": "http://localhost:3900/mcp"
- }
- }
-}
-```
-
-For clients requiring stdio transport, use the bundled local shim (`docs/mcp.json`):
-
-```json
-{
- "mcpServers": {
- "voicestudio": {
- "command": "python",
- "args": ["-m", "backend.mcp_shim"],
- "cwd": "/path/to/VoiceStudio"
- }
- }
-}
-```
-
-See the [MCP guide](docs/mcp.md) for tools (`generate_speech`, `clone_voice`, `transcribe`), file streaming modes, and client bindings.
-
-### Google Colab
-
-[](https://colab.research.google.com/github/debpalash/VoiceStudio/blob/main/notebooks/OmniVoice_Studio_Colab.ipynb)
-
-The [notebook](notebooks/OmniVoice_Studio_Colab.ipynb) runs the app and web UI on a Colab GPU. Colab is remote compute, so uploaded audio and project data do not remain local to your machine.
-
-
+See [Electron setup](electron/README.md) for prerequisites and backend configuration. VoiceStudio is in active development; report bugs through [GitHub Issues](https://github.com/debpalash/VoiceStudio/issues).
## Documentation
-| Need | Read |
+| Need | Start here |
|---|---|
-| Install | [macOS](docs/install/macos.md) · [Windows](docs/install/windows.md) · [Linux](docs/install/linux.md) · [Docker](docs/install/docker.md) |
-| Fix setup | [Troubleshooting](docs/install/troubleshooting.md) · [model downloads](docs/downloading-models.md) · [Hugging Face token](docs/setup/huggingface-token.md) |
-| Choose an engine | [Engine guides](docs/engines/README.md) · [benchmarks](docs/benchmarks.md) · [expressive speech](docs/expressive-speech.md) |
-| Tune hardware | [Performance](docs/performance.md) · [remote workers](docs/remote-workers.md) |
-| Build integrations | [Speech platform](docs/speech-platform.md) · [Private production API](docs/production-private-api.md) · [API auth](docs/api-auth.md) · [MCP](docs/mcp.md) · [examples](examples/README.md) |
-| Build VoiceStudio | [Contributing](.github/CONTRIBUTING.md) · [engine acceptance](docs/engine-acceptance.md) |
-| Track changes | [Changelog](CHANGELOG.md) · [roadmap](docs/ROADMAP.md) · [latest release](https://github.com/debpalash/VoiceStudio/releases/latest) |
-| Remove everything | [Uninstall guide](docs/install/uninstall.md) |
+| Setup help | [Troubleshooting](docs/install/troubleshooting.md) · [Model downloads](docs/downloading-models.md) |
+| Models & audio quality | [Engine guides](docs/engines/README.md) · [Benchmarks](docs/benchmarks.md) |
+| Integrations | [Local API](docs/speech-platform.md) · [MCP](docs/mcp.md) · [Examples](examples/README.md) |
+| Development | [Contributing](.github/CONTRIBUTING.md) · [Electron](electron/README.md) · [Changelog](CHANGELOG.md) |
-
+Agent skills: `npx skills add debpalash/VoiceStudio`
-## FAQ
+## Support VoiceStudio
-
-Does it work on Apple Silicon and Intel Macs?
+[Ko-fi](https://ko-fi.com/debpalash) · [PayPal](https://paypal.me/palashCoder) · [Sponsor the project](SPONSORS.md) · [Partnerships](mailto:partner@voicestudio.sh)
-Apple Silicon is supported with MPS and MLX options. Intel Macs cannot run the local backend because current PyTorch wheels are unavailable; they can connect to a remote backend. See [macOS installation](docs/install/macos.md).
-
+## License & responsible use
-
-How much VRAM do I need?
-
-A GPU is optional. Use 4 GB VRAM as the minimum for accelerated work and 8 GB+ for the default multi-stage workflow. Large optional engines can require 12 to 16 GB or more. Check the [benchmarks](docs/benchmarks.md) and engine guide.
-
-
-
-Why does a longer reference clip not always improve the clone?
-
-Cloning is zero-shot: the clip is a prompt, not training data. Use 5 to 15 seconds of one speaker, close to the microphone, without music, noise, or reverb. Match the tone and pace you want in the output. For training, see [data preparation](docs/data_preparation.md) and [training](docs/training.md).
-
-
-
-Can I use generated audio commercially?
-
-VoiceStudio's application license does not restrict generated audio, but it does not grant rights under a model's separate terms. The default OmniVoice repository labels its pretrained weights CC-BY-NC and includes a tokenizer under separate community terms. Review the selected model terms before commercial use.
-
-
-
-Does VoiceStudio collect data?
-
-Not unless you opt in. Analytics is off by default and skipping consent keeps it off. When enabled, the app sends allowlisted, content-free usage metadata. Text, audio, file names, voices, and projects are excluded. Change this at **Settings → Privacy**.
-
-
-
-How do I remove VoiceStudio and its data?
-
-Use `scripts/uninstall.sh` on macOS/Linux or `scripts\uninstall.ps1` on Windows. Both show a dry run before deletion. See the [uninstall guide](docs/install/uninstall.md) for every path.
-
-
-## Community and contributing
-
-- [GitHub Issues](https://github.com/debpalash/VoiceStudio/issues) for reproducible bugs and feature requests.
-- [Discord](https://discord.gg/bzQavDfVV9) for setup help and project discussion.
-- [Good first issues](https://github.com/debpalash/VoiceStudio/labels/good%20first%20issue) for a scoped starting point.
-- [Contributing guide](.github/CONTRIBUTING.md) for setup, tests, and pull requests.
-
-
-
-
-
-
-
-## Support development
-
-VoiceStudio is free and has no paid tier. Donations fund development and infrastructure.
-
-[Ko-fi](https://ko-fi.com/debpalash) · [PayPal](https://paypal.me/palashCoder) · [Sponsorship details](SPONSORS.md)
-
-## Responsible use and safety
-
-VoiceStudio enables zero-shot voice cloning and speech generation on personal hardware. Please use it responsibly:
-- **Consent:** Only clone or synthesize voices with explicit permission from the speaker.
-- **Audio provenance:** VoiceStudio integrates [AudioSeal](https://github.com/facebookresearch/audioseal) imperceptible watermarking by default to detect and identify synthetic speech without altering sound quality.
-- **Local privacy:** For the default local workflow, audio recordings, transcripts, voices, and projects remain strictly on your local disk; data leaves your device only when you explicitly configure remote workers or external ASR endpoints.
-
-## License
-
-VoiceStudio is licensed under [AGPL-3.0](LICENSE). You may run it, modify it, and use it internally. The application license itself does not restrict selling generated audio, but downloaded model and tokenizer terms may. If you modify VoiceStudio and provide that modified version as a network service, AGPL requires you to offer the corresponding source under the same license. A commercial license for VoiceStudio-owned code is available for proprietary embedding; it does not relicense third-party models. Contact **VoiceStudio@palash.dev**. See [LICENSE-NOTICE.md](LICENSE-NOTICE.md) for the plain-language scope.
-
-Optional engines and downloaded models retain their own licenses. The bundled `omnivoice/` Python code is Apache-2.0 upstream; the default downloaded weights and audio tokenizer use separate terms.
-
-## Acknowledgments
-
-VoiceStudio builds on [OmniVoice](https://github.com/k2-fsa/OmniVoice), [WhisperX](https://github.com/m-bain/whisperX), [Demucs](https://github.com/facebookresearch/demucs), [Pyannote](https://github.com/pyannote/pyannote-audio), [CTranslate2](https://github.com/OpenNMT/CTranslate2), [AudioSeal](https://github.com/facebookresearch/audioseal), [Tauri](https://tauri.app), [Supertonic](https://huggingface.co/Supertone/supertonic-3), [Sherpa-ONNX](https://github.com/k2-fsa/sherpa-onnx), [GPT-SoVITS](https://github.com/RVC-Boss/GPT-SoVITS), and [PocketTTS](https://kyutai.org).
-
-
+[AGPL-3.0](LICENSE). Models have their own licenses; review them before commercial use. Clone voices only with permission. See [license details](LICENSE-NOTICE.md).
diff --git a/README_CN.md b/README_CN.md
index 0c998c22..4e4b331d 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -1,697 +1,74 @@
-*本文档是 [README.md](README.md) 的简体中文翻译;若与英文版有出入,以英文版为准。*
-
-

+
VoiceStudio
-
原名 OmniVoice-Studio
-
创造声音,讲述故事,文件始终属于你。♡
-
在一个开源桌面工作室里完成克隆、设计、配音、听写和有声书制作。
默认本地优先。没有订阅,也没有用量计费;联网服务始终由你主动选择。
-
+
你的声音,你的故事,在你的电脑上创作。
+
使用本地 AI 克隆声音、翻译配音、语音听写和制作有声书。
- 快速开始 ·
- 功能 ·
- 为什么选择 VoiceStudio ·
- 引擎 ·
- API ·
- 捐赠 ·
- 参与贡献 ·
+ 下载 ·
+ 开始使用 ·
+ 文档 ·
Discord ·
- English
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ English
-
+
-
-

-
+新 Electron 桌面界面,使用此分支及内置演示声音录制。正式发布版本的界面可能有所不同。
-> **声音很私人,创作空间也应该真正属于你。** VoiceStudio 的核心流程运行在你的硬件上:克隆、设计、配音、听写,并以 646 种语言创作,不需要订阅,也没有用量计费。联网引擎和服务始终是清晰可见的可选项,而不是隐藏依赖。
+## 用 VoiceStudio 创作
-> [!WARNING]
-> **活跃 Beta 阶段。** 各版本之间可能出现故障——如需最新修复,请从源码运行。非常欢迎 Bug 报告和 PR:[提交 Issue](https://github.com/debpalash/VoiceStudio/issues) 或 [加入 Discord](https://discord.gg/bzQavDfVV9)。
+- **声音克隆与设计**:上传参考录音,或用文字描述你想要的声音。
+- **视频配音**:转录、翻译、分配说话人,并编辑语音时间轴。
+- **语音听写**:通过悬浮录音组件录制、转录和复制文字。
+- **长篇创作**:制作多角色脚本、有声书和批量任务。
+- **模型管理**:选择语音合成与转录引擎、语言及计算设备。
-
+本地工作流在你的硬件上运行。远程服务为可选功能;使用情况分析须经同意才会启用。
-## ⚡ 快速开始
+
+
+  |
+  |
+
+ | 声音克隆 | 视频配音 |
+
-
-
-000?style=for-the-badge&logo=apple&logoColor=white)
-
-0078D4?style=for-the-badge&logo=windows&logoColor=white)
-
-FCC624?style=for-the-badge&logo=linux&logoColor=black)
-
-
三个按钮都会打开最新发布页——在资源列表中下载对应你系统的安装包。
-
macOS:首次启动需要一次性批准——右键点击 → 打开(macOS 15 上为 系统设置 → 隐私与安全性 → “仍要打开”)。无需终端。为什么? · Intel Mac:不支持本地后端(#889)——详情。
-
+## 开始使用
-选择你的操作系统,按指南从头到尾操作:
+从 [Releases](https://github.com/debpalash/VoiceStudio/releases/latest) 下载,然后阅读对应平台的安装指南:
-- 🍎 **macOS** — [docs/install/macos.md](docs/install/macos.md)
-- 🪟 **Windows** — [docs/install/windows.md](docs/install/windows.md)
-- 🐧 **Linux** — [docs/install/linux.md](docs/install/linux.md)
-- 🐳 **Docker** — [docs/install/docker.md](docs/install/docker.md) · [Docker Hub: `palashdeb/omnivoice-studio`](https://hub.docker.com/r/palashdeb/omnivoice-studio)
+**[macOS](docs/install/macos.md) · [Windows](docs/install/windows.md) · [Linux](docs/install/linux.md) · [Docker](docs/install/docker.md)**
+
+打开声音克隆页面,选择已有声音或添加清晰的参考录音,输入文字并生成。按提示安装所需模型。硬件要求因引擎而异,详见[性能指南](docs/performance.md)。
+
+**从源码运行 Electron 预览版:**
```bash
-# Docker 快速运行 (CPU / 本地环回模式)
-docker run -d -p 127.0.0.1:3900:3900 -v omnivoice-data:/app/omnivoice_data --name voicestudio palashdeb/omnivoice-studio:stable
+git clone https://github.com/debpalash/VoiceStudio.git
+cd VoiceStudio
+bun install
+cd electron
+bun run dev
```
-**三步克隆出你的第一个声音:**
+环境要求和后端配置见 [Electron 开发指南](electron/README.md)。项目仍在积极开发中,可通过 [GitHub Issues](https://github.com/debpalash/VoiceStudio/issues) 反馈问题。
-1. **安装并启动。** 首次启动会自动搭建 Python 运行环境并下载模型权重——启动画面会逐步显示进度(仅首次,需要几分钟;之后即开即用)。
-2. 从启动台打开**语音克隆**,拖入任意声音的 **3 秒音频**。
-3. **输入一句话,点击生成。** 音频在你的设备上生成并保存,支持 646 种语言(商业使用前请审阅所选模型与分词器的许可条款)。
+## 文档
-### 🎧 音频示例
-
-在线试听 VoiceStudio 本地生成的实际音频样例:
-
-| 工作流 | 提示词 / 参考音频 | 生成音频 |
-|---|---|---|
-| **声音克隆** | [demo_voice.wav](backend/assets/samples/demo_voice.wav) | [demo_clone_output.wav](backend/assets/samples/demo_clone_output.wav) |
-| **声音设计** (美语新闻主播) | *"清晰、权威的美国广播级音色"* | [demo_voice_design_us_news_anchor.wav](backend/assets/samples/voice_design/demo_voice_design_us_news_anchor.wav) |
-| **声音设计** (英式有声书) | *"温暖生动的英式故事讲述音色"* | [demo_voice_design_audiobook_uk_narrator.wav](backend/assets/samples/voice_design/demo_voice_design_audiobook_uk_narrator.wav) |
-| **视频配音** (多语种) | [source.src.wav](backend/assets/samples/demo/dubbing/source.src.wav) | [西班牙语](backend/assets/samples/demo/dubbing/dubbed_es.src.wav) · [法语](backend/assets/samples/demo/dubbing/dubbed_fr.src.wav) · [日语](backend/assets/samples/demo/dubbing/dubbed_ja.src.wav) · [中文](backend/assets/samples/demo/dubbing/dubbed_zh.src.wav) |
-
-觉得慢?[docs/performance.md](docs/performance.md) 讲清了生成时间到底花在哪里、有哪些调优开关,以及“它变慢了”的三个经典原因。各引擎/设备的实测数据见 [docs/benchmarks.md](docs/benchmarks.md)。
-
-> 正在从 **[CorentinJ/Real-Time-Voice-Cloning](https://github.com/CorentinJ/Real-Time-Voice-Cloning)**(现已归档)迁移过来?我们有专门的迁移指南:[docs/migration/real-time-voice-cloning.md](docs/migration/real-time-voice-cloning.md)。
-
-
-🧰 卡住了?自检、Token 与受限网络
-
-
-
-先运行内置自检——在应用中打开 **设置 → 关于 → “运行自检”**,或在源码检出目录中执行
-`uv run python backend/main.py --diagnose`(加 `--deep` 还会实际加载当前引擎进行测试)。然后查看
-[docs/install/troubleshooting.md](docs/install/troubleshooting.md) 中排名前
-10 的安装错误。运行时出错时,应用内的错误界面会直接深链到对应条目;**设置 → 关于 →
-“保存诊断包”** 会把脱敏日志与自检报告打包,方便附在 Bug 报告里。
-
-Hugging Face Token 的配置见
-[docs/setup/huggingface-token.md](docs/setup/huggingface-token.md)。说话人分离相关的模型访问门槛见
-[docs/features/diarization.md](docs/features/diarization.md)。下载速度、⚡ 快速下载(Xet)状态,以及受限网络 / 镜像选项见
-[docs/downloading-models.md](docs/downloading-models.md)。
-
-
-
----
-
-
-
-## ✨ 功能
-
-八大主打功能——折叠区里还有十二项等你展开。
-
-
-
-
- 🎙️ 语音克隆
- 3 秒音频 → 复刻任何声音。 646 种语言,零样本。
- |
-
- 🎨 声音设计
- 性别、年龄、口音、音高、语速、 情感、方言——随心调节。
- |
-
- 🎬 视频配音
- YouTube 链接或文件 → 转录 → 翻译 → 重新配音 → MP4。
- |
-
- 📖 有声书编辑器
- 导入文本、EPUB 或 PDF。自动分章、 响度归一、元数据。导出 .m4b。
- |
-
-
-
- 🎭 故事模式
- 多声音编辑器。逐行分配声音、 预览、导出完整配音阵容。
- |
-
- ⌨️ 听写工具
- 在任何应用中按 ⌘+⇧+Space。 转录、自动粘贴、随即消失。
- |
-
- 🔐 本地优先
- 核心创作流程 留在你的设备上。
- |
-
- 🤖 MCP 服务器
- 从 Claude、Cursor 或 任何 MCP 客户端使用 VoiceStudio。
- |
-
-
-
-
-……还有 12 项——人声分离、说话人分离、批量处理、水印、诊断等等
-
-
-
-- 🔊 **人声分离** — 基于 Demucs:把语音从音乐中分离出来,同时保留背景音床。
-- 👥 **说话人分离** — Pyannote + WhisperX 自动识别谁说了什么。
-- 📦 **批量队列** — 拖入 50 个视频就可以走开;每个任务都有独立进度条。
-- 🛡️ **AI 水印** — AudioSeal(Meta):不可见,且能在压缩后留存。
-- 🔬 **诊断** — 自检套件、错误日志、脱敏诊断包。
-- ⚡ **GPU 自动检测** — CUDA · MPS · ROCm(Linux,需手动开启)· CPU;显存 ≤8 GB 时自动卸载。
-- 🧭 **引擎路由** — 逐引擎 GPU 预检;绝不静默回退到 CPU。
-- 🧩 **可扩展** — 继承 `TTSBackend`,约 50 行代码即可接入任意引擎。
-- 🎒 **便携声音角色** — 将声音导出为 `.ovsvoice` 包:身份 + 水印。
-- ♾️ **无限长 TTS** — 按句分块生成,没有长度上限,可经 WebSocket 流式输出。
-- 🌐 **远程后端** — 让 UI 指向远程服务器;对 Tailscale 友好,支持 Bearer 认证。
-- 🧠 **听写 + LLM** — 用本地 LLM 润色转录文本,可选回声消除。
-
-
-
----
-
-
-
-## 💡 为什么选择 VoiceStudio?
-
-云端语音工具很方便,但工作流会依赖账号、用量计费和他人的基础设施。VoiceStudio 在你的硬件上提供完整工作室;只有你主动选择时,才会使用联网集成。
-
-| | **ElevenLabs** | **VoiceStudio** |
-|---|---|---|
-| **价格** | 订阅与用量限制 | 免费且开源(AGPL-3.0)· 专有用途可选 [商业许可证](#license) |
-| **语音克隆** | ✅ 3 秒音频 | ✅ 3 秒音频,零样本 |
-| **声音设计** | ✅ 性别、年龄 | ✅ 性别、年龄、口音、音高、风格、方言 |
-| **有声书 / 故事** | ❌ | ✅ 完整有声书编辑器 + 多声音故事(EPUB/PDF 导入,.m4b 导出) |
-| **语言** | 取决于套餐和模型 | **646** |
-| **视频配音** | ✅ 仅云端 | ✅ 完全本地 |
-| **数据隐私** | 音频在远端处理 | 核心流程在本地运行;联网服务必须主动选择 |
-| **API 密钥** | 需要账号 | 本地流程不需要 |
-| **GPU 支持** | 不适用(云端) | CUDA · Apple Silicon · ROCm(Linux)· CPU |
-| **桌面应用** | ❌ | ✅ macOS · Windows · Linux |
-| **TTS 引擎** | 1 | **16** — [完整矩阵](#tts-engines) |
-| **ASR 引擎** | 1 | **11** — [完整阵容](#asr-engines) |
-| **MCP 服务器** | ❌ | ✅ 可从 Claude、Cursor 及任何 MCP 客户端使用 |
-| **自检** | ❌ | ✅ 诊断套件、错误日志、脱敏调试包 |
-| **可定制** | ❌ 闭源 | ✅ 随你 Fork、扩展、发布 |
-
-专业级语音 AI,去掉订阅,也去掉云端。
-
-
-
-
心动了?来和我们一起构建吧。
-

-
-
-
----
-
-## 🖥️ 系统要求
-
-| | **最低配置** | **推荐配置** |
-|---|---|---|
-| **操作系统** | Windows 10、macOS 12+(Apple Silicon)、Ubuntu 24.04+(glibc 2.39+) | 任意现代 64 位操作系统 |
-| **内存** | 8 GB | 16 GB+ |
-| **显存(GPU)** | 4 GB(自动将 TTS 卸载到 CPU) | 8 GB+(NVIDIA RTX 3060+) |
-| **硬盘** | 10 GB 可用空间(模型 + 缓存) | 20 GB+ SSD |
-| **Python** | 3.10+(由 `uv` 管理) | 3.11–3.12 |
-| **GPU** | 可选——CPU 也能跑 | NVIDIA CUDA · Apple Silicon MPS · AMD ROCm(仅 Linux) |
-
-> [!TIP]
-> 对于显存 **≤8 GB** 的 GPU,VoiceStudio 会在转录期间自动将 TTS 卸载到 CPU——无需配置。不需要专用 GPU;整条流水线都可以在 CPU 上运行(只是慢一些)。
-
-> [!NOTE]
-> **AMD GPU:** ROCm 加速**仅限 Linux 且需手动开启**——在首次运行的设置界面选择 **“AMD GPU (ROCm)”**,或设置 `OMNIVOICE_TORCH_VARIANT=rocm`([docs/install/linux.md](docs/install/linux.md#amd-gpu-rocm))。在 **Docker/Podman** 中请改用专门的 ROCm 镜像:`ghcr.io/debpalash/omnivoice-studio:rocm`([docs/install/docker.md](docs/install/docker.md#pull-and-run-amd-gpu--rocm))。**在 Windows 上,AMD GPU(含 Ryzen AI 核显)只能以 CPU 运行**:PyTorch 没有 Windows 版 ROCm 轮子,因此 Windows 上的 GPU 加速仅限 NVIDIA/CUDA([docs/install/windows.md](docs/install/windows.md#gpu-support))。
-
-> [!IMPORTANT]
-> **macOS Intel(x86_64)不支持本地后端:** 应用 UI 可以安装,但 Python 后端无法运行,因为 PyTorch 已不再发布 Intel Mac 轮子([#889](https://github.com/debpalash/VoiceStudio/issues/889))。Intel Mac 用户仍可让 UI 指向另一台机器上的远程后端——参见 [docs/install/macos.md](docs/install/macos.md)。
-
-
-
-### 💡 按硬件推荐引擎配置
-
-| 硬件配置 | 推荐 TTS 引擎 | 推荐 ASR 语音识别 | 优势 |
-|---|---|---|---|
-| **Apple Silicon (M1–M4)** | [MLX-Audio](docs/engines/mlx-audio.md) · [OmniVoice](docs/engines/omnivoice.md) (MPS) | [MLX Whisper](docs/engines/mlx-whisper.md) · [Parakeet MLX](docs/engines/parakeet-mlx.md) | 原生统一内存,macOS 上延迟最低、性能最强 |
-| **NVIDIA 显卡 (8 GB+ 显存)** | [OmniVoice](docs/engines/omnivoice.md) · [CosyVoice 3](docs/engines/cosyvoice.md) | [WhisperX](docs/engines/whisperx.md) | 极致零样本克隆品质、字级时间戳对齐与说话人分离 |
-| **低显存 / 仅 CPU 设备** | [PocketTTS](docs/engines/pockettts.md) · [Sherpa-ONNX](docs/engines/sherpa-onnx.md) · [KittenTTS](docs/engines/kittentts.md) | [Moonshine](docs/engines/moonshine.md) · [Faster-Whisper](docs/engines/faster-whisper.md) (`int8`) | 超低内存占用,针对 CPU 指令集深度优化 |
-
-
-
-### 🗣️ TTS 引擎
-
-**16 个引擎,一个选择器。** VoiceStudio(默认,支持 600+ 语言)始终可用;另有七个引擎可选装并自动检测(CosyVoice 3、GPT-SoVITS、VoxCPM2、MOSS-TTS-Nano、KittenTTS、MLX-Audio、Sherpa-ONNX),外加八个按需延迟安装的引擎(IndexTTS 2.5、OmniVoice GGUF、OmniVoice 子进程版、PocketTTS、Supertonic 3、MOSS-TTS-v1.5、dots.tts、Confucius4-TTS)。在 **设置 → TTS 引擎** 中切换;所选引擎将应用于所有语音合成场景。**每个引擎都有独立指南:[docs/engines](docs/engines/README.md)(英文)。**
-
-
-📊 完整矩阵——16 个引擎 × 平台 × 克隆/指令 × 许可证
-
-
-
-| 引擎 | 语言 | 克隆 | 指令 | Linux | macOS ARM | Windows | 许可证 |
-|--------|:---------:|:-----:|:--------:|:-----:|:---------:|:-------:|:-------:|
-| **VoiceStudio**(默认,由 k2-fsa/OmniVoice 驱动) | 600+ | ✅ | ✅ | ✅ CUDA/CPU | ✅ MPS | ✅ CUDA/CPU | 内置 |
-| **CosyVoice 3** | 9 + 18 种方言 | ✅ | ✅ | ✅ CUDA/CPU | ✅ MPS | ✅ CUDA/CPU | Apache-2.0 |
-| **GPT-SoVITS** | 5 | ✅ | — | ✅ CUDA/CPU | — | ✅ CUDA/CPU | MIT |
-| **VoxCPM2** | 30 | ✅ | ✅ | ✅ CUDA/CPU | ✅ MPS | ✅ CUDA/CPU | Apache-2.0 |
-| **MOSS-TTS-Nano** | 20 | ✅ | — | ✅ CUDA/CPU | ✅ CPU | ✅ CUDA/CPU | Apache-2.0 |
-| **KittenTTS** | 英语 | — | — | ✅ CPU | ✅ CPU | ✅ CPU | MIT |
-| **MLX-Audio**(Kokoro、Qwen3-TTS、CSM、Dia 等) | 多语言 | 因模型而异 | 因模型而异 | ❌ | ✅ 原生 | ❌ | 因模型而异 |
-| **Sherpa-ONNX** | 20+ | — | — | ✅ CUDA/CPU | ✅ CPU | ✅ CUDA/CPU | Apache-2.0 |
-| **IndexTTS 2.5** ⚡ | 中文 · 英语 · 日语 · 西班牙语 · 阿拉伯语 | ✅ | — | ✅ CUDA | — | ✅ CUDA | Bilibili 模型许可¹ |
-| **OmniVoice GGUF** ⚡ | 600+ | ✅ | ✅ | ✅ CPU | ✅ CPU | ✅ CPU | 内置 |
-| **Supertonic 3** ⚡ | 31 | — | — | ✅ CPU | ✅ CPU | ✅ CPU | OpenRAIL-M |
-| **MOSS-TTS-v1.5** ⚡(8B) | 31 | ✅ | — | ✅ CUDA/CPU | ✅ CPU | ✅ CUDA/CPU | Apache-2.0 |
-| **dots.tts** ⚡(2B) | 24 | ✅ | — | ✅ CUDA/CPU | ✅ CPU | ❌ | Apache-2.0 |
-| **Confucius4-TTS** ⚡ | 14 | ✅ | — | ✅ CUDA/CPU | ✅ CPU | ✅ CUDA/CPU | Apache-2.0 |
-
-¹ 若月活跃用户超过 1 亿,或年收入超过人民币 10 亿元,使用 IndexTTS 2.5
-前必须另行取得 Bilibili 的书面许可。启用可选边车前,请审阅其
-[模型许可](https://huggingface.co/IndexTeam/IndexTTS-2.5/blob/main/LICENSE)。
-
-> **CUDA** = GPU 加速 · **MPS** = Apple Silicon Metal · **CPU** = 随处可运行,大模型较慢 · KittenTTS 和 MOSS-TTS-Nano 可在 CPU 上实时运行 · MLX-Audio 仅限 Apple Silicon · ⚡ = 延迟注册(首次使用时安装)
->
-> **克隆**能力的意义不止于单段生成:视频配音(以及任何固定了声音的批量任务)需要参考音频克隆来保持说话人身份,因此把不支持克隆的引擎(KittenTTS、Sherpa-ONNX、Supertonic 3)设为当前引擎时,这些任务会在开始前就给出可操作的失败提示,而不是静默回退到 VoiceStudio。
->
-> **MOSS-TTS-v1.5**(8B,约 16 GB)、**dots.tts**(2B,约 9 GB)和 **Confucius4-TTS** 是重量级可选引擎,从本地克隆在各自独立的 venv 中运行。三者均不支持 Apple Silicon MPS(在 Mac 上以 CPU 运行);dots.tts 没有 Windows 路径;Confucius4 建议使用 CUDA(CPU 可用,约为实时时长的 17 倍)。详情:[MOSS-TTS-v1.5](docs/engines/moss-tts-v15.md) · [dots.tts](docs/engines/dots-tts.md) · [Confucius4-TTS](docs/engines/confucius4-tts.md)。
-
-
-
-
-
-### 🎧 ASR 引擎
-
-**11 个引擎**——它们驱动听写、视频配音和字幕。**WhisperX** 是跨平台的默认引擎(约 100 种语言,词级时间对齐);其余引擎均为可选装并自动检测。在 **设置 → 引擎** 中切换。十个完全在本地设备上运行;第十一个(OpenAI 兼容)是可选的远程客户端,可用于 Qwen3-ASR 或任何兼容的服务器。
-
-
-📊 完整阵容——11 个引擎、各自的强项与计算类型说明
-
-
-
-| 引擎 | `OMNIVOICE_ASR_BACKEND` | 语言 | 最适合 |
-|--------|-------------------------|:---------:|----------|
-| **WhisperX**(默认) | `whisperx` | ~100 | 配音与字幕——通过 wav2vec2 强制对齐实现词级时间对齐 |
-| **Faster-Whisper** | `faster-whisper` | ~100 | Linux / macOS / Windows 上的快速转录(CTranslate2) |
-| **Faster-Whisper(隔离)** | `faster-whisper-isolated` | ~100 | 与 Faster-Whisper 相同,但在子进程中崩溃隔离——ASR 崩溃不会拖垮整个应用 |
-| **MLX Whisper** | `mlx-whisper` | ~100 | Apple Silicon 原生速度(Apple MLX / Metal) |
-| **PyTorch Whisper** | `pytorch-whisper` | ~100 | 经 🤗 Transformers 的 CUDA / CPU 兜底方案(无需 cuDNN 8) |
-| **Parakeet TDT** | `nemo-parakeet` | 英语 + 25 种欧洲语言 | 即使在 CPU 上也能以约 10 倍实时速度达到 SOTA 精度,自动语言检测(NVIDIA NeMo,CUDA/CPU) |
-| **Moonshine** | `moonshine` | 英语 | 边缘设备 / 低延迟,ONNX |
-| **FunASR** | `funasr` | 50+ | 多语言一体化——内置 VAD + 行内说话人分离(SenseVoice) |
-| **sherpa-onnx**(实时听写) | `sherpa-onnx-asr` | 25 种欧洲语言 + 90+ | 实时、快于实时的听写——小体积流式/离线 ONNX 模型(Parakeet TDT v3/v2、流式 Zipformer 与 Paraformer、Whisper Tiny),CPU 运行,macOS / Windows / Linux 表现完全一致。在 **设置 → 语音** 中按模型选择。 |
-| **OpenAI 兼容** ⚠️ 远程 | `openai-compat-asr` | 取决于服务器 | 当下通往 **Qwen3-ASR** 的路径(自托管服务器,无需等 transformers 支持)、任何 OpenAI 兼容的转录端点,或 OpenAI 官方 API——无需安装,在 **设置 → 引擎**(ASR 标签页)中配置并测试连接。音频会离开你的设备,发送到你指定的任何服务器;参见 [docs/engines/openai-compatible-asr.md](docs/engines/openai-compatible-asr.md)。 |
-
-> Whisper 系列引擎覆盖约 100 种语言;**FunASR / SenseVoice** 额外提供一条多语言一体化路径,内置语音活动检测与行内说话人分离。**sherpa-onnx** 驱动实时听写的模型选择器——你边说,文字边出现。除可选的 OpenAI 兼容远程客户端外,所有引擎都在本地设备上运行——无需 API 密钥,无需云端。
-
-> **GPU 不支持高效 float16?** 在较老的 NVIDIA GPU(Maxwell/Pascal、GTX 16xx)上,或在 CTranslate2/cuDNN 版本不匹配之后,CTranslate2 系 ASR 引擎(WhisperX、Faster-Whisper)无法运行 `float16`,VoiceStudio 会自动改用 `int8` 重试——无需配置。如果转录仍然失败,可用 `ASR_COMPUTE_TYPE` 环境变量固定计算类型(逃生舱口):`ASR_COMPUTE_TYPE=int8`(CPU 用 `float32`)。将其设为 `int8` 并重启后端。
-
-
-
----
-
-## 🏗️ 架构
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ Frontend (React) │
-│ DubTab · VoiceConsole · Stories · Audiobook · Gallery │
-│ Dictation · BatchQueue · Diagnostics · MCP Client │
-├─────────────────────────────────────────────────────────────┤
-│ Backend (FastAPI) │
-│ 100+ API endpoints · SSE+WSS streaming · SQLite │
-├──────────┬──────────┬──────────┬──────────┬────────────────┤
-│ WhisperX │ Demucs │VoiceStudio │ Pyannote │ Engine Routing │
-│ (+7 ASR │ Source │ (+10 │ Diariz- │ ↳ GPU preflight │
-│ engines) │ Sep. │ TTS) │ ation │ ↳ No silent CPU │
-└──────────┴──────────┴──────────┴──────────┴────────────────┘
- CUDA / MPS / ROCm / CPU (auto-detected + routed)
-```
-
-
-
-## 🔌 OpenAI 兼容 API
-
-已经有会说 OpenAI 音频 API 的脚本、智能体或工具?把它指向 `http://localhost:3900/v1` 即可——不需要密钥,也不用改代码。后端为音频端点内置了即插即用的兼容接口,直接接到你当前启用的 TTS/ASR 引擎(没错,`voice` 参数接受你克隆的声音配置 ID)。
-
-| 端点 | 作用 |
+| 需求 | 链接 |
|---|---|
-| `POST /v1/audio/speech` | TTS——输入文本;输出 `mp3` / `wav` / `flac` / `opus` / `pcm`。`tts-1` / `tts-1-hd` 映射到你当前启用的引擎;也接受 OpenAI 的声音名称(`alloy` 等)。 |
-| `POST /v1/audio/transcriptions` | STT——输入音频文件;输出 `json`、`text`、`verbose_json`、`srt` 或 `vtt`。`whisper-1` 映射到你当前启用的 ASR 引擎。 |
-| `GET /v1/audio/voices` | VoiceStudio 扩展——列出所有声音配置和引擎,客户端可据此发现你的克隆声音。 |
+| 安装帮助 | [故障排查](docs/install/troubleshooting.md) · [模型下载](docs/downloading-models.md) |
+| 模型与音质 | [引擎指南](docs/engines/README.md) · [基准测试](docs/benchmarks.md) |
+| 集成 | [本地 API](docs/speech-platform.md) · [MCP](docs/mcp.md) · [示例](examples/README.md) |
+| 参与开发 | [贡献指南](.github/CONTRIBUTING.md) · [Electron](electron/README.md) · [更新日志](CHANGELOG.md) |
-```sh
-curl http://localhost:3900/v1/audio/speech \
- -H "Content-Type: application/json" \
- -d '{"model": "tts-1", "voice": "alloy", "input": "Generated on my own hardware.", "response_format": "wav"}' \
- --output speech.wav
-```
+安装智能体技能:`npx skills add debpalash/VoiceStudio`
-```python
-from openai import OpenAI
-client = OpenAI(base_url="http://localhost:3900/v1", api_key="none") # any string works — nothing checks it
+## 支持 VoiceStudio
-result = client.audio.transcriptions.create(model="whisper-1", file=open("clip.wav", "rb"))
-print(result.text)
-```
+[Ko-fi](https://ko-fi.com/debpalash) · [PayPal](https://paypal.me/palashCoder) · [赞助项目](SPONSORS.md) · [商务合作](mailto:partner@voicestudio.sh)
-想要完整的接口(100+ 端点)?完整的 REST API 参考已内嵌在应用中——**设置 → OpenAPI 参考**(由 Scalar 驱动),或点击页脚的 `{}` 按钮。
+## 许可与负责任使用
-### 📓 在 Google Colab 上运行
-
-[](https://colab.research.google.com/github/debpalash/VoiceStudio/blob/main/notebooks/OmniVoice_Studio_Colab.ipynb)
-
-没有本地 GPU?官方笔记本([notebooks/OmniVoice_Studio_Colab.ipynb](notebooks/OmniVoice_Studio_Colab.ipynb))可在免费的 Colab T4 上启动完整应用(包含 Web 界面):在笔记本内直接构建前端,用 uv 安装后端(复用 Colab 预装的 CUDA PyTorch),并通过 Colab 内置端口代理打开界面。无需第三方隧道,也无需任何 API 密钥。随后还有一套覆盖全部主要功能的 API 导览,全部可在笔记本内直接播放:多语言 TTS、声音克隆与声音设计、已保存的声音档案、语音转写、AI 水印检测、OpenAI 兼容 API、多角色故事、带章节的 m4b 有声书,以及一个附带人声分离音轨的迷你视频配音。
-
-### 🤝 智能体技能(Agent Skills)
-
-用一条命令教会你的 AI 智能体(Claude Code、Cursor、Codex 等)使用 VoiceStudio:
-
-```sh
-npx skills add debpalash/omnivoice-studio
-```
-
-内含两个 [skills](https://skills.sh):**`omnivoice`**——让任何智能体通过你的本地安装进行语音合成与转录(包括你克隆的声音),免费且离线;以及 **`oss-maintainer`**——本项目所遵循的维护者方法论,适合任何用智能体运营自己开源项目的人。
-
-### 🔌 模型上下文协议(MCP 服务器)
-
-VoiceStudio 在 `http://localhost:3900/mcp` 挂载了 MCP 服务,可供 Claude Desktop、Cursor 与自主智能体调用:
-
-```json
-{
- "mcpServers": {
- "voicestudio": {
- "url": "http://localhost:3900/mcp"
- }
- }
-}
-```
-
-对于需要 stdio 管道传输的客户端,请使用内置的本地桥接脚本(`docs/mcp.json`):
-
-```json
-{
- "mcpServers": {
- "voicestudio": {
- "command": "python",
- "args": ["-m", "backend.mcp_shim"],
- "cwd": "/path/to/VoiceStudio"
- }
- }
-}
-```
-
-支持 `generate_speech`、`clone_voice`、`transcribe` 等工具与流式文件输出模式,详见 [docs/mcp.md](docs/mcp.md)。
-
----
-
-## 🗺️ 路线图
-
-### 🔜 即将推出
-
-- 🎬 **唇形同步 v2** — 使用 wav2lip 进行视觉语音时间对齐
-- 🌐 **在线演示** — 无需安装即可体验 VoiceStudio
-- 🔌 **插件市场** — 社区贡献的 TTS 引擎与特效
-- 🎵 **实时变声器** — 通话中的麦克风实时变声
-
-
-✅ 已经发布的一切——按类别列出的“成绩单”
-
-
-
-| 分类 | 功能 |
-|----------|----------|
-| **长内容** | 有声书编辑器(文本/EPUB/PDF → 分章 .m4b)、Stories 多声音编辑器、两遍响度归一母带处理、渲染中断后的崩溃续渲、发音控制 + SSML-lite 韵律 |
-| **配音** | 完整流水线(转录→翻译→合成→封装)、场景感知分割、唇形同步评分、流式 TTS、逐说话人声音分配、Smart Fit 时长匹配 + 二次 QC、独立的配音主页 |
-| **声音** | 零样本克隆、声音设计、A/B 对比、声音预览控件、支持收藏/标签的声音库、便携声音角色包(`.ovsvoice`)、声音控制台工作区 |
-| **音频** | Demucs 人声分离、逐段增益、选择性音轨导出、分轨/SRT/VTT/MP3 导出、按句分块实现的无限长 TTS |
-| **多语言** | 多语言批量选择器、顺序 GPU 执行的批量配音队列 |
-| **说话人分离** | Pyannote 机器学习分离、自动说话人克隆提取、逐说话人声音分配 |
-| **ASR** | 9 个引擎(WhisperX、Faster-Whisper、隔离版 Faster-Whisper、MLX Whisper、PyTorch Whisper、Parakeet TDT、Moonshine、FunASR/SenseVoice、sherpa-onnx 实时听写)、崩溃隔离的子进程后端 |
-| **TTS** | 14 个引擎(VoiceStudio、CosyVoice 3、GPT-SoVITS、VoxCPM2、MOSS-TTS-Nano、KittenTTS、MLX-Audio、Sherpa-ONNX,+ 延迟安装:IndexTTS 2.5、OmniVoice GGUF、Supertonic 3、MOSS-TTS-v1.5、dots.tts、Confucius4-TTS)、带 GPU 预检的引擎路由 |
-| **基础设施** | Docker 部署、CUDA/MPS/ROCm 自动检测、cuDNN 8 兼容、显存感知模型卸载、引擎路由(绝不静默回退 CPU)、诊断套件与错误日志、受限网络镜像支持 |
-| **AI 溯源** | AudioSeal 不可见水印(类似 SynthID)、视频徽标叠加、水印检测 API |
-| **用户体验** | 撤销/重做、键盘快捷键、拖放、会话持久化、首次启动按屏幕推荐界面缩放,以及原生 WebKitGTK 缩放 |
-| **实时事件** | WebSocket 事件总线——数据变更时即时刷新侧边栏、指数退避重连 |
-| **状态管理** | Zustand 状态迁移——`uiSlice`、`pillSlice`、`dubSlice`、`generateSlice`、`prefsSlice`、`glossarySlice` |
-| **桌面** | 跨平台 Tauri 安装程序(macOS DMG——Apple Silicon;Intel 不支持本地后端,#889——Windows MSI、Linux deb/AppImage)、自动更新基础设施、单实例约束、关闭最小化到托盘、macOS Gatekeeper 修复 |
-| **听写** | 全局系统级热键(`⌘+⇧+Space`)、无边框浮动控件、WebSocket 流式 ASR、自动粘贴、可自定义热键、本地 LLM 转录润色 |
-| **批量流水线** | 完整批量 TTS:提取 → 转录 → 翻译 → 生成 → 混音 → 导出,带实时进度追踪 |
-| **MCP 服务器** | 让 VoiceStudio 成为 Claude、Cursor 及任何 MCP 客户端的本地 TTS/STT 提供方 |
-| **远程后端** | 让桌面 UI 指向远程后端 URL,支持 Bearer 认证(附 Tailscale 文档) |
-| **可靠性** | 启动开屏的卡死看门狗、逐引擎 GPU 兼容矩阵、引擎二进制不可执行时的可操作报错、setuptools 自动修复 |
-
-
-
----
-
-
-
-## 💜 赞助 / 捐赠
-
-VoiceStudio 由一位开发者使用 Claude Code 和 AI 智能体独立打造——而智能体账单是实打实的(过去三个月花了数千美元)。如果 VoiceStudio 为你创造了价值,帮忙分担一小部分账单,就能让开发保持全职推进。
-
-
-
-**本月智能体账单基金**
-
-

-
-
-
-

-
-

-
-
-
每一美元都直接用于支付智能体账单——让 VoiceStudio 的开发持续不断。
-
-
-
-
来自 VoiceStudio 作者的更多应用——同样的本地优先理念:
-Opal 💠(播放一切——AI 时代的媒体播放器)·
-memxt 🧠(Claude Code 与编码智能体的本地记忆)。
-给它们点个 ⭐ 也是一种支持 → 详见下文。
-
-
-
-
-
-### 🌟 赞助商
-
-VoiceStudio **免费**且采用 **AGPL-3.0** 许可——没有付费版,没有 SaaS 收入。赞助商让开发得以持续,作为回报,可以在这里、在应用内(顶级档位还包括项目官网)获得一个徽标位。这是一份感谢,绝不是付费墙。**[查看档位并成为赞助商 →](SPONSORS.md)**
-
-
-
-
-
-**这里可以是你的徽标** — [成为赞助商](SPONSORS.md)
-
-
-
-
-
-💡 GitHub 也会在本仓库顶部显示一个 **Sponsor** 按钮,经由 .github/FUNDING.yml 指向相同的链接。
-
----
-
-## 💬 社区
-
-
-

-
-
设置类问题我们几小时内就会回复,而不是几天。
-
-
-
-里面都在聊什么
-
-
-
-| 频道 | 那里发生什么 |
-|---------|--------------------|
-| `#announcements` | 发布消息与重大时刻——新版本最先在这里公布 |
-| `#releases` + `#changelog` | 每一个构建,以及里面究竟有什么 |
-| `#issues` | 以论坛帖子形式提交的 Bug 报告——直接分诊进 GitHub Issues |
-| `#ideas` | 功能请求,供讨论与投票 |
-| `#discuss-ideas` | 动手之前的设计讨论 |
-| `#general` | 安装帮助、GPU 疑难排查,以及晒你的配音成果 |
-
-
-
----
-
-
-
-## 🤝 参与贡献
-
-非常欢迎——Bug 修复、新的 TTS 引擎适配器、UI 改进、文档、翻译。统统欢迎。
-
-- 📖 阅读 **[贡献指南](.github/CONTRIBUTING.md)** 了解环境搭建、代码风格和 PR 工作流
-- 🐛 浏览 [good first issues](https://github.com/debpalash/VoiceStudio/labels/good%20first%20issue)
-- 💬 加入我们的 [Discord](https://discord.gg/bzQavDfVV9) 讨论想法或寻求帮助
-
----
-
-## ❓ 常见问题
-
-
-真的能和 ElevenLabs 一样好吗?
-
-诚实的回答:取决于你要做什么。
-
-VoiceStudio 真正有竞争力的地方:从干净的参考音频进行语音克隆(最先进的开源扩散 TTS)、语言覆盖(646 种语言对他们的 32 种),以及所有结构性优势——没有按字符计费、没有用量上限、音频不离开你的设备、完整的流水线可定制性(14 个 TTS 引擎、10 个 ASR 引擎、翻译方案随你选)。
-
-ElevenLabs 仍然领先的地方:开箱即用的稳定性与打磨程度,尤其是英语 TTS。他们的单一模型经过深度调优;我们的质量取决于你选择的引擎、你的硬件,以及(对克隆而言)参考音频——干燥、近麦的音频比嘈杂或有回声的音频克隆效果好得多。
-
-具体到配音:配音是一条链——转录 → 翻译 → 克隆 → 合成——在你的素材上,它只取决于最薄弱的一环。如果部分输出语无伦次,先检查片段表里的原文:当转录本身就错了,换一个 ASR 引擎或使用更干净的源音频——修复点通常在这里,而不是声音。
-
-拿你的真实素材试试——免费,下载一次即可。许多用户直接用它替换了 ElevenLabs;也有人两个都留着。这两种结果我们都乐见。
-
-
-
-能在 Apple Silicon(M1/M2/M3/M4)上运行吗?
-
-可以。MPS 加速会被自动检测。在 Apple 硬件上,MLX 优化的 Whisper 模型可提供更快的转录速度。不支持 Intel Mac:应用 UI 可以安装,但本地 Python 后端无法运行,因为 PyTorch 已不再发布 Intel Mac 轮子(#889)——Intel Mac 只能配合远程后端使用。
-
-
-
-需要多少显存?
-
-最低 4 GB。 显存 ≤8 GB 时,TTS 模型会在转录期间自动卸载到 CPU。8 GB 以上时,所有组件同时在 GPU 上运行。完全没有 GPU?CPU 模式也能用——只是慢一些(TTS 约慢 3 倍)。
-
-
-
-可以用于商业用途吗?
-
-可以——商业使用免费,基于 AGPL-3.0:运行它、出售用它生成的音频、为客户的视频配音、在团队中部署。只有一项义务:如果你修改了 VoiceStudio 并通过网络向他人提供该修改版本,你必须依据相同条款分享修改后的源代码。想把它嵌入闭源产品?可获取商业许可证——参见许可证。
-
-
-
-支持哪些语言?
-
-通过 VoiceStudio 模型的 TTS 支持 646 种语言。转录(WhisperX)支持 99 种语言。翻译覆盖范围取决于目标语言对。
-
-
-
-可以添加自己的 TTS 引擎吗?
-
-可以。在 backend/services/tts_backend.py 中继承 TTSBackend,并将其添加到 _REGISTRY 字典中——约 50 行代码。十四个内置引擎均以此方式实现;参见 TTS 引擎。
-
-
-
-VoiceStudio 会收集我的任何数据吗?
-
-除非你明确同意,否则不会。首次运行时应用会询问你——一个页面、两个同等分量的按钮,没有预先勾选。在你回答“是”之前,VoiceStudio 什么都不发送:没有分析、没有遥测、没有账号、没有“回传”。跳过提问就等于“否”。无论如何,你的文本、音频、声音和项目永远不会离开你的设备。
-
-如果你选择同意(也可随时在 设置 → 隐私 → “帮助改进 VoiceStudio” 中开关),发送的只是匿名、不含内容的使用统计:生成信息(引擎、语言、生成耗时、字符数量、错误类型),以及应用生命周期——一次安装信号、版本更新(版本号之间)、崩溃(错误类别和分桶后的运行时长,绝不含日志)、错误类型(有上限、去重),以及卸载时的一次告别信号。绝不包含你的文本、音频、文件名或任何可识别信息——这由代码中的属性白名单强制保证(backend/core/analytics.py),而不只是一句承诺。源码构建根本没有分析数据的接收端,因此根本不会询问。你自己的统计数字在 设置 → 用量 中查看,本地计算,不发送到任何地方。
-
-
-
-如何卸载它 / 删除它的所有数据?
-
-VoiceStudio 完全本地运行——卸载就是删除应用及其写入的文件夹(模型缓存、Python 环境、你的声音/项目、配置)。运行 scripts/uninstall.sh(macOS/Linux)或 scripts\uninstall.ps1(Windows)——它会先以干跑方式列出每个文件夹及其大小,加 --yes 才会真正删除。完整的各平台路径列表和应用移除步骤见 docs/install/uninstall.md。
-
-
-## 🛡️ 负责任使用与安全
-
-VoiceStudio 在个人硬件上提供零样本语音克隆与语音创作能力。我们提倡负责任的技术使用:
-- **明确授权:** 严禁在未经说话人本人知情并明确授权的情况下克隆其声音。
-- **AI 溯源:** VoiceStudio 默认集成 [AudioSeal](https://github.com/facebookresearch/audioseal) 不可见神经音频水印,在完全不影响听感音质的前提下精准标记合成语音。
-- **本地隐私:** 默认本地工作流下,所有音频、声音档案、项目与转录文本始终保存在你的本地设备上;仅当你主动配置远程工作节点或第三方 ASR 端点时,相应数据才会传输到对应服务。
-
----
-
-
-
-## 📜 许可证
-
-VoiceStudio 是基于 [**GNU Affero 通用公共许可证 v3.0(AGPL-3.0)**](https://www.gnu.org/licenses/agpl-3.0.html) 的自由开源软件。
-
-**可免费用于任何用途——包括商业和企业内部用途。** 运行它、出售用它生成的音频、为自己或客户的视频配音、在团队中推广——全部免费,无需许可证。作为一份**网络著佐权(copyleft)**许可证,AGPL 增加了一项义务:如果你**修改**了 VoiceStudio 并通过网络向他人提供该修改版本,你必须依据相同的 AGPL-3.0 条款向他们提供该修改版本的完整对应源代码。
-
-希望将 VoiceStudio 嵌入**闭源或专有**产品或服务、又不受 AGPL-3.0 著佐权义务约束的组织,可获取**商业许可证**。**定价方案即将推出。** 咨询:**VoiceStudio@palash.dev**。
-
-捆绑的 `omnivoice/` TTS 模型(作者 Han Zhu)在上游仍为 Apache-2.0 许可。完整且具约束力的条款请参见 [`LICENSE`](LICENSE)。
-
----
-
-## 🙏 致谢
-
-VoiceStudio 站在这些杰出开源工作的肩膀上:
-
-| 项目 | 作用 |
-|---------|------|
-| [**VoiceStudio (k2-fsa)**](https://github.com/k2-fsa/OmniVoice) | 零样本扩散 TTS 引擎——核心语音合成模型 |
-| [**WhisperX**](https://github.com/m-bain/whisperX) | 词级别语音识别与时间对齐 |
-| [**Demucs (Meta)**](https://github.com/facebookresearch/demucs) | 音乐源分离,用于人声分离 |
-| [**Pyannote**](https://github.com/pyannote/pyannote-audio) | 说话人分离——谁说了什么 |
-| [**CTranslate2**](https://github.com/OpenNMT/CTranslate2) | CPU 和 GPU 上的优化 Transformer 推理 |
-| [**AudioSeal (Meta)**](https://github.com/facebookresearch/audioseal) | 用于 AI 溯源的不可见神经音频水印 |
-| [**Tauri**](https://tauri.app) | 原生桌面应用框架 |
-| [**Supertone / Supertonic 3**](https://huggingface.co/Supertone/supertonic-3) | ONNX TTS 引擎——31 种语言,CPU 高效 |
-| [**Sherpa-ONNX**](https://github.com/k2-fsa/sherpa-onnx) | 支持 WASM 的通用 TTS/ASR 运行时 |
-| [**GPT-SoVITS**](https://github.com/RVC-Boss/GPT-SoVITS) | 零样本 TTS 引擎——5 种语言,RTF 0.014 |
-
----
-
-
-
-## 🧰 来自同一作者的更多本地开源项目
-
-喜欢这种本地优先的理念?它是一脉相承的——同一位作者,同一条准则:**你的数据只留在你的设备上。** 全部项目见 [palash.dev](https://palash.dev)。
-
-
-
-
-
-
-
- 播放一切。AI 时代的媒体播放器。
- 视频、动漫、漫画、种子、Jellyfin 和 Plex——一个播放器全部搞定,并内置本地 AI 记忆与上下文。使用 Zig 编写,支持 macOS 和 Windows。
-
-
-
-
- |
-
-
-
-
- 经基准测试验证的最快开源 AI 记忆系统。
- 为 Claude Code 和编码智能体提供本地长期记忆——基于 SQLite + 嵌入向量的 MCP 服务器,100% 在你的设备上运行。你的智能体终于能记住昨天了。
-
-
-
-
- |
-
-
-
----
-
-
-
-
-
-如果你读到了这里,你就是我们的同路人。
-**[⭐ 给这个仓库点个 Star](https://github.com/debpalash/VoiceStudio)**,让更多人能找到它。
-**[💬 加入 Discord](https://discord.gg/bzQavDfVV9)**,分享你的作品。
-**[❤️ 支持开发](https://ko-fi.com/debpalash)**——资助让 VoiceStudio 持续发布的 AI 智能体账单。
-
-
-
-
-
-
-
-
-
-
-
+应用采用 [AGPL-3.0](LICENSE) 许可。模型遵循各自的许可,商用前请确认其条款。克隆声音前须取得本人许可。详见[许可说明](LICENSE-NOTICE.md)。
diff --git a/docs/integration-directory.md b/docs/integration-directory.md
new file mode 100644
index 00000000..00b4f851
--- /dev/null
+++ b/docs/integration-directory.md
@@ -0,0 +1,20 @@
+# Integration directory
+
+Directory entries are illustrative, not paid sponsors, endorsements, or verified VoiceStudio integrations. Icons are bundled locally so viewing the catalog sends no logo requests to providers. Brand marks belong to their respective owners.
+
+| Company | Official source | Icon source |
+|---|---|---|
+| Twilio | [Website](https://www.twilio.com) | Bundled site icon |
+| Plivo | [Website](https://www.plivo.com) | Bundled site icon |
+| Telnyx | [Website](https://telnyx.com) | Bundled site icon |
+| n8n | [Website](https://n8n.io) | Bundled site icon |
+| Zapier | [Website](https://zapier.com) | Bundled site icon |
+| Make | [Website](https://www.make.com) | Bundled generic mark |
+| GitHub | [Website](https://github.com) | Bundled site icon |
+| GitHub Container Registry | [Website](https://ghcr.io) | Bundled GitHub icon |
+| Docker | [Website](https://www.docker.com) | Bundled site icon |
+| Model Context Protocol | [Website](https://modelcontextprotocol.io) | Bundled site icon |
+| OpenAI Agents | [Guide](https://platform.openai.com/docs/guides/agents) | Bundled local mark |
+| Claude Code | [Guide](https://docs.anthropic.com/en/docs/claude-code) | Bundled site icon |
+| Codex CLI | [Repository](https://github.com/openai/codex) | Bundled local mark |
+| VoiceStudio API | [Repository](https://github.com/debpalash/VoiceStudio) | Bundled local mark |
diff --git a/docs/media/electron/README.md b/docs/media/electron/README.md
new file mode 100644
index 00000000..c7e402d4
--- /dev/null
+++ b/docs/media/electron/README.md
@@ -0,0 +1,19 @@
+# README media
+
+Captured from the Electron renderer on Linux, September 16, 2026. These images show the development branch, not a claim about a published release. The browser capture runs the same renderer as Electron; native window decorations are excluded.
+
+Only the bundled demo voice appears. Personal profiles, history, and projects are filtered from the capture context, and API mutations are blocked. The normal app and its local storage are left alone.
+
+With the Electron development server running:
+
+```bash
+CHROMIUM_PATH=/usr/bin/chromium node scripts/capture-readme-electron.mjs
+```
+
+The script writes PNG screenshots here and prints the temporary WebM path. Convert that recording to the main GIF (replace `recording.webm` with that path):
+
+```bash
+ffmpeg -y -ss 1 -i recording.webm -vf 'fps=8,scale=1120:-1:flags=lanczos,split[s0][s1];[s0]palettegen=stats_mode=diff[p];[s1][p]paletteuse=dither=bayer:bayer_scale=3' -loop 0 docs/media/electron/voicestudio.gif
+```
+
+The README uses the GIF plus the cloning and dubbing screenshots. Design and model screenshots are captured as companion stills. The official logo and repository badges retain their existing assets.
diff --git a/docs/media/electron/dubbing.png b/docs/media/electron/dubbing.png
new file mode 100644
index 0000000000000000000000000000000000000000..d1745a342de02078c882c5f8810033e8051c5972
GIT binary patch
literal 161926
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
vu2a{p
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