mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-07 01:55:51 +08:00
feat(tts): dedicated ATIS broadcast voice on Speaches
The ATIS tag now resolves to en_GB-alba-medium — outside both voice pools — instead of sharing 'verse' with the user's own readback voice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -212,7 +212,7 @@ export default defineEventHandler(async (event) => {
|
||||
voice,
|
||||
};
|
||||
const speachesVoice = provider === "speaches"
|
||||
? resolveSpeachesVoice(voice, speachesFallback)
|
||||
? resolveSpeachesVoice(voice, speachesFallback, body?.tag)
|
||||
: null;
|
||||
const ttsVoice = speachesVoice?.voice ?? voice;
|
||||
const providerModel = speachesVoice
|
||||
|
||||
@@ -28,6 +28,14 @@ describe('resolveSpeachesVoice', () => {
|
||||
assert.deepEqual(resolveSpeachesVoice('', fallback), fallback)
|
||||
})
|
||||
|
||||
it('gives the ATIS broadcast its own dedicated speaker', () => {
|
||||
const atis = resolveSpeachesVoice('verse', fallback, 'atis')
|
||||
assert.match(atis.voice, /^en_/)
|
||||
assert.notEqual(atis.voice, resolveSpeachesVoice('verse', fallback).voice)
|
||||
const allPoolVoices = Object.values(SPEACHES_VOICE_MAP).map(v => v.voice)
|
||||
assert.equal(allPoolVoices.includes(atis.voice), false, 'ATIS voice must not be in any pool')
|
||||
})
|
||||
|
||||
it('keeps controller and pilot voices audibly disjoint', () => {
|
||||
const controller = ['alloy', 'echo', 'onyx', 'sage'].map(v => resolveSpeachesVoice(v, fallback).voice)
|
||||
const pilots = ['verse', 'ash', 'ballad', 'coral', 'fable', 'nova', 'shimmer']
|
||||
|
||||
@@ -34,7 +34,18 @@ export const SPEACHES_VOICE_MAP: Record<string, SpeachesVoice> = {
|
||||
shimmer: piper('en_US-kristin-medium'),
|
||||
}
|
||||
|
||||
export function resolveSpeachesVoice(logical: string, fallback: SpeachesVoice): SpeachesVoice {
|
||||
/**
|
||||
* ATIS is a robotic broadcast in the real world — it gets a dedicated speaker
|
||||
* outside every pool so it never sounds like a controller or a pilot.
|
||||
*/
|
||||
export const ATIS_SPEACHES_VOICE: SpeachesVoice = piper('en_GB-alba-medium')
|
||||
|
||||
export function resolveSpeachesVoice(
|
||||
logical: string,
|
||||
fallback: SpeachesVoice,
|
||||
tag?: string,
|
||||
): SpeachesVoice {
|
||||
if ((tag || '').trim().toLowerCase() === 'atis') return ATIS_SPEACHES_VOICE
|
||||
const key = (logical || '').trim().toLowerCase()
|
||||
return SPEACHES_VOICE_MAP[key] ?? fallback
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user