-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweb.py
More file actions
211 lines (174 loc) · 6.17 KB
/
Copy pathweb.py
File metadata and controls
211 lines (174 loc) · 6.17 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
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
"""
Main Web Service for CodeBuddy2API
"""
import asyncio
import logging
import time
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from src.codebuddy_router import router as codebuddy_router, lifecycle_manager
from src.codebuddy_auth_router import router as codebuddy_auth_router
from src.settings_router import router as settings_router
from src.frontend_router import router as frontend_router
from src.health_router import health_router
from src.circuit_breaker import CircuitBreakerManager
from src.health_db import HealthDatabase
from src.alerting import AlertManager
from src.credit_checker import credit_checker
from config import get_server_host, get_server_port, get_log_level
logging.basicConfig(
level=getattr(logging, get_log_level().upper()),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
_server_start_time: float = 0.0
@asynccontextmanager
async def lifespan(app: FastAPI):
global _server_start_time
_server_start_time = time.time()
logger.info("Starting CodeBuddy2API Service")
HealthDatabase.get_instance()
cb = CircuitBreakerManager.get_instance()
alert_mgr = AlertManager.get_instance()
cb.set_on_state_change(alert_mgr.on_state_change)
await alert_mgr.start()
from src import health_monitor
await health_monitor.startup()
from src.codebuddy_token_manager import codebuddy_token_manager
await credit_checker.start(codebuddy_token_manager)
try:
await lifecycle_manager.startup()
yield
finally:
await credit_checker.stop()
await alert_mgr.stop()
await lifecycle_manager.shutdown()
logger.info("CodeBuddy2API Service stopped")
app = FastAPI(
title="CodeBuddy2API",
description="CodeBuddy API proxy with OpenAI-compatible interface",
version="2.0.0",
lifespan=lifespan
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(
frontend_router,
tags=["Frontend"]
)
app.include_router(
codebuddy_auth_router,
prefix="/codebuddy",
tags=["CodeBuddy OAuth2 Authentication"]
)
app.include_router(
codebuddy_router,
prefix="/codebuddy",
tags=["CodeBuddy Compatible API"]
)
app.include_router(
settings_router,
prefix="/api",
tags=["Settings Management"]
)
app.include_router(
health_router,
tags=["Health & Circuit Breaker"]
)
@app.get("/health")
async def health_check():
from src.codebuddy_token_manager import codebuddy_token_manager as tm
creds_info = tm.get_credentials_info()
total = len(creds_info)
healthy = sum(
1 for c in creds_info
if not c.get("is_expired") and not c.get("is_exhausted") and not c.get("is_disabled")
)
expired = sum(1 for c in creds_info if c.get("is_expired"))
exhausted = sum(1 for c in creds_info if c.get("is_exhausted") and not c.get("is_expired"))
disabled = sum(1 for c in creds_info if c.get("is_disabled"))
if total == 0 or healthy == 0:
status = "critical"
elif healthy / total < 0.2:
status = "degraded"
else:
status = "healthy"
uptime_seconds = round(time.time() - _server_start_time, 1) if _server_start_time else 0.0
return {
"status": status,
"service": "codebuddy2api",
"total_credentials": total,
"healthy_credentials": healthy,
"expired_credentials": expired,
"exhausted_credentials": exhausted,
"disabled_credentials": disabled,
"server_uptime_seconds": uptime_seconds,
}
@app.get("/health/providers")
async def provider_health():
"""Per-provider health status from the background monitor."""
from src import health_monitor
return health_monitor.get_all_health()
@app.get("/logs")
async def get_request_logs(n: int = 100):
"""Return last N request log entries (JSONL-backed)."""
from src.request_logger import request_logger
entries = request_logger.get_recent(n)
stats = request_logger.get_stats_summary()
return {"stats": stats, "entries": entries}
@app.get("/")
async def root():
return {
"service": "CodeBuddy2API",
"version": "2.0.0",
"description": "CodeBuddy API proxy with OpenAI-compatible interface",
"endpoints": {
"models": "/codebuddy/v1/models",
"chat": "/codebuddy/v1/chat/completions",
"credentials": "/codebuddy/v1/credentials",
"stats": "/codebuddy/v1/stats",
"filter_reload": "/api/filters/reload",
"auth_start": "/codebuddy/auth/start",
"auth_poll": "/codebuddy/auth/poll",
"auth_callback": "/codebuddy/auth/callback",
"get_settings": "/api/settings",
"save_settings": "/api/settings"
}
}
if __name__ == "__main__":
from hypercorn.asyncio import serve
from hypercorn.config import Config
port = get_server_port()
host = get_server_host()
logger.info("=" * 60)
logger.info("Starting CodeBuddy2API")
logger.info("=" * 60)
logger.info(f"Main Service: http://{host}:{port}")
logger.info("=" * 60)
logger.info("Web Interface:")
logger.info(f" Admin Panel: http://{host}:{port}/")
logger.info("=" * 60)
logger.info("API Endpoints:")
logger.info(f" Models: GET http://{host}:{port}/codebuddy/v1/models")
logger.info(f" Chat: POST http://{host}:{port}/codebuddy/v1/chat/completions")
logger.info(f" Credentials: GET http://{host}:{port}/codebuddy/v1/credentials")
logger.info(f" Stats: GET http://{host}:{port}/codebuddy/v1/stats")
logger.info(f" Filter Reload: POST http://{host}:{port}/api/filters/reload")
logger.info("=" * 60)
logger.info("Authentication:")
logger.info(" Set CODEBUDDY_PASSWORD environment variable")
logger.info(" Use Bearer token in Authorization header")
logger.info("=" * 60)
config = Config()
config.bind = [f"{host}:{port}", f"[::]:{port}"]
config.accesslog = None
config.errorlog = "-"
config.loglevel = "INFO"
config.use_colors = True
asyncio.run(serve(app, config))