Hasitha16 commited on
Commit
5053036
Β·
verified Β·
1 Parent(s): 153383c

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +248 -248
main.py CHANGED
@@ -1,249 +1,249 @@
1
- from fastapi import FastAPI, Request, Header, HTTPException
2
- from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
3
- from fastapi.openapi.utils import get_openapi
4
- from fastapi.openapi.docs import get_swagger_ui_html
5
- from pydantic import BaseModel
6
- from transformers import pipeline
7
- from io import StringIO
8
- import os, csv, logging
9
- from openai import OpenAI
10
- from app.model import summarize_review, smart_summarize # import both
11
- from typing import Optional
12
-
13
- app = FastAPI(
14
- title="🧠 NeuroPulse AI",
15
- description="Multilingual GenAI for smarter feedback β€” summarization, sentiment, emotion, aspects, Q&A and tags.",
16
- version="2025.1.0",
17
- openapi_url="/openapi.json",
18
- docs_url=None,
19
- redoc_url="/redoc"
20
- )
21
-
22
- @app.get("/docs", include_in_schema=False)
23
- def custom_swagger_ui():
24
- return get_swagger_ui_html(
25
- openapi_url=app.openapi_url,
26
- title="🧠 Swagger UI - NeuroPulse AI",
27
- swagger_favicon_url="https://cdn-icons-png.flaticon.com/512/3794/3794616.png",
28
- swagger_js_url="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui-bundle.js",
29
- swagger_css_url="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui.css",
30
- )
31
-
32
- @app.get("/", response_class=HTMLResponse)
33
- def root():
34
- return """
35
- <html>
36
- <head>
37
- <title>NeuroPulse AI</title>
38
- <style>
39
- body {
40
- font-family: 'Segoe UI', sans-serif;
41
- background: linear-gradient(135deg, #f0f4ff, #fef3c7);
42
- margin: 0;
43
- padding: 60px;
44
- text-align: center;
45
- color: #1f2937;
46
- }
47
- .container {
48
- background: white;
49
- padding: 40px;
50
- border-radius: 16px;
51
- max-width: 800px;
52
- margin: auto;
53
- box-shadow: 0 10px 30px rgba(0,0,0,0.08);
54
- animation: fadeIn 1s ease-in-out;
55
- }
56
- @keyframes fadeIn {
57
- from {opacity: 0; transform: translateY(20px);}
58
- to {opacity: 1; transform: translateY(0);}
59
- }
60
- h1 {
61
- font-size: 36px;
62
- margin-bottom: 12px;
63
- color: #4f46e5;
64
- }
65
- p {
66
- font-size: 18px;
67
- margin-bottom: 32px;
68
- }
69
- .btn {
70
- display: inline-block;
71
- margin: 8px;
72
- padding: 14px 24px;
73
- border-radius: 8px;
74
- font-weight: 600;
75
- color: white;
76
- text-decoration: none;
77
- background: linear-gradient(90deg, #4f46e5, #6366f1);
78
- transition: all 0.3s ease;
79
- }
80
- .btn:hover {
81
- transform: translateY(-2px);
82
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
83
- }
84
- .btn.red {
85
- background: linear-gradient(90deg, #dc2626, #ef4444);
86
- }
87
- </style>
88
- </head>
89
- <body>
90
- <div class="container">
91
- <h1>🧠 Welcome to <strong>NeuroPulse AI</strong></h1>
92
- <p>Smarter AI feedback analysis β€” Summarization, Sentiment, Emotion, Aspects, LLM Q&A, and Metadata Tags.</p>
93
- <a class="btn" href="/docs">πŸ“˜ Swagger UI</a>
94
- <a class="btn red" href="/redoc">πŸ“• ReDoc</a>
95
- </div>
96
- </body>
97
- </html>
98
- """
99
-
100
- # --- Models ---
101
- class ReviewInput(BaseModel):
102
- text: str
103
- model: str = "distilbert-base-uncased-finetuned-sst-2-english"
104
- industry: str = "Generic"
105
- aspects: bool = False
106
- follow_up: str = None
107
- product_category: str = None
108
- device: str = None
109
-
110
- class BulkReviewInput(BaseModel):
111
- reviews: list[str]
112
- model: str = "distilbert-base-uncased-finetuned-sst-2-english"
113
- industry: Optional[list[str]] = None
114
- aspects: bool = False
115
- product_category: Optional[list[str]] = None
116
- device: Optional[list[str]] = None
117
-
118
- class ChatInput(BaseModel):
119
- question: str
120
- context: str
121
-
122
- class TranslationInput(BaseModel):
123
- text: str
124
- target_lang: str = "fr"
125
-
126
- # --- Auth & Logging ---
127
- VALID_API_KEY = "my-secret-key"
128
- logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
129
-
130
- # --- Load Models Once ---
131
- summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6")
132
- emotion_model = pipeline("text-classification", model="j-hartmann/emotion-english-distilroberta-base", top_k=1)
133
- sentiment_pipelines = {
134
- "distilbert-base-uncased-finetuned-sst-2-english": pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english"),
135
- "nlptown/bert-base-multilingual-uncased-sentiment": pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
136
- }
137
-
138
- # --- Analyze (Bulk) ---
139
- @app.post("/bulk/")
140
- async def bulk(data: BulkReviewInput, x_api_key: str = Header(None)):
141
- if x_api_key != VALID_API_KEY:
142
- raise HTTPException(status_code=401, detail="Invalid or missing API key")
143
-
144
- sentiment_pipeline = sentiment_pipelines[data.model]
145
- summaries = summarizer(data.reviews, max_length=80, min_length=20, truncation=True)
146
- sentiments = sentiment_pipeline(data.reviews)
147
- emotions = emotion_model(data.reviews)
148
-
149
- results = []
150
- for i, review in enumerate(data.reviews):
151
- label = sentiments[i]["label"]
152
- if "star" in label:
153
- stars = int(label[0])
154
- label = "NEGATIVE" if stars <= 2 else "NEUTRAL" if stars == 3 else "POSITIVE"
155
-
156
- result = {
157
- "review": review,
158
- "summary": summaries[i]["summary_text"],
159
- "sentiment": label,
160
- "emotion": emotions[i][0]["label"],
161
- "aspects": [],
162
- "product_category": data.product_category[i] if data.product_category else None,
163
- "device": data.device[i] if data.device else None,
164
- "industry": data.industry[i] if data.industry else None,
165
- }
166
- results.append(result)
167
-
168
- return {"results": results}
169
-
170
- @app.post("/analyze/")
171
- async def analyze(request: Request, data: ReviewInput, x_api_key: str = Header(None), download: str = None):
172
- if x_api_key != VALID_API_KEY:
173
- raise HTTPException(status_code=401, detail="Invalid or missing API key")
174
-
175
- sentiment_pipeline = sentiment_pipelines.get(data.model)
176
- summary = smart_summarize(data.text) if request.query_params.get("smart") == "1" else summarize_review(data.text)
177
- sentiment = sentiment_pipeline(data.text)[0]
178
- label = sentiment["label"]
179
- if "star" in label:
180
- stars = int(label[0])
181
- label = "NEGATIVE" if stars <= 2 else "NEUTRAL" if stars == 3 else "POSITIVE"
182
-
183
- emotion = emotion_model(data.text)[0][0]["label"]
184
-
185
- aspects_list = []
186
- if data.aspects:
187
- for asp in ["battery", "price", "camera"]:
188
- if asp in data.text.lower():
189
- asp_result = sentiment_pipeline(asp + " " + data.text)[0]
190
- aspects_list.append({
191
- "aspect": asp,
192
- "sentiment": asp_result["label"],
193
- "score": asp_result["score"]
194
- })
195
-
196
- follow_up_response = chat_llm(data.follow_up, data.text) if data.follow_up else None
197
-
198
- return {
199
- "summary": summary,
200
- "sentiment": {"label": label, "score": sentiment["score"]},
201
- "emotion": emotion,
202
- "aspects": aspects_list,
203
- "follow_up": follow_up_response,
204
- "product_category": data.product_category,
205
- "device": data.device,
206
- "industry": data.industry
207
- }
208
- # --- Translate ---
209
- @app.post("/translate/")
210
- async def translate(data: TranslationInput):
211
- translator = pipeline("translation", model=f"Helsinki-NLP/opus-mt-en-{data.target_lang}")
212
- return {"translated_text": translator(data.text)[0]["translation_text"]}
213
-
214
- # --- LLM Agent Chat ---
215
- @app.post("/chat/")
216
- async def chat(input: ChatInput, x_api_key: str = Header(None)):
217
- if x_api_key != VALID_API_KEY:
218
- raise HTTPException(status_code=401, detail="Invalid or missing API key")
219
- return {"response": chat_llm(input.question, input.context)}
220
-
221
- def chat_llm(question, context):
222
- client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
223
- res = client.chat.completions.create(
224
- model="gpt-3.5-turbo",
225
- messages=[
226
- {"role": "system", "content": "You are a helpful AI review analyst."},
227
- {"role": "user", "content": f"Context: {context}\nQuestion: {question}"}
228
- ]
229
- )
230
- return res.choices[0].message.content.strip()
231
-
232
- # --- Custom OpenAPI ---
233
- def custom_openapi():
234
- if app.openapi_schema:
235
- return app.openapi_schema
236
- openapi_schema = get_openapi(
237
- title=app.title,
238
- version=app.version,
239
- description="""
240
- <b><span style='color:#4f46e5'>NeuroPulse AI</span></b> Β· Smart GenAI Feedback Engine<br>
241
- Summarize reviews, detect sentiment/emotion, extract aspects, tag metadata, and ask GPT follow-ups.
242
- """,
243
- routes=app.routes
244
- )
245
- openapi_schema["openapi"] = "3.0.0"
246
- app.openapi_schema = openapi_schema
247
- return app.openapi_schema
248
-
249
  app.openapi = custom_openapi
 
1
+ from fastapi import FastAPI, Request, Header, HTTPException
2
+ from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
3
+ from fastapi.openapi.utils import get_openapi
4
+ from fastapi.openapi.docs import get_swagger_ui_html
5
+ from pydantic import BaseModel
6
+ from transformers import pipeline
7
+ from io import StringIO
8
+ import os, csv, logging
9
+ from openai import OpenAI
10
+ from model import summarize_review, smart_summarize
11
+ from typing import Optional
12
+
13
+ app = FastAPI(
14
+ title="🧠 NeuroPulse AI",
15
+ description="Multilingual GenAI for smarter feedback β€” summarization, sentiment, emotion, aspects, Q&A and tags.",
16
+ version="2025.1.0",
17
+ openapi_url="/openapi.json",
18
+ docs_url=None,
19
+ redoc_url="/redoc"
20
+ )
21
+
22
+ @app.get("/docs", include_in_schema=False)
23
+ def custom_swagger_ui():
24
+ return get_swagger_ui_html(
25
+ openapi_url=app.openapi_url,
26
+ title="🧠 Swagger UI - NeuroPulse AI",
27
+ swagger_favicon_url="https://cdn-icons-png.flaticon.com/512/3794/3794616.png",
28
+ swagger_js_url="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui-bundle.js",
29
+ swagger_css_url="https://cdn.jsdelivr.net/npm/[email protected]/swagger-ui.css",
30
+ )
31
+
32
+ @app.get("/", response_class=HTMLResponse)
33
+ def root():
34
+ return """
35
+ <html>
36
+ <head>
37
+ <title>NeuroPulse AI</title>
38
+ <style>
39
+ body {
40
+ font-family: 'Segoe UI', sans-serif;
41
+ background: linear-gradient(135deg, #f0f4ff, #fef3c7);
42
+ margin: 0;
43
+ padding: 60px;
44
+ text-align: center;
45
+ color: #1f2937;
46
+ }
47
+ .container {
48
+ background: white;
49
+ padding: 40px;
50
+ border-radius: 16px;
51
+ max-width: 800px;
52
+ margin: auto;
53
+ box-shadow: 0 10px 30px rgba(0,0,0,0.08);
54
+ animation: fadeIn 1s ease-in-out;
55
+ }
56
+ @keyframes fadeIn {
57
+ from {opacity: 0; transform: translateY(20px);}
58
+ to {opacity: 1; transform: translateY(0);}
59
+ }
60
+ h1 {
61
+ font-size: 36px;
62
+ margin-bottom: 12px;
63
+ color: #4f46e5;
64
+ }
65
+ p {
66
+ font-size: 18px;
67
+ margin-bottom: 32px;
68
+ }
69
+ .btn {
70
+ display: inline-block;
71
+ margin: 8px;
72
+ padding: 14px 24px;
73
+ border-radius: 8px;
74
+ font-weight: 600;
75
+ color: white;
76
+ text-decoration: none;
77
+ background: linear-gradient(90deg, #4f46e5, #6366f1);
78
+ transition: all 0.3s ease;
79
+ }
80
+ .btn:hover {
81
+ transform: translateY(-2px);
82
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
83
+ }
84
+ .btn.red {
85
+ background: linear-gradient(90deg, #dc2626, #ef4444);
86
+ }
87
+ </style>
88
+ </head>
89
+ <body>
90
+ <div class="container">
91
+ <h1>🧠 Welcome to <strong>NeuroPulse AI</strong></h1>
92
+ <p>Smarter AI feedback analysis β€” Summarization, Sentiment, Emotion, Aspects, LLM Q&A, and Metadata Tags.</p>
93
+ <a class="btn" href="/docs">πŸ“˜ Swagger UI</a>
94
+ <a class="btn red" href="/redoc">πŸ“• ReDoc</a>
95
+ </div>
96
+ </body>
97
+ </html>
98
+ """
99
+
100
+ # --- Models ---
101
+ class ReviewInput(BaseModel):
102
+ text: str
103
+ model: str = "distilbert-base-uncased-finetuned-sst-2-english"
104
+ industry: str = "Generic"
105
+ aspects: bool = False
106
+ follow_up: str = None
107
+ product_category: str = None
108
+ device: str = None
109
+
110
+ class BulkReviewInput(BaseModel):
111
+ reviews: list[str]
112
+ model: str = "distilbert-base-uncased-finetuned-sst-2-english"
113
+ industry: Optional[list[str]] = None
114
+ aspects: bool = False
115
+ product_category: Optional[list[str]] = None
116
+ device: Optional[list[str]] = None
117
+
118
+ class ChatInput(BaseModel):
119
+ question: str
120
+ context: str
121
+
122
+ class TranslationInput(BaseModel):
123
+ text: str
124
+ target_lang: str = "fr"
125
+
126
+ # --- Auth & Logging ---
127
+ VALID_API_KEY = "my-secret-key"
128
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
129
+
130
+ # --- Load Models Once ---
131
+ summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6")
132
+ emotion_model = pipeline("text-classification", model="j-hartmann/emotion-english-distilroberta-base", top_k=1)
133
+ sentiment_pipelines = {
134
+ "distilbert-base-uncased-finetuned-sst-2-english": pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english"),
135
+ "nlptown/bert-base-multilingual-uncased-sentiment": pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
136
+ }
137
+
138
+ # --- Analyze (Bulk) ---
139
+ @app.post("/bulk/")
140
+ async def bulk(data: BulkReviewInput, x_api_key: str = Header(None)):
141
+ if x_api_key != VALID_API_KEY:
142
+ raise HTTPException(status_code=401, detail="Invalid or missing API key")
143
+
144
+ sentiment_pipeline = sentiment_pipelines[data.model]
145
+ summaries = summarizer(data.reviews, max_length=80, min_length=20, truncation=True)
146
+ sentiments = sentiment_pipeline(data.reviews)
147
+ emotions = emotion_model(data.reviews)
148
+
149
+ results = []
150
+ for i, review in enumerate(data.reviews):
151
+ label = sentiments[i]["label"]
152
+ if "star" in label:
153
+ stars = int(label[0])
154
+ label = "NEGATIVE" if stars <= 2 else "NEUTRAL" if stars == 3 else "POSITIVE"
155
+
156
+ result = {
157
+ "review": review,
158
+ "summary": summaries[i]["summary_text"],
159
+ "sentiment": label,
160
+ "emotion": emotions[i][0]["label"],
161
+ "aspects": [],
162
+ "product_category": data.product_category[i] if data.product_category else None,
163
+ "device": data.device[i] if data.device else None,
164
+ "industry": data.industry[i] if data.industry else None,
165
+ }
166
+ results.append(result)
167
+
168
+ return {"results": results}
169
+
170
+ @app.post("/analyze/")
171
+ async def analyze(request: Request, data: ReviewInput, x_api_key: str = Header(None), download: str = None):
172
+ if x_api_key != VALID_API_KEY:
173
+ raise HTTPException(status_code=401, detail="Invalid or missing API key")
174
+
175
+ sentiment_pipeline = sentiment_pipelines.get(data.model)
176
+ summary = smart_summarize(data.text) if request.query_params.get("smart") == "1" else summarize_review(data.text)
177
+ sentiment = sentiment_pipeline(data.text)[0]
178
+ label = sentiment["label"]
179
+ if "star" in label:
180
+ stars = int(label[0])
181
+ label = "NEGATIVE" if stars <= 2 else "NEUTRAL" if stars == 3 else "POSITIVE"
182
+
183
+ emotion = emotion_model(data.text)[0][0]["label"]
184
+
185
+ aspects_list = []
186
+ if data.aspects:
187
+ for asp in ["battery", "price", "camera"]:
188
+ if asp in data.text.lower():
189
+ asp_result = sentiment_pipeline(asp + " " + data.text)[0]
190
+ aspects_list.append({
191
+ "aspect": asp,
192
+ "sentiment": asp_result["label"],
193
+ "score": asp_result["score"]
194
+ })
195
+
196
+ follow_up_response = chat_llm(data.follow_up, data.text) if data.follow_up else None
197
+
198
+ return {
199
+ "summary": summary,
200
+ "sentiment": {"label": label, "score": sentiment["score"]},
201
+ "emotion": emotion,
202
+ "aspects": aspects_list,
203
+ "follow_up": follow_up_response,
204
+ "product_category": data.product_category,
205
+ "device": data.device,
206
+ "industry": data.industry
207
+ }
208
+ # --- Translate ---
209
+ @app.post("/translate/")
210
+ async def translate(data: TranslationInput):
211
+ translator = pipeline("translation", model=f"Helsinki-NLP/opus-mt-en-{data.target_lang}")
212
+ return {"translated_text": translator(data.text)[0]["translation_text"]}
213
+
214
+ # --- LLM Agent Chat ---
215
+ @app.post("/chat/")
216
+ async def chat(input: ChatInput, x_api_key: str = Header(None)):
217
+ if x_api_key != VALID_API_KEY:
218
+ raise HTTPException(status_code=401, detail="Invalid or missing API key")
219
+ return {"response": chat_llm(input.question, input.context)}
220
+
221
+ def chat_llm(question, context):
222
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
223
+ res = client.chat.completions.create(
224
+ model="gpt-3.5-turbo",
225
+ messages=[
226
+ {"role": "system", "content": "You are a helpful AI review analyst."},
227
+ {"role": "user", "content": f"Context: {context}\nQuestion: {question}"}
228
+ ]
229
+ )
230
+ return res.choices[0].message.content.strip()
231
+
232
+ # --- Custom OpenAPI ---
233
+ def custom_openapi():
234
+ if app.openapi_schema:
235
+ return app.openapi_schema
236
+ openapi_schema = get_openapi(
237
+ title=app.title,
238
+ version=app.version,
239
+ description="""
240
+ <b><span style='color:#4f46e5'>NeuroPulse AI</span></b> Β· Smart GenAI Feedback Engine<br>
241
+ Summarize reviews, detect sentiment/emotion, extract aspects, tag metadata, and ask GPT follow-ups.
242
+ """,
243
+ routes=app.routes
244
+ )
245
+ openapi_schema["openapi"] = "3.0.0"
246
+ app.openapi_schema = openapi_schema
247
+ return app.openapi_schema
248
+
249
  app.openapi = custom_openapi