flare / config /config_models.py
ciyidogan's picture
Upload 3 files
d40867b verified
"""
Configuration Models for Flare Platform
"""
from pydantic import BaseModel, Field, field_serializer
from datetime import datetime
from typing import Optional, List, Dict, Any
class BaseModelWithDatetime(BaseModel):
"""Base model with consistent datetime serialization"""
class Config:
# Datetime'ları her zaman ISO 8601 formatında serialize et
json_encoders = {
datetime: lambda v: v.isoformat() if v else None
}
# ===================== User & Auth =====================
class UserConfig(BaseModelWithDatetime):
username: str
password_hash: str
salt: Optional[str] = None
# ===================== Provider Models =====================
class ProviderDefinition(BaseModelWithDatetime):
type: str # llm, tts, stt
name: str
display_name: str
requires_endpoint: bool
requires_api_key: bool
requires_repo_info: Optional[bool] = False
description: str
features: Optional[Dict[str, Any]] = Field(default_factory=dict)
def has_feature(self, feature_name: str) -> bool:
"""Check if provider has a specific feature"""
return feature_name in self.features if self.features else False
def get_feature(self, feature_name: str, default: Any = None) -> Any:
"""Get feature value with default"""
if not self.features:
return default
return self.features.get(feature_name, default)
def get_feature_bool(self, feature_name: str, default: bool = False) -> bool:
"""Get boolean feature value"""
if not self.features:
return default
value = self.features.get(feature_name, default)
if isinstance(value, bool):
return value
if isinstance(value, str):
return value.lower() in ('true', '1', 'yes', 'on')
return bool(value)
def get_feature_int(self, feature_name: str, default: int = 0) -> int:
"""Get integer feature value"""
if not self.features:
return default
value = self.features.get(feature_name, default)
try:
return int(value)
except (ValueError, TypeError):
return default
def get_feature_str(self, feature_name: str, default: str = "") -> str:
"""Get string feature value"""
if not self.features:
return default
value = self.features.get(feature_name, default)
return str(value) if value is not None else default
class ProviderSettings(BaseModelWithDatetime):
name: str
api_key: Optional[str] = None
endpoint: Optional[str] = None
settings: Optional[Dict[str, Any]] = Field(default_factory=dict)
# ===================== Global Config =====================
class GlobalConfig(BaseModelWithDatetime):
llm_provider: ProviderSettings = Field(
default_factory=lambda: ProviderSettings(
name="spark_cloud",
api_key="",
endpoint="http://localhost:8080",
settings={}
)
)
tts_provider: ProviderSettings = Field(
default_factory=lambda: ProviderSettings(
name="no_tts",
api_key="",
endpoint=None,
settings={}
)
)
stt_provider: ProviderSettings = Field(
default_factory=lambda: ProviderSettings(
name="no_stt",
api_key="",
endpoint=None,
settings={}
)
)
providers: List[ProviderDefinition] = Field(default_factory=list)
users: List[UserConfig] = Field(default_factory=list)
last_update_date: Optional[str] = None
last_update_user: Optional[str] = None
def is_cloud_mode(self) -> bool:
"""Check if running in cloud mode"""
import os
return bool(os.environ.get("SPACE_ID"))
def get_provider_config(self, provider_type: str, provider_name: str) -> Optional[ProviderDefinition]:
"""Get provider definition by type and name"""
return next(
(p for p in self.providers if p.type == provider_type and p.name == provider_name),
None
)
# ===================== Localization Models =====================
class LocalizedExample(BaseModelWithDatetime):
locale_code: str
example: str
class LocalizedCaption(BaseModelWithDatetime):
locale_code: str
caption: str
# ===================== Parameter Models =====================
class ParameterConfig(BaseModelWithDatetime):
name: str
caption: List[LocalizedCaption]
type: str # str, int, float, bool, date
required: bool = True
variable_name: str
extraction_prompt: Optional[str] = None
validation_regex: Optional[str] = None
invalid_prompt: Optional[str] = None
type_error_prompt: Optional[str] = None
def canonical_type(self) -> str:
"""Get canonical type name"""
return self.type.lower()
def get_caption_for_locale(self, locale: str) -> str:
"""Get caption for specific locale"""
for cap in self.caption:
if cap.locale_code == locale:
return cap.caption
# Fallback to first caption
return self.caption[0].caption if self.caption else self.name
# ===================== Intent Models =====================
class IntentConfig(BaseModelWithDatetime):
name: str
caption: str
requiresApproval: Optional[bool] = False
dependencies: List[str] = Field(default_factory=list)
examples: List[LocalizedExample] = Field(default_factory=list)
detection_prompt: str
parameters: List[ParameterConfig] = Field(default_factory=list)
action: str
fallback_timeout_prompt: Optional[str] = None
fallback_error_prompt: Optional[str] = None
def get_examples_for_locale(self, locale: str) -> List[str]:
"""Get examples for specific locale"""
examples = []
for ex in self.examples:
if ex.locale_code == locale:
examples.append(ex.example)
# Fallback to any available examples if locale not found
if not examples and self.examples:
# Try language part only (tr-TR -> tr)
if '-' in locale:
lang_code = locale.split('-')[0]
for ex in self.examples:
if ex.locale_code.startswith(lang_code):
examples.append(ex.example)
# If still no examples, return all examples
if not examples:
examples = [ex.example for ex in self.examples]
return examples
def get_examples_for_locale(self, locale: str) -> List[str]:
"""Get examples for specific locale"""
examples = []
for ex in self.examples:
if ex.locale_code == locale:
examples.append(ex.example)
# Fallback to any available examples if locale not found
if not examples and self.examples:
# Try language part only (tr-TR -> tr)
if '-' in locale:
lang_code = locale.split('-')[0]
for ex in self.examples:
if ex.locale_code.startswith(lang_code):
examples.append(ex.example)
# If still no examples, return all examples
if not examples:
examples = [ex.example for ex in self.examples]
return examples
# ===================== LLM Configuration =====================
class GenerationConfig(BaseModelWithDatetime):
max_new_tokens: int = 512
temperature: float = 0.7
top_p: float = 0.9
top_k: Optional[int] = None
repetition_penalty: Optional[float] = None
do_sample: Optional[bool] = True
num_beams: Optional[int] = None
length_penalty: Optional[float] = None
early_stopping: Optional[bool] = None
class LLMConfiguration(BaseModelWithDatetime):
repo_id: str
generation_config: GenerationConfig = Field(default_factory=GenerationConfig)
use_fine_tune: bool = False
fine_tune_zip: Optional[str] = ""
# ===================== Version Models =====================
class VersionConfig(BaseModelWithDatetime):
no: int
caption: str
description: Optional[str] = None
published: bool = False
deleted: bool = False
general_prompt: str
welcome_prompt: Optional[str] = None
llm: LLMConfiguration
intents: List[IntentConfig] = Field(default_factory=list)
created_date: str
created_by: str
publish_date: Optional[str] = None
published_by: Optional[str] = None
last_update_date: Optional[str] = None
last_update_user: Optional[str] = None
# ===================== Project Models =====================
class ProjectConfig(BaseModelWithDatetime):
id: int
name: str
caption: str
icon: Optional[str] = "folder"
description: Optional[str] = None
enabled: bool = True
default_locale: str = "tr"
supported_locales: List[str] = Field(default_factory=lambda: ["tr"])
timezone: str = "Europe/Istanbul"
region: str = "tr-TR"
versions: List[VersionConfig] = Field(default_factory=list)
version_id_counter: int = 1
deleted: bool = False
created_date: str
created_by: str
last_update_date: Optional[str] = None
last_update_user: Optional[str] = None
# ===================== API Models =====================
class RetryConfig(BaseModelWithDatetime):
retry_count: int = 3
backoff_seconds: int = 2
strategy: str = "static" # static, exponential
class AuthConfig(BaseModelWithDatetime):
enabled: bool
token_endpoint: Optional[str] = None
response_token_path: Optional[str] = None
token_request_body: Optional[Dict[str, Any]] = None
token_refresh_endpoint: Optional[str] = None
token_refresh_body: Optional[Dict[str, Any]] = None
class ResponseMapping(BaseModelWithDatetime):
variable_name: str
type: str # str, int, float, bool, date
json_path: str
caption: List[LocalizedCaption]
class APIConfig(BaseModelWithDatetime):
name: str
url: str
method: str = "POST"
headers: Dict[str, str] = Field(default_factory=dict)
body_template: Dict[str, Any] = Field(default_factory=dict)
timeout_seconds: int = 10
retry: RetryConfig = Field(default_factory=RetryConfig)
proxy: Optional[str] = None
auth: Optional[AuthConfig] = None
response_prompt: Optional[str] = None
response_mappings: List[ResponseMapping] = Field(default_factory=list)
deleted: bool = False
created_date: Optional[str] = None
created_by: Optional[str] = None
last_update_date: Optional[str] = None
last_update_user: Optional[str] = None
# ===================== Activity Log =====================
class ActivityLogEntry(BaseModelWithDatetime):
id: Optional[int] = None
timestamp: str
username: str
action: str
entity_type: str
entity_name: Optional[str] = None
details: Optional[str] = None
# ===================== Root Configuration =====================
class ServiceConfig(BaseModelWithDatetime):
global_config: GlobalConfig = Field(alias="config")
projects: List[ProjectConfig] = Field(default_factory=list)
apis: List[APIConfig] = Field(default_factory=list)
activity_log: List[ActivityLogEntry] = Field(default_factory=list)
project_id_counter: int = 1
last_update_date: Optional[str] = None
last_update_user: Optional[str] = None
class Config:
populate_by_name = True
def build_index(self) -> None:
"""Build indexes for quick lookup"""
# This method can be extended to build various indexes
pass
def get_api(self, api_name: str) -> Optional[APIConfig]:
"""Get API config by name"""
return next((api for api in self.apis if api.name == api_name), None)
# For backward compatibility - alias
GlobalConfiguration = GlobalConfig