Yermek68 commited on
Commit
ac8fce8
·
verified ·
1 Parent(s): 7c1c2e5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -194
app.py CHANGED
@@ -4,247 +4,101 @@ import time
4
  import json
5
  import logging
6
  import traceback
7
- from contextlib import asynccontextmanager
8
- from typing import Dict, Any
9
-
10
  from fastapi import FastAPI, HTTPException
11
  from fastapi.middleware.cors import CORSMiddleware
12
  from pydantic import BaseModel, Field
 
 
13
 
14
- # ===================== ЛОГИРОВАНИЕ =====================
15
-
16
  logging.basicConfig(
17
  level=logging.INFO,
18
  format="%(asctime)s [%(levelname)s] %(message)s",
19
  handlers=[logging.StreamHandler(sys.stderr)],
20
  )
 
21
 
22
- logger = logging.getLogger("eroha-app")
23
-
24
- # ===================== БЕЗОПАСНЫЕ ИМПОРТЫ =====================
25
-
26
  try:
27
  from transformers import pipeline
28
  from langdetect import detect
29
- except Exception as e: # noqa: BLE001
30
- # ВАЖНО: без параметра file=...
31
  logger.error("[ImportError] transformers/langdetect not available: %s", e, exc_info=True)
 
 
32
 
33
- pipeline = None # type: ignore[assignment]
34
- # запасной детектор языка
35
- def detect(text: str) -> str: # type: ignore[no-redef]
36
- return "en"
37
-
38
-
39
- # ===================== НАСТРОЙКИ HF =====================
40
-
41
  HF_HOME = "/tmp/huggingface"
42
  os.environ["HF_HOME"] = HF_HOME
43
  os.makedirs(HF_HOME, exist_ok=True)
44
 
45
- # ===================== Pydantic-модели =====================
46
-
47
-
48
- class SummarizeRequest(BaseModel):
49
- text: str = Field(..., min_length=3, max_length=1_000_000)
50
-
51
- def clean_text(self) -> str:
52
- return self.text.strip()
53
-
54
-
55
- class CheckRequest(BaseModel):
56
- data: str = Field(..., min_length=1, max_length=500_000)
57
-
58
- def clean_text(self) -> str:
59
- return self.data.strip()
60
-
61
-
62
- # ===================== КЭШ МОДЕЛЕЙ =====================
63
-
64
  _model_cache: Dict[str, Any] = {}
65
 
66
-
67
- def safe_detect_lang(text: str) -> str:
68
- try:
69
- lang = detect(text)
70
- return lang or "en"
71
- except Exception: # noqa: BLE001
72
- return "en"
73
-
74
-
75
  def get_model(lang: str):
76
  if pipeline is None:
77
  raise RuntimeError("Transformers pipeline is not available")
78
-
79
  if lang in _model_cache:
80
- logger.info("[ModelCache] Using cached model for %s", lang)
81
  return _model_cache[lang]
82
-
83
  model_map = {
84
  "ru": "IlyaGusev/mbart_ru_sum_gazeta",
85
- "kk": "facebook/mbart-large-50-many-to-many-mmt",
86
- "de": "facebook/bart-large-cnn",
87
- "es": "facebook/mbart-large-50-many-to-many-mmt",
88
- "fr": "facebook/mbart-large-50-many-to-many-mmt",
89
  "en": "facebook/bart-large-cnn",
90
  }
91
  model_name = model_map.get(lang, "facebook/bart-large-cnn")
92
-
93
- logger.info("[ModelLoad] Loading model for %s: %s", lang, model_name)
94
  model = pipeline("summarization", model=model_name, device=-1)
95
  _model_cache[lang] = model
96
- logger.info("[ModelLoad] Cached model for %s", lang)
97
  return model
98
 
99
-
100
- # ===================== LIFESPAN (WARMUP) =====================
101
-
102
  @asynccontextmanager
103
- async def lifespan(app: FastAPI): # noqa: ARG001
104
  start = time.time()
105
- logger.info("[Lifespan] Application startup – warmup models...")
106
-
107
- try:
108
- if pipeline is not None:
109
- for lang in ("en", "ru"):
110
- try:
111
- get_model(lang)
112
- except Exception as e: # noqa: BLE001
113
- logger.error("[Lifespan] Warmup failed for %s: %s", lang, e, exc_info=True)
114
- else:
115
- logger.warning("[Lifespan] transformers pipeline is None – warmup skipped")
116
- except Exception as e: # noqa: BLE001
117
- logger.error("[Lifespan] Warmup error: %s", e, exc_info=True)
118
-
119
- elapsed = time.time() - start
120
- logger.info("[Lifespan] Startup warmup finished in %.2f s", elapsed)
121
-
122
  yield
 
123
 
124
- logger.info("[Lifespan] Application shutdown")
 
125
 
 
 
 
126
 
127
- app = FastAPI(
128
- title="Eroha AI Summarizer PRO",
129
- version="3.4",
130
- lifespan=lifespan,
131
- )
132
-
133
- app.add_middleware(
134
- CORSMiddleware,
135
- allow_origins=["*"],
136
- allow_methods=["*"],
137
- allow_headers=["*"],
138
- )
139
-
140
- # ===================== ЭНДПОИНТЫ =====================
141
-
142
 
 
143
  @app.get("/")
144
  async def root():
145
- return {
146
- "status": "ok",
147
- "version": "v3.4",
148
- "cached_models": list(_model_cache.keys()),
149
- "endpoints": ["/ping", "/check", "/summarize", "/warmup"],
150
- }
151
-
152
 
153
  @app.get("/ping")
154
  async def ping():
155
- return {
156
- "status": "healthy",
157
- "cached_models": list(_model_cache.keys()),
158
- }
159
-
160
-
161
- @app.get("/warmup")
162
- async def warmup():
163
- try:
164
- if pipeline is None:
165
- return {
166
- "status": "skipped",
167
- "reason": "transformers pipeline is not available",
168
- }
169
-
170
- loaded = []
171
- for lang in ("en", "ru"):
172
- try:
173
- get_model(lang)
174
- loaded.append(lang)
175
- except Exception as e: # noqa: BLE001
176
- logger.error("[Warmup] Failed for %s: %s", lang, e, exc_info=True)
177
-
178
- return {
179
- "status": "ok",
180
- "preloaded": loaded,
181
- "cache_size": len(_model_cache),
182
- }
183
- except Exception as e: # noqa: BLE001
184
- logger.error("[Warmup] Error: %s", e, exc_info=True)
185
- raise HTTPException(status_code=500, detail="Warmup failed") from e
186
-
187
-
188
- @app.post("/check")
189
- async def check_text(req: CheckRequest):
190
- try:
191
- text = req.clean_text()
192
- lang = safe_detect_lang(text)
193
- return {
194
- "status": "success",
195
- "preview": text[:150],
196
- "length": len(text),
197
- "detected_language": lang,
198
- }
199
- except Exception as e: # noqa: BLE001
200
- logger.error("/check error: %s", traceback.format_exc())
201
- raise HTTPException(status_code=500, detail=str(e)) from e
202
-
203
 
204
  @app.post("/summarize")
205
  async def summarize(req: SummarizeRequest):
206
- try:
207
- text = req.clean_text()
208
- if not text:
209
- raise HTTPException(status_code=400, detail="Text cannot be empty")
210
-
211
- lang = safe_detect_lang(text)
212
- model = get_model(lang)
213
-
214
- max_input_length = 3000
215
- input_text = text[:max_input_length]
216
-
217
- result = model(input_text, max_length=180, min_length=40, do_sample=False)
218
- summary = result[0]["summary_text"].replace("", " ").strip()
219
-
220
- seo_json_ld = {
221
- "@context": "https://schema.org",
222
- "@type": "NewsArticle",
223
- "headline": summary[:80],
224
- "inLanguage": lang,
225
- "publisher": {
226
- "@type": "Organization",
227
- "name": "Eroha AI Publisher",
228
- },
229
- }
230
-
231
- return {
232
- "status": "success",
233
- "language": lang,
234
- "summary": summary,
235
- "summary_length": len(summary),
236
- "original_length": len(text),
237
- "truncated": len(text) > max_input_length,
238
- "seo_json_ld": seo_json_ld,
239
- }
240
- except HTTPException:
241
- raise
242
- except Exception as e: # noqa: BLE001
243
- logger.error("/summarize error: %s", traceback.format_exc())
244
- raise HTTPException(status_code=500, detail=str(e)) from e
245
-
246
-
247
- if __name__ == "__main__":
248
- import uvicorn
249
-
250
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
4
  import json
5
  import logging
6
  import traceback
 
 
 
7
  from fastapi import FastAPI, HTTPException
8
  from fastapi.middleware.cors import CORSMiddleware
9
  from pydantic import BaseModel, Field
10
+ from contextlib import asynccontextmanager
11
+ from typing import Dict, Any
12
 
13
+ # ======= ЛОГИРОВАНИЕ =======
 
14
  logging.basicConfig(
15
  level=logging.INFO,
16
  format="%(asctime)s [%(levelname)s] %(message)s",
17
  handlers=[logging.StreamHandler(sys.stderr)],
18
  )
19
+ logger = logging.getLogger("eroha-api")
20
 
21
+ # ======= ИМПОРТЫ =======
 
 
 
22
  try:
23
  from transformers import pipeline
24
  from langdetect import detect
25
+ except Exception as e:
 
26
  logger.error("[ImportError] transformers/langdetect not available: %s", e, exc_info=True)
27
+ pipeline = None
28
+ def detect(text): return "en"
29
 
30
+ # ======= НАСТРОЙКИ =======
 
 
 
 
 
 
 
31
  HF_HOME = "/tmp/huggingface"
32
  os.environ["HF_HOME"] = HF_HOME
33
  os.makedirs(HF_HOME, exist_ok=True)
34
 
35
+ # ======= МОДЕЛИ =======
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  _model_cache: Dict[str, Any] = {}
37
 
 
 
 
 
 
 
 
 
 
38
  def get_model(lang: str):
39
  if pipeline is None:
40
  raise RuntimeError("Transformers pipeline is not available")
 
41
  if lang in _model_cache:
 
42
  return _model_cache[lang]
 
43
  model_map = {
44
  "ru": "IlyaGusev/mbart_ru_sum_gazeta",
 
 
 
 
45
  "en": "facebook/bart-large-cnn",
46
  }
47
  model_name = model_map.get(lang, "facebook/bart-large-cnn")
 
 
48
  model = pipeline("summarization", model=model_name, device=-1)
49
  _model_cache[lang] = model
 
50
  return model
51
 
52
+ # ======= FastAPI =======
 
 
53
  @asynccontextmanager
54
+ async def lifespan(app: FastAPI):
55
  start = time.time()
56
+ logger.info("[Startup] warming up models...")
57
+ for lang in ("en", "ru"):
58
+ try: get_model(lang)
59
+ except Exception as e: logger.error("Warmup failed: %s", e)
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  yield
61
+ logger.info("[Shutdown] done")
62
 
63
+ app = FastAPI(title="Eroha Agent API", version="v3.5", lifespan=lifespan)
64
+ app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
65
 
66
+ # ======= МОДЕЛИ ЗАПРОСОВ =======
67
+ class SummarizeRequest(BaseModel):
68
+ text: str = Field(..., min_length=3, max_length=1_000_000)
69
 
70
+ class MemoryRequest(BaseModel):
71
+ key: str
72
+ content: str
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
+ # ======= ЭНДПОИНТЫ =======
75
  @app.get("/")
76
  async def root():
77
+ return {"status": "ok", "version": "v3.5"}
 
 
 
 
 
 
78
 
79
  @app.get("/ping")
80
  async def ping():
81
+ return {"status": "healthy", "cache": list(_model_cache.keys())}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
  @app.post("/summarize")
84
  async def summarize(req: SummarizeRequest):
85
+ lang = "ru" if "а" in req.text.lower() else "en"
86
+ model = get_model(lang)
87
+ result = model(req.text[:2000], max_length=180, min_length=50, do_sample=False)
88
+ return {"summary": result[0]["summary_text"].strip(), "lang": lang}
89
+
90
+ # ======= MEMORY API =======
91
+ @app.post("/memorize")
92
+ async def memorize(req: MemoryRequest):
93
+ with open("memory.json", "a") as f:
94
+ f.write(json.dumps(req.dict(), ensure_ascii=False) + "\\n")
95
+ return {"status": "saved"}
96
+
97
+ @app.post("/retrieve")
98
+ async def retrieve(req: MemoryRequest):
99
+ if not os.path.exists("memory.json"):
100
+ return {"found": []}
101
+ with open("memory.json", "r") as f:
102
+ lines = [json.loads(l) for l in f]
103
+ found = [l for l in lines if req.key.lower() in l["key"].lower()]
104
+ return {"found": found}