Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -54,7 +54,6 @@ def load_ai_model():
|
|
| 54 |
global ai_generator
|
| 55 |
print("π€ Loading 500M Parameter AI Model (Qwen2.5-0.5B)... This may take a minute.")
|
| 56 |
try:
|
| 57 |
-
# Qwen 0.5B ek chota aur bohot smart model hai jo CPU par achha chalta hai
|
| 58 |
model_id = "Qwen/Qwen2.5-0.5B-Instruct"
|
| 59 |
ai_generator = pipeline(
|
| 60 |
"text-generation",
|
|
@@ -69,28 +68,24 @@ def load_ai_model():
|
|
| 69 |
|
| 70 |
# --- 3. ASYNC AI INFERENCE HELPERS ---
|
| 71 |
def _generate_text(prompt: str, max_tokens: int):
|
| 72 |
-
# Chat template format for Instruct models
|
| 73 |
messages = [{"role": "user", "content": prompt}]
|
| 74 |
result = ai_generator(
|
| 75 |
messages,
|
| 76 |
max_new_tokens=max_tokens,
|
| 77 |
do_sample=True,
|
| 78 |
-
temperature=0.
|
| 79 |
top_p=0.9
|
| 80 |
)
|
| 81 |
-
# Return extracted AI response
|
| 82 |
return result[0]['generated_text'][-1]['content']
|
| 83 |
|
| 84 |
async def run_ai_task(prompt: str, max_tokens: int = 150):
|
| 85 |
if not ai_generator:
|
| 86 |
return "AI model is not initialized."
|
| 87 |
|
| 88 |
-
# Check if AI is overloaded
|
| 89 |
if ai_semaphore.locked():
|
| 90 |
return "β οΈ AI Servers are currently at full capacity handling other users. Please try again in a few seconds."
|
| 91 |
|
| 92 |
async with ai_semaphore:
|
| 93 |
-
# Run Heavy AI task in a separate thread so FastAPI doesn't block
|
| 94 |
loop = asyncio.get_event_loop()
|
| 95 |
response = await loop.run_in_executor(None, _generate_text, prompt, max_tokens)
|
| 96 |
return response
|
|
@@ -109,11 +104,10 @@ async def log_query_encrypted(req_id: str, query: str):
|
|
| 109 |
@asynccontextmanager
|
| 110 |
async def lifespan(app: FastAPI):
|
| 111 |
load_dataset()
|
| 112 |
-
# Load AI in background so server starts immediately
|
| 113 |
asyncio.get_event_loop().run_in_executor(None, load_ai_model)
|
| 114 |
yield
|
| 115 |
|
| 116 |
-
app = FastAPI(title="AI
|
| 117 |
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
|
| 118 |
|
| 119 |
|
|
@@ -132,7 +126,6 @@ def perform_core_search(query: str):
|
|
| 132 |
|
| 133 |
scored_results.sort(key=lambda x: x[0], reverse=True)
|
| 134 |
|
| 135 |
-
# π SMART FILTER PREDICTION π
|
| 136 |
best_score = scored_results[0][0] if scored_results else 0
|
| 137 |
if best_score > 85:
|
| 138 |
prediction = "High confidence: We found exact matches for your query."
|
|
@@ -164,12 +157,10 @@ async def standard_search(q: str = Query(...), background_tasks: BackgroundTasks
|
|
| 164 |
background_tasks.add_task(log_query_encrypted, req_id, q)
|
| 165 |
|
| 166 |
is_adult = any(word in q.lower() for word in ["porn", "sex", "xxx", "nude"])
|
| 167 |
-
|
| 168 |
results, prediction = perform_core_search(q)
|
| 169 |
|
| 170 |
-
# AI Summary Generation (Short summary based on top 2 results)
|
| 171 |
ai_summary = "AI Summary not available."
|
| 172 |
-
if results and not ai_semaphore.locked():
|
| 173 |
context = " ".join([r.get("title", "") + ". " + r.get("description", "") for r in results[:2]])
|
| 174 |
prompt = f"Summarize the following search results about '{q}' in 2 short sentences. Results: {context}"
|
| 175 |
ai_summary = await run_ai_task(prompt, max_tokens=60)
|
|
@@ -189,9 +180,39 @@ async def standard_search(q: str = Query(...), background_tasks: BackgroundTasks
|
|
| 189 |
return JSONResponse(content=response, headers={"X-Safety-Message": "you are safe you can do anything"})
|
| 190 |
return response
|
| 191 |
|
| 192 |
-
|
|
|
|
| 193 |
@app.get("/aimode")
|
| 194 |
-
async def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
req_id = str(uuid.uuid4())
|
| 196 |
background_tasks.add_task(log_query_encrypted, req_id, q)
|
| 197 |
|
|
@@ -200,30 +221,43 @@ async def ai_mode_search(q: str = Query(...), background_tasks: BackgroundTasks
|
|
| 200 |
if not results:
|
| 201 |
return {
|
| 202 |
"ai_response": f"I couldn't find any information about '{q}' in my database to give you an accurate answer.",
|
|
|
|
| 203 |
"results": []
|
| 204 |
}
|
| 205 |
|
| 206 |
-
# Build RAG Context
|
| 207 |
context = ""
|
| 208 |
-
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
|
| 211 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
User Query: {q}
|
| 213 |
|
| 214 |
Search Results Data:
|
| 215 |
{context}
|
| 216 |
|
|
|
|
| 217 |
Answer:"""
|
| 218 |
|
|
|
|
| 219 |
ai_reply = await run_ai_task(prompt, max_tokens=250)
|
| 220 |
|
| 221 |
return {
|
| 222 |
"request_id": req_id,
|
| 223 |
"ai_response": ai_reply,
|
| 224 |
"smart_prediction": prediction,
|
| 225 |
-
"
|
| 226 |
-
"results": results[:5]
|
| 227 |
}
|
| 228 |
|
| 229 |
if __name__ == "__main__":
|
|
|
|
| 54 |
global ai_generator
|
| 55 |
print("π€ Loading 500M Parameter AI Model (Qwen2.5-0.5B)... This may take a minute.")
|
| 56 |
try:
|
|
|
|
| 57 |
model_id = "Qwen/Qwen2.5-0.5B-Instruct"
|
| 58 |
ai_generator = pipeline(
|
| 59 |
"text-generation",
|
|
|
|
| 68 |
|
| 69 |
# --- 3. ASYNC AI INFERENCE HELPERS ---
|
| 70 |
def _generate_text(prompt: str, max_tokens: int):
|
|
|
|
| 71 |
messages = [{"role": "user", "content": prompt}]
|
| 72 |
result = ai_generator(
|
| 73 |
messages,
|
| 74 |
max_new_tokens=max_tokens,
|
| 75 |
do_sample=True,
|
| 76 |
+
temperature=0.6, # Thoda kam temperature taaki precise answer de
|
| 77 |
top_p=0.9
|
| 78 |
)
|
|
|
|
| 79 |
return result[0]['generated_text'][-1]['content']
|
| 80 |
|
| 81 |
async def run_ai_task(prompt: str, max_tokens: int = 150):
|
| 82 |
if not ai_generator:
|
| 83 |
return "AI model is not initialized."
|
| 84 |
|
|
|
|
| 85 |
if ai_semaphore.locked():
|
| 86 |
return "β οΈ AI Servers are currently at full capacity handling other users. Please try again in a few seconds."
|
| 87 |
|
| 88 |
async with ai_semaphore:
|
|
|
|
| 89 |
loop = asyncio.get_event_loop()
|
| 90 |
response = await loop.run_in_executor(None, _generate_text, prompt, max_tokens)
|
| 91 |
return response
|
|
|
|
| 104 |
@asynccontextmanager
|
| 105 |
async def lifespan(app: FastAPI):
|
| 106 |
load_dataset()
|
|
|
|
| 107 |
asyncio.get_event_loop().run_in_executor(None, load_ai_model)
|
| 108 |
yield
|
| 109 |
|
| 110 |
+
app = FastAPI(title="Nebulix AI Search Engine", lifespan=lifespan)
|
| 111 |
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
|
| 112 |
|
| 113 |
|
|
|
|
| 126 |
|
| 127 |
scored_results.sort(key=lambda x: x[0], reverse=True)
|
| 128 |
|
|
|
|
| 129 |
best_score = scored_results[0][0] if scored_results else 0
|
| 130 |
if best_score > 85:
|
| 131 |
prediction = "High confidence: We found exact matches for your query."
|
|
|
|
| 157 |
background_tasks.add_task(log_query_encrypted, req_id, q)
|
| 158 |
|
| 159 |
is_adult = any(word in q.lower() for word in ["porn", "sex", "xxx", "nude"])
|
|
|
|
| 160 |
results, prediction = perform_core_search(q)
|
| 161 |
|
|
|
|
| 162 |
ai_summary = "AI Summary not available."
|
| 163 |
+
if results and not ai_semaphore.locked():
|
| 164 |
context = " ".join([r.get("title", "") + ". " + r.get("description", "") for r in results[:2]])
|
| 165 |
prompt = f"Summarize the following search results about '{q}' in 2 short sentences. Results: {context}"
|
| 166 |
ai_summary = await run_ai_task(prompt, max_tokens=60)
|
|
|
|
| 180 |
return JSONResponse(content=response, headers={"X-Safety-Message": "you are safe you can do anything"})
|
| 181 |
return response
|
| 182 |
|
| 183 |
+
|
| 184 |
+
# π FAST AI MODE (Short Answer: 20-25 Tokens) π
|
| 185 |
@app.get("/aimode")
|
| 186 |
+
async def ai_mode_short(q: str = Query(...), background_tasks: BackgroundTasks = BackgroundTasks()):
|
| 187 |
+
req_id = str(uuid.uuid4())
|
| 188 |
+
background_tasks.add_task(log_query_encrypted, req_id, q)
|
| 189 |
+
|
| 190 |
+
results, prediction = perform_core_search(q)
|
| 191 |
+
|
| 192 |
+
if not results:
|
| 193 |
+
return {"ai_response": "No relevant info found.", "results": []}
|
| 194 |
+
|
| 195 |
+
context = " ".join([f"{r.get('title', '')} - {r.get('description', '')}" for r in results[:2]])
|
| 196 |
+
|
| 197 |
+
prompt = f"""You are a smart Search Assistant. Answer the user's query based on the context in exactly 20 to 25 words. Be direct.
|
| 198 |
+
User Query: {q}
|
| 199 |
+
Context: {context}
|
| 200 |
+
Short Answer:"""
|
| 201 |
+
|
| 202 |
+
# Max tokens limited to 35 to ensure the answer stays around 20-25 words
|
| 203 |
+
ai_reply = await run_ai_task(prompt, max_tokens=35)
|
| 204 |
+
|
| 205 |
+
return {
|
| 206 |
+
"request_id": req_id,
|
| 207 |
+
"ai_response": ai_reply,
|
| 208 |
+
"smart_prediction": prediction,
|
| 209 |
+
"results": results[:5]
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
# π NEW: SMART CHAT RAG MODE (Deep Answer: 250 Tokens + URLs) π
|
| 214 |
+
@app.get("/aimodechat")
|
| 215 |
+
async def ai_mode_chat(q: str = Query(...), background_tasks: BackgroundTasks = BackgroundTasks()):
|
| 216 |
req_id = str(uuid.uuid4())
|
| 217 |
background_tasks.add_task(log_query_encrypted, req_id, q)
|
| 218 |
|
|
|
|
| 221 |
if not results:
|
| 222 |
return {
|
| 223 |
"ai_response": f"I couldn't find any information about '{q}' in my database to give you an accurate answer.",
|
| 224 |
+
"sources": [],
|
| 225 |
"results": []
|
| 226 |
}
|
| 227 |
|
| 228 |
+
# Build Deep RAG Context & Extract Sources
|
| 229 |
context = ""
|
| 230 |
+
sources_used = []
|
| 231 |
+
|
| 232 |
+
for i, r in enumerate(results[:4]): # Top 4 results for deep context
|
| 233 |
+
url = r.get("url", "#")
|
| 234 |
+
title = r.get("title", "Unknown Title")
|
| 235 |
+
desc = r.get("description", "")
|
| 236 |
|
| 237 |
+
context += f"Source {i+1} [{title}]: {desc}\n"
|
| 238 |
+
sources_used.append({"id": i+1, "title": title, "url": url})
|
| 239 |
+
|
| 240 |
+
prompt = f"""You are Nebulix AI, a highly intelligent and helpful search assistant.
|
| 241 |
+
Your task is to provide a comprehensive, well-structured, and accurate answer to the user's query using ONLY the provided search results.
|
| 242 |
+
If the search results do not contain the answer, politely say so.
|
| 243 |
+
|
| 244 |
User Query: {q}
|
| 245 |
|
| 246 |
Search Results Data:
|
| 247 |
{context}
|
| 248 |
|
| 249 |
+
Provide a detailed response (up to 250 tokens). Do not include the prompt in your output.
|
| 250 |
Answer:"""
|
| 251 |
|
| 252 |
+
# Generating full 250 tokens deep answer
|
| 253 |
ai_reply = await run_ai_task(prompt, max_tokens=250)
|
| 254 |
|
| 255 |
return {
|
| 256 |
"request_id": req_id,
|
| 257 |
"ai_response": ai_reply,
|
| 258 |
"smart_prediction": prediction,
|
| 259 |
+
"sources": sources_used, # Includes URLs explicitly
|
| 260 |
+
"results": results[:5]
|
| 261 |
}
|
| 262 |
|
| 263 |
if __name__ == "__main__":
|