File size: 3,407 Bytes
87c7efb
 
 
 
 
 
 
04b94fe
87c7efb
 
 
14b6ee2
87c7efb
 
14b6ee2
87c7efb
04b94fe
87c7efb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
Flare – Configuration Loader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
• JSONC (comment-json) desteği
• Pydantic şema + runtime validation
• Global erişim için singleton ConfigProvider.get()
"""

import pathlib
from functools import lru_cache
from typing import Dict, List, Optional

import commentjson as jsonc
from pydantic import BaseModel, Field, validator

CONFIG_PATH = pathlib.Path(__file__).parent / "service_config.jsonc"


# === Pydantic Schemas =======================================================
class RetryConfig(BaseModel):
    max_attempts: int = 3
    backoff_seconds: int = 2
    strategy: str = Field("static", regex="^(static|exponential)$")


class ProxyConfig(BaseModel):
    enabled: bool = False
    url: Optional[str] = None


class AuthConfig(BaseModel):
    enabled: bool = False
    token_endpoint: Optional[str] = None
    body_template: Dict[str, str] = {}
    response_token_path: Optional[str] = None
    token_refresh_endpoint: Optional[str] = None
    token_refresh_body: Dict[str, str] = {}

    @validator("token_endpoint", always=True)
    def _require_endpoint(cls, v, values):
        if values["enabled"] and not v:
            raise ValueError("Auth enabled but token_endpoint missing")
        return v


class APIConfig(BaseModel):
    url: str
    method: str = Field("POST", regex="^(GET|POST|PUT|DELETE|PATCH)$")
    headers: Dict[str, str] = {}
    body_template: Dict[str, str] = {}
    timeout_seconds: int = 10
    retry: RetryConfig = RetryConfig()
    auth: AuthConfig = AuthConfig()
    proxy: ProxyConfig = ProxyConfig()
    response_prompt: str


class ParameterConfig(BaseModel):
    name: str
    type: str
    required: bool = True
    extraction_prompt: str
    validation_regex: Optional[str] = None
    invalid_prompt: Optional[str] = None
    type_error_prompt: Optional[str] = None


class IntentConfig(BaseModel):
    name: str
    caption: Optional[str]
    locale: str = "tr-TR"
    dependencies: List[str] = []
    examples: List[str]
    detection_prompt: str
    parameters: List[ParameterConfig] = []
    action: str
    fallback_timeout_prompt: Optional[str] = None
    fallback_error_prompt: Optional[str] = None


class LLMConfig(BaseModel):
    repo_id: str
    generation_config: Dict[str, float]
    use_fine_tune: bool = False
    fine_tune_zip: Optional[str] = None


class VersionConfig(BaseModel):
    version_number: int
    published: bool
    general_prompt: str
    llm: LLMConfig
    intents: List[IntentConfig]


class ProjectConfig(BaseModel):
    name: str
    enabled: bool = True
    last_version_number: int
    versions: List[VersionConfig]


class UserConfig(BaseModel):
    username: str
    password_hash: str
    salt: str


class GlobalConfig(BaseModel):
    work_mode: str = Field(..., regex="^(hfcloud|cloud|on-premise)$")
    cloud_token: Optional[str]
    spark_endpoint: str
    users: List[UserConfig]


class RootConfig(BaseModel):
    config: GlobalConfig
    projects: List[ProjectConfig]
    apis: Dict[str, APIConfig]


# === Singleton Loader =======================================================
class ConfigProvider:
    @staticmethod
    @lru_cache
    def get(path: str = None) -> RootConfig:
        cfg_file = pathlib.Path(path) if path else CONFIG_PATH
        with cfg_file.open("r", encoding="utf-8") as f:
            data = jsonc.load(f)
        return RootConfig.parse_obj(data)