-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.py
More file actions
131 lines (104 loc) · 4.53 KB
/
main.py
File metadata and controls
131 lines (104 loc) · 4.53 KB
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
from fastapi import FastAPI, HTTPException, Header
from fastapi.middleware.cors import CORSMiddleware
import pandas as pd
import os
from sqlalchemy import create_engine
import json
from fetch_news import get_all_news
from process_data_india import process_and_push_to_db
from fastapi.responses import FileResponse
app = FastAPI(
title="Internal Bharat News API",
description="Serverless API for fetching processed Indian heatmap data."
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/favicon.ico", include_in_schema=False)
async def favicon():
return FileResponse("favicon.ico")
@app.get("/")
async def root():
return {"message": "Bharat News API is live Go to '/api/news' or '/api/news/state_code' . Hit /docs for documentation."}
@app.get("/api/news")
async def get_news():
"""Serves the latest heatmap data with clean, structured arrays."""
try:
db_url = os.environ.get("DATABASE_URL")
if not db_url:
raise HTTPException(status_code=500, detail="Database not configured.")
engine = create_engine(db_url)
df = pd.read_sql("SELECT * FROM heatmap_data", engine)
df.fillna("", inplace=True)
records = df.to_dict(orient='records')
# Unpack the JSON strings back into native arrays
for record in records:
try:
record['headlines'] = json.loads(record['headlines'])
except:
record['headlines'] = []
return records
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/news/{state_code}")
async def get_news_by_state(state_code: str):
"""Fetch news for a specific state using its 2-letter code."""
try:
db_url = os.environ.get("DATABASE_URL")
if not db_url:
raise HTTPException(status_code=500, detail="Database not configured.")
engine = create_engine(db_url)
query = 'SELECT * FROM heatmap_data WHERE "Code" = %(state_code)s'
df = pd.read_sql(query, engine, params={"state_code": state_code.upper()})
if df.empty:
raise HTTPException(status_code=404, detail=f"No news found for state code: {state_code.upper()}")
df.fillna("", inplace=True)
# 1. Extract the single dictionary
record = df.to_dict(orient='records')[0]
# 2. Unpack the stringified database column back into a real Python list
try:
record['headlines'] = json.loads(record['headlines'])
except:
record['headlines'] = []
# 3. Return the clean object
return record
except Exception as e:
if isinstance(e, HTTPException):
raise e
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/cron/update")
async def trigger_update(authorization: str = Header(None)):
"""Vercel Cron hits this endpoint every hour to refresh the database."""
expected_secret = os.environ.get("CRON_SECRET")
if not authorization or authorization != f"Bearer {expected_secret}":
raise HTTPException(status_code=401, detail="Unauthorized.")
try:
print("🚀 Serverless Cron triggered. Fetching news...")
news_data = await get_all_news()
process_and_push_to_db(news_data)
return {"status": "success", "message": "Database updated successfully."}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Pipeline failed: {str(e)}")
@app.get("/api/health")
async def health_check():
"""Instantly verify the freshness of the database."""
try:
db_url = os.environ.get("DATABASE_URL")
if not db_url:
raise HTTPException(status_code=500, detail="Database not configured.")
engine = create_engine(db_url)
# Fetch only the timestamp from a single row
query = 'SELECT last_updated FROM heatmap_data LIMIT 1'
df = pd.read_sql(query, engine)
if df.empty:
return {"status": "empty", "last_updated": None}
return {
"status": "healthy",
"last_updated": df['last_updated'].iloc[0]
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))