ciyidogan commited on
Commit
f0673f4
·
verified ·
1 Parent(s): 447c15c

Update config_provider.py

Browse files
Files changed (1) hide show
  1. config_provider.py +84 -89
config_provider.py CHANGED
@@ -1,130 +1,125 @@
1
  """
2
- Flare – Configuration Loader
3
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
- JSONC (comment-json) desteği
5
- • Pydantic şema + runtime validation
6
- • Global erişim için singleton ConfigProvider.get()
7
  """
8
 
9
- import pathlib
10
- from functools import lru_cache
11
- from typing import Dict, List, Optional
12
-
13
- import commentjson as jsonc
14
- from pydantic import BaseModel, Field, validator
15
 
16
- CONFIG_PATH = pathlib.Path(__file__).parent / "service_config.jsonc"
 
 
 
17
 
 
 
18
 
19
- # === Pydantic Schemas =======================================================
20
  class RetryConfig(BaseModel):
21
- max_attempts: int = 3
 
 
 
22
  backoff_seconds: int = 2
23
- strategy: str = Field("static", regex="^(static|exponential)$")
24
-
25
-
26
- class ProxyConfig(BaseModel):
27
- enabled: bool = False
28
- url: Optional[str] = None
29
-
30
-
31
- class AuthConfig(BaseModel):
32
- enabled: bool = False
33
- token_endpoint: Optional[str] = None
34
- body_template: Dict[str, str] = {}
35
- response_token_path: Optional[str] = None
36
- token_refresh_endpoint: Optional[str] = None
37
- token_refresh_body: Dict[str, str] = {}
38
-
39
- @validator("token_endpoint", always=True)
40
- def _require_endpoint(cls, v, values):
41
- if values["enabled"] and not v:
42
- raise ValueError("Auth enabled but token_endpoint missing")
43
- return v
44
-
45
-
46
- class APIConfig(BaseModel):
47
- url: str
48
- method: str = Field("POST", regex="^(GET|POST|PUT|DELETE|PATCH)$")
49
- headers: Dict[str, str] = {}
50
- body_template: Dict[str, str] = {}
51
- timeout_seconds: int = 10
52
- retry: RetryConfig = RetryConfig()
53
- auth: AuthConfig = AuthConfig()
54
- proxy: ProxyConfig = ProxyConfig()
55
- response_prompt: str
56
 
57
 
58
  class ParameterConfig(BaseModel):
59
  name: str
60
- type: str
61
  required: bool = True
62
- extraction_prompt: str
63
- validation_regex: Optional[str] = None
64
  invalid_prompt: Optional[str] = None
65
- type_error_prompt: Optional[str] = None
66
 
67
 
68
  class IntentConfig(BaseModel):
69
  name: str
70
- caption: Optional[str]
71
- locale: str = "tr-TR"
72
- dependencies: List[str] = []
73
- examples: List[str]
74
- detection_prompt: str
75
- parameters: List[ParameterConfig] = []
76
  action: str
77
- fallback_timeout_prompt: Optional[str] = None
78
  fallback_error_prompt: Optional[str] = None
79
 
80
 
81
- class LLMConfig(BaseModel):
82
- repo_id: str
83
- generation_config: Dict[str, float]
84
- use_fine_tune: bool = False
85
- fine_tune_zip: Optional[str] = None
86
-
87
-
88
  class VersionConfig(BaseModel):
89
- version_number: int
90
- published: bool
91
  general_prompt: str
92
- llm: LLMConfig
93
- intents: List[IntentConfig]
94
 
95
 
96
  class ProjectConfig(BaseModel):
97
  name: str
98
- enabled: bool = True
99
- last_version_number: int
100
  versions: List[VersionConfig]
101
 
102
 
103
- class UserConfig(BaseModel):
104
- username: str
105
- password_hash: str
106
- salt: str
 
107
 
108
 
109
- class GlobalConfig(BaseModel):
110
- work_mode: str = Field(..., regex="^(hfcloud|cloud|on-premise)$")
111
- cloud_token: Optional[str]
112
- spark_endpoint: str
113
- users: List[UserConfig]
 
 
 
 
114
 
115
 
116
- class RootConfig(BaseModel):
117
- config: GlobalConfig
118
  projects: List[ProjectConfig]
119
  apis: Dict[str, APIConfig]
 
 
120
 
121
 
122
- # === Singleton Loader =======================================================
123
  class ConfigProvider:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  @staticmethod
125
- @lru_cache
126
- def get(path: str = None) -> RootConfig:
127
- cfg_file = pathlib.Path(path) if path else CONFIG_PATH
128
- with cfg_file.open("r", encoding="utf-8") as f:
129
- data = jsonc.load(f)
130
- return RootConfig.parse_obj(data)
 
 
 
 
 
 
 
 
 
 
 
 
1
  """
2
+ Flare – ConfigProvider
3
+ ~~~~~~~~~~~~~~~~~~~~~~
4
+ service_config.jsonc dosyasını tek sefer parse eder, nesnelere map eder
5
+ • Pydantic v2 kullanımı (Field(..., pattern=…))
 
6
  """
7
 
8
+ from __future__ import annotations
 
 
 
 
 
9
 
10
+ import json
11
+ import re
12
+ from pathlib import Path
13
+ from typing import Dict, List, Optional
14
 
15
+ from pydantic import BaseModel, Field, HttpUrl, ValidationError
16
+ from utils import log
17
 
18
+ # -------------------- Model tanımları --------------------
19
  class RetryConfig(BaseModel):
20
+ strategy: str = Field( # static | exponential
21
+ "static", pattern=r"^(static|exponential)$"
22
+ )
23
+ retry_count: int = 3
24
  backoff_seconds: int = 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
 
27
  class ParameterConfig(BaseModel):
28
  name: str
29
+ type: str = Field(..., pattern=r"^(int|float|str|bool)$")
30
  required: bool = True
 
 
31
  invalid_prompt: Optional[str] = None
 
32
 
33
 
34
  class IntentConfig(BaseModel):
35
  name: str
 
 
 
 
 
 
36
  action: str
37
+ parameters: List[ParameterConfig] = []
38
  fallback_error_prompt: Optional[str] = None
39
 
40
 
 
 
 
 
 
 
 
41
  class VersionConfig(BaseModel):
42
+ id: int
43
+ caption: str
44
  general_prompt: str
45
+ is_published: bool = Field(False, alias="published")
46
+ intents: List[IntentConfig] = []
47
 
48
 
49
  class ProjectConfig(BaseModel):
50
  name: str
51
+ caption: str
 
52
  versions: List[VersionConfig]
53
 
54
 
55
+ class APIAuthConfig(BaseModel):
56
+ token_endpoint: HttpUrl
57
+ refresh_endpoint: Optional[HttpUrl] = None
58
+ client_id: str
59
+ client_secret: str
60
 
61
 
62
+ class APIConfig(BaseModel):
63
+ name: str
64
+ url: HttpUrl
65
+ method: str = Field("GET", pattern=r"^(GET|POST|PUT|PATCH|DELETE)$")
66
+ timeout_seconds: int = 10
67
+ proxy: Optional[str] = None
68
+ auth: Optional[APIAuthConfig] = None
69
+ response_prompt: Optional[str] = None
70
+ retry: Optional[RetryConfig] = None
71
 
72
 
73
+ class ServiceConfig(BaseModel):
 
74
  projects: List[ProjectConfig]
75
  apis: Dict[str, APIConfig]
76
+ locale: str = "tr-TR"
77
+ retry: RetryConfig = RetryConfig()
78
 
79
 
80
+ # -------------------- Provider singleton ----------------
81
  class ConfigProvider:
82
+ """service_config.jsonc okur, tekil instance döndürür."""
83
+
84
+ _config: Optional[ServiceConfig] = None
85
+ _CONFIG_PATH = Path(__file__).parent / "service_config.jsonc"
86
+
87
+ @classmethod
88
+ def get(cls) -> ServiceConfig:
89
+ if cls._config is None:
90
+ cls._config = cls._load_config()
91
+ return cls._config
92
+
93
+ # ---------------- internal ----------------
94
+ @classmethod
95
+ def _load_config(cls) -> ServiceConfig:
96
+ log(f"📥 Loading service config from {cls._CONFIG_PATH.name} …")
97
+ raw = cls._CONFIG_PATH.read_text(encoding="utf-8")
98
+ json_str = cls._strip_jsonc(raw)
99
+ try:
100
+ data = json.loads(json_str)
101
+ cfg = ServiceConfig.model_validate(data)
102
+ log("✅ Service config loaded successfully.")
103
+ return cfg
104
+ except (json.JSONDecodeError, ValidationError) as exc:
105
+ log(f"❌ Config validation error: {exc}")
106
+ raise
107
+
108
  @staticmethod
109
+ def _strip_jsonc(content: str) -> str:
110
+ """Remove // and /* */ comments for JSONC."""
111
+ # Remove // lines
112
+ content = re.sub(r"//.*", "", content)
113
+ # Remove /* … */ blocks
114
+ content = re.sub(r"/\*.*?\*/", "", content, flags=re.S)
115
+ return content
116
+
117
+
118
+ # --------------- Convenience aliases for imports ---------------
119
+ RetryConfig = RetryConfig
120
+ ParameterConfig = ParameterConfig
121
+ IntentConfig = IntentConfig
122
+ VersionConfig = VersionConfig
123
+ APIConfig = APIConfig
124
+ ProjectConfig = ProjectConfig
125
+ ServiceConfig = ServiceConfig