Merge branch 'codex/review-1861' into codex/pr-queue-integration
# Conflicts: # CHANGELOG.md
This commit is contained in:
@@ -16,6 +16,7 @@ the frozen-backend fallback mirror it for their toolchains.
|
||||
- Tilde-separated number ranges are spoken clearly without running their endpoints together (#1821) — thanks @flutterkage2k!
|
||||
- Voice modes use themed tabs, with Synthesize and Convert pinned below their scrolling forms (#1823)
|
||||
- Voice cloning now starts with a clear upload-or-record choice, reveals recording and reference details only when needed, and keeps sampling controls under Production Overrides (#1817)
|
||||
- The first-run welcome line uses an instruction accepted by OmniVoice and VoiceDesign engines (#1861) — thanks @psiberfunk!
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -67,6 +68,8 @@ the frozen-backend fallback mirror it for their toolchains.
|
||||
- The notification count stays inside the title bar instead of clipping above the bell (#1823)
|
||||
- The workspace engine menu opens beside its button instead of at the opposite edge of the page (#1823)
|
||||
- Cloning reuses the dubbing language picker with flags, search, and single selection, opening above the pinned synthesis controls (#1823)
|
||||
- The first-run welcome line uses an instruction accepted by OmniVoice and VoiceDesign engines (#1861) — thanks @psiberfunk!
|
||||
|
||||
|
||||
## [0.5.2] — 2026-09-02
|
||||
|
||||
|
||||
+5
-10
@@ -1,3 +1,4 @@
|
||||
import { firstSoundRequest } from './utils/firstSound';
|
||||
import React, {
|
||||
useState,
|
||||
useRef,
|
||||
@@ -699,16 +700,10 @@ function App() {
|
||||
if (!pending) return;
|
||||
(async () => {
|
||||
try {
|
||||
const fd = new FormData();
|
||||
fd.append('text', i18n.t('firstrun.first_sound_text'));
|
||||
// Functional model prompt (not user-facing copy) — keeps the demo
|
||||
// voice warm without depending on seeded profiles.
|
||||
fd.append('instruct', 'A warm, friendly narrator voice, medium pace');
|
||||
fd.append('num_step', '16');
|
||||
const res = await apiFetch(`${API}/generate`, {
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
});
|
||||
const res = await apiFetch(
|
||||
`${API}/generate`,
|
||||
firstSoundRequest(i18n.t('firstrun.first_sound_text')),
|
||||
);
|
||||
const blob = await res.blob();
|
||||
await playBlobAudio(blob, { label: i18n.t('player.generated_audio') });
|
||||
toast.success(i18n.t('firstrun.first_sound_done'), { duration: 7000 });
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { firstSoundRequest } from '../utils/firstSound';
|
||||
|
||||
describe('onboarding first-sound request', () => {
|
||||
it('posts localized text and a nonempty voice-design instruction as multipart form data', () => {
|
||||
const request = firstSoundRequest('Welcome to VoiceStudio');
|
||||
expect(request.method).toBe('POST');
|
||||
expect(request.body).toBeInstanceOf(FormData);
|
||||
expect(Object.fromEntries(request.body)).toEqual({
|
||||
text: 'Welcome to VoiceStudio',
|
||||
instruct: 'middle-aged, low pitch',
|
||||
num_step: '16',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import defaults from './firstSound.json';
|
||||
|
||||
// Taxonomy tokens also provide the nonempty description VoiceDesign requires.
|
||||
export function firstSoundRequest(text) {
|
||||
const body = new FormData();
|
||||
body.append('text', text);
|
||||
body.append('instruct', defaults.instruct);
|
||||
body.append('num_step', String(defaults.num_step));
|
||||
return { method: 'POST', body };
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"instruct": "middle-aged, low pitch",
|
||||
"num_step": 16
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""The actual onboarding defaults must pass the runtime engine validator."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from omnivoice.models.omnivoice import _resolve_instruct
|
||||
|
||||
|
||||
def test_first_sound_instruction_passes_runtime_taxonomy_validation():
|
||||
defaults = json.loads(
|
||||
(Path(__file__).parents[1] / "frontend/src/utils/firstSound.json").read_text()
|
||||
)
|
||||
instruct = defaults["instruct"]
|
||||
# VoiceDesign requires a nonempty description; OmniVoice validates tokens.
|
||||
assert instruct.strip()
|
||||
assert _resolve_instruct(instruct) == instruct
|
||||
assert _resolve_instruct(instruct, use_zh=True)
|
||||
Reference in New Issue
Block a user