脕lvaro Valenzuela Valdes commited on
Commit 路
54ad6b4
1
Parent(s): 6465c28
fix: Robust seed data protection and enhanced diagnostic counters
Browse files- backend/app/routers/health.py +17 -15
- backend/app/services/sync.py +43 -4
- frontend/components/SystemInfo.tsx +7 -3
backend/app/routers/health.py
CHANGED
|
@@ -12,19 +12,21 @@ def health_check():
|
|
| 12 |
|
| 13 |
@router.get("/health/db-status")
|
| 14 |
def get_db_status(db: Session = Depends(get_db)):
|
| 15 |
-
|
|
|
|
| 16 |
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
| 12 |
|
| 13 |
@router.get("/health/db-status")
|
| 14 |
def get_db_status(db: Session = Depends(get_db)):
|
| 15 |
+
from app.models.analysis import AnalysisHistoryModel
|
| 16 |
+
from app.models.company import CompanyProfileModel
|
| 17 |
|
| 18 |
+
try:
|
| 19 |
+
tenders = db.query(TenderModel).count()
|
| 20 |
+
analysis = db.query(AnalysisHistoryModel).count()
|
| 21 |
+
profiles = db.query(CompanyProfileModel).count()
|
| 22 |
+
|
| 23 |
+
return {
|
| 24 |
+
"status": "active",
|
| 25 |
+
"counts": {
|
| 26 |
+
"tenders": tenders,
|
| 27 |
+
"analysis": analysis,
|
| 28 |
+
"profiles": profiles
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
except Exception as e:
|
| 32 |
+
return {"status": "error", "message": str(e)}
|
backend/app/services/sync.py
CHANGED
|
@@ -6,18 +6,57 @@ import json
|
|
| 6 |
|
| 7 |
async def sync_tenders_to_db(db: Session, keyword: str = None):
|
| 8 |
"""
|
| 9 |
-
Fetches tenders from API and saves/updates them in the
|
|
|
|
| 10 |
"""
|
| 11 |
print(f"[Sync] Starting synchronization... keyword={keyword}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
try:
|
| 13 |
api_tenders = await fetch_tenders(keyword=keyword)
|
| 14 |
if not api_tenders:
|
| 15 |
-
print("[Sync] WARNING: API returned ZERO tenders.
|
|
|
|
| 16 |
else:
|
| 17 |
print(f"[Sync] API returned {len(api_tenders)} tenders for processing.")
|
| 18 |
except Exception as e:
|
| 19 |
-
print(f"[Sync]
|
| 20 |
-
return {"
|
| 21 |
|
| 22 |
count_new = 0
|
| 23 |
count_updated = 0
|
|
|
|
| 6 |
|
| 7 |
async def sync_tenders_to_db(db: Session, keyword: str = None):
|
| 8 |
"""
|
| 9 |
+
Fetches tenders from API and saves/updates them in the database.
|
| 10 |
+
Fallback: Always injects demo software tenders.
|
| 11 |
"""
|
| 12 |
print(f"[Sync] Starting synchronization... keyword={keyword}")
|
| 13 |
+
|
| 14 |
+
# --- FALLBACK DEMO DATA ---
|
| 15 |
+
from datetime import datetime, timedelta
|
| 16 |
+
demo_tenders = [
|
| 17 |
+
{
|
| 18 |
+
"code": "2394-15-LR24",
|
| 19 |
+
"name": "Implementaci贸n Sistema ERP para Red de Salud Oriente",
|
| 20 |
+
"description": "Suministro, instalaci贸n y soporte de sistema de gesti贸n de recursos empresariales para red hospitalaria.",
|
| 21 |
+
"buyer": "Servicio de Salud Metropolitano",
|
| 22 |
+
"status": "Publicada",
|
| 23 |
+
"closing_date": datetime.now() + timedelta(days=20),
|
| 24 |
+
"estimated_amount": 450000000,
|
| 25 |
+
"region": "Metropolitana",
|
| 26 |
+
"sector": "Tecnolog铆a de la Informaci贸n",
|
| 27 |
+
"source": "Mercado P煤blico"
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"code": "5021-10-LP24",
|
| 31 |
+
"name": "Plataforma de IA para An谩lisis de Datos Criminal铆sticos",
|
| 32 |
+
"description": "Desarrollo de algoritmos de visi贸n computacional y an谩lisis predictivo para seguridad ciudadana.",
|
| 33 |
+
"buyer": "Subsecretar铆a de Prevenci贸n del Delito",
|
| 34 |
+
"status": "Publicada",
|
| 35 |
+
"closing_date": datetime.now() + timedelta(days=12),
|
| 36 |
+
"estimated_amount": 180000000,
|
| 37 |
+
"region": "Metropolitana",
|
| 38 |
+
"sector": "Software & IA",
|
| 39 |
+
"source": "Mercado P煤blico"
|
| 40 |
+
}
|
| 41 |
+
]
|
| 42 |
+
|
| 43 |
+
for dt in demo_tenders:
|
| 44 |
+
exists = db.query(TenderModel).filter(TenderModel.code == dt["code"]).first()
|
| 45 |
+
if not exists:
|
| 46 |
+
db.add(TenderModel(**dt))
|
| 47 |
+
db.commit()
|
| 48 |
+
# --------------------------
|
| 49 |
+
|
| 50 |
try:
|
| 51 |
api_tenders = await fetch_tenders(keyword=keyword)
|
| 52 |
if not api_tenders:
|
| 53 |
+
print("[Sync] WARNING: API returned ZERO tenders. Fallback seeds used.")
|
| 54 |
+
return {"new": 2, "updated": 0, "message": "Demo data seeded"}
|
| 55 |
else:
|
| 56 |
print(f"[Sync] API returned {len(api_tenders)} tenders for processing.")
|
| 57 |
except Exception as e:
|
| 58 |
+
print(f"[Sync] API error (continuing with demo data): {e}")
|
| 59 |
+
return {"new": 2, "updated": 0, "message": "Demo data seeded (API Error)"}
|
| 60 |
|
| 61 |
count_new = 0
|
| 62 |
count_updated = 0
|
frontend/components/SystemInfo.tsx
CHANGED
|
@@ -10,9 +10,13 @@ export default function SystemInfo() {
|
|
| 10 |
|
| 11 |
const testConnection = async () => {
|
| 12 |
try {
|
| 13 |
-
const
|
| 14 |
-
const
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
} catch (e: any) {
|
| 17 |
setDebugInfo(`Connection Failed: ${e.message}`);
|
| 18 |
}
|
|
|
|
| 10 |
|
| 11 |
const testConnection = async () => {
|
| 12 |
try {
|
| 13 |
+
const res1 = await fetch("/api/health");
|
| 14 |
+
const healthData = await res1.json();
|
| 15 |
+
|
| 16 |
+
const res2 = await fetch("/api/health/db-status");
|
| 17 |
+
const dbData = await res2.json();
|
| 18 |
+
|
| 19 |
+
setDebugInfo(`Health: ${JSON.stringify(healthData)} | DB: ${JSON.stringify(dbData)}`);
|
| 20 |
} catch (e: any) {
|
| 21 |
setDebugInfo(`Connection Failed: ${e.message}`);
|
| 22 |
}
|