Spaces:
Sleeping
Sleeping
| """ | |
| Raven AI β Response Engine | |
| Handles response generation with streaming, document processing, | |
| image understanding, data analysis, and web search. | |
| """ | |
| import io | |
| import base64 | |
| from groq import Groq | |
| from config import GROQ_API_KEY, GROQ_MODEL, GROQ_MODEL_FAST, GROQ_VISION_MODEL, GROQ_WHISPER_MODEL | |
| from emotion_engine import get_persona, detect_crisis, detect_intent, get_intent_prompt | |
| client = Groq(api_key=GROQ_API_KEY) | |
| def clean_history(conversation_history): | |
| return [ | |
| {"role": m["role"], "content": m["content"]} | |
| for m in conversation_history | |
| if m.get("role") in ["user", "assistant"] and m.get("content") | |
| ] | |
| INTENT_TEMPERATURES = { | |
| "coding": 0.5, | |
| "learning": 0.5, | |
| "deep_dive": 0.6, | |
| "question": 0.65, | |
| "creative": 0.85, | |
| "venting": 0.75, | |
| "advice": 0.7, | |
| "casual": 0.75, | |
| "crisis": 0.6, | |
| } | |
| def get_temperature(intent): | |
| return INTENT_TEMPERATURES.get(intent, 0.75) | |
| def build_system_prompt(emotion, persona, intent, extra_context=""): | |
| intent_instruction = get_intent_prompt(intent) | |
| context_block = f"\n\nAdditional context provided by the user:\n{extra_context}" if extra_context else "" | |
| return f"""You are Raven β a brilliant, knowledgeable, and genuinely warm AI assistant built for real conversations. You're not just a chatbot β you're a thinking partner, tutor, coder, writer, analyst, and friend. | |
| Your primary job is to be deeply useful β give accurate answers, explain things clearly, help solve problems, write code, do calculations, create content, analyze data, and provide real value. You do this with warmth and personality, never in a cold or robotic way. | |
| The user appears to be feeling: {emotion}. | |
| Subtly shape your delivery to be: {persona}. | |
| The user's intent is: {intent}. | |
| How to handle this: {intent_instruction} | |
| {context_block} | |
| βββ CORE CAPABILITIES βββ | |
| π EXPLAINING & TEACHING: | |
| - Break complex topics into digestible parts | |
| - Use analogies and real-world examples | |
| - Build from basics to depth β like a patient tutor | |
| - Adapt explanation level to the user's understanding | |
| - For technical topics, include both high-level overview and detailed breakdown | |
| π» CODING & DEVELOPMENT: | |
| - ALWAYS put ALL code, config, and markup inside fenced code blocks with the correct language tag β NEVER write code outside a code block. This applies to EVERY language: ```python, ```java, ```c, ```cpp, ```javascript, ```typescript, ```html, ```css, ```json, ```yaml, ```sql, ```bash, ```xml, ```go, ```rust, ```ruby, ```php, ```swift, ```kotlin, ```dart, ```r, ```matlab, ```shell, ```powershell, ```dockerfile, ```toml, ```ini, ```csv, etc. | |
| - Before writing code, briefly explain your APPROACH and ARCHITECTURE (what files, what structure, what flow) | |
| - Ensure the code structure is CORRECT β proper imports at top, logical function/class order, correct indentation | |
| - Ensure the implementation FLOW is correct β functions should be called in the right order, data should flow logically between components | |
| - Write COMPLETE, WORKING code β never leave placeholders like "# your code here" or "pass". Every function must be fully implemented | |
| - Include error handling, input validation, and edge cases | |
| - Add clear comments explaining WHY, not just WHAT | |
| - If debugging, identify root cause first, explain the bug, then provide the fixed code | |
| - For complex projects, break into files/modules and explain the structure: | |
| * Show folder structure first | |
| * Then provide each file with complete code | |
| * Explain how files connect to each other | |
| - Suggest best practices, design patterns, and optimizations | |
| - If the user's approach has issues, point them out and suggest a better way | |
| - For web apps: ensure routes, templates, static files are all correctly connected | |
| - For APIs: ensure endpoints, request/response formats, error codes are all proper | |
| - For algorithms: explain time/space complexity | |
| βοΈ WRITING & CONTENT: | |
| - Essays, reports, assignments, project documentation | |
| - Emails, messages in any tone (formal, casual, persuasive) | |
| - Stories, scripts, poems, creative pieces | |
| - Technical documentation, README files | |
| - Rewrite/improve existing text β grammar, structure, tone | |
| - Match the user's creative vision when doing creative work | |
| π DATA ANALYSIS: | |
| - Analyze tables, CSV data, numbers, statistics | |
| - Identify trends, patterns, outliers | |
| - Explain findings in plain language | |
| - Suggest visualizations and insights | |
| - Help with statistical concepts and calculations | |
| π§© PROBLEM SOLVING & DECISIONS: | |
| - Compare options with pros/cons | |
| - Consider user constraints (budget, time, skill level) | |
| - Give clear, actionable recommendations | |
| - Break complex problems into manageable steps | |
| - Think through edge cases and trade-offs | |
| π DOCUMENT PROCESSING: | |
| - Summarize documents, papers, articles | |
| - Extract key points and main arguments | |
| - Generate Q&A from content β great for exam prep | |
| - Create flashcards and study notes | |
| - Rewrite in simpler language | |
| - Identify important topics and themes | |
| π§ MULTI-STEP REASONING: | |
| - Break complex problems into logical steps | |
| - Combine knowledge from multiple domains | |
| - Plan workflows and architectures | |
| - Show your reasoning process clearly | |
| βββ CORE PRINCIPLES βββ | |
| - Be knowledgeable and thorough β but never dry or textbook-like | |
| - Be warm and friendly β natural warmth, not performative cheerfulness | |
| - Match your energy to the user's emotion and intent | |
| - Never water down an answer because of someone's emotional state | |
| - Be honest and direct β say what you mean | |
| - Use natural conversational language β like a brilliant friend | |
| - For calculations, always show working step by step | |
| - For long/detailed requests, ALWAYS deliver full content. Never truncate | |
| - If the user uploads a file, analyze it thoroughly | |
| - The emotional awareness shapes HOW you say things, never WHAT you say | |
| - Use markdown formatting: headers, bullet points, bold, code blocks | |
| - For GK, science, history β be comprehensive with interesting context | |
| - ONLY provide code when the user explicitly asks for code, a script, implementation, debugging help, or a programming task. For conceptual/theoretical questions, explain in plain language WITHOUT code blocks unless the user specifically requests code or an example implementation | |
| - When you DO provide code: (1) Write a small bold label like **`Python:`** or **`JavaScript:`** ABOVE each code block so the user can see the language, AND (2) use the correct language tag in the fence (```python, ```javascript, etc.). NEVER use bare ``` without a language tag. ALWAYS do both β the visible label AND the fence tag.""" | |
| def get_response(user_message, emotion, conversation_history, extra_context=""): | |
| """Non-streaming response (used for summaries, titles, etc.)""" | |
| if detect_crisis(user_message): | |
| return _crisis_response() | |
| intent = detect_intent(user_message, emotion) | |
| persona = get_persona(emotion) | |
| system_prompt = build_system_prompt(emotion, persona, intent, extra_context) | |
| temp = get_temperature(intent) | |
| messages = [{"role": "system", "content": system_prompt}] | |
| messages += clean_history(conversation_history[-20:]) | |
| messages.append({"role": "user", "content": user_message}) | |
| try: | |
| response = client.chat.completions.create( | |
| model=GROQ_MODEL, | |
| messages=messages, | |
| max_tokens=4096, | |
| temperature=temp, | |
| ) | |
| except Exception: | |
| response = client.chat.completions.create( | |
| model=GROQ_MODEL_FAST, | |
| messages=messages, | |
| max_tokens=4096, | |
| temperature=temp, | |
| ) | |
| return response.choices[0].message.content.strip() | |
| def get_response_stream(user_message, emotion, conversation_history, extra_context=""): | |
| """ | |
| Streaming response generator β yields chunks of text as they arrive. | |
| Used for the main chat interface for real-time text display. | |
| """ | |
| if detect_crisis(user_message): | |
| yield _crisis_response() | |
| return | |
| intent = detect_intent(user_message, emotion) | |
| persona = get_persona(emotion) | |
| system_prompt = build_system_prompt(emotion, persona, intent, extra_context) | |
| temp = get_temperature(intent) | |
| messages = [{"role": "system", "content": system_prompt}] | |
| messages += clean_history(conversation_history[-20:]) | |
| messages.append({"role": "user", "content": user_message}) | |
| try: | |
| stream = client.chat.completions.create( | |
| model=GROQ_MODEL, | |
| messages=messages, | |
| max_tokens=4096, | |
| temperature=temp, | |
| stream=True, | |
| ) | |
| except Exception: | |
| stream = client.chat.completions.create( | |
| model=GROQ_MODEL_FAST, | |
| messages=messages, | |
| max_tokens=4096, | |
| temperature=temp, | |
| stream=True, | |
| ) | |
| for chunk in stream: | |
| if chunk.choices[0].delta.content is not None: | |
| yield chunk.choices[0].delta.content | |
| def generate_title(user_message): | |
| """Generate a short conversation title from the first message.""" | |
| try: | |
| response = client.chat.completions.create( | |
| model=GROQ_MODEL_FAST, | |
| messages=[{ | |
| "role": "user", | |
| "content": f"Generate a 3-5 word title for a conversation that starts with this message. Reply with ONLY the title, no quotes, no punctuation at the end.\n\nMessage: \"{user_message}\"" | |
| }], | |
| max_tokens=15, | |
| temperature=0.5, | |
| ) | |
| title = response.choices[0].message.content.strip().strip('"').strip("'") | |
| return title[:50] # cap length | |
| except Exception: | |
| return user_message[:40] + "..." | |
| # ββ Image Understanding (Groq Vision) ββββββββββββββββββββββββββββββββββββββ | |
| def analyze_image(image_data, user_message="Describe this image in detail."): | |
| """Analyze one or more images using Groq's vision model (max 5).""" | |
| try: | |
| # Support both single image (bytes) and multiple images (list of bytes) | |
| if isinstance(image_data, list): | |
| images = image_data[:5] # Llama 4 Scout supports max 5 | |
| else: | |
| images = [image_data] | |
| content = [{"type": "text", "text": user_message}] | |
| for img_bytes in images: | |
| b64 = base64.b64encode(img_bytes).decode("utf-8") | |
| content.append({ | |
| "type": "image_url", | |
| "image_url": {"url": f"data:image/png;base64,{b64}"} | |
| }) | |
| response = client.chat.completions.create( | |
| model=GROQ_VISION_MODEL, | |
| messages=[{"role": "user", "content": content}], | |
| max_tokens=4096, | |
| temperature=0.5, | |
| ) | |
| return response.choices[0].message.content.strip() | |
| except Exception as e: | |
| return f"I couldn't analyze the image right now. Error: {str(e)}" | |
| # ββ Voice/Audio Transcription (Groq Whisper) ββββββββββββββββββββββββββββββββ | |
| def transcribe_audio(audio_bytes, filename="audio.wav"): | |
| """Transcribe audio using Groq's Whisper model.""" | |
| try: | |
| audio_file = io.BytesIO(audio_bytes) | |
| audio_file.name = filename | |
| transcription = client.audio.transcriptions.create( | |
| model=GROQ_WHISPER_MODEL, | |
| file=audio_file, | |
| response_format="text", | |
| ) | |
| return transcription.strip() if isinstance(transcription, str) else transcription.text.strip() | |
| except Exception as e: | |
| return f"Couldn't transcribe audio: {str(e)}" | |
| # ββ Document Processing βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def process_document(file_content, filename, action="summarize"): | |
| """Process uploaded documents with various actions.""" | |
| action_prompts = { | |
| "summarize": "Summarize this document concisely, capturing all key points and main arguments.", | |
| "key_points": "Extract the key points from this document as a bulleted list. Be thorough.", | |
| "questions": "Generate 10-15 exam-style questions (mix of short answer and long answer) from this document. Include answers.", | |
| "flashcards": "Create flashcards from this document. Format: Q: [question] β A: [answer]. Cover all important concepts.", | |
| "simplify": "Rewrite this document in simpler language that a high school student could understand. Keep all important information.", | |
| "topics": "Identify and list all important topics covered in this document, with a brief description of each.", | |
| "notes": "Convert this document into well-organized study notes with headings, subheadings, and bullet points.", | |
| } | |
| prompt = action_prompts.get(action, action_prompts["summarize"]) | |
| full_prompt = f"""{prompt} | |
| Document ({filename}): | |
| --- | |
| {file_content[:12000]} | |
| ---""" | |
| try: | |
| response = client.chat.completions.create( | |
| model=GROQ_MODEL, | |
| messages=[ | |
| {"role": "system", "content": "You are an expert document analyst and educator. Process the given document thoroughly and accurately."}, | |
| {"role": "user", "content": full_prompt} | |
| ], | |
| max_tokens=4096, | |
| temperature=0.3, | |
| ) | |
| return response.choices[0].message.content.strip() | |
| except Exception: | |
| try: | |
| response = client.chat.completions.create( | |
| model=GROQ_MODEL_FAST, | |
| messages=[ | |
| {"role": "system", "content": "You are an expert document analyst. Process the given document thoroughly."}, | |
| {"role": "user", "content": full_prompt} | |
| ], | |
| max_tokens=4096, | |
| temperature=0.3, | |
| ) | |
| return response.choices[0].message.content.strip() | |
| except Exception as e: | |
| return f"Error processing document: {str(e)}" | |
| # ββ Data Analysis βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def analyze_data(df_summary, user_question="Analyze this data and provide insights."): | |
| """Analyze data from a DataFrame summary.""" | |
| prompt = f"""{user_question} | |
| Here is the data summary: | |
| {df_summary} | |
| Provide: | |
| 1. Key observations and patterns | |
| 2. Notable statistics or outliers | |
| 3. Actionable insights | |
| 4. Suggested visualizations if relevant""" | |
| try: | |
| response = client.chat.completions.create( | |
| model=GROQ_MODEL, | |
| messages=[ | |
| {"role": "system", "content": "You are an expert data analyst. Analyze the data thoroughly, identify patterns, and provide clear insights."}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| max_tokens=4096, | |
| temperature=0.4, | |
| ) | |
| return response.choices[0].message.content.strip() | |
| except Exception as e: | |
| return f"Error analyzing data: {str(e)}" | |
| # ββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _crisis_response(): | |
| return """I can hear that you're going through something really difficult right now. | |
| You don't have to face this alone. Please reach out to someone who can help: | |
| π iCall (India): 9152987821 | |
| π Vandrevala Foundation: 1860-2662-345 (24/7) | |
| π International Association for Suicide Prevention: https://www.iasp.info/resources/Crisis_Centres/ | |
| I'm here to talk if you need me.""" | |
| def search_and_respond(user_message, emotion, conversation_history, extra_context=""): | |
| """Legacy wrapper β returns (response, searched_web).""" | |
| response = get_response(user_message, emotion, conversation_history, extra_context) | |
| return response, False | |