ai-studio / app.py
Divy Patel
Clean deployment with comprehensive LFS tracking
3bd43fa
Raw
History Blame Contribute Delete
17.8 kB
import os
import requests
import json
import re
import io
import tempfile
import base64
from pathlib import Path
from datetime import datetime, timedelta, timezone
from bs4 import BeautifulSoup
from flask import Flask, request, Response, stream_with_context, send_from_directory
from supertonic import TTS
# ================================================================================
# FLASK APP INITIALIZATION
# ================================================================================
app = Flask(__name__, static_folder='.', static_url_path='')
# ----------------------------------------------------------------------------
# INIT RENDERLIB
# ----------------------------------------------------------------------------
print("Loading RenderLib...")
try:
from renderlib import RenderLib
renderer = RenderLib()
print("RenderLib loaded successfully!")
except ImportError as e:
print(f"RenderLib not installed yet or error: {e}")
renderer = None
# ----------------------------------------------------------------------------
# INIT TTS MODEL
# ----------------------------------------------------------------------------
print("Loading Supertonic TTS Model...")
try:
tts = TTS(auto_download=True)
print("TTS Model loaded successfully!")
except Exception as e:
print(f"Error initializing TTS: {e}")
tts = None
VOICES = ["M1", "M2", "M3", "M4", "M5", "F1", "F2", "F3", "F4", "F5"]
LANGUAGES = {
"English": "en", "Korean": "ko", "Japanese": "ja", "Arabic": "ar",
"Bulgarian": "bg", "Czech": "cs", "Danish": "da", "German": "de",
"Greek": "el", "Spanish": "es", "Estonian": "et", "Finnish": "fi",
"French": "fr", "Hindi": "hi"
}
VOICE_STYLES_CACHE = {}
# ----------------------------------------------------------------------------
# DYNAMIC MODEL CONFIGURATION & MAPPING
# ----------------------------------------------------------------------------
NVIDIA_API_KEY = os.environ.get("NVIDIA_API_KEY", "")
INVOKE_URL = "https://integrate.api.nvidia.com/v1/chat/completions"
# Mapping Custom Names to NVIDIA API Model IDs
MODEL_MAPPING = {
"Vedika 4.1 Flash": "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning", # Fastest / Reasoning ALWAYS ON (Images + Video)
"Vedika 2.5 Balanced": "meta/llama-3.2-90b-vision-instruct", # Middle / Image Only / No Reasoning
"Vedika 5.6 Pro": "stepfun-ai/step-3.7-flash" # Pro / Reasoning Inherently ON / Image Only
}
# ----------------------------------------------------------------------------
# HELPER FUNCTIONS (AUTONOMOUS TOOLS)
# ----------------------------------------------------------------------------
def analyze_intent(text):
text_lower = text.lower()
search_keywords = ['news', 'latest', 'today', 'weather', 'price', 'score', 'update', 'current', 'search', 'who won', 'who is', 'what is', 'stock', 'match', 'न्यूज़', 'आज', 'खबर', 'मौसम', 'बताओ']
location_keywords = ['near me', 'my location', 'where am i', 'weather', 'local', 'nearby', 'around me', 'यहाँ', 'मेरे पास', 'लोकेशन']
needs_search = any(kw in text_lower for kw in search_keywords)
needs_location = any(kw in text_lower for kw in location_keywords)
return needs_search, needs_location
def get_address_from_coords(lat, lon):
try:
url = f"https://nominatim.openstreetmap.org/reverse?format=json&lat={lat}&lon={lon}"
headers = {'User-Agent': 'Vedika_AI_System_by_Divy_Patel'}
response = requests.get(url, headers=headers, timeout=5)
data = response.json()
return data.get('display_name', f"Lat: {lat}, Lon: {lon}")
except Exception:
return f"Lat: {lat}, Lon: {lon}"
def web_search_scraper(query, num_results=5, user_address=None):
results = []
serpapi_key = os.environ.get("SERPAPI_KEY")
if not serpapi_key: return results
search_query = query
if user_address and any(kw in query.lower() for kw in ["near", "nearby", "distance", "local", "weather"]):
search_query = f"{query} near {user_address}"
try:
params = {"engine": "google", "q": search_query, "api_key": serpapi_key, "num": num_results, "hl": "en", "gl": "in"}
response = requests.get("https://serpapi.com/search", params=params, timeout=10)
data = response.json()
if "organic_results" in data:
for item in data["organic_results"]:
if item.get("title") and item.get("snippet"):
results.append({"title": item["title"], "link": item.get("link", ""), "snippet": item["snippet"]})
except Exception: pass
return results
def get_live_web_data(query):
url = f"https://news.google.com/rss/search?q={query}&hl=en&gl=IN&ceid=IN:en"
headers = {"User-Agent": "Mozilla/5.0"}
tech_kw = ["ai", "smartphone", "mobile", "tech", "google", "apple", "india", "world", "market"]
results = []
try:
response = requests.get(url, headers=headers, timeout=6)
if response.status_code == 200:
soup = BeautifulSoup(response.text, "html.parser")
for item in soup.find_all('item'):
title = item.title.text if item.title else ""
if any(k in title.lower() for k in tech_kw) and "stock" not in title.lower():
results.append({
"title": title,
"snippet": f"Pub: {item.pubdate.text if item.pubdate else ''}",
"link": item.link.text if item.link else "#"
})
if len(results) >= 5: break
except Exception: pass
return results
# ----------------------------------------------------------------------------
# SYSTEM PROMPT ENGINEERING ENGINE
# ----------------------------------------------------------------------------
def generate_system_prompt(model_name, current_date, location_instruction, custom_prompt, personalization_data=None):
base_identity = f"[CRITICAL IDENTITY OVERRIDE]\nName: {model_name}\nCreator/Engineer: Divy Patel\nCurrent Time: {current_date}.{location_instruction}\n\n"
# INTUITIVE INTELLIGENCE (MEMORY) LAYER
memory_instruction = ""
if personalization_data:
memory_instruction = f"""
--- [INTUITIVE INTELLIGENCE: MEMORY LAYER ACTIVE] ---
You have access to an "Intuitive Intelligence" memory layer containing persistent user information:
{personalization_data}
[MEMORY USAGE INSTRUCTIONS]:
1. Use this memory context to personalize your responses and maintain continuity across conversations.
2. Reference stored facts naturally without explicitly mentioning "memory" or "database".
3. Avoid re-asking questions about information already stored in your memory.
4. Build upon known preferences, experiences, and relationships when responding.
[MEMORY AUTO-SAVE PROTOCOL - CRITICAL]:
- When you learn NEW important facts about the user (preferences, experiences, relationships, goals, etc.), you MUST save them to memory.
- To save memory, include this exact format in your response: __MEMORY_ACTION__{{"action": "update_personalization", "email": "user@example.com", "type": "memory", "content": "New fact to save"}}__END_MEMORY_ACTION__
- ONLY trigger memory saves when the personalization toggle is ON (indicated by memory data being present in your prompt).
- Save meaningful, lasting information. Do not save trivial or temporary details.
- Multiple memory actions can be included if multiple new facts emerge.
--- [END MEMORY LAYER] ---
"""
if custom_prompt:
return base_identity + memory_instruction + custom_prompt
if model_name == "Vedika 4.1 Flash":
return base_identity + memory_instruction + """You are Vedika 4.1 Flash, a fast Omni-modal AI created by Divy Patel.
[CRITICAL INSTRUCTION: Format your deep reasoning inside <think> and </think> tags before providing the final answer.]
CRITICAL RULES YOU MUST FOLLOW EXACTLY:
1. NO LONG INTRODUCTIONS. Answer directly.
2. If asked for code, provide ONLY the exact working code and a 1-2 line explanation.
3. DO NOT get confused by complex tasks. Break them down into simple, basic steps.
4. Always respect the user. Divy Patel is your creator.
5. Formatting: Use standard Markdown. No fluff."""
elif model_name == "Vedika 2.5 Balanced":
return base_identity + memory_instruction + """You are Vedika 2.5 Balanced, an advanced Vision AI created by Divy Patel.
Your goal is to balance deep analytical accuracy with practical, fast solutions.
- You specialize in analyzing images and providing well-reasoned, logical breakdowns of visual data.
- Write clean, efficient code with necessary comments.
- Maintain a helpful, professional tone."""
elif model_name == "Vedika 5.6 Pro":
return base_identity + memory_instruction + """You are Vedika 5.6 Pro, an elite, enterprise-grade AI architect engineered by Divy Patel.
[CRITICAL INSTRUCTION: Format your complex architectural reasoning inside <think> and </think> tags before answering.]
Your mandate is to deliver highly optimized, production-ready solutions and profound technical insights.
- Architecture: Provide scalable, secure, and robust system designs.
- Complexity: Handle massive codebases and deep abstractions effortlessly.
- Formatting: Meticulously use LaTeX for mathematical/algorithmic complexity (Big O) and structured Markdown tables for comparisons.
- Tone: Professional, authoritative, and objective."""
return base_identity + memory_instruction + "You are Vedika, an AI engineered by Divy Patel. Be helpful and concise."
# ----------------------------------------------------------------------------
# ROUTES
# ----------------------------------------------------------------------------
@app.route('/')
def home():
return send_from_directory('.', 'index.html')
@app.route('/api/render', methods=['POST'])
def render_content():
if renderer is None:
return Response(json.dumps({"error": "RenderLib not available."}), status=500, mimetype='application/json')
data = request.get_json() or {}
try:
result = renderer.render(data.get("subject", "math"), data.get("method", "to_latex"), *(data.get("args", [data.get("expression")] if data.get("expression") else [])), **data.get("kwargs", {}))
return Response(json.dumps({"result": result}), mimetype='application/json')
except Exception as e:
return Response(json.dumps({"error": str(e)}), status=500, mimetype='application/json')
@app.route('/api/chat', methods=['POST'])
def chat():
if not NVIDIA_API_KEY:
return Response(json.dumps({"error": "NVIDIA_API_KEY missing."}), mimetype='application/json', status=500)
data = request.get_json() or {}
user_message = data.get("message", "")
attachments = data.get("attachments", [])
history = data.get("history", [])
location = data.get("location") # Silently sent by frontend
requested_model_name = data.get("model", "Vedika 4.1 Flash")
api_model_id = MODEL_MAPPING.get(requested_model_name, MODEL_MAPPING["Vedika 4.1 Flash"])
ist_time = datetime.now(timezone.utc) + timedelta(hours=5, minutes=30)
current_date = ist_time.strftime("%A, %d %B %Y, %I:%M %p IST")
# AUTONOMOUS INTENT DETECTION
needs_search, needs_location = analyze_intent(user_message)
user_address = None
location_instruction = ""
if (needs_location or needs_search) and location and location.get('lat'):
user_address = get_address_from_coords(location['lat'], location['lng'])
location_instruction = f"\n[USER REAL-TIME LOCATION: {user_address}]"
system_prompt = generate_system_prompt(
model_name=requested_model_name,
current_date=current_date,
location_instruction=location_instruction,
custom_prompt=data.get("system_prompt", None),
personalization_data=data.get("personalization_data", None)
)
# AUTONOMOUS WEB SEARCH INJECTION
if needs_search:
search_context = ""
scraped_data = web_search_scraper(user_message, user_address=user_address)
news_data = get_live_web_data(user_message)
if scraped_data:
search_context += "\n\n--- [LIVE AUTONOMOUS SEARCH] ---\n" + "".join([f"{i+1}. {r['title']}: {r['snippet']}\n" for i, r in enumerate(scraped_data)])
if news_data:
search_context += "\n--- [LIVE AUTONOMOUS NEWS] ---\n" + "".join([f"{i+1}. {r['title']}: {r['snippet']}\n" for i, r in enumerate(news_data)])
if search_context:
user_message = f"{user_message}\n{search_context}\n[COMMAND: Base your final answer strictly on the real-time facts provided above. Do not mention that you performed a search, just give the answer naturally.]"
messages = [{"role": "system", "content": system_prompt}]
for msg in history:
if msg == history[-1] and msg.get("role") == "user": continue
role = msg.get("role", "user")
content = msg.get("content", "")
if isinstance(content, list): content = " ".join([i["text"] for i in content if i.get("type") == "text"])
if "Gemma" in content or "DeepMind" in content: continue
if content: messages.append({"role": role if role in ["system", "user", "assistant"] else "user", "content": str(content)})
# Handling Multimodal attachments
if attachments:
content_payload = [{"type": "text", "text": user_message}]
for att in attachments:
b64 = att.get("data")
att_type = att.get("type")
if att_type == "image":
content_payload.append({"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}})
elif att_type == "video":
# ONLY Vedika 4.1 Flash supports video.
if requested_model_name == "Vedika 4.1 Flash":
content_payload.append({"type": "video_url", "video_url": {"url": f"data:video/mp4;base64,{b64}"}})
messages.append({"role": "user", "content": content_payload})
else:
messages.append({"role": "user", "content": user_message})
# Base payload structure
payload = {
"model": api_model_id,
"messages": messages,
"stream": True,
"top_p": 0.95
}
if requested_model_name == "Vedika 4.1 Flash":
payload["max_tokens"] = 65536
payload["reasoning_budget"] = 16384
payload["temperature"] = 0.6
payload["chat_template_kwargs"] = {"enable_thinking": True} # ALWAYS TRUE to prevent hallucination
elif requested_model_name == "Vedika 2.5 Balanced":
payload["max_tokens"] = 2977
payload["temperature"] = 1.0
payload["frequency_penalty"] = 0
payload["presence_penalty"] = 0
payload["top_p"] = 1
elif requested_model_name == "Vedika 5.6 Pro":
payload["max_tokens"] = 16384
payload["seed"] = 42
payload["temperature"] = 1.0
try:
response = requests.post(INVOKE_URL, headers={"Authorization": f"Bearer {NVIDIA_API_KEY}", "Accept": "text/event-stream"}, json=payload, stream=True, timeout=60)
if response.status_code != 200:
return Response(f"data: {json.dumps({'error': f'API Error {response.status_code}'})}\n\n", mimetype='text/event-stream')
def generate():
for line in response.iter_lines():
if line:
decoded = line.decode("utf-8")
if decoded.startswith("data: ") and "[DONE]" not in decoded:
try:
data_json = json.loads(decoded[6:])
if "choices" in data_json and len(data_json["choices"]) > 0:
delta = data_json["choices"][0].get("delta", {})
if "content" in delta and delta["content"]:
delta["content"] = delta["content"].replace("<|channel|>thought <|channel|>", "<think>\n").replace("<|channel|>answer <|channel|>", "\n</think>\n")
yield "data: " + json.dumps(data_json) + "\n\n"
except Exception:
yield decoded + "\n\n"
else:
yield decoded + "\n\n"
return Response(stream_with_context(generate()), mimetype='text/event-stream')
except Exception as e:
return Response(f"data: {json.dumps({'error': str(e)})}\n\n", mimetype='text/event-stream')
@app.route('/api/tts', methods=['POST'])
def generate_tts():
if tts is None: return Response(json.dumps({"error": "TTS offline"}), status=500, mimetype='application/json')
data = request.get_json() or {}
text, voice, lang = data.get("text", ""), data.get("voice", "M2"), data.get("language_name", "English")
if not text.strip(): return Response(json.dumps({"error": "Empty text"}), status=400, mimetype='application/json')
try:
if voice not in VOICE_STYLES_CACHE: VOICE_STYLES_CACHE[voice] = tts.get_voice_style(voice_name=voice)
wav, _ = tts.synthesize(text, voice_style=VOICE_STYLES_CACHE[voice], lang=LANGUAGES.get(lang, "en"))
with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as tmp:
tmp_path = tmp.name
tts.save_audio(wav, tmp_path)
with open(tmp_path, 'rb') as f: audio_data = f.read()
os.unlink(tmp_path)
return Response(audio_data, mimetype="audio/wav")
except Exception as e:
return Response(json.dumps({"error": str(e)}), status=500, mimetype='application/json')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)