mendeld commited on
Commit
3c55cf0
·
verified ·
1 Parent(s): 3333dc7

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -261
app.py DELETED
@@ -1,261 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- import secrets
5
- from pathlib import Path
6
- from types import SimpleNamespace
7
- from typing import Any
8
-
9
- # ZeroGPU: import spaces before GPU-sensitive modules.
10
- try:
11
- import spaces
12
- except ImportError:
13
- class _SpacesFallback:
14
- @staticmethod
15
- def GPU(*args, **kwargs):
16
- def deco(fn):
17
- return fn
18
- return deco
19
- spaces = _SpacesFallback()
20
-
21
- import gradio as gr
22
- import uvicorn
23
- from fastapi import FastAPI, Request, HTTPException
24
- from fastapi.responses import JSONResponse, FileResponse, HTMLResponse
25
- from fastapi.middleware.cors import CORSMiddleware
26
- from pydantic import BaseModel, Field
27
- from starlette.middleware.base import BaseHTTPMiddleware
28
- from starlette.middleware.sessions import SessionMiddleware
29
-
30
- from bh56_core import BH56_VERSION, STORE, LIVE_LOG, admin_auth, admin_role
31
- from bh56_ui import (
32
- BASE_CSS,
33
- PAGE_JS,
34
- build_admin_ui,
35
- clean_history,
36
- prepare_message,
37
- generate_answer,
38
- )
39
- from ac_frontend import ac_frontend_html, admin_login_html
40
-
41
- os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "False")
42
- os.environ.setdefault("HF_HUB_DISABLE_TELEMETRY", "1")
43
- os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
44
-
45
- SESSION_SECRET = os.getenv("BH56_SESSION_SECRET", "") or secrets.token_urlsafe(48)
46
-
47
- app = FastAPI(
48
- title=f"Artificial Chachma (AC) {BH56_VERSION}",
49
- docs_url=None,
50
- redoc_url=None,
51
- openapi_url=None,
52
- )
53
- app.add_middleware(SessionMiddleware, secret_key=SESSION_SECRET, https_only=True, same_site="lax", max_age=1800)
54
-
55
- allowed_origins = [
56
- x.strip() for x in os.getenv(
57
- "BH56_CORS_ORIGINS",
58
- "https://5bcheder.com,https://www.5bcheder.com",
59
- ).split(",") if x.strip()
60
- ]
61
- app.add_middleware(
62
- CORSMiddleware,
63
- allow_origins=allowed_origins,
64
- allow_credentials=True,
65
- allow_methods=["GET", "POST"],
66
- allow_headers=["Content-Type", "Authorization", "X-Requested-With"],
67
- )
68
-
69
-
70
- class SecurityHeadersMiddleware(BaseHTTPMiddleware):
71
- async def dispatch(self, request: Request, call_next):
72
- response = await call_next(request)
73
- frame_ancestors = os.getenv(
74
- "BH56_FRAME_ANCESTORS",
75
- "'self' https://huggingface.co https://*.huggingface.co https://5bcheder.com https://www.5bcheder.com https://*.hf.space",
76
- )
77
- response.headers["X-Content-Type-Options"] = "nosniff"
78
- response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
79
- response.headers["Permissions-Policy"] = "geolocation=(self), microphone=(self), camera=()"
80
- response.headers["Content-Security-Policy"] = f"frame-ancestors {frame_ancestors};"
81
- response.headers["Cache-Control"] = "no-store" if request.url.path.startswith("/admin") else "private, max-age=0"
82
- return response
83
-
84
-
85
- app.add_middleware(SecurityHeadersMiddleware)
86
-
87
- ICON_PATH = Path(__file__).with_name("ac_app_icon.png")
88
-
89
-
90
- @app.get("/ac_app_icon.png", include_in_schema=False)
91
- def ac_app_icon():
92
- return FileResponse(str(ICON_PATH), media_type="image/png", headers={"Cache-Control":"public, max-age=86400"})
93
-
94
-
95
- @app.get("/health")
96
- def health():
97
- return JSONResponse({
98
- "ok": True,
99
- "name": "Artificial Chachma (AC)",
100
- "version": BH56_VERSION,
101
- "persistent_storage": STORE.persistent_enabled,
102
- "frontend": "custom-fixed-shell",
103
- })
104
-
105
-
106
- def _session_id(request: Request) -> str:
107
- sid = request.session.get("ac_sid")
108
- if not isinstance(sid, str) or len(sid) < 12:
109
- sid = secrets.token_urlsafe(16)
110
- request.session["ac_sid"] = sid
111
- return sid
112
-
113
-
114
- class ChatPayload(BaseModel):
115
- message: str = Field(min_length=1, max_length=12000)
116
- history: list[dict[str, Any]] = Field(default_factory=list)
117
- mode: str = "Binah"
118
- answer_length: str = "Normal"
119
- study_mode: str = "Explain"
120
-
121
-
122
- @app.get("/", response_class=HTMLResponse, include_in_schema=False)
123
- def home():
124
- return HTMLResponse(ac_frontend_html(is_admin=False))
125
-
126
-
127
- @app.post("/api/chat", include_in_schema=False)
128
- def api_chat(payload: ChatPayload, request: Request):
129
- history = clean_history(payload.history)[-60:]
130
- prepared, _, browser_history, _, _ = prepare_message(
131
- payload.message,
132
- history,
133
- history,
134
- "Saved",
135
- {},
136
- )
137
- fake_request = SimpleNamespace(
138
- session_hash=_session_id(request),
139
- username="",
140
- )
141
- result = generate_answer(
142
- prepared,
143
- browser_history,
144
- "Saved",
145
- {},
146
- payload.mode if payload.mode in {"Chachma", "Binah", "Daas"} else "Binah",
147
- payload.answer_length if payload.answer_length in {"Short", "Normal", "Detailed"} else "Normal",
148
- payload.study_mode if payload.study_mode in {"Explain", "Hint first", "Quiz me", "Study mode"} else "Explain",
149
- fake_request,
150
- )
151
- new_history, _, _, status, details = result
152
- return {
153
- "history": clean_history(new_history),
154
- "status": str(status or ""),
155
- "details": str(details or ""),
156
- }
157
-
158
-
159
- class AdminLoginPayload(BaseModel):
160
- username: str = Field(min_length=1, max_length=120)
161
- password: str = Field(min_length=1, max_length=300)
162
-
163
-
164
- @app.post("/api/admin/login", include_in_schema=False)
165
- def admin_login(payload: AdminLoginPayload, request: Request):
166
- if not admin_auth(payload.username, payload.password):
167
- raise HTTPException(status_code=401, detail="Incorrect username or password.")
168
- request.session["admin_user"] = payload.username.strip()
169
- return {"ok": True}
170
-
171
-
172
- def _admin_from_session(request: Request) -> tuple[str, str]:
173
- user = str(request.session.get("admin_user") or "")
174
- role = admin_role(user)
175
- if role not in {"main", "admin"}:
176
- request.session.pop("admin_user", None)
177
- raise HTTPException(status_code=401, detail="Admin authentication required.")
178
- return user, role
179
-
180
-
181
- @app.get("/admin", response_class=HTMLResponse, include_in_schema=False)
182
- def admin_home(request: Request):
183
- try:
184
- user, role = _admin_from_session(request)
185
- except HTTPException:
186
- return HTMLResponse(admin_login_html())
187
- return HTMLResponse(ac_frontend_html(is_admin=True, username=user, role=role))
188
-
189
-
190
- @app.get("/api/admin/dashboard", include_in_schema=False)
191
- def api_admin_dashboard(request: Request):
192
- user, role = _admin_from_session(request)
193
- cfg = STORE.config()
194
- live = LIVE_LOG.snapshot(100)
195
- return {
196
- "user": user,
197
- "role": "Head Admin" if role == "main" else "Admin",
198
- "version": BH56_VERSION,
199
- "live_requests": len(live),
200
- "emergency_pause": bool(cfg.get("paused")),
201
- "persistent_storage": bool(STORE.persistent_enabled),
202
- }
203
-
204
-
205
- @app.get("/api/admin/chats", include_in_schema=False)
206
- def api_admin_chats(request: Request):
207
- user, role = _admin_from_session(request)
208
- rows = LIVE_LOG.snapshot(200)
209
- if role != "main":
210
- rows = [r for r in rows if r.get("role", "student") == "student"]
211
- rows = list(reversed(rows[-100:]))
212
- return {
213
- "chats": [{
214
- "time": r.get("time", ""),
215
- "session": r.get("session", ""),
216
- "role": r.get("role", "student"),
217
- "mode": r.get("mode", ""),
218
- "user": r.get("user", ""),
219
- "response": r.get("response", ""),
220
- } for r in rows]
221
- }
222
-
223
-
224
- @app.post("/api/admin/logout", include_in_schema=False)
225
- def api_admin_logout(request: Request):
226
- request.session.pop("admin_user", None)
227
- return {"ok": True}
228
-
229
-
230
- # Keep the existing full Gradio admin console available for advanced controls.
231
- # It is NOT the visible student/admin shell, so its page sizing cannot make the
232
- # Hugging Face App tab grow.
233
- admin_ui = build_admin_ui()
234
- app = gr.mount_gradio_app(
235
- app,
236
- admin_ui,
237
- path="/admin-console",
238
- auth=admin_auth,
239
- auth_message="AC Admin — authorized administrators only.",
240
- footer_links=[],
241
- show_error=False,
242
- max_file_size="25mb",
243
- enable_monitoring=False,
244
- mcp_server=False,
245
- ssr_mode=False,
246
- pwa=False,
247
- theme=gr.themes.Base(),
248
- css=BASE_CSS,
249
- js=PAGE_JS,
250
- )
251
-
252
- try:
253
- import spaces.zero as _spaces_zero
254
- if hasattr(_spaces_zero, "startup"):
255
- _spaces_zero.startup()
256
- except Exception as exc:
257
- print(f"[AC ZeroGPU] startup report note: {exc}")
258
-
259
- if __name__ == "__main__":
260
- port = int(os.getenv("GRADIO_SERVER_PORT", os.getenv("PORT", "7860")))
261
- uvicorn.run(app, host="0.0.0.0", port=port, log_level="info")