import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.routers import analysis, company, health, tenders, documents, oc from app.database import engine, Base, SessionLocal from app.models.tender import TenderModel from app.models.analysis import AnalysisHistoryModel from app.models.company import CompanyProfileModel from app.models.oc import OCModel from app.config import settings from datetime import datetime, timedelta import json # Create tables Base.metadata.create_all(bind=engine) app = FastAPI(title="AndesOps AI") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Routes app.include_router(health.router, prefix="/api", tags=["Health"]) app.include_router(tenders.router, prefix="/api", tags=["Tenders"]) app.include_router(analysis.router, prefix="/api", tags=["Analysis"]) app.include_router(company.router, prefix="/api", tags=["Company"]) app.include_router(documents.router, prefix="/api", tags=["Documents"]) app.include_router(oc.router, prefix="/api", tags=["Purchase Orders"]) @app.on_event("startup") async def startup_event(): print("!!! BACKEND STARTING UP !!!") db = SessionLocal() try: print(f"Checking database at: {settings.database_url}") count = db.query(TenderModel).count() print(f"Current tender count: {count}") if count == 0: print("Auto-seeding database...") # Basic Company Profile - Independent check if not db.query(CompanyProfileModel).first(): print("Seeding Company Profile...") db.add(CompanyProfileModel( name="Andes Digital Solutions", industry="Software Engineering", services="AI & Cloud", experience="10 years", regions="Nacional", documents_available="RUT, Portfolio" )) db.commit() # Software Tenders tenders_to_add = [ TenderModel( code="2394-15-LR24", name="ERP Implementation - Health Sector", description="Large scale ERP for hospital network.", buyer="Servicio de Salud", status="Publicada", closing_date=datetime.now() + timedelta(days=15), estimated_amount=450000000, region="Metropolitana", sector="Software", source="Mercado Público", items=[], attachments=[] ), TenderModel( code="5021-10-LP24", name="AI Platform for Crime Analysis", description="Machine learning and predictive models.", buyer="Subsecretaría de Prevención del Delito", status="Publicada", closing_date=datetime.now() + timedelta(days=10), estimated_amount=180000000, region="Nacional", sector="AI & Software", source="Mercado Público", items=[], attachments=[] ), TenderModel( code="1022-5-LP24", name="Cybersecurity Operations Center (SOC)", description="24/7 monitoring and incident response.", buyer="Ministerio del Interior", status="Publicada", closing_date=datetime.now() + timedelta(days=5), estimated_amount=320000000, region="Metropolitana", sector="Cybersecurity", source="Mercado Público", items=[], attachments=[] ), TenderModel( code="8821-2-LR24", name="Cloud Migration Strategy", description="Migration of legacy systems to AWS/Azure.", buyer="Tesorería General", status="Publicada", closing_date=datetime.now() + timedelta(days=25), estimated_amount=120000000, region="Valparaíso", sector="Cloud", source="Mercado Público", items=[ {"name": "Migration Service", "quantity": 1, "unit": "Unit"}, {"name": "Cloud Storage 100TB", "quantity": 1, "unit": "Year"} ], attachments=[ {"name": "Bases_Tecnicas.pdf", "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"}, {"name": "Anexo_Economico.docx", "url": "https://calibre-ebook.com/downloads/demos/demo.docx"} ] ) ] for t in tenders_to_add: if not db.query(TenderModel).filter(TenderModel.code == t.code).first(): db.add(t) db.commit() except Exception as e: print(f"Seed error: {e}") finally: db.close() @app.get("/") def read_root(): return {"message": "Welcome to AndesOps AI API"}