Files
viettranx 82ca0f117b refactor(tts): collapse adapter triplication; honest concurrency comment
Post-review cleanup of Phase 4. Closes Finding #9 properly and corrects
the Finding #13 documentation lie surfaced in the code-review report.

Capability schema:
- Replace `AgentOverridable bool` with `AgentOverridableAs string` on
  ParamSchema. Empty string = not overridable; non-empty = the generic
  key alias (`"speed"`, `"emotion"`, `"style"`).
- Each provider declaration now carries the alias inline, so the
  generic↔native mapping has a single TS-readable source.

Frontend:
- Web `tts-override-block.tsx` drops the inline `GENERIC_TO_NATIVE`
  literal and derives the bidirectional adapter from the filtered
  capability params (each param self-describes its alias). Adapter
  tests rewritten around the new shape.
- Desktop `AgentDetailPanel.tsx` drops the 45-line inline IIFE in
  favour of a new `<TtsOverrideFineTune>` component that uses the
  same alias-based mapping.

Backend:
- Move `AgentTTSParamsAllowedKeys` + `ValidateAgentTTSParams` to
  `internal/audio/agent_params_adapter.go`. HTTP `validate.go` and WS
  `gateway/methods/agents_update.go` both delegate, eliminating the
  duplicated `{speed, emotion, style}` literal.

Cleanup:
- Delete orphan i18n keys `MsgTtsParamInvalidJSON` and
  `MsgTtsParamDependsOn` from `keys.go` + en/vi/zh catalogs (no
  in-code references; DependsOn is FE-only, JSON parse failures
  already surface via slog).

Documentation:
- `prompt-settings-section.tsx` Finding #13 comment rewritten to
  honestly describe the best-effort merge into a fresh local copy of
  the cached `otherConfig` prop. Concurrent-tab clobber remains
  possible — server-side JSON-merge-patch endpoint planned for v2.

Tests: 9 backend suites (race), web 217/217, desktop build clean,
both Go build tags pass.
2026-04-20 07:14:56 +07:00

89 lines
2.5 KiB
Go

package openai
import "github.com/nextlevelbuilder/goclaw/internal/audio"
// openAIModels is the static allowlist of supported OpenAI TTS models.
var openAIModels = []string{
"tts-1",
"tts-1-hd",
"gpt-4o-mini-tts",
}
// openAIVoices is the full 13-voice catalog. tts-1/tts-1-hd support only 9
// (ballad/verse/marin/cedar are gpt-4o-mini-tts only), but backend accepts any
// voice ID — model-compatibility is surfaced as UI help text only.
var openAIVoices = []audio.VoiceOption{
{VoiceID: "alloy", Name: "Alloy"},
{VoiceID: "ash", Name: "Ash"},
{VoiceID: "ballad", Name: "Ballad"},
{VoiceID: "coral", Name: "Coral"},
{VoiceID: "echo", Name: "Echo"},
{VoiceID: "fable", Name: "Fable"},
{VoiceID: "onyx", Name: "Onyx"},
{VoiceID: "nova", Name: "Nova"},
{VoiceID: "sage", Name: "Sage"},
{VoiceID: "shimmer", Name: "Shimmer"},
{VoiceID: "verse", Name: "Verse"},
{VoiceID: "marin", Name: "Marin"},
{VoiceID: "cedar", Name: "Cedar"},
}
var (
speedMin = 0.25
speedMax = 4.0
speedStep = 0.05
)
// openAIParams is the enriched param schema for OpenAI TTS.
// Defaults MUST match the hardcoded values in tts.go (characterization fixture).
var openAIParams = []audio.ParamSchema{
{
Key: "speed",
Type: audio.ParamTypeRange,
Label: "Speed",
Description: "Speech speed multiplier (0.25 = slowest, 4.0 = fastest).",
Default: 1.0,
Min: &speedMin,
Max: &speedMax,
Step: &speedStep,
AgentOverridableAs: "speed",
},
{
Key: "response_format",
Type: audio.ParamTypeEnum,
Label: "Output Format",
Default: "mp3",
Enum: []audio.EnumOption{
{Value: "mp3", Label: "MP3"},
{Value: "opus", Label: "Opus"},
{Value: "aac", Label: "AAC"},
{Value: "flac", Label: "FLAC"},
{Value: "wav", Label: "WAV"},
{Value: "pcm", Label: "PCM"},
},
},
{
Key: "instructions",
Type: audio.ParamTypeText,
Label: "Instructions",
Description: "System-level style prompt (gpt-4o-mini-tts only). Advanced.",
Default: "",
Group: "advanced",
DependsOn: []audio.Dependency{
{Field: "model", Op: "eq", Value: "gpt-4o-mini-tts"},
},
},
}
// Capabilities returns the full capability schema for the OpenAI TTS provider.
func (p *Provider) Capabilities() audio.ProviderCapabilities {
return audio.ProviderCapabilities{
Provider: "openai",
DisplayName: "OpenAI TTS",
RequiresAPIKey: true,
Models: openAIModels,
Voices: openAIVoices,
Params: openAIParams,
}
}