mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-10 08:05:22 +02:00
176 lines
5.7 KiB
Python
176 lines
5.7 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, Field, model_validator
|
|
|
|
from api.schemas.user_configuration import EffectiveAIModelConfiguration
|
|
from api.services.configuration.registry import (
|
|
DograhEmbeddingsConfiguration,
|
|
DograhLLMService,
|
|
DograhSTTService,
|
|
DograhTTSService,
|
|
EmbeddingsConfig,
|
|
LLMConfig,
|
|
RealtimeConfig,
|
|
ServiceProviders,
|
|
STTConfig,
|
|
TTSConfig,
|
|
)
|
|
|
|
DOGRAH_SPEED_OPTIONS: tuple[float, ...] = (0.8, 1.0, 1.2)
|
|
DOGRAH_DEFAULT_VOICE = "default"
|
|
DOGRAH_DEFAULT_LANGUAGE = "multi"
|
|
|
|
|
|
class DograhManagedAIModelConfiguration(BaseModel):
|
|
api_key: str
|
|
voice: str = DOGRAH_DEFAULT_VOICE
|
|
speed: float = Field(default=1.0)
|
|
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
|
|
tts: TTSConfig
|
|
stt: STTConfig
|
|
embeddings: EmbeddingsConfig | None = None
|
|
|
|
@model_validator(mode="after")
|
|
def reject_dograh_providers(self):
|
|
_reject_dograh_provider("llm", self.llm)
|
|
_reject_dograh_provider("tts", self.tts)
|
|
_reject_dograh_provider("stt", self.stt)
|
|
_reject_dograh_provider("embeddings", self.embeddings)
|
|
return self
|
|
|
|
|
|
class BYOKRealtimeAIModelConfiguration(BaseModel):
|
|
realtime: RealtimeConfig
|
|
llm: LLMConfig
|
|
embeddings: EmbeddingsConfig | None = None
|
|
|
|
@model_validator(mode="after")
|
|
def reject_dograh_providers(self):
|
|
_reject_dograh_provider("llm", self.llm)
|
|
_reject_dograh_provider("embeddings", self.embeddings)
|
|
return self
|
|
|
|
|
|
class BYOKAIModelConfiguration(BaseModel):
|
|
mode: Literal["pipeline", "realtime"]
|
|
pipeline: BYOKPipelineAIModelConfiguration | None = None
|
|
realtime: BYOKRealtimeAIModelConfiguration | None = None
|
|
|
|
@model_validator(mode="after")
|
|
def validate_selected_mode(self):
|
|
if self.mode == "pipeline" and self.pipeline is None:
|
|
raise ValueError("byok.pipeline is required when byok.mode is pipeline")
|
|
if self.mode == "realtime" and self.realtime is None:
|
|
raise ValueError("byok.realtime is required when byok.mode is realtime")
|
|
return self
|
|
|
|
|
|
class OrganizationAIModelConfigurationV2(BaseModel):
|
|
version: Literal[2] = 2
|
|
mode: Literal["dograh", "byok"]
|
|
dograh: DograhManagedAIModelConfiguration | None = None
|
|
byok: BYOKAIModelConfiguration | None = None
|
|
|
|
@model_validator(mode="after")
|
|
def validate_selected_mode(self):
|
|
if self.mode == "dograh" and self.dograh is None:
|
|
raise ValueError("dograh configuration is required when mode is dograh")
|
|
if self.mode == "byok" and self.byok is None:
|
|
raise ValueError("byok configuration is required when mode is byok")
|
|
return self
|
|
|
|
|
|
class OrganizationAIModelConfigurationPreferences(BaseModel):
|
|
test_phone_number: str | None = None
|
|
timezone: str | None = None
|
|
|
|
|
|
class OrganizationAIModelConfigurationResponse(BaseModel):
|
|
configuration: dict | None
|
|
effective_configuration: dict
|
|
preferences: OrganizationAIModelConfigurationPreferences
|
|
source: Literal["organization_v2", "legacy_user_v1", "empty"]
|
|
|
|
|
|
def compile_ai_model_configuration_v2(
|
|
configuration: OrganizationAIModelConfigurationV2,
|
|
) -> EffectiveAIModelConfiguration:
|
|
if configuration.mode == "dograh":
|
|
if configuration.dograh is None:
|
|
raise ValueError("dograh configuration is required")
|
|
return _compile_dograh_configuration(configuration.dograh)
|
|
|
|
if configuration.byok is None:
|
|
raise ValueError("byok configuration is required")
|
|
if configuration.byok.mode == "pipeline":
|
|
if configuration.byok.pipeline is None:
|
|
raise ValueError("byok.pipeline is required")
|
|
pipeline = configuration.byok.pipeline
|
|
return EffectiveAIModelConfiguration(
|
|
llm=pipeline.llm,
|
|
tts=pipeline.tts,
|
|
stt=pipeline.stt,
|
|
embeddings=pipeline.embeddings,
|
|
is_realtime=False,
|
|
)
|
|
|
|
if configuration.byok.realtime is None:
|
|
raise ValueError("byok.realtime is required")
|
|
realtime = configuration.byok.realtime
|
|
return EffectiveAIModelConfiguration(
|
|
llm=realtime.llm,
|
|
realtime=realtime.realtime,
|
|
embeddings=realtime.embeddings,
|
|
is_realtime=True,
|
|
)
|
|
|
|
|
|
def _compile_dograh_configuration(
|
|
configuration: DograhManagedAIModelConfiguration,
|
|
) -> EffectiveAIModelConfiguration:
|
|
return EffectiveAIModelConfiguration(
|
|
llm=DograhLLMService(
|
|
provider=ServiceProviders.DOGRAH,
|
|
api_key=configuration.api_key,
|
|
model="default",
|
|
),
|
|
tts=DograhTTSService(
|
|
provider=ServiceProviders.DOGRAH,
|
|
api_key=configuration.api_key,
|
|
model="default",
|
|
voice=configuration.voice,
|
|
speed=configuration.speed,
|
|
),
|
|
stt=DograhSTTService(
|
|
provider=ServiceProviders.DOGRAH,
|
|
api_key=configuration.api_key,
|
|
model="default",
|
|
language=configuration.language,
|
|
),
|
|
embeddings=DograhEmbeddingsConfiguration(
|
|
provider=ServiceProviders.DOGRAH,
|
|
api_key=configuration.api_key,
|
|
model="default",
|
|
),
|
|
is_realtime=False,
|
|
)
|
|
|
|
|
|
def _reject_dograh_provider(section: str, service) -> None:
|
|
if service is None:
|
|
return
|
|
if getattr(service, "provider", None) == ServiceProviders.DOGRAH:
|
|
raise ValueError(f"BYOK {section} cannot use Dograh provider")
|