churnsight-ai / main.py
Hasitha16's picture
Update main.py
57d0c46 verified
raw
history blame
6.58 kB
from fastapi import FastAPI, Request, Header, HTTPException, UploadFile, File
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.openapi.utils import get_openapi
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from transformers import pipeline
from io import StringIO
import os, csv, logging
from model import summarize_review, smart_summarize
from typing import Optional
app = FastAPI(
title="🧠 NeuroPulse AI",
description="Multilingual GenAI for smarter feedback — summarization, sentiment, emotion, aspects, Q&A and tags.",
version="2025.1.0",
openapi_url="/openapi.json",
docs_url=None,
redoc_url="/redoc"
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/docs", include_in_schema=False)
def custom_swagger_ui():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title="🧠 Swagger UI - NeuroPulse AI",
swagger_favicon_url="https://cdn-icons-png.flaticon.com/512/3794/3794616.png",
swagger_js_url="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui-bundle.js",
swagger_css_url="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui.css",
)
@app.get("/", response_class=HTMLResponse)
def root():
return open("app/static/index.html").read()
class ReviewInput(BaseModel):
text: str
model: str = "distilbert-base-uncased-finetuned-sst-2-english"
industry: Optional[str] = None
aspects: bool = False
follow_up: Optional[str] = None
product_category: Optional[str] = None
device: Optional[str] = None
intelligence: Optional[bool] = False
verbosity: Optional[str] = "detailed"
explain: Optional[bool] = False
class BulkReviewInput(BaseModel):
reviews: list[str]
model: str = "distilbert-base-uncased-finetuned-sst-2-english"
industry: Optional[list[str]] = None
aspects: bool = False
product_category: Optional[list[str]] = None
device: Optional[list[str]] = None
VALID_API_KEY = "my-secret-key"
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6")
emotion_model = pipeline("text-classification", model="j-hartmann/emotion-english-distilroberta-base", top_k=1)
sentiment_pipelines = {
"distilbert-base-uncased-finetuned-sst-2-english": pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english"),
"nlptown/bert-base-multilingual-uncased-sentiment": pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
}
def auto_fill(value: Optional[str], default: str = "Generic") -> str:
if not value or value.strip().lower() == "auto-detect":
return default
return value
@app.post("/bulk/")
async def bulk(data: BulkReviewInput, x_api_key: str = Header(None)):
if x_api_key != VALID_API_KEY:
raise HTTPException(status_code=401, detail="Invalid or missing API key")
sentiment_pipeline = sentiment_pipelines[data.model]
summaries = summarizer(data.reviews, max_length=80, min_length=20, truncation=True)
sentiments = sentiment_pipeline(data.reviews)
emotions = emotion_model(data.reviews)
results = []
for i, review in enumerate(data.reviews):
label = sentiments[i]["label"]
if "star" in label:
stars = int(label[0])
label = "NEGATIVE" if stars <= 2 else "NEUTRAL" if stars == 3 else "POSITIVE"
result = {
"review": review,
"summary": summaries[i]["summary_text"],
"sentiment": label,
"emotion": emotions[i][0]["label"],
"aspects": [],
"product_category": auto_fill(data.product_category[i]) if data.product_category else None,
"device": auto_fill(data.device[i], "Web") if data.device else None,
"industry": auto_fill(data.industry[i]) if data.industry else None,
}
results.append(result)
return {"results": results}
@app.post("/analyze/")
async def analyze(request: Request, data: ReviewInput, x_api_key: str = Header(None)):
if x_api_key != VALID_API_KEY:
raise HTTPException(status_code=401, detail="Invalid or missing API key")
sentiment_pipeline = sentiment_pipelines.get(data.model)
summary = smart_summarize(data.text) if request.query_params.get("smart") == "1" else summarize_review(data.text)
sentiment = sentiment_pipeline(data.text)[0]
label = sentiment["label"]
if "star" in label:
stars = int(label[0])
label = "NEGATIVE" if stars <= 2 else "NEUTRAL" if stars == 3 else "POSITIVE"
emotion = emotion_model(data.text)[0][0]["label"]
aspects_list = []
if data.aspects:
for asp in ["battery", "price", "camera"]:
if asp in data.text.lower():
asp_result = sentiment_pipeline(asp + " " + data.text)[0]
aspects_list.append({
"aspect": asp,
"sentiment": asp_result["label"],
"score": asp_result["score"]
})
follow_up_response = None
if data.follow_up and data.intelligence:
follow_up_response = f"[Mocked Detailed Answer in {data.verbosity} mode]"
explanation = "This summary was generated using transformer-based sequence modeling and contextual keyword expansion." if data.explain else None
return {
"summary": summary,
"sentiment": {"label": label, "score": sentiment["score"]},
"emotion": emotion,
"aspects": aspects_list,
"follow_up": follow_up_response,
"explanation": explanation,
"product_category": auto_fill(data.product_category),
"device": auto_fill(data.device, "Web"),
"industry": auto_fill(data.industry)
}
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title=app.title,
version=app.version,
description="""
<b><span style='color:#4f46e5'>NeuroPulse AI</span></b> · Smart GenAI Feedback Engine<br>
Summarize reviews, detect sentiment/emotion, extract aspects, tag metadata, and ask GPT follow-ups.
""",
routes=app.routes
)
openapi_schema["openapi"] = "3.0.0"
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi