mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-22 08:38:13 +02:00
chore: fix dograh v2 speed option
This commit is contained in:
parent
c554256db1
commit
8006d0edcd
5 changed files with 100 additions and 30 deletions
|
|
@ -17,7 +17,10 @@ from api.enums import OrganizationConfigurationKey, PostHogEvent
|
|||
from api.schemas.ai_model_configuration import (
|
||||
DOGRAH_DEFAULT_LANGUAGE,
|
||||
DOGRAH_DEFAULT_VOICE,
|
||||
DOGRAH_SPEED_MAX,
|
||||
DOGRAH_SPEED_MIN,
|
||||
DOGRAH_SPEED_OPTIONS,
|
||||
DOGRAH_SPEED_STEP,
|
||||
OrganizationAIModelConfigurationResponse,
|
||||
OrganizationAIModelConfigurationV2,
|
||||
)
|
||||
|
|
@ -265,6 +268,11 @@ async def get_model_configuration_v2_defaults(
|
|||
"voices": [DOGRAH_DEFAULT_VOICE],
|
||||
"allow_custom_input": _dograh_allows_custom_voice(),
|
||||
"speeds": list(DOGRAH_SPEED_OPTIONS),
|
||||
"speed_range": {
|
||||
"min": DOGRAH_SPEED_MIN,
|
||||
"max": DOGRAH_SPEED_MAX,
|
||||
"step": DOGRAH_SPEED_STEP,
|
||||
},
|
||||
"languages": DOGRAH_STT_LANGUAGES,
|
||||
"defaults": {
|
||||
"voice": DOGRAH_DEFAULT_VOICE,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ from api.services.configuration.registry import (
|
|||
TTSConfig,
|
||||
)
|
||||
|
||||
DOGRAH_SPEED_MIN = 0.5
|
||||
DOGRAH_SPEED_MAX = 2.0
|
||||
DOGRAH_SPEED_STEP = 0.1
|
||||
DOGRAH_SPEED_OPTIONS: tuple[float, ...] = (0.8, 1.0, 1.2)
|
||||
DOGRAH_DEFAULT_VOICE = "default"
|
||||
DOGRAH_DEFAULT_LANGUAGE = "multi"
|
||||
|
|
@ -49,16 +52,9 @@ class EffectiveAIModelConfiguration(BaseModel):
|
|||
class DograhManagedAIModelConfiguration(BaseModel):
|
||||
api_key: str
|
||||
voice: str = DOGRAH_DEFAULT_VOICE
|
||||
speed: float = Field(default=1.0)
|
||||
speed: float = Field(default=1.0, ge=DOGRAH_SPEED_MIN, le=DOGRAH_SPEED_MAX)
|
||||
language: str = DOGRAH_DEFAULT_LANGUAGE
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_speed(self):
|
||||
if self.speed not in DOGRAH_SPEED_OPTIONS:
|
||||
allowed = ", ".join(str(speed) for speed in DOGRAH_SPEED_OPTIONS)
|
||||
raise ValueError(f"Dograh speed must be one of: {allowed}")
|
||||
return self
|
||||
|
||||
|
||||
class BYOKPipelineAIModelConfiguration(BaseModel):
|
||||
llm: LLMConfig
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ from api.enums import OrganizationConfigurationKey
|
|||
from api.schemas.ai_model_configuration import (
|
||||
DOGRAH_DEFAULT_LANGUAGE,
|
||||
DOGRAH_DEFAULT_VOICE,
|
||||
DOGRAH_SPEED_OPTIONS,
|
||||
DOGRAH_SPEED_MAX,
|
||||
DOGRAH_SPEED_MIN,
|
||||
BYOKAIModelConfiguration,
|
||||
BYOKPipelineAIModelConfiguration,
|
||||
BYOKRealtimeAIModelConfiguration,
|
||||
|
|
@ -436,7 +437,11 @@ def _convert_any_dograh_legacy_configuration(
|
|||
dograh_key: str,
|
||||
) -> OrganizationAIModelConfigurationV2:
|
||||
speed = getattr(configuration.tts, "speed", 1.0)
|
||||
if speed not in DOGRAH_SPEED_OPTIONS:
|
||||
try:
|
||||
speed = float(speed)
|
||||
except (TypeError, ValueError):
|
||||
speed = 1.0
|
||||
if not DOGRAH_SPEED_MIN <= speed <= DOGRAH_SPEED_MAX:
|
||||
speed = 1.0
|
||||
return OrganizationAIModelConfigurationV2(
|
||||
mode="dograh",
|
||||
|
|
|
|||
|
|
@ -59,13 +59,27 @@ def test_dograh_v2_compiles_to_effective_managed_pipeline_with_embeddings():
|
|||
assert effective.managed_service_version == 2
|
||||
|
||||
|
||||
def test_dograh_v2_rejects_non_predefined_speed():
|
||||
def test_dograh_v2_accepts_numeric_speed_in_registry_range():
|
||||
config = OrganizationAIModelConfigurationV2(
|
||||
mode="dograh",
|
||||
dograh=DograhManagedAIModelConfiguration(
|
||||
api_key="mps-secret",
|
||||
speed=1.5,
|
||||
),
|
||||
)
|
||||
|
||||
effective = compile_ai_model_configuration_v2(config)
|
||||
|
||||
assert effective.tts.speed == 1.5
|
||||
|
||||
|
||||
def test_dograh_v2_rejects_out_of_range_speed():
|
||||
with pytest.raises(ValidationError):
|
||||
OrganizationAIModelConfigurationV2(
|
||||
mode="dograh",
|
||||
dograh=DograhManagedAIModelConfiguration(
|
||||
api_key="mps-secret",
|
||||
speed=1.5,
|
||||
speed=2.5,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -238,6 +252,33 @@ def test_legacy_all_dograh_pipeline_converts_to_dograh_v2():
|
|||
assert config.dograh.api_key == "mps-secret"
|
||||
|
||||
|
||||
def test_legacy_dograh_pipeline_conversion_preserves_numeric_speed():
|
||||
legacy = EffectiveAIModelConfiguration(
|
||||
llm=DograhLLMService(
|
||||
provider="dograh",
|
||||
api_key=["mps-secret"],
|
||||
model="default",
|
||||
),
|
||||
tts=DograhTTSService(
|
||||
provider="dograh",
|
||||
api_key=["mps-secret"],
|
||||
model="default",
|
||||
voice="default",
|
||||
speed=1.5,
|
||||
),
|
||||
stt=DograhSTTService(
|
||||
provider="dograh",
|
||||
api_key=["mps-secret"],
|
||||
model="default",
|
||||
),
|
||||
)
|
||||
|
||||
config = convert_legacy_ai_model_configuration_to_v2(legacy)
|
||||
|
||||
assert config.mode == "dograh"
|
||||
assert config.dograh.speed == 1.5
|
||||
|
||||
|
||||
def test_legacy_mixed_dograh_pipeline_converts_to_dograh_v2():
|
||||
legacy = EffectiveAIModelConfiguration(
|
||||
llm=OpenAILLMService(
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ interface DograhDefaults {
|
|||
voices: string[];
|
||||
allow_custom_input?: boolean;
|
||||
speeds: number[];
|
||||
speed_range?: {
|
||||
min: number;
|
||||
max: number;
|
||||
step?: number;
|
||||
};
|
||||
languages: string[];
|
||||
defaults: {
|
||||
voice: string;
|
||||
|
|
@ -66,6 +71,11 @@ function firstApiKey(value: unknown): string {
|
|||
return typeof value === "string" ? value : "";
|
||||
}
|
||||
|
||||
function numberOrDefault(value: unknown, fallback: number): number {
|
||||
const parsed = typeof value === "number" ? value : Number(value);
|
||||
return Number.isFinite(parsed) ? parsed : fallback;
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> | null {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? value as Record<string, unknown>
|
||||
|
|
@ -170,7 +180,7 @@ function buildDograhState(
|
|||
return {
|
||||
api_key: String(configuredDograh.api_key || ""),
|
||||
voice: String(configuredDograh.voice || fallback.voice),
|
||||
speed: Number(configuredDograh.speed || fallback.speed),
|
||||
speed: numberOrDefault(configuredDograh.speed, fallback.speed),
|
||||
language: String(configuredDograh.language || fallback.language),
|
||||
};
|
||||
}
|
||||
|
|
@ -182,7 +192,7 @@ function buildDograhState(
|
|||
return {
|
||||
api_key: firstApiKey(llm?.api_key || tts?.api_key || stt?.api_key),
|
||||
voice: String(tts?.voice || fallback.voice),
|
||||
speed: Number(tts?.speed || fallback.speed),
|
||||
speed: numberOrDefault(tts?.speed, fallback.speed),
|
||||
language: String(stt?.language || fallback.language),
|
||||
};
|
||||
}
|
||||
|
|
@ -272,6 +282,7 @@ export function AIModelConfigurationV2Editor({
|
|||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const allowCustomVoice = defaults.dograh.allow_custom_input ?? false;
|
||||
const dograhSpeedRange = defaults.dograh.speed_range ?? { min: 0.5, max: 2.0, step: 0.1 };
|
||||
|
||||
useEffect(() => {
|
||||
const rawConfiguration = asRecord(configuration);
|
||||
|
|
@ -288,6 +299,15 @@ export function AIModelConfigurationV2Editor({
|
|||
setIsSavingDograh(true);
|
||||
setError(null);
|
||||
try {
|
||||
if (
|
||||
!Number.isFinite(dograh.speed)
|
||||
|| dograh.speed < dograhSpeedRange.min
|
||||
|| dograh.speed > dograhSpeedRange.max
|
||||
) {
|
||||
throw new Error(
|
||||
`Dograh speed must be between ${dograhSpeedRange.min} and ${dograhSpeedRange.max}.`,
|
||||
);
|
||||
}
|
||||
await onSave({
|
||||
version: 2,
|
||||
mode: "dograh",
|
||||
|
|
@ -413,22 +433,22 @@ export function AIModelConfigurationV2Editor({
|
|||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>Speed</Label>
|
||||
<Select
|
||||
value={String(dograh.speed)}
|
||||
onValueChange={(speed) => setDograh({ ...dograh, speed: Number(speed) })}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select speed" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{defaults.dograh.speeds.map((speed) => (
|
||||
<SelectItem key={speed} value={String(speed)}>
|
||||
{speed}x
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Label htmlFor="dograh-speed">Speed</Label>
|
||||
<Input
|
||||
id="dograh-speed"
|
||||
type="number"
|
||||
min={dograhSpeedRange.min}
|
||||
max={dograhSpeedRange.max}
|
||||
step={dograhSpeedRange.step ?? 0.1}
|
||||
value={dograh.speed}
|
||||
onChange={(event) => {
|
||||
const speed = event.currentTarget.valueAsNumber;
|
||||
setDograh({
|
||||
...dograh,
|
||||
speed: Number.isFinite(speed) ? speed : defaults.dograh.defaults.speed,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 sm:col-span-2">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue