Files
contexta_be/app/main.py
belviskhoremk 92d4c2fc5e feat: add appointments, campaigns, admin, storage, tests and various updates
- Add new routers: admin, appointments, campaigns
- Add storage service and logging config
- Add migrations directory and test suite with pytest config
- Add supabase_migration_features.sql
- Update models, dependencies, config, and existing routers
- Remove whatsapp_service (deleted)
- Update pyproject.toml and uv.lock dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:11:58 +00:00

124 lines
5.6 KiB
Python

from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, Response
import logging
from app.logging_config import configure_logging
configure_logging() # Must be called before any logger is created
from app.config import settings
from app.routers import auth, chatbots, documents, chat, marketplace, billing, models, analytics, inbox, leads, upload
from app.routers.documents import router_url_sources
from app.routers.leads import leads_public_router
from app.routers.channels import router as channels_router, webhook_router as channels_webhook_router
from app.routers import admin as admin_router
from app.routers.appointments import router as appointments_router, public_router as appointments_public_router
from app.routers.campaigns import router as campaigns_router
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("Contexta API starting up...")
logger.info(f"Environment: {settings.app_env}")
logger.info(f"Allowed origins: {settings.allowed_origins_list}")
yield
logger.info("Contexta API shutting down...")
# ── App ──────────────────────────────────────────────────────────────────────────
app = FastAPI(
title="Contexta API",
description="AI Chatbot Platform - Create, deploy and share custom AI chatbots powered by your data",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan,
)
# ── Middleware ─────────────────────────────────────────────────────────────────
app.add_middleware(
CORSMiddleware,
allow_origins=settings.allowed_origins_list,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ── Routers ────────────────────────────────────────────────────────────────────
app.include_router(auth.router, prefix="/api/v1")
app.include_router(chatbots.router, prefix="/api/v1")
app.include_router(documents.router, prefix="/api/v1")
app.include_router(chat.router, prefix="/api/v1")
app.include_router(marketplace.router, prefix="/api/v1")
app.include_router(billing.router, prefix="/api/v1")
app.include_router(models.router, prefix="/api/v1")
app.include_router(analytics.router, prefix="/api/v1")
app.include_router(inbox.router, prefix="/api/v1")
app.include_router(leads.router, prefix="/api/v1")
app.include_router(upload.router, prefix="/api/v1")
app.include_router(router_url_sources, prefix="/api/v1")
app.include_router(leads_public_router, prefix="/api/v1")
app.include_router(channels_router, prefix="/api/v1")
app.include_router(channels_webhook_router, prefix="/api/v1")
app.include_router(appointments_router, prefix="/api/v1")
app.include_router(appointments_public_router, prefix="/api/v1")
app.include_router(campaigns_router, prefix="/api/v1")
app.include_router(admin_router.router, prefix="/api/v1")
# ── Widget ─────────────────────────────────────────────────────────────────────
@app.get("/widget.js", include_in_schema=False)
async def serve_widget():
from app.services.widget import generate_widget_js
return Response(
content=generate_widget_js(settings.app_url),
media_type="application/javascript",
headers={
# Allow any site to load this script tag cross-origin
"Access-Control-Allow-Origin": "*",
# Cache for 1 hour in browsers / CDN; revalidate when stale
"Cache-Control": "public, max-age=3600, stale-while-revalidate=86400",
# Prevent MIME sniffing
"X-Content-Type-Options": "nosniff",
},
)
# ── Health & Info ──────────────────────────────────────────────────────────────
@app.get("/")
async def root():
return {
"name": "Contexta API",
"version": "1.0.0",
"status": "running",
"docs": "/docs",
}
@app.get("/health")
async def health():
return {"status": "healthy", "environment": settings.app_env}
# ── Prometheus Metrics ──────────────────────────────────────────────────────────
try:
from prometheus_fastapi_instrumentator import Instrumentator
Instrumentator().instrument(app).expose(app, endpoint="/metrics", include_in_schema=False)
logger.info("Prometheus metrics enabled at /metrics")
except ImportError:
logger.info("prometheus-fastapi-instrumentator not installed, metrics endpoint disabled")
# ── Sentry ─────────────────────────────────────────────────────────────────────
if settings.sentry_dsn:
import sentry_sdk
sentry_sdk.init(dsn=settings.sentry_dsn, traces_sample_rate=0.1)
logger.info("Sentry initialized")
if __name__ == "__main__":
import uvicorn
uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)