rasAli02 commited on
Commit
718ccb6
Β·
1 Parent(s): cacd84c

feat: integrate MongoDB Atlas persistence and update backend config

Browse files
Files changed (1) hide show
  1. backend/app.py +71 -13
backend/app.py CHANGED
@@ -16,10 +16,55 @@ from datetime import datetime, timezone
16
  # ── Import the agent pipeline ───────────────────────────────────────────────
17
  from agents import run_pipeline, generate_social_post
18
 
19
- # ── In-memory store (HF Spaces has no persistent DB) ────────────────────────
20
- # For a real deployment, swap with MongoDB or a HF Dataset-backed store.
21
- _inspections: list = []
22
- _journal: list = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
 
25
  def _now_iso() -> str:
@@ -47,7 +92,7 @@ async def inspect(image_base64: str, notes: str = "", product_spec: str = "", so
47
  "source": source or "upload",
48
  "transcript": transcript,
49
  }
50
- _inspections.insert(0, inspection)
51
 
52
  summary = _summarize(inspection)
53
  return json.dumps({
@@ -60,18 +105,20 @@ async def inspect(image_base64: str, notes: str = "", product_spec: str = "", so
60
 
61
  # ── 2. List inspections ─────────────────────────────────────────────────────
62
  async def list_inspections(limit: int = 50):
63
- items = [_summarize(doc) for doc in _inspections[:limit]]
 
64
  return json.dumps({"items": items, "total": len(items)})
65
 
66
 
67
  # ── 3. Metrics ───────────────────────────────────────────────────────────────
68
  async def metrics():
69
- total = len(_inspections)
 
70
  verdict_counts = {"pass": 0, "warn": 0, "fail": 0}
71
  defect_type_counts = {}
72
  confidences = []
73
 
74
- for doc in _inspections:
75
  summary = _summarize(doc)
76
  v = summary["verdict"] if summary["verdict"] in verdict_counts else "warn"
77
  verdict_counts[v] += 1
@@ -175,10 +222,12 @@ async def blueprint():
175
 
176
  # ── 6. Journal ──────────────────────────────────────────────────────────────
177
  async def journal_list():
 
178
  # Auto-seed if empty
179
- if not _journal:
180
  await _seed_journal()
181
- return json.dumps({"items": _journal, "total": len(_journal)})
 
182
 
183
 
184
  async def journal_create(title: str, body: str, tags: str = ""):
@@ -197,11 +246,14 @@ async def journal_create(title: str, body: str, tags: str = ""):
197
  "x_post": social.get("x_post", ""),
198
  "linkedin_post": social.get("linkedin_post", ""),
199
  }
200
- _journal.insert(0, entry)
201
  return json.dumps(entry)
202
 
203
 
204
  async def _seed_journal():
 
 
 
205
  seeds = [
206
  {
207
  "title": "Kickoff: ForgeSight on AMD Developer Cloud",
@@ -224,13 +276,14 @@ async def _seed_journal():
224
  social = await generate_social_post(s["title"], s["body"])
225
  except Exception:
226
  social = {"x_post": "", "linkedin_post": ""}
227
- _journal.insert(0, {
228
  "id": str(uuid.uuid4()),
229
  "created_at": _now_iso(),
230
  **s,
231
  "x_post": social.get("x_post", ""),
232
  "linkedin_post": social.get("linkedin_post", ""),
233
- })
 
234
 
235
 
236
  # ── Helpers ──────────────────────────────────────────────────────────────────
@@ -370,4 +423,9 @@ with gr.Blocks(title="ForgeSight β€” AMD MI300X QC Copilot") as demo:
370
 
371
 
372
  if __name__ == "__main__":
 
 
 
 
 
373
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
16
  # ── Import the agent pipeline ───────────────────────────────────────────────
17
  from agents import run_pipeline, generate_social_post
18
 
19
+ # ── MONGODB PERSISTENCE (optional, falls back to in-memory) ──────────────────
20
+ MONGO_URL = os.getenv("MONGO_URL", "")
21
+ _db = None
22
+ _inspections_col = None
23
+ _journal_col = None
24
+
25
+ # In-memory fallback
26
+ _mem_inspections: list = []
27
+ _mem_journal: list = []
28
+
29
+ async def _init_db():
30
+ """Attempt to connect to MongoDB; silently fall back to in-memory if unavailable."""
31
+ global _db, _inspections_col, _journal_col
32
+ if not MONGO_URL:
33
+ return
34
+ try:
35
+ from motor.motor_asyncio import AsyncIOMotorClient
36
+ client = AsyncIOMotorClient(MONGO_URL, serverSelectionTimeoutMS=4000)
37
+ await client.admin.command("ping")
38
+ _db = client["forgesight"]
39
+ _inspections_col = _db["inspections"]
40
+ _journal_col = _db["journal"]
41
+ print("βœ… MongoDB connected – persistence enabled")
42
+ except Exception as e:
43
+ print(f"⚠️ MongoDB unavailable ({e}) – using in-memory storage")
44
+
45
+ async def _db_insert_inspection(doc: dict):
46
+ if _inspections_col is not None:
47
+ await _inspections_col.insert_one({**doc, "_id": doc["id"]})
48
+ else:
49
+ _mem_inspections.insert(0, doc)
50
+
51
+ async def _db_list_inspections(limit=50) -> list:
52
+ if _inspections_col is not None:
53
+ cursor = _inspections_col.find({}, {"_id": 0}).sort("created_at", -1).limit(limit)
54
+ return await cursor.to_list(length=limit)
55
+ return _mem_inspections[:limit]
56
+
57
+ async def _db_insert_journal(doc: dict):
58
+ if _journal_col is not None:
59
+ await _journal_col.insert_one({**doc, "_id": doc["id"]})
60
+ else:
61
+ _mem_journal.insert(0, doc)
62
+
63
+ async def _db_list_journal(limit=50) -> list:
64
+ if _journal_col is not None:
65
+ cursor = _journal_col.find({}, {"_id": 0}).sort("created_at", -1).limit(limit)
66
+ return await cursor.to_list(length=limit)
67
+ return _mem_journal[:limit]
68
 
69
 
70
  def _now_iso() -> str:
 
92
  "source": source or "upload",
93
  "transcript": transcript,
94
  }
95
+ await _db_insert_inspection(inspection)
96
 
97
  summary = _summarize(inspection)
98
  return json.dumps({
 
105
 
106
  # ── 2. List inspections ─────────────────────────────────────────────────────
107
  async def list_inspections(limit: int = 50):
108
+ docs = await _db_list_inspections(limit)
109
+ items = [_summarize(doc) for doc in docs]
110
  return json.dumps({"items": items, "total": len(items)})
111
 
112
 
113
  # ── 3. Metrics ───────────────────────────────────────────────────────────────
114
  async def metrics():
115
+ docs = await _db_list_inspections(500)
116
+ total = len(docs)
117
  verdict_counts = {"pass": 0, "warn": 0, "fail": 0}
118
  defect_type_counts = {}
119
  confidences = []
120
 
121
+ for doc in docs:
122
  summary = _summarize(doc)
123
  v = summary["verdict"] if summary["verdict"] in verdict_counts else "warn"
124
  verdict_counts[v] += 1
 
222
 
223
  # ── 6. Journal ──────────────────────────────────────────────────────────────
224
  async def journal_list():
225
+ docs = await _db_list_journal(50)
226
  # Auto-seed if empty
227
+ if not docs:
228
  await _seed_journal()
229
+ docs = await _db_list_journal(50)
230
+ return json.dumps({"items": docs, "total": len(docs)})
231
 
232
 
233
  async def journal_create(title: str, body: str, tags: str = ""):
 
246
  "x_post": social.get("x_post", ""),
247
  "linkedin_post": social.get("linkedin_post", ""),
248
  }
249
+ await _db_insert_journal(entry)
250
  return json.dumps(entry)
251
 
252
 
253
  async def _seed_journal():
254
+ existing = await _db_list_journal(1)
255
+ if existing:
256
+ return
257
  seeds = [
258
  {
259
  "title": "Kickoff: ForgeSight on AMD Developer Cloud",
 
276
  social = await generate_social_post(s["title"], s["body"])
277
  except Exception:
278
  social = {"x_post": "", "linkedin_post": ""}
279
+ entry = {
280
  "id": str(uuid.uuid4()),
281
  "created_at": _now_iso(),
282
  **s,
283
  "x_post": social.get("x_post", ""),
284
  "linkedin_post": social.get("linkedin_post", ""),
285
+ }
286
+ await _db_insert_journal(entry)
287
 
288
 
289
  # ── Helpers ──────────────────────────────────────────────────────────────────
 
423
 
424
 
425
  if __name__ == "__main__":
426
+ import asyncio
427
+ # Initialize DB before launching
428
+ loop = asyncio.get_event_loop()
429
+ loop.run_until_complete(_init_db())
430
+
431
  demo.launch(server_name="0.0.0.0", server_port=7860)