-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.py
More file actions
116 lines (89 loc) · 3.65 KB
/
config.py
File metadata and controls
116 lines (89 loc) · 3.65 KB
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
# -*- coding: utf-8 -*-
# config.py
"""
### Description:
Root configuration for AI provider selection, API key resolution, and endpoint setup.
Mirrors the root config.js — loads .env, validates keys, and exposes shared constants
and helpers consumed by all lesson modules.
---
@Author: Claude Sonnet 4.6
@Created on: 09.03.2026
@Based on: `config.js`
"""
import sys
import os
# Force UTF-8 output on Windows (cp1252 terminal can't encode emoji/non-ASCII)
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
from pathlib import Path
from dotenv import load_dotenv
ROOT_DIR = Path(__file__).parent
ROOT_ENV_FILE = ROOT_DIR / ".env"
RESPONSES_ENDPOINTS = {
"openai": "https://api.openai.com/v1/responses",
"openrouter": "https://openrouter.ai/api/v1/responses",
}
VALID_PROVIDERS = {"openai", "openrouter"}
if ROOT_ENV_FILE.exists():
load_dotenv(ROOT_ENV_FILE)
OPENAI_API_KEY: str = (os.environ.get("OPENAI_API_KEY") or "").strip()
OPENROUTER_API_KEY: str = (os.environ.get("OPENROUTER_API_KEY") or "").strip()
_requested_provider: str = (os.environ.get("AI_PROVIDER") or "").strip().lower()
_has_openai_key = bool(OPENAI_API_KEY)
_has_openrouter_key = bool(OPENROUTER_API_KEY)
if not _has_openai_key and not _has_openrouter_key:
print("\033[31mError: API key is not set\033[0m", file=sys.stderr)
print(f" Create: {ROOT_ENV_FILE}", file=sys.stderr)
print(" Add one of:", file=sys.stderr)
print(" OPENAI_API_KEY=sk-...", file=sys.stderr)
print(" OPENROUTER_API_KEY=sk-or-v1-...", file=sys.stderr)
sys.exit(1)
if _requested_provider and _requested_provider not in VALID_PROVIDERS:
print(
"\033[31mError: AI_PROVIDER must be one of: openai, openrouter\033[0m",
file=sys.stderr,
)
sys.exit(1)
def _resolve_provider() -> str:
if _requested_provider:
if _requested_provider == "openai" and not _has_openai_key:
print(
"\033[31mError: AI_PROVIDER=openai requires OPENAI_API_KEY\033[0m",
file=sys.stderr,
)
sys.exit(1)
if _requested_provider == "openrouter" and not _has_openrouter_key:
print(
"\033[31mError: AI_PROVIDER=openrouter requires OPENROUTER_API_KEY\033[0m",
file=sys.stderr,
)
sys.exit(1)
return _requested_provider
return "openai" if _has_openai_key else "openrouter"
AI_PROVIDER: str = _resolve_provider()
print(f"Using AI provider: {AI_PROVIDER}")
AI_API_KEY: str = OPENAI_API_KEY if AI_PROVIDER == "openai" else OPENROUTER_API_KEY
RESPONSES_API_ENDPOINT: str = RESPONSES_ENDPOINTS[AI_PROVIDER]
EXTRA_API_HEADERS: dict = {}
if AI_PROVIDER == "openrouter":
_referer = (os.environ.get("OPENROUTER_HTTP_REFERER") or "").strip()
_app_name = (os.environ.get("OPENROUTER_APP_NAME") or "").strip()
if _referer:
EXTRA_API_HEADERS["HTTP-Referer"] = _referer
if _app_name:
EXTRA_API_HEADERS["X-Title"] = _app_name
def resolve_model_for_provider(model: str) -> str:
"""Return the model identifier adjusted for the active provider.
Args:
model: Base model name, e.g. ``'gpt-5.2'``.
Returns:
Model string ready to send to the API.
Raises:
ValueError: If ``model`` is not a non-empty string.
"""
if not isinstance(model, str) or not model.strip():
raise ValueError("Model must be a non-empty string")
if AI_PROVIDER != "openrouter" or "/" in model:
return model
return f"openai/{model}" if model.startswith("gpt-") else model