Nebulixlabs commited on
Commit
b26652e
·
verified ·
1 Parent(s): 7530207

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +142 -160
app.py CHANGED
@@ -6,79 +6,50 @@ import uvicorn
6
  import re
7
  import multiprocessing
8
  import urllib.parse
9
- import psutil
10
  from contextlib import asynccontextmanager
11
  from fastapi import FastAPI, Query, Form
 
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from huggingface_hub import hf_hub_download
14
- import numpy as np
15
- import bm25s
16
  import aiohttp
17
  from bs4 import BeautifulSoup
 
18
 
19
- # 🔥 COMPREHENSIVE HOTFIX FOR HUGGING FACE SPACES / OPTIMUM
20
- # The new Transformers library removed TensorFlow checks, but Optimum still looks for them.
21
- # We inject these functions into the root namespace BEFORE Optimum imports them.
22
- import transformers
23
- import transformers.utils
24
- import transformers.utils.import_utils
25
-
26
- def _is_false(): return False
27
- def _is_true(): return True
28
-
29
- # Patch the Root Namespace
30
- transformers.is_tf_available = _is_false
31
- transformers.is_torch_available = _is_true
32
- # Patch the Utils Namespace
33
- transformers.utils.is_tf_available = _is_false
34
- transformers.utils.is_torch_available = _is_true
35
- # Patch the Import Utils Namespace
36
- transformers.utils.import_utils.is_tf_available = _is_false
37
- transformers.utils.import_utils.is_torch_available = _is_true
38
-
39
- # NOW it is safe to import optimum
40
- from transformers import AutoTokenizer, pipeline
41
- from optimum.onnxruntime import ORTModelForCausalLM
42
- import onnxruntime as ort
43
-
44
- # --- 1. SETUP & STRICT CPU ALLOCATION ---
45
  TOTAL_CORES = multiprocessing.cpu_count()
46
  AI_CORES = max(1, int(TOTAL_CORES * 0.4))
47
-
48
- # Try to strictly enforce CPU Affinity, fallback safely if Docker/Space restricts permissions
49
- try:
50
- p = psutil.Process()
51
- p.cpu_affinity(list(range(AI_CORES)))
52
- print(f"🖥️ Total Cores: {TOTAL_CORES} | 🔒 Process strictly bound to {AI_CORES} cores.")
53
- except Exception as e:
54
- print(f"🖥️ Total Cores: {TOTAL_CORES} | Allocating {AI_CORES} cores to AI. (Strict affinity skipped: {e})")
55
 
56
  raw_data = []
57
  suggestion_list = []
58
  bm25_index = None
59
-
60
- MAX_CONCURRENT_AI = 1
61
  ai_semaphore = asyncio.Semaphore(MAX_CONCURRENT_AI)
62
  ai_generator = None
63
- ai_tokenizer = None
64
 
65
  # --- TRACKING & TRUST SYSTEM ---
66
- URL_STATS = {}
 
 
67
  AI_RESPONSE_CACHE = {}
68
  MAX_CACHE_SIZE = 5000
69
- STOP_WORDS = ["the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with", "is", "are"]
70
  HF_TOKEN = os.getenv("HF_TOKEN")
71
 
 
72
  ADULT_KEYWORDS = {
73
  "porn", "sex", "nude", "nsfw", "xxx", "adult", "erotic", "onlyfans",
74
- "mms", "chudai", "bhabhi", "devar", "xvideos", "pornhub",
75
- "brazzers", "mia khalifa", "bf video", "blue film", "kamasutra",
76
  "boobs", "tits", "ass", "booty", "naked", "desi porn", "hot desi", "xnxx",
77
  "kacha badam", "ullu", "kooku", "mastram", "gandi baat", "nangi", "nanga",
78
  "sex tape", "milf", "stepmom", "incest", "playboy", "scandal", "leaked"
79
  }
80
 
81
- # --- 2. ADVANCED NLP & ULTRA-FAST INDEXING ---
82
  def tokenize(text):
83
  if not text: return []
84
  tokens = re.findall(r'[a-z0-9]+', str(text).lower())
@@ -93,74 +64,65 @@ def load_and_index_dataset():
93
  try:
94
  dataset_path = hf_hub_download(
95
  repo_id="Nebulixlabs/Ultimate-Search-Engine-Dataset",
96
- filename="dataset.jsonl", repo_type="dataset", token=HF_TOKEN
 
 
97
  )
98
  except Exception as e:
99
  print(f"⚠️ Hugging Face Download failed: {e}")
100
 
101
- boosted_corpus_texts = []
102
- MAX_RECORDS_TO_LOAD = 150000
103
 
104
  if os.path.exists(dataset_path):
105
  with open(dataset_path, "r", encoding="utf-8") as f:
106
  for i, line in enumerate(f):
107
- if i >= MAX_RECORDS_TO_LOAD: break
 
 
108
  if line.strip():
109
  try:
110
  doc = json.loads(line)
111
  url = doc.get("url", "")
112
- title_str = doc.get("title", "")
113
- desc_str = doc.get("description", "")
114
 
115
  if url not in URL_STATS:
116
  URL_STATS[url] = {"user_visits": 0, "ai_visits": 0, "is_trusted": False}
117
 
118
  raw_data.append(doc)
 
 
119
  if title_str and len(title_str) < 60:
120
  suggestion_list.append(title_str.lower())
121
 
122
- # TF weighting before feeding to bm25s
123
- boosted_text = f"{title_str} " * 5 + f"{desc_str} " * 3 + url
124
- boosted_corpus_texts.append(boosted_text)
125
- except: pass
 
 
 
 
126
 
127
- if boosted_corpus_texts:
128
- print("⚡ Building Ultra-Fast BM25s Index (Rust/C Optimized)...")
129
  suggestion_list = sorted(list(set(suggestion_list)))
130
- corpus_tokens = bm25s.tokenize(boosted_corpus_texts, stopwords=STOP_WORDS)
131
- bm25_index = bm25s.BM25()
132
- bm25_index.index(corpus_tokens)
133
- print(f"🚀 Indexing Complete! {len(raw_data)} records ready.")
134
  else:
135
  print("❌ Dataset file not found!")
136
 
137
  def load_ai_models():
138
- global ai_generator, ai_tokenizer
139
- print("🤖 Downloading & Optimizing Ultra-Small 135M Model for ONNX...")
140
  try:
141
- model_id = "HuggingFaceTB/SmolLM2-135M-Instruct"
142
-
143
- # Strictly configure ONNX to use exactly the allowed CPU cores
144
- sess_options = ort.SessionOptions()
145
- sess_options.intra_op_num_threads = AI_CORES
146
- sess_options.inter_op_num_threads = 1
147
-
148
- ai_tokenizer = AutoTokenizer.from_pretrained(model_id)
149
-
150
- # export=True auto-converts the model to ONNX for massive CPU speedup
151
- model = ORTModelForCausalLM.from_pretrained(
152
- model_id,
153
- export=True,
154
- session_options=sess_options
155
- )
156
-
157
  ai_generator = pipeline(
158
  "text-generation",
159
- model=model,
160
- tokenizer=ai_tokenizer,
161
- device=-1 # -1 Forces strictly CPU
162
  )
163
- print("✅ ONNX Accelerated 135M AI Engine Loaded! System ready.")
164
  except Exception as e:
165
  print(f"❌ Model Loading Failed: {e}")
166
 
@@ -176,13 +138,16 @@ async def scrape_and_find_best_chunk(url, query):
176
  if resp.status == 200:
177
  html = await resp.text()
178
  soup = BeautifulSoup(html, "html.parser")
179
- text = " ".join([tag.get_text(strip=True) for tag in soup.find_all(['p', 'h1', 'h2', 'h3'])])
 
 
180
  if not text: return ""
181
 
182
  chunks = chunk_text(text)
183
  query_tokens = set(tokenize(query))
184
 
185
- best_chunk, max_score = "", 0
 
186
  early_stop_threshold = max(1, len(query_tokens) // 2)
187
 
188
  for chunk in chunks:
@@ -198,7 +163,7 @@ async def scrape_and_find_best_chunk(url, query):
198
  return ""
199
  return ""
200
 
201
- # --- 4. CORE SEARCH ALGORITHM (Fast Pre-filtering) ---
202
  async def perform_core_search(raw_query: str):
203
  if not raw_data or not bm25_index:
204
  return [], "Search index not ready.", 0
@@ -207,60 +172,68 @@ async def perform_core_search(raw_query: str):
207
  query_tokens = tokenize(query)
208
  user_wants_adult = any(adult_word in query for adult_word in ADULT_KEYWORDS)
209
 
210
- if query_tokens:
211
- bm25_query_tokens = bm25s.tokenize([query], stopwords=STOP_WORDS)
212
- scores = bm25_index.get_scores(bm25_query_tokens)[0]
213
- else:
214
- scores = np.ones(len(raw_data))
215
-
216
  scored_results = []
217
  seen_urls = set()
218
-
219
- # Fast Pre-filtering
220
- top_n = min(1000, len(scores))
221
- top_indices = np.argsort(scores)[::-1][:top_n]
222
-
223
- for index in top_indices:
224
- score = float(scores[index])
225
- if score < 0.1 and query_tokens: continue
226
 
227
- doc = raw_data[index]
228
- doc_url = doc.get("url", "")
229
-
230
- if doc_url in seen_urls: continue
231
-
232
- parsed_url = urllib.parse.urlparse(doc_url)
233
- domain = parsed_url.netloc.lower().replace("www.", "")
234
- path = parsed_url.path.strip("/")
235
-
236
- doc_title = doc.get("title", "").lower()
237
- doc_desc = doc.get("description", "").lower()
238
- doc_text = doc_title + " " + doc_desc + " " + doc_url
239
-
240
- is_adult_doc = doc.get("tag", "general").lower() in ["adult", "nsfw"] or any(aw in doc_text for aw in ADULT_KEYWORDS)
241
- if not user_wants_adult and is_adult_doc: continue
242
 
243
- final_score = score
244
- query_clean = query.replace(" ", "")
245
- domain_clean = domain.replace(" ", "")
246
-
247
- if query_clean == domain_clean or domain_clean.startswith(query_clean + "."):
248
- final_score *= 50.0 if not path else 10.0
249
- elif query_clean in domain_clean:
250
- final_score *= 25.0 if not path else 5.0
 
 
 
 
 
 
251
 
252
- if query in doc_title: final_score *= 5.0
253
- elif all(word in doc_title for word in query_tokens): final_score *= 3.0
254
- if query in doc_desc: final_score *= 2.0
255
 
256
- stats = URL_STATS.get(doc_url, {"user_visits": 0, "ai_visits": 0, "is_trusted": False})
257
- if stats.get("is_trusted", False): final_score *= 2.0
258
- final_score += (stats.get("user_visits", 0) * 0.05) + (stats.get("ai_visits", 0) * 0.1)
259
-
260
- seen_urls.add(doc_url)
261
- doc_copy = doc.copy()
262
- doc_copy["trust_stats"] = stats
263
- scored_results.append((final_score, doc_copy))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
  scored_results.sort(key=lambda x: x[0], reverse=True)
266
  best_score = scored_results[0][0] if scored_results else 0
@@ -269,29 +242,19 @@ async def perform_core_search(raw_query: str):
269
  final_results = [{"match_score": round(s, 2), **doc} for s, doc in scored_results[:100]]
270
  return final_results, prediction, best_score
271
 
272
- # --- AI GENERATION HELPER (Non-Blocking) ---
273
- def _generate_text_sync(messages, max_tokens: int):
274
- # Formats messages accurately using the model's chat template
275
- prompt = ai_tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
276
-
277
- # Generate output
278
- result = ai_generator(
279
- prompt,
280
- max_new_tokens=max_tokens,
281
- do_sample=True,
282
- temperature=0.3,
283
- top_p=0.85,
284
- return_full_text=False # Ensures we only get the generated answer, not the prompt
285
- )
286
- return result[0]['generated_text'].strip()
287
 
288
  async def run_ai_task(messages, max_tokens: int, query_key: str):
289
  if not ai_generator: return "⚠️ AI Model is starting up."
290
  if query_key in AI_RESPONSE_CACHE: return AI_RESPONSE_CACHE[query_key]
291
 
292
  async with ai_semaphore:
293
- # Pushes generation to a thread so FastAPI doesn't freeze
294
- response = await asyncio.to_thread(_generate_text_sync, messages, max_tokens)
295
  if len(AI_RESPONSE_CACHE) > MAX_CACHE_SIZE: AI_RESPONSE_CACHE.clear()
296
  AI_RESPONSE_CACHE[query_key] = response
297
  return response
@@ -304,7 +267,10 @@ async def lifespan(app: FastAPI):
304
  yield
305
 
306
  app = FastAPI(title="Nebulix Advanced Text AI & RAG Engine", lifespan=lifespan)
307
- app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
 
 
 
308
 
309
  @app.get("/suggest")
310
  async def get_suggestions(q: str = Query(..., min_length=1)):
@@ -314,13 +280,15 @@ async def get_suggestions(q: str = Query(..., min_length=1)):
314
 
315
  @app.post("/track-click")
316
  async def track_url_click(url: str = Query(...)):
317
- if url not in URL_STATS: URL_STATS[url] = {"user_visits": 0, "ai_visits": 0, "is_trusted": False}
 
318
  URL_STATS[url]["user_visits"] += 1
319
  return {"status": "success", "url": url, "visits": URL_STATS[url]["user_visits"]}
320
 
321
  @app.get("/url-stats")
322
  async def get_url_stats(url: str = Query(...)):
323
- return {"url": url, "stats": URL_STATS.get(url, {"user_visits": 0, "ai_visits": 0, "is_trusted": False})}
 
324
 
325
  @app.get("/search")
326
  async def pure_search(q: str = Query(...)):
@@ -337,14 +305,20 @@ async def ai_mode_short(q: str = Query(...)):
337
 
338
  context = " ".join([f"{r.get('title', '')} - {r.get('description', '')}" for r in results[:3]])
339
 
 
340
  messages = [
341
- {"role": "system", "content": "You are a concise AI. Answer in EXACTLY 1 to 2 sentences (Max 80 words). YOU MUST ENCLOSE ANY IMPORTANT KEYWORD, NAME, OR FACTUAL DETAIL IN PARENTHESES, like (this)."},
 
 
 
342
  {"role": "user", "content": f"Query: {q}\nContext: {context}"}
343
  ]
344
 
 
345
  ai_reply = await run_ai_task(messages, 80, query_key=f"short_{q}")
346
  return {"request_id": req_id, "ai_response": ai_reply, "results": results}
347
 
 
348
  async def process_rag_chat(q: str):
349
  req_id = str(uuid.uuid4())
350
  needs_rag = any(w in q.lower() for w in ["what", "who", "where", "how", "why", "tell me", "explain", "latest", "best"])
@@ -355,6 +329,7 @@ async def process_rag_chat(q: str):
355
 
356
  if needs_rag and results:
357
  top_urls = results[:10]
 
358
  tasks = [scrape_and_find_best_chunk(doc["url"], q) for doc in top_urls]
359
  scraped_chunks = await asyncio.gather(*tasks)
360
 
@@ -365,14 +340,21 @@ async def process_rag_chat(q: str):
365
 
366
  if url not in URL_STATS: URL_STATS[url] = {"user_visits": 0, "ai_visits": 0, "is_trusted": False}
367
  URL_STATS[url]["ai_visits"] += 1
368
- if URL_STATS[url]["ai_visits"] >= 100: URL_STATS[url]["is_trusted"] = True
 
 
369
  doc["trust_stats"] = URL_STATS[url]
370
 
371
- context_parts.append(f"Source [{i+1}] ({url}): {chunk if chunk else doc.get('description', '')}")
372
- used_sources.append(doc)
 
 
 
 
373
 
374
  rag_context = "\n".join(context_parts)
375
 
 
376
  system_prompt = "You are a Smart AI Search Assistant. Provide a detailed answer. YOU MUST ENCLOSE EVERY IMPORTANT KEYWORD, ENTITY, OR FACTUAL DETAIL INSIDE PARENTHESES, like (keyword). Always mention the Source URL if you use its information."
377
  if not needs_rag:
378
  system_prompt = "You are a helpful AI Assistant. Answer the user's query conversationally, BUT ENCLOSE IMPORTANT WORDS IN PARENTHESES like (word)."
@@ -382,6 +364,7 @@ async def process_rag_chat(q: str):
382
  {"role": "user", "content": f"Query: {q}\n\nLive Context Data:\n{rag_context}" if needs_rag else f"Query: {q}"}
383
  ]
384
 
 
385
  ai_reply = await run_ai_task(messages, 200, query_key=f"chat_{q}_{needs_rag}")
386
 
387
  return {
@@ -400,6 +383,5 @@ async def ai_mode_chat_get(q: str = Query(...)):
400
  async def ai_mode_chat_post(q: str = Form(...)):
401
  return await process_rag_chat(q)
402
 
403
- # Using `app` variable directly prevents Spaces routing errors if the file is named differently
404
  if __name__ == "__main__":
405
- uvicorn.run(app, host="0.0.0.0", port=7860, workers=1)
 
6
  import re
7
  import multiprocessing
8
  import urllib.parse
 
9
  from contextlib import asynccontextmanager
10
  from fastapi import FastAPI, Query, Form
11
+ from fastapi.responses import JSONResponse
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from huggingface_hub import hf_hub_download
14
+ from rank_bm25 import BM25Okapi
15
+ import torch
16
  import aiohttp
17
  from bs4 import BeautifulSoup
18
+ from transformers import pipeline
19
 
20
+ # --- 1. SETUP & CPU ALLOCATION ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  TOTAL_CORES = multiprocessing.cpu_count()
22
  AI_CORES = max(1, int(TOTAL_CORES * 0.4))
23
+ torch.set_num_threads(AI_CORES)
24
+ print(f"🖥️ Total Cores: {TOTAL_CORES} | Allocating {AI_CORES} cores strictly to AI.")
 
 
 
 
 
 
25
 
26
  raw_data = []
27
  suggestion_list = []
28
  bm25_index = None
29
+ MAX_CONCURRENT_AI = max(1, AI_CORES)
 
30
  ai_semaphore = asyncio.Semaphore(MAX_CONCURRENT_AI)
31
  ai_generator = None
 
32
 
33
  # --- TRACKING & TRUST SYSTEM ---
34
+ URL_STATS = {} # Format: { "https://example.com": {"user_visits": 0, "ai_visits": 0, "is_trusted": False} }
35
+
36
+ # --- AI CACHING SYSTEM ---
37
  AI_RESPONSE_CACHE = {}
38
  MAX_CACHE_SIZE = 5000
39
+ STOP_WORDS = {"the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with", "is", "are"}
40
  HF_TOKEN = os.getenv("HF_TOKEN")
41
 
42
+ # 🔥 MASSIVE DESI & MODERN ADULT KEYWORDS LIST
43
  ADULT_KEYWORDS = {
44
  "porn", "sex", "nude", "nsfw", "xxx", "adult", "erotic", "onlyfans",
45
+ "mms", "chudai", "bhabhi", "devar", "savita bhabhi", "xvideos", "pornhub",
46
+ "brazzers", "mia khalifa", "bf video", "blue film", "kamasutra", "nude",
47
  "boobs", "tits", "ass", "booty", "naked", "desi porn", "hot desi", "xnxx",
48
  "kacha badam", "ullu", "kooku", "mastram", "gandi baat", "nangi", "nanga",
49
  "sex tape", "milf", "stepmom", "incest", "playboy", "scandal", "leaked"
50
  }
51
 
52
+ # --- 2. ADVANCED NLP & INDEXING ---
53
  def tokenize(text):
54
  if not text: return []
55
  tokens = re.findall(r'[a-z0-9]+', str(text).lower())
 
64
  try:
65
  dataset_path = hf_hub_download(
66
  repo_id="Nebulixlabs/Ultimate-Search-Engine-Dataset",
67
+ filename="dataset.jsonl",
68
+ repo_type="dataset",
69
+ token=HF_TOKEN
70
  )
71
  except Exception as e:
72
  print(f"⚠️ Hugging Face Download failed: {e}")
73
 
74
+ tokenized_corpus = []
75
+ MAX_RECORDS_TO_LOAD = 150000 # Prevent OOM Crash
76
 
77
  if os.path.exists(dataset_path):
78
  with open(dataset_path, "r", encoding="utf-8") as f:
79
  for i, line in enumerate(f):
80
+ if i >= MAX_RECORDS_TO_LOAD:
81
+ break
82
+
83
  if line.strip():
84
  try:
85
  doc = json.loads(line)
86
  url = doc.get("url", "")
 
 
87
 
88
  if url not in URL_STATS:
89
  URL_STATS[url] = {"user_visits": 0, "ai_visits": 0, "is_trusted": False}
90
 
91
  raw_data.append(doc)
92
+
93
+ title_str = doc.get("title", "")
94
  if title_str and len(title_str) < 60:
95
  suggestion_list.append(title_str.lower())
96
 
97
+ title_tokens = tokenize(title_str)
98
+ desc_tokens = tokenize(doc.get("description", ""))
99
+ url_tokens = tokenize(url)
100
+
101
+ boosted_tokens = (title_tokens * 5) + (desc_tokens * 3) + url_tokens
102
+ tokenized_corpus.append(boosted_tokens)
103
+ except:
104
+ pass
105
 
106
+ if tokenized_corpus:
107
+ print("⚡ Building High-Speed BM25 Okapi Index...")
108
  suggestion_list = sorted(list(set(suggestion_list)))
109
+ bm25_index = BM25Okapi(tokenized_corpus)
110
+ print(f"🚀 Indexing Complete! {len(raw_data)} records ready for search.")
 
 
111
  else:
112
  print("❌ Dataset file not found!")
113
 
114
  def load_ai_models():
115
+ global ai_generator
116
+ print("🤖 Loading Small & Fast 360M Text AI Model...")
117
  try:
118
+ # 🔥 Using a small 360M parameter model for strict fast performance
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  ai_generator = pipeline(
120
  "text-generation",
121
+ model="HuggingFaceTB/SmolLM2-360M-Instruct",
122
+ device=-1,
123
+ torch_dtype=torch.float32
124
  )
125
+ print("✅ Small AI Model Loaded! System ready.")
126
  except Exception as e:
127
  print(f"❌ Model Loading Failed: {e}")
128
 
 
138
  if resp.status == 200:
139
  html = await resp.text()
140
  soup = BeautifulSoup(html, "html.parser")
141
+ tags_to_extract = ['p', 'h1', 'h2', 'h3']
142
+ text = " ".join([tag.get_text(strip=True) for tag in soup.find_all(tags_to_extract)])
143
+
144
  if not text: return ""
145
 
146
  chunks = chunk_text(text)
147
  query_tokens = set(tokenize(query))
148
 
149
+ best_chunk = ""
150
+ max_score = 0
151
  early_stop_threshold = max(1, len(query_tokens) // 2)
152
 
153
  for chunk in chunks:
 
163
  return ""
164
  return ""
165
 
166
+ # --- 4. CORE SEARCH ALGORITHM & RANKING ---
167
  async def perform_core_search(raw_query: str):
168
  if not raw_data or not bm25_index:
169
  return [], "Search index not ready.", 0
 
172
  query_tokens = tokenize(query)
173
  user_wants_adult = any(adult_word in query for adult_word in ADULT_KEYWORDS)
174
 
175
+ scores = bm25_index.get_scores(query_tokens) if query_tokens else [1.0] * len(raw_data)
 
 
 
 
 
176
  scored_results = []
177
  seen_urls = set()
 
 
 
 
 
 
 
 
178
 
179
+ for index, score in enumerate(scores):
180
+ if score > 0.1 or not query_tokens:
181
+ doc = raw_data[index]
182
+ doc_url = doc.get("url", "")
 
 
 
 
 
 
 
 
 
 
 
183
 
184
+ if doc_url in seen_urls: continue
185
+
186
+ parsed_url = urllib.parse.urlparse(doc_url)
187
+ domain = parsed_url.netloc.lower().replace("www.", "")
188
+ path = parsed_url.path.strip("/")
189
+
190
+ doc_title = doc.get("title", "").lower()
191
+ doc_desc = doc.get("description", "").lower()
192
+ doc_text = doc_title + " " + doc_desc + " " + doc_url
193
+
194
+ is_adult_doc = doc.get("tag", "general").lower() in ["adult", "nsfw"] or any(aw in doc_text for aw in ADULT_KEYWORDS)
195
+
196
+ if not user_wants_adult and is_adult_doc:
197
+ continue
198
 
199
+ final_score = score
200
+ query_clean = query.replace(" ", "")
201
+ domain_clean = domain.replace(" ", "")
202
 
203
+ # 🔥 1. SUPER RANKING FOR DOMAINS
204
+ if query_clean == domain_clean or domain_clean.startswith(query_clean + "."):
205
+ if not path:
206
+ final_score *= 50.0 # EXACT MATCH ROOT DOMAIN -> 50x Boost
207
+ else:
208
+ final_score *= 10.0 # EXACT MATCH BUT SUBPAGE -> 10x Boost
209
+ elif query_clean in domain_clean:
210
+ if not path:
211
+ final_score *= 25.0 # PARTIAL ROOT DOMAIN -> 25x Boost
212
+ else:
213
+ final_score *= 5.0 # PARTIAL MATCH SUBPAGE -> 5x Boost
214
+
215
+ # 🔥 2. KEYWORD & TITLE MATCH BOOST
216
+ if query in doc_title:
217
+ final_score *= 5.0 # EXACT query present in Title -> 5x
218
+ elif all(word in doc_title for word in query_tokens):
219
+ final_score *= 3.0 # All query words present in Title -> 3x
220
+
221
+ if query in doc_desc:
222
+ final_score *= 2.0 # EXACT query in Description -> 2x
223
+
224
+ # 🔥 3. CONTEXTUAL TRUST BOOST
225
+ stats = URL_STATS.get(doc_url, {"user_visits": 0, "ai_visits": 0, "is_trusted": False})
226
+ if stats.get("is_trusted", False):
227
+ final_score *= 2.0
228
+
229
+ final_score += (stats.get("user_visits", 0) * 0.05) + (stats.get("ai_visits", 0) * 0.1)
230
+
231
+ seen_urls.add(doc_url)
232
+
233
+ doc_copy = doc.copy()
234
+ doc_copy["trust_stats"] = stats
235
+
236
+ scored_results.append((final_score, doc_copy))
237
 
238
  scored_results.sort(key=lambda x: x[0], reverse=True)
239
  best_score = scored_results[0][0] if scored_results else 0
 
242
  final_results = [{"match_score": round(s, 2), **doc} for s, doc in scored_results[:100]]
243
  return final_results, prediction, best_score
244
 
245
+ # --- AI GENERATION HELPER ---
246
+ def _generate_text(messages, max_tokens: int):
247
+ prompt = "\n".join([f"{m['role'].capitalize()}: {m['content']}" for m in messages]) + "\nAssistant:"
248
+ result = ai_generator(prompt, max_new_tokens=max_tokens, do_sample=True, temperature=0.3, top_p=0.85)
249
+ text_out = result[0]['generated_text'].split("Assistant:")[-1].strip()
250
+ return text_out
 
 
 
 
 
 
 
 
 
251
 
252
  async def run_ai_task(messages, max_tokens: int, query_key: str):
253
  if not ai_generator: return "⚠️ AI Model is starting up."
254
  if query_key in AI_RESPONSE_CACHE: return AI_RESPONSE_CACHE[query_key]
255
 
256
  async with ai_semaphore:
257
+ response = await asyncio.to_thread(_generate_text, messages, max_tokens)
 
258
  if len(AI_RESPONSE_CACHE) > MAX_CACHE_SIZE: AI_RESPONSE_CACHE.clear()
259
  AI_RESPONSE_CACHE[query_key] = response
260
  return response
 
267
  yield
268
 
269
  app = FastAPI(title="Nebulix Advanced Text AI & RAG Engine", lifespan=lifespan)
270
+
271
+ app.add_middleware(
272
+ CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"]
273
+ )
274
 
275
  @app.get("/suggest")
276
  async def get_suggestions(q: str = Query(..., min_length=1)):
 
280
 
281
  @app.post("/track-click")
282
  async def track_url_click(url: str = Query(...)):
283
+ if url not in URL_STATS:
284
+ URL_STATS[url] = {"user_visits": 0, "ai_visits": 0, "is_trusted": False}
285
  URL_STATS[url]["user_visits"] += 1
286
  return {"status": "success", "url": url, "visits": URL_STATS[url]["user_visits"]}
287
 
288
  @app.get("/url-stats")
289
  async def get_url_stats(url: str = Query(...)):
290
+ stats = URL_STATS.get(url, {"user_visits": 0, "ai_visits": 0, "is_trusted": False})
291
+ return {"url": url, "stats": stats}
292
 
293
  @app.get("/search")
294
  async def pure_search(q: str = Query(...)):
 
305
 
306
  context = " ".join([f"{r.get('title', '')} - {r.get('description', '')}" for r in results[:3]])
307
 
308
+ # 🔥 AI MODE SYSTEM PROMPT (STRICT: Max 80 Words & Use Brackets for Important Terms)
309
  messages = [
310
+ {
311
+ "role": "system",
312
+ "content": "You are a concise AI. Answer in EXACTLY 1 to 2 sentences (Max 80 words). YOU MUST ENCLOSE ANY IMPORTANT KEYWORD, NAME, OR FACTUAL DETAIL IN PARENTHESES, like (this)."
313
+ },
314
  {"role": "user", "content": f"Query: {q}\nContext: {context}"}
315
  ]
316
 
317
+ # Max tokens set to 80 to keep it very short (aprox 20 generated tokens logic based on your 4 word multiplier).
318
  ai_reply = await run_ai_task(messages, 80, query_key=f"short_{q}")
319
  return {"request_id": req_id, "ai_response": ai_reply, "results": results}
320
 
321
+
322
  async def process_rag_chat(q: str):
323
  req_id = str(uuid.uuid4())
324
  needs_rag = any(w in q.lower() for w in ["what", "who", "where", "how", "why", "tell me", "explain", "latest", "best"])
 
329
 
330
  if needs_rag and results:
331
  top_urls = results[:10]
332
+
333
  tasks = [scrape_and_find_best_chunk(doc["url"], q) for doc in top_urls]
334
  scraped_chunks = await asyncio.gather(*tasks)
335
 
 
340
 
341
  if url not in URL_STATS: URL_STATS[url] = {"user_visits": 0, "ai_visits": 0, "is_trusted": False}
342
  URL_STATS[url]["ai_visits"] += 1
343
+ if URL_STATS[url]["ai_visits"] >= 100:
344
+ URL_STATS[url]["is_trusted"] = True
345
+
346
  doc["trust_stats"] = URL_STATS[url]
347
 
348
+ if chunk:
349
+ context_parts.append(f"Source [{i+1}] ({url}): {chunk}")
350
+ used_sources.append(doc)
351
+ else:
352
+ context_parts.append(f"Source [{i+1}] ({url}): {doc.get('description', '')}")
353
+ used_sources.append(doc)
354
 
355
  rag_context = "\n".join(context_parts)
356
 
357
+ # 🔥 AI CHAT SYSTEM PROMPT (Use Brackets for Important Terms)
358
  system_prompt = "You are a Smart AI Search Assistant. Provide a detailed answer. YOU MUST ENCLOSE EVERY IMPORTANT KEYWORD, ENTITY, OR FACTUAL DETAIL INSIDE PARENTHESES, like (keyword). Always mention the Source URL if you use its information."
359
  if not needs_rag:
360
  system_prompt = "You are a helpful AI Assistant. Answer the user's query conversationally, BUT ENCLOSE IMPORTANT WORDS IN PARENTHESES like (word)."
 
364
  {"role": "user", "content": f"Query: {q}\n\nLive Context Data:\n{rag_context}" if needs_rag else f"Query: {q}"}
365
  ]
366
 
367
+ # Max tokens set to 200 for detailed chat mode.
368
  ai_reply = await run_ai_task(messages, 200, query_key=f"chat_{q}_{needs_rag}")
369
 
370
  return {
 
383
  async def ai_mode_chat_post(q: str = Form(...)):
384
  return await process_rag_chat(q)
385
 
 
386
  if __name__ == "__main__":
387
+ uvicorn.run(app, host="0.0.0.0", port=7860)