Spaces:
Build error
Build error
| import streamlit as st | |
| from typing import Dict | |
| from datetime import datetime | |
| import anthropic | |
| from src.utils.session import get_tutor_context | |
| from src.utils.config import get_anthropic_api_key | |
| class AITutorService: | |
| def __init__(self): | |
| self.initialize_client() | |
| self.load_avatar_assets() | |
| def initialize_client(self): | |
| """Initialize Anthropic client""" | |
| self.client = anthropic.Anthropic(api_key=get_anthropic_api_key()) | |
| def load_avatar_assets(self): | |
| """Load avatar assets and animations""" | |
| self.avatar_states = { | |
| 'neutral': """ | |
| <svg width="100" height="100" viewBox="0 0 100 100"> | |
| <circle cx="50" cy="50" r="45" fill="#4A90E2"/> | |
| <circle cx="35" cy="40" r="5" fill="white"/> | |
| <circle cx="65" cy="40" r="5" fill="white"/> | |
| <path d="M 30 60 Q 50 70 70 60" stroke="white" fill="none" stroke-width="3"/> | |
| </svg> | |
| """, | |
| 'thinking': """ | |
| <svg width="100" height="100" viewBox="0 0 100 100"> | |
| <circle cx="50" cy="50" r="45" fill="#4A90E2"/> | |
| <circle cx="35" cy="40" r="5" fill="white"/> | |
| <circle cx="65" cy="40" r="5" fill="white"/> | |
| <path d="M 30 65 Q 50 65 70 65" stroke="white" fill="none" stroke-width="3"/> | |
| </svg> | |
| """, | |
| 'happy': """ | |
| <svg width="100" height="100" viewBox="0 0 100 100"> | |
| <circle cx="50" cy="50" r="45" fill="#4A90E2"/> | |
| <circle cx="35" cy="40" r="5" fill="white"/> | |
| <circle cx="65" cy="40" r="5" fill="white"/> | |
| <path d="M 30 60 Q 50 80 70 60" stroke="white" fill="none" stroke-width="3"/> | |
| </svg> | |
| """ | |
| } | |
| def display_avatar(self, state: str = 'neutral'): | |
| """Display the AI tutor avatar""" | |
| st.markdown(f""" | |
| <div style="display: flex; justify-content: center; margin: 20px 0;"> | |
| {self.avatar_states.get(state, self.avatar_states['neutral'])} | |
| </div> | |
| """, unsafe_allow_html=True) | |
| def generate_response(self, user_input: str) -> str: | |
| """Generate contextualized response using Claude""" | |
| context = get_tutor_context() | |
| prompt = self.build_prompt(user_input, context) | |
| # Generate response using Claude | |
| message = self.client.messages.create( | |
| model="claude-3-opus-20240229", | |
| max_tokens=1024, | |
| temperature=0.7, | |
| system="You are an expert AI tutor, skilled at explaining complex concepts clearly and engaging students in their learning journey. Provide detailed, accurate explanations while maintaining an encouraging tone.", | |
| messages=[ | |
| { | |
| "role": "user", | |
| "content": prompt | |
| } | |
| ] | |
| ) | |
| response = message.content[0].text | |
| # Analyze sentiment (Claude can do this as part of its response) | |
| sentiment_score = 0.8 if any(word in response.lower() for word in ['great', 'excellent', 'good job', 'well done']) else 0.5 | |
| # Update engagement metrics | |
| self.update_engagement_metrics(user_input, response, sentiment_score) | |
| return response | |
| def build_prompt(self, user_input: str, context: Dict) -> str: | |
| """Build a context-aware prompt for Claude""" | |
| topic_context = f"Current topic: {context'current_topic'}\n" if context'current_topic' else "" | |
| chat_context = "\n".join( | |
| f"Student: {msg['content']}" if msg'role' == 'user' else f"Tutor: {msg'content'}" | |
| for msg in context'chat_history'-3: | |
| ]) | |
| return f""" | |
| You are an educational AI tutor helping a student learn. | |
| {topic_context} | |
| Difficulty level: {context'difficulty_level'} | |
| Learning style: {context'learning_style'} | |
| Previous conversation: | |
| {chat_context} | |
| Student: {user_input} | |
| Provide a clear, helpful response that: | |
| 1. Addresses the student's question directly | |
| 2. Explains concepts in an engaging way | |
| 3. Uses examples when appropriate | |
| 4. Encourages deeper understanding | |
| 5. Maintains a supportive tone | |
| If the question is about code, include working code examples. | |
| If the topic is complex, break it down into simpler parts. | |
| """ | |
| def update_engagement_metrics(self, user_input: str, response: str, sentiment_score: float): | |
| """Update student engagement metrics""" | |
| context = get_tutor_context() | |
| context'engagement_metrics'.append({ | |
| 'timestamp': datetime.now().isoformat(), | |
| 'sentiment_score': sentiment_score, | |
| 'interaction_length': len(user_input) | |
| }) |