Spaces:
Running
Running
File size: 4,736 Bytes
87c7efb c40bd8f 87c7efb 04b94fe f0673f4 14b6ee2 f0673f4 04b94fe f0673f4 87c7efb f0673f4 87c7efb c40bd8f f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 87c7efb f0673f4 c40bd8f 87c7efb c40bd8f f0673f4 |
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
"""
Flare – ConfigProvider (JSONC-safe)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
• Pydantic v2 (pattern=…)
• Yorum ayıklayıcı string literal’leri korur
"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Dict, List, Optional
from pydantic import BaseModel, Field, HttpUrl, ValidationError
from utils import log
# -------------------- Model tanımları --------------------
class RetryConfig(BaseModel):
strategy: str = Field("static", pattern=r"^(static|exponential)$")
retry_count: int = 3
backoff_seconds: int = 2
class ParameterConfig(BaseModel):
name: str
type: str = Field(..., pattern=r"^(int|float|str|bool)$")
required: bool = True
invalid_prompt: Optional[str] = None
class IntentConfig(BaseModel):
name: str
action: str
parameters: List[ParameterConfig] = []
fallback_error_prompt: Optional[str] = None
class VersionConfig(BaseModel):
id: int
caption: str
general_prompt: str
is_published: bool = Field(False, alias="published")
intents: List[IntentConfig] = []
class ProjectConfig(BaseModel):
name: str
caption: str
versions: List[VersionConfig]
class APIAuthConfig(BaseModel):
token_endpoint: HttpUrl
refresh_endpoint: Optional[HttpUrl] = None
client_id: str
client_secret: str
class APIConfig(BaseModel):
name: str
url: HttpUrl
method: str = Field("GET", pattern=r"^(GET|POST|PUT|PATCH|DELETE)$")
timeout_seconds: int = 10
proxy: Optional[str] = None
auth: Optional[APIAuthConfig] = None
response_prompt: Optional[str] = None
retry: Optional[RetryConfig] = None
class ServiceConfig(BaseModel):
projects: List[ProjectConfig]
apis: Dict[str, APIConfig]
locale: str = "tr-TR"
retry: RetryConfig = RetryConfig()
# -------------------- Provider singleton ----------------
class ConfigProvider:
_config: Optional[ServiceConfig] = None
_CONFIG_PATH = Path(__file__).parent / "service_config.jsonc"
@classmethod
def get(cls) -> ServiceConfig:
if cls._config is None:
cls._config = cls._load_config()
return cls._config
# ---------------- internal ----------------
@classmethod
def _load_config(cls) -> ServiceConfig:
log(f"📥 Loading service config from {cls._CONFIG_PATH.name} …")
raw = cls._CONFIG_PATH.read_text(encoding="utf-8")
json_str = cls._strip_jsonc(raw)
try:
data = json.loads(json_str)
cfg = ServiceConfig.model_validate(data)
log("✅ Service config loaded successfully.")
return cfg
except (json.JSONDecodeError, ValidationError) as exc:
log(f"❌ Config validation error: {exc}")
raise
# -------- robust JSONC stripper ----------
@staticmethod
def _strip_jsonc(text: str) -> str:
"""Remove // line comments and /* block comments */ without touching string literals."""
OUT, IN_STR, ESC, IN_SLASH, IN_BLOCK = 0, 1, 2, 3, 4
state = OUT
res = []
i = 0
while i < len(text):
ch = text[i]
if state == OUT:
if ch == '"':
state = IN_STR
res.append(ch)
elif ch == '/':
# Could be // or /* – peek next char
nxt = text[i + 1] if i + 1 < len(text) else ""
if nxt == '/':
state = IN_SLASH
i += 1 # skip nxt in loop
elif nxt == '*':
state = IN_BLOCK
i += 1
else:
res.append(ch)
else:
res.append(ch)
elif state == IN_STR:
res.append(ch)
if ch == '\\':
state = ESC # escape next
elif ch == '"':
state = OUT
elif state == ESC:
res.append(ch)
state = IN_STR
elif state == IN_SLASH:
if ch == '\n':
res.append(ch) # keep newline
state = OUT
elif state == IN_BLOCK:
if ch == '*' and i + 1 < len(text) and text[i + 1] == '/':
i += 1 # skip /
state = OUT
i += 1
return ''.join(res)
# --------------- exports ---------------
RetryConfig = RetryConfig
ParameterConfig = ParameterConfig
IntentConfig = IntentConfig
VersionConfig = VersionConfig
APIConfig = APIConfig
ProjectConfig = ProjectConfig
ServiceConfig = ServiceConfig
|