ciyidogan commited on
Commit
27e2bbc
Β·
verified Β·
1 Parent(s): 5cb59ca

Update config_provider.py

Browse files
Files changed (1) hide show
  1. config_provider.py +108 -14
config_provider.py CHANGED
@@ -5,11 +5,11 @@ Flare – ConfigProvider (date type support)
5
  from __future__ import annotations
6
  import json, os
7
  from pathlib import Path
8
- from typing import Any, Dict, List, Optional
9
  import commentjson
10
 
11
  from utils import log
12
- from pydantic import BaseModel, Field, HttpUrl, ValidationError
13
  from encryption_utils import decrypt
14
 
15
  class GlobalConfig(BaseModel):
@@ -70,9 +70,20 @@ class APIAuthConfig(BaseModel):
70
  enabled: bool = False
71
  token_endpoint: Optional[HttpUrl] = None
72
  response_token_path: str = "access_token"
73
- token_request_body: str = "{}" # JSON string
74
  token_refresh_endpoint: Optional[HttpUrl] = None
75
- token_refresh_body: str = "{}" # JSON string
 
 
 
 
 
 
 
 
 
 
 
76
 
77
  class Config:
78
  extra = "allow"
@@ -89,14 +100,32 @@ class APIConfig(BaseModel):
89
  name: str
90
  url: HttpUrl
91
  method: str = Field("GET", pattern=r"^(GET|POST|PUT|PATCH|DELETE)$")
92
- headers: str = "{}" # JSON string
93
- body_template: str = "{}" # JSON string
94
  timeout_seconds: int = 10
95
  retry: RetryConfig = RetryConfig()
96
- proxy: Optional[str | ProxyConfig] = None
97
  auth: Optional[APIAuthConfig] = None
98
  response_prompt: Optional[str] = None
99
- response_mappings: List[ResponseMappingConfig] = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  class Config:
102
  extra = "allow"
@@ -147,12 +176,22 @@ class LLMConfig(BaseModel):
147
 
148
 
149
  class VersionConfig(BaseModel):
150
- id: int = Field(..., alias="version_number")
 
151
  caption: Optional[str] = ""
152
  published: bool = False
153
  general_prompt: str
154
- llm: "LLMConfig"
155
- intents: List["IntentConfig"]
 
 
 
 
 
 
 
 
 
156
 
157
  class Config:
158
  extra = "allow"
@@ -170,7 +209,7 @@ class ProjectConfig(BaseModel):
170
  supported_languages: List[str] = Field(default_factory=lambda: ["tr"])
171
  timezone: str = "Europe/Istanbul"
172
  region: str = "tr-TR"
173
- last_version_number: Optional[int] = None
174
  versions: List[VersionConfig]
175
 
176
  # Audit fields
@@ -184,11 +223,29 @@ class ProjectConfig(BaseModel):
184
  extra = "allow"
185
 
186
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  # ---------------- Service Config ---------
188
  class ServiceConfig(BaseModel):
189
  global_config: GlobalConfig = Field(..., alias="config")
190
  projects: List[ProjectConfig]
191
  apis: List[APIConfig]
 
 
 
 
 
 
192
 
193
  # runtime helpers (skip validation)
194
  _api_by_name: Dict[str, APIConfig] = {}
@@ -196,8 +253,39 @@ class ServiceConfig(BaseModel):
196
  def build_index(self):
197
  self._api_by_name = {a.name: a for a in self.apis}
198
 
199
- def get_api(self, name: str) -> APIConfig | None:
200
  return self._api_by_name.get(name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
 
203
  # ---------------- Provider Singleton -----
@@ -275,4 +363,10 @@ class ConfigProvider:
275
  log("βœ… Running in on-premise mode with .env file")
276
  else:
277
  log("⚠️ Running in on-premise mode but .env file not found")
278
- log("πŸ“Œ Copy .env.example to .env and configure it")
 
 
 
 
 
 
 
5
  from __future__ import annotations
6
  import json, os
7
  from pathlib import Path
8
+ from typing import Any, Dict, List, Optional, Union
9
  import commentjson
10
 
11
  from utils import log
12
+ from pydantic import BaseModel, Field, HttpUrl, ValidationError, field_validator
13
  from encryption_utils import decrypt
14
 
15
  class GlobalConfig(BaseModel):
 
70
  enabled: bool = False
71
  token_endpoint: Optional[HttpUrl] = None
72
  response_token_path: str = "access_token"
73
+ token_request_body: Dict[str, Any] = Field({}, alias="body_template")
74
  token_refresh_endpoint: Optional[HttpUrl] = None
75
+ token_refresh_body: Dict[str, Any] = {}
76
+
77
+ @field_validator('token_request_body', 'token_refresh_body', mode='before')
78
+ def parse_json_strings(cls, v):
79
+ """Parse JSON strings to dict"""
80
+ if isinstance(v, str):
81
+ try:
82
+ return json.loads(v)
83
+ except json.JSONDecodeError:
84
+ log(f"⚠️ Invalid JSON string in auth config: {v}")
85
+ return {}
86
+ return v
87
 
88
  class Config:
89
  extra = "allow"
 
100
  name: str
101
  url: HttpUrl
102
  method: str = Field("GET", pattern=r"^(GET|POST|PUT|PATCH|DELETE)$")
103
+ headers: Dict[str, Any] = {}
104
+ body_template: Dict[str, Any] = {}
105
  timeout_seconds: int = 10
106
  retry: RetryConfig = RetryConfig()
107
+ proxy: Optional[Union[str, ProxyConfig]] = None
108
  auth: Optional[APIAuthConfig] = None
109
  response_prompt: Optional[str] = None
110
+ response_mappings: List[ResponseMappingConfig] = [] # Yeni alan
111
+
112
+ # Audit fields
113
+ last_update_date: Optional[str] = None
114
+ last_update_user: Optional[str] = None
115
+ created_date: Optional[str] = None
116
+ created_by: Optional[str] = None
117
+ deleted: bool = False
118
+
119
+ @field_validator('headers', 'body_template', mode='before')
120
+ def parse_json_strings(cls, v):
121
+ """Parse JSON strings to dict"""
122
+ if isinstance(v, str):
123
+ try:
124
+ return json.loads(v)
125
+ except json.JSONDecodeError:
126
+ log(f"⚠️ Invalid JSON string in API config: {v}")
127
+ return {}
128
+ return v
129
 
130
  class Config:
131
  extra = "allow"
 
176
 
177
 
178
  class VersionConfig(BaseModel):
179
+ id: int
180
+ version_number: int
181
  caption: Optional[str] = ""
182
  published: bool = False
183
  general_prompt: str
184
+ llm: LLMConfig
185
+ intents: List[IntentConfig]
186
+
187
+ # Audit fields
188
+ last_update_date: Optional[str] = None
189
+ last_update_user: Optional[str] = None
190
+ created_date: Optional[str] = None
191
+ created_by: Optional[str] = None
192
+ deleted: bool = False
193
+ publish_date: Optional[str] = None
194
+ published_by: Optional[str] = None
195
 
196
  class Config:
197
  extra = "allow"
 
209
  supported_languages: List[str] = Field(default_factory=lambda: ["tr"])
210
  timezone: str = "Europe/Istanbul"
211
  region: str = "tr-TR"
212
+ version_id_counter: int = 1
213
  versions: List[VersionConfig]
214
 
215
  # Audit fields
 
223
  extra = "allow"
224
 
225
 
226
+ # ---------------- Activity Log -----------
227
+ class ActivityLogEntry(BaseModel):
228
+ id: int
229
+ timestamp: str
230
+ user: str
231
+ action: str
232
+ entity_type: str
233
+ entity_id: Optional[int] = None
234
+ entity_name: Optional[str] = None
235
+ details: Optional[str] = None
236
+
237
+
238
  # ---------------- Service Config ---------
239
  class ServiceConfig(BaseModel):
240
  global_config: GlobalConfig = Field(..., alias="config")
241
  projects: List[ProjectConfig]
242
  apis: List[APIConfig]
243
+ activity_log: List[ActivityLogEntry] = []
244
+
245
+ # Config level fields
246
+ project_id_counter: int = 1
247
+ last_update_date: Optional[str] = None
248
+ last_update_user: Optional[str] = None
249
 
250
  # runtime helpers (skip validation)
251
  _api_by_name: Dict[str, APIConfig] = {}
 
253
  def build_index(self):
254
  self._api_by_name = {a.name: a for a in self.apis}
255
 
256
+ def get_api(self, name: str) -> Optional[APIConfig]:
257
  return self._api_by_name.get(name)
258
+
259
+ def to_jsonc_dict(self) -> dict:
260
+ """Convert to dict for saving to JSONC file"""
261
+ data = self.model_dump(by_alias=True, exclude={'_api_by_name'})
262
+
263
+ # Convert API configs
264
+ for api in data.get('apis', []):
265
+ # Convert headers and body_template to JSON strings
266
+ if 'headers' in api and isinstance(api['headers'], dict):
267
+ api['headers'] = json.dumps(api['headers'], ensure_ascii=False)
268
+ if 'body_template' in api and isinstance(api['body_template'], dict):
269
+ api['body_template'] = json.dumps(api['body_template'], ensure_ascii=False)
270
+
271
+ # Convert auth configs
272
+ if 'auth' in api and api['auth']:
273
+ if 'token_request_body' in api['auth'] and isinstance(api['auth']['token_request_body'], dict):
274
+ api['auth']['token_request_body'] = json.dumps(api['auth']['token_request_body'], ensure_ascii=False)
275
+ if 'token_refresh_body' in api['auth'] and isinstance(api['auth']['token_refresh_body'], dict):
276
+ api['auth']['token_refresh_body'] = json.dumps(api['auth']['token_refresh_body'], ensure_ascii=False)
277
+
278
+ return data
279
+
280
+ def save(self):
281
+ """Save configuration to file"""
282
+ config_path = Path(__file__).parent / "service_config.jsonc"
283
+ data = self.to_jsonc_dict()
284
+
285
+ with open(config_path, 'w', encoding='utf-8') as f:
286
+ json.dump(data, f, ensure_ascii=False, indent=2)
287
+
288
+ log("βœ… Configuration saved to service_config.jsonc")
289
 
290
 
291
  # ---------------- Provider Singleton -----
 
363
  log("βœ… Running in on-premise mode with .env file")
364
  else:
365
  log("⚠️ Running in on-premise mode but .env file not found")
366
+ log("πŸ“Œ Copy .env.example to .env and configure it")
367
+
368
+ @classmethod
369
+ def save(cls):
370
+ """Save current configuration to file"""
371
+ if cls._instance:
372
+ cls._instance.save()