Spaces:
Sleeping
Sleeping
| """ | |
| Vish AI - Virtual Intelligent System Hub | |
| Lightweight multimodal AI assistant optimized for Hugging Face Spaces | |
| Production-ready version | |
| """ | |
| import gradio as gr | |
| import os | |
| from datetime import datetime | |
| import time | |
| import importlib | |
| # Supabase imports | |
| try: | |
| from supabase import create_client, Client | |
| SUPABASE_AVAILABLE = True | |
| except ImportError: | |
| SUPABASE_AVAILABLE = False | |
| print("β οΈ Supabase not available - running in demo mode") | |
| # AI model imports | |
| torch = None | |
| try: | |
| torch = importlib.import_module("torch") | |
| AI_AVAILABLE = True | |
| except ImportError: | |
| AI_AVAILABLE = False | |
| torch = None | |
| if not AI_AVAILABLE: | |
| print("β οΈ AI models not available - using fallback mode") | |
| # Supabase configuration | |
| SUPABASE_URL = os.getenv("NEXT_PUBLIC_SUPABASE_URL", "https://lyebtceryednzafhyunq.supabase.co") | |
| SUPABASE_KEY = os.getenv("NEXT_PUBLIC_SUPABASE_ANON_KEY", "") | |
| # Initialize Supabase client | |
| supabase = None | |
| if SUPABASE_AVAILABLE and SUPABASE_KEY: | |
| try: | |
| supabase = create_client(SUPABASE_URL, SUPABASE_KEY) | |
| print("β Supabase connected successfully") | |
| except Exception as e: | |
| print(f"β οΈ Supabase initialization error: {e}") | |
| else: | |
| print("β οΈ Supabase credentials not configured") | |
| # Global variables for unified model | |
| phi3_model = None | |
| phi3_tokenizer = None | |
| def initialize_models(): | |
| """Initialize Phi-3 unified model for all AI tasks""" | |
| global phi3_model, phi3_tokenizer | |
| if not AI_AVAILABLE: | |
| print("β οΈ AI libraries not available - using demo mode") | |
| return False | |
| try: | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| import traceback | |
| # Load Phi-3 Mini - Unified model for all tasks (~7.4GB) | |
| print("π₯ Loading Phi-3 Mini unified model...") | |
| print(" Model: microsoft/Phi-3-mini-4k-instruct") | |
| print(" Capabilities: Chat, Summarization, Sentiment Analysis") | |
| print(" This may take 5-15 minutes on first run (downloading ~7GB)...") | |
| # Load tokenizer | |
| print(" Loading tokenizer...") | |
| phi3_tokenizer = AutoTokenizer.from_pretrained( | |
| "microsoft/Phi-3-mini-4k-instruct", | |
| trust_remote_code=True | |
| ) | |
| print(" β Tokenizer loaded") | |
| # Load model with CPU optimization for Hugging Face Spaces | |
| print(" Loading model (this is the slow part)...") | |
| phi3_model = AutoModelForCausalLM.from_pretrained( | |
| "microsoft/Phi-3-mini-4k-instruct", | |
| device_map="cpu", | |
| torch_dtype=torch.float32, # Use float32 for CPU | |
| trust_remote_code=True, | |
| low_cpu_mem_usage=True | |
| ) | |
| print("β Phi-3 Mini model loaded successfully!") | |
| print("π Unified model ready for all tasks!") | |
| print(f" Model parameters: {phi3_model.num_parameters():,}") | |
| return True | |
| except Exception as e: | |
| print(f"β Error loading Phi-3 model: {e}") | |
| print("Detailed error:") | |
| import traceback | |
| traceback.print_exc() | |
| return False | |
| def verify_user_token(token: str) -> dict: | |
| """Verify Supabase user authentication token""" | |
| if not supabase or not token: | |
| return {"authenticated": False, "user": None} | |
| try: | |
| user = supabase.auth.get_user(token) | |
| return {"authenticated": True, "user": user.user.email if user.user else None} | |
| except Exception as e: | |
| return {"authenticated": False, "error": str(e)} | |
| def log_interaction(user_email: str, prompt: str, response: str, model_type: str): | |
| """Log user interactions to Supabase""" | |
| if not supabase: | |
| return | |
| try: | |
| data = { | |
| "user_email": user_email, | |
| "prompt": prompt, | |
| "response": response, | |
| "model_type": model_type, | |
| "timestamp": datetime.utcnow().isoformat() | |
| } | |
| supabase.table("vish_ai_logs").insert(data).execute() | |
| except Exception as e: | |
| print(f"Logging error: {e}") | |
| def generate_phi3_response(prompt: str, max_new_tokens: int = 256, temperature: float = 0.7) -> str: | |
| """Generate response using Phi-3 model""" | |
| if not phi3_model or not phi3_tokenizer: | |
| return None | |
| try: | |
| # Format prompt for Phi-3 instruct format | |
| messages = [{"role": "user", "content": prompt}] | |
| # Apply chat template | |
| formatted_prompt = phi3_tokenizer.apply_chat_template( | |
| messages, | |
| tokenize=False, | |
| add_generation_prompt=True | |
| ) | |
| # Tokenize | |
| inputs = phi3_tokenizer(formatted_prompt, return_tensors="pt") | |
| # Generate | |
| with torch.no_grad(): | |
| outputs = phi3_model.generate( | |
| **inputs, | |
| max_new_tokens=max_new_tokens, | |
| temperature=temperature, | |
| do_sample=True, | |
| top_p=0.9, | |
| pad_token_id=phi3_tokenizer.eos_token_id | |
| ) | |
| # Decode and extract response | |
| full_response = phi3_tokenizer.decode(outputs[0], skip_special_tokens=True) | |
| # Extract only the assistant's response (after the prompt) | |
| if "<|assistant|>" in full_response: | |
| response = full_response.split("<|assistant|>")[-1].strip() | |
| else: | |
| response = full_response[len(formatted_prompt):].strip() | |
| return response | |
| except Exception as e: | |
| print(f"Error generating response: {e}") | |
| return None | |
| def chat_with_vish(message: str, history: list, auth_token: str = "") -> str: | |
| """Main chat function with authentication""" | |
| # Verify authentication (optional - remove if you want public access) | |
| user_info = verify_user_token(auth_token) if auth_token else {"authenticated": False} | |
| user_email = user_info.get("user", "anonymous") | |
| if not AI_AVAILABLE or not phi3_model: | |
| # Fallback response when AI is not available | |
| fallback = "π€ **Vish AI (Demo Mode)**\n\nYou said: _{}_\n\nβ οΈ AI models are not loaded. This happens when:\n- Running in Python 3.14 (PyTorch not supported)\n- First deployment (models downloading)\n\nβ **This will work perfectly on Hugging Face Spaces!**\n\n_Response time: <0.1s_".format(message) | |
| history.append([message, fallback]) | |
| return history | |
| try: | |
| start_time = time.time() | |
| # Build context from history | |
| context = "" | |
| if history: | |
| for h in history[-3:]: # Last 3 exchanges for context | |
| context += f"User: {h[0]}\nAssistant: {h[1]}\n" | |
| # Create prompt with context | |
| prompt = f"{context}User: {message}\nAssistant:" | |
| if context: | |
| prompt = f"Previous conversation:\n{context}\nCurrent question: {message}\n\nProvide a helpful and concise response:" | |
| else: | |
| prompt = f"Question: {message}\n\nProvide a helpful and concise response:" | |
| # Generate response using Phi-3 | |
| assistant_response = generate_phi3_response(prompt, max_new_tokens=200, temperature=0.7) | |
| if not assistant_response: | |
| assistant_response = "I apologize, but I encountered an error generating a response. Please try again." | |
| elapsed_time = time.time() - start_time | |
| # Log interaction | |
| log_interaction(user_email, message, assistant_response, "chat") | |
| final_response = f"{assistant_response}\n\nβ‘ _Response time: {elapsed_time:.2f}s_" | |
| history.append([message, final_response]) | |
| return history | |
| except Exception as e: | |
| error_msg = f"β Error: {str(e)}" | |
| history.append([message, error_msg]) | |
| return history | |
| def summarize_text(text: str, auth_token: str = "") -> str: | |
| """Summarize long text using Phi-3""" | |
| user_info = verify_user_token(auth_token) if auth_token else {"authenticated": False} | |
| user_email = user_info.get("user", "anonymous") | |
| if not AI_AVAILABLE or not phi3_model: | |
| # Fallback summary | |
| word_count = len(text.split()) | |
| return f"π **Summary (Demo Mode)**\n\nReceived {word_count} words.\n\nFirst 150 characters:\n_{text[:150]}_...\n\nβ οΈ Full AI summarization available on Hugging Face Spaces!\n\n_Processing time: <0.1s_" | |
| try: | |
| if len(text.split()) < 50: | |
| return "β οΈ Text is too short to summarize. Please provide at least 50 words." | |
| start_time = time.time() | |
| # Truncate if too long (model context limit) | |
| max_chars = 3000 | |
| if len(text) > max_chars: | |
| text = text[:max_chars] + "..." | |
| # Create summarization prompt | |
| prompt = f"Summarize the following text concisely in 2-3 sentences:\n\n{text}\n\nSummary:" | |
| # Generate summary using Phi-3 | |
| summary = generate_phi3_response(prompt, max_new_tokens=150, temperature=0.3) | |
| if not summary: | |
| return "β Error generating summary. Please try again." | |
| elapsed_time = time.time() - start_time | |
| log_interaction(user_email, text[:100], summary, "summarization") | |
| return f"{summary}\n\nβ‘ _Processing time: {elapsed_time:.2f}s_" | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| def analyze_sentiment(text: str, auth_token: str = "") -> str: | |
| """Analyze sentiment of text using Phi-3""" | |
| user_info = verify_user_token(auth_token) if auth_token else {"authenticated": False} | |
| user_email = user_info.get("user", "anonymous") | |
| if not AI_AVAILABLE or not phi3_model: | |
| # Simple fallback sentiment | |
| positive_words = ['good', 'great', 'excellent', 'happy', 'love', 'wonderful', 'amazing', 'fantastic', 'brilliant'] | |
| negative_words = ['bad', 'terrible', 'awful', 'hate', 'sad', 'horrible', 'worst', 'poor', 'disappointing'] | |
| text_lower = text.lower() | |
| pos_count = sum(1 for word in positive_words if word in text_lower) | |
| neg_count = sum(1 for word in negative_words if word in text_lower) | |
| if pos_count > neg_count: | |
| emoji, label, score = "π", "POSITIVE", 0.85 | |
| elif neg_count > pos_count: | |
| emoji, label, score = "π", "NEGATIVE", 0.85 | |
| else: | |
| emoji, label, score = "π", "NEUTRAL", 0.50 | |
| return f"{emoji} **{label}** (Demo - Simple keyword detection)\n\nConfidence: ~{score:.0%}\n\nβ οΈ Full AI sentiment analysis available on Hugging Face Spaces!\n\n_Analysis time: <0.1s_" | |
| try: | |
| start_time = time.time() | |
| # Create sentiment analysis prompt | |
| prompt = f"Analyze the sentiment of the following text. Respond with only one word: POSITIVE, NEGATIVE, or NEUTRAL.\n\nText: {text[:500]}\n\nSentiment:" | |
| # Generate sentiment using Phi-3 | |
| result = generate_phi3_response(prompt, max_new_tokens=10, temperature=0.1) | |
| if not result: | |
| return "β Error analyzing sentiment. Please try again." | |
| # Parse result | |
| result_upper = result.upper().strip() | |
| if "POSITIVE" in result_upper: | |
| label = "POSITIVE" | |
| emoji = "π" | |
| elif "NEGATIVE" in result_upper: | |
| label = "NEGATIVE" | |
| emoji = "π" | |
| else: | |
| label = "NEUTRAL" | |
| emoji = "οΏ½" | |
| elapsed_time = time.time() - start_time | |
| log_interaction(user_email, text[:100], f"{label}", "sentiment") | |
| return f"{emoji} **{label}**\n\nβ‘ _Analysis time: {elapsed_time:.2f}s_" | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| def get_model_info() -> str: | |
| """Get information about loaded models""" | |
| info = """ | |
| ## π€ Vish AI - Unified AI Model | |
| **Powered by Microsoft Phi-3 Mini 4K Instruct:** | |
| - Model: microsoft/Phi-3-mini-4k-instruct | |
| - Size: ~7.4GB (optimized for CPU) | |
| - Context: 4K tokens | |
| - Capabilities: Chat, Summarization, Sentiment Analysis | |
| **Performance:** | |
| - Chat: ~1-3s per response | |
| - Summarization: ~2-4s per summary | |
| - Sentiment Analysis: ~0.5-2s per analysis | |
| **Features:** | |
| - Single unified model for all tasks | |
| - Fine-tunable for custom requirements | |
| - Optimized for CPU inference | |
| - Production-ready architecture | |
| **Advantages over previous setup:** | |
| - Better quality responses (3.8B parameters vs 82M-300M) | |
| - Consistent performance across all tasks | |
| - Single model to maintain and fine-tune | |
| - More context-aware understanding | |
| """ | |
| return info | |
| # Initialize models on startup | |
| print("=" * 60) | |
| print("π Initializing Vish AI - Production Ready") | |
| print("=" * 60) | |
| print(f"Python Version: 3.x") | |
| print(f"AI Available: {AI_AVAILABLE}") | |
| print(f"Supabase Available: {SUPABASE_AVAILABLE}") | |
| print("=" * 60) | |
| if AI_AVAILABLE: | |
| print("\nπ Starting Phi-3 model initialization...") | |
| models_loaded = initialize_models() | |
| if models_loaded: | |
| print("\nβ All systems ready!") | |
| else: | |
| print("\nβ οΈ Running in demo mode") | |
| else: | |
| print("\nβ οΈ AI libraries not available - running in demo mode") | |
| print("π‘ This is normal for Python 3.14 - deploy to Hugging Face Spaces for full AI!") | |
| print("=" * 60) | |
| # Create Gradio Interface | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Vish AI") as demo: | |
| # Dynamic header based on AI availability | |
| if AI_AVAILABLE and phi3_model: | |
| status_badge = "π’ **PRODUCTION** - Phi-3 AI Model Active" | |
| else: | |
| status_badge = "π‘ **DEMO MODE** - Deploy to Hugging Face for Full AI" | |
| gr.Markdown(f""" | |
| # π Vish AI - Virtual Intelligent System Hub | |
| ### Lightweight, Fast, Multimodal AI Assistant | |
| {status_badge} | |
| Optimized for Hugging Face Spaces | Powered by Supabase | |
| """) | |
| with gr.Tabs(): | |
| # Chat Tab | |
| with gr.Tab("π¬ Chat Assistant"): | |
| with gr.Row(): | |
| with gr.Column(scale=4): | |
| chatbot = gr.Chatbot(height=400, label="Vish AI Chat", type="tuples") | |
| msg = gr.Textbox( | |
| label="Your Message", | |
| placeholder="Ask me anything...", | |
| lines=2 | |
| ) | |
| with gr.Row(): | |
| submit = gr.Button("Send", variant="primary") | |
| clear = gr.Button("Clear") | |
| with gr.Column(scale=1): | |
| auth_token_chat = gr.Textbox( | |
| label="π Auth Token (Optional)", | |
| type="password", | |
| placeholder="Supabase JWT token", | |
| lines=3 | |
| ) | |
| gr.Markdown(""" | |
| **Usage Tips:** | |
| - Just type and chat! | |
| - No token needed for demo | |
| - Add token for logging | |
| """) | |
| def respond(message, history, token): | |
| return chat_with_vish(message, history or [], token) | |
| submit.click(respond, inputs=[msg, chatbot, auth_token_chat], outputs=chatbot) | |
| msg.submit(respond, inputs=[msg, chatbot, auth_token_chat], outputs=chatbot) | |
| clear.click(lambda: [], None, chatbot, queue=False) | |
| # Summarization Tab | |
| with gr.Tab("π Text Summarizer"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| input_text = gr.Textbox( | |
| label="Enter Text to Summarize", | |
| placeholder="Paste your long text here (minimum 50 words)...", | |
| lines=10 | |
| ) | |
| auth_token_sum = gr.Textbox( | |
| label="Auth Token (Optional)", | |
| type="password" | |
| ) | |
| summarize_btn = gr.Button("Summarize", variant="primary") | |
| with gr.Column(): | |
| summary_output = gr.Textbox( | |
| label="Summary", | |
| lines=10 | |
| ) | |
| summarize_btn.click(summarize_text, [input_text, auth_token_sum], summary_output) | |
| # Sentiment Analysis Tab | |
| with gr.Tab("π Sentiment Analysis"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| sentiment_input = gr.Textbox( | |
| label="Enter Text to Analyze", | |
| placeholder="How do you feel about this?", | |
| lines=5 | |
| ) | |
| auth_token_sent = gr.Textbox( | |
| label="Auth Token (Optional)", | |
| type="password" | |
| ) | |
| analyze_btn = gr.Button("Analyze Sentiment", variant="primary") | |
| with gr.Column(): | |
| sentiment_output = gr.Textbox( | |
| label="Sentiment Result", | |
| lines=5 | |
| ) | |
| analyze_btn.click(analyze_sentiment, [sentiment_input, auth_token_sent], sentiment_output) | |
| # Model Info Tab | |
| with gr.Tab("βΉοΈ Model Info"): | |
| gr.Markdown(get_model_info()) | |
| gr.Markdown(""" | |
| --- | |
| **VIJ Project** | Powered by Supabase & Hugging Face | Built with β€οΈ by Vishwas | |
| """) | |
| # Launch the app | |
| if __name__ == "__main__": | |
| demo.queue() # Enable queuing for better performance | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False | |
| ) | |