File size: 4,660 Bytes
4289ed3
 
c9fab0c
 
 
9bf7fc2
c9fab0c
 
 
86d056b
9bf7fc2
 
07505ba
ff0ff86
c9fab0c
9bf7fc2
1618cb4
9bf7fc2
 
 
ee2e962
 
1a9eef9
 
 
86d056b
9609347
9bf7fc2
c9fab0c
 
 
 
 
 
e96aee8
c9fab0c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e96aee8
 
 
 
 
 
c9fab0c
e96aee8
c9fab0c
 
e96aee8
c9fab0c
9609347
86d056b
 
e96aee8
 
 
 
86d056b
 
554dd77
 
86d056b
554dd77
1a9eef9
 
 
9609347
ee2e962
 
 
 
 
 
 
 
 
9bf7fc2
 
9609347
9bf7fc2
2cfcf56
9609347
2cfcf56
4aebf77
ff0ff86
 
ee2e962
0c928ad
 
 
 
 
 
ee2e962
 
4aebf77
9bf7fc2
 
4aebf77
9bf7fc2
 
 
 
 
 
 
9609347
4289ed3
 
 
 
 
 
 
9609347
f394afd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import asyncio
from contextlib import asynccontextmanager
import os
import threading
from dotenv import load_dotenv
from fastapi.responses import RedirectResponse
from config import SanatanConfig
from db import SanatanDatabase
from drive_downloader import ZipDownloader
from modules.firebase.listener import start_firestore_listener
import uvicorn
from fastapi import FastAPI
from modules.dropbox.audio import cleanup_audio_url_cache
# from modules.home.app import home_app
from modules.youtube_metadata.app import initialize_youtube_metadata_and_poll, youtube_metadata_app
from server import router as mobile_router
# from app import gradio_app  # your Blocks object
import gradio as gr
import logging
from fastapi import Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from contextlib import asynccontextmanager

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()

logger.setLevel(logging.INFO)


def init():
    logger.info("Application Initializing ...")
    load_dotenv(override=True)
    try:
        SanatanDatabase().test_sanity()
    except Exception as e:
        logger.warning("Sanity Test Failed - %s", e)
        logger.info("Downloading database ...")
        downloader = ZipDownloader(
            service_account_json=os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON")
        )
        zip_path = downloader.download_zip_from_drive(
            file_id=os.getenv("CHROMADB_FILE_ID"),
            output_path=SanatanConfig.dbStorePath,
        )
        downloader.unzip(zip_path, extract_to="./")

    # add global index
    # delete taniyan records
    logger.info("STARTED: Deleting Taniyans ...")
    sanatanDatabase = SanatanDatabase()
    sanatanDatabase.delete_taniyans_in_divya_prabandham()
    logger.info("STARED: Building Global Index for all scriptures ...")
    sanatanDatabase.build_global_index_for_all_scriptures()
    logger.info("FINISHED: Building Global Index for all scriptures ...")
    # Launch the whole thing in a background thread
    logger.info("STARTED: Initializing youtube metadata poller...")
    yt_init_thread = threading.Thread(target=initialize_youtube_metadata_and_poll, daemon=True)
    yt_init_thread.start()
    logger.info("FINISHED: Initializing youtube metadata poller...")


@asynccontextmanager
async def fn_lifespan(app: FastAPI):
    logging.info("πŸš€ Starting Lifespan ...")
    ######  Initialize the database ######
    init()
    ######  Initialize the database ######
    logging.info("πŸš€ Starting Firestore listener...")
    start_firestore_listener()
    yield
    logging.info("πŸ›‘ Firestore listener shutdown (no explicit cleanup needed).")
    
app = FastAPI(title="Sanatan AI Unified Server",lifespan=fn_lifespan)
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

# Allow all origins (for dev)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # or ["https://your-flutter-web-app.com"]
    allow_credentials=True,
    allow_methods=["*"],  # GET, POST, PUT, DELETE, OPTIONS
    allow_headers=["*"],  # e.g. Authorization, Content-Type
)

# Mount mobile endpoints
app.include_router(mobile_router, prefix="/api")

# Convert Gradio Blocks to ASGI app
# app = gr.mount_gradio_app(app, gradio_app,"/sanatan_ai_web")

# app = gr.mount_gradio_app(app, youtube_metadata_app,"/yt_web")

##### Commenting out to bypass GRADIO ISSUES ON 24-Nov-2025
# app = gr.mount_gradio_app(app, home_app,"/web")

from fastapi.responses import FileResponse

@app.get("/firebase-messaging-sw.js")
async def firebase_sw():
    return FileResponse("static/firebase-messaging-sw.js")

app.mount("/home", StaticFiles(directory="static", html=True), name="static")

# Redirect root URL to /home/
@app.get("/")
async def redirect_to_web():
    return RedirectResponse(url="/home/")

@app.middleware("http")
async def log_requests(request: Request, call_next):
    logging.info(f"Request: {request.method} {request.url}")
    response = await call_next(request)
    logging.info(f"Response status: {response.status_code}")
    return response

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup code: start cache cleanup
    asyncio.create_task(cleanup_audio_url_cache())
    yield
    # Shutdown code (optional) can go here

if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=False, access_log=False, log_level=logging.WARNING)