cryogenic22 commited on
Commit
ffedf43
·
verified ·
1 Parent(s): ee76500

Update src/components/ai_tutor.py

Browse files
Files changed (1) hide show
  1. src/components/ai_tutor.py +13 -173
src/components/ai_tutor.py CHANGED
@@ -1,144 +1,6 @@
1
  import streamlit as st
2
- from datetime import datetime
3
- import anthropic
4
- import os
5
- from typing import Dict
6
-
7
- class AITutorService:
8
- def __init__(self):
9
- self._client = None
10
- self.initialize_client()
11
- self._load_avatar_assets()
12
-
13
- def initialize_client(self):
14
- """Initialize Anthropic client with better error handling"""
15
- try:
16
- # First try getting API key from Streamlit secrets
17
- api_key = None
18
- if hasattr(st, 'secrets') and 'ANTHROPIC_API_KEY' in st.secrets:
19
- api_key = st.secrets['ANTHROPIC_API_KEY']
20
-
21
- # If not in secrets, try environment variable
22
- if not api_key:
23
- api_key = os.getenv('ANTHROPIC_API_KEY')
24
-
25
- if not api_key:
26
- st.error("Anthropic API key not found. Please set ANTHROPIC_API_KEY in .streamlit/secrets.toml or environment variables.")
27
- st.info("For testing, you can set this up locally by creating a .streamlit/secrets.toml file with:\nANTHROPIC_API_KEY='your-key-here'")
28
- return
29
-
30
- self._client = anthropic.Anthropic(api_key=api_key)
31
-
32
- except Exception as e:
33
- st.error(f"Failed to initialize Anthropic client: {str(e)}")
34
- self._client = None
35
-
36
- def _load_avatar_assets(self):
37
- """Initialize avatar states and assets"""
38
- self.avatar_states = {
39
- 'neutral': """
40
- <svg width="100" height="100" viewBox="0 0 100 100">
41
- <circle cx="50" cy="50" r="45" fill="#4A90E2"/>
42
- <circle cx="35" cy="40" r="5" fill="white"/>
43
- <circle cx="65" cy="40" r="5" fill="white"/>
44
- <path d="M 30 65 Q 50 65 70 65" stroke="white" fill="none" stroke-width="3"/>
45
- </svg>
46
- """,
47
- 'thinking': """
48
- <svg width="100" height="100" viewBox="0 0 100 100">
49
- <circle cx="50" cy="50" r="45" fill="#4A90E2"/>
50
- <circle cx="35" cy="40" r="5" fill="white"/>
51
- <circle cx="65" cy="40" r="5" fill="white"/>
52
- <path d="M 30 60 Q 50 70 70 60" stroke="white" fill="none" stroke-width="3"/>
53
- </svg>
54
- """,
55
- 'happy': """
56
- <svg width="100" height="100" viewBox="0 0 100 100">
57
- <circle cx="50" cy="50" r="45" fill="#4A90E2"/>
58
- <circle cx="35" cy="40" r="5" fill="white"/>
59
- <circle cx="65" cy="40" r="5" fill="white"/>
60
- <path d="M 30 60 Q 50 80 70 60" stroke="white" fill="none" stroke-width="3"/>
61
- </svg>
62
- """
63
- }
64
-
65
- @property
66
- def client(self):
67
- """Property to safely access the Anthropic client"""
68
- if self._client is None:
69
- raise ValueError("Anthropic client not properly initialized")
70
- return self._client
71
-
72
- def display_avatar(self, state: str = 'neutral'):
73
- """Display the AI tutor avatar"""
74
- avatar_svg = self.avatar_states.get(state, self.avatar_states['neutral'])
75
- st.markdown(f"""
76
- <div style="display: flex; justify-content: center; margin: 20px 0;">
77
- {avatar_svg}
78
- </div>
79
- """, unsafe_allow_html=True)
80
-
81
- def generate_response(self, user_input: str) -> str:
82
- """Generate response using Claude with better error handling"""
83
- if not self._client:
84
- return "I apologize, but I'm not properly connected right now. Please check the API configuration."
85
-
86
- try:
87
- # Get session context
88
- context = st.session_state.get('tutor_context', {})
89
- current_topic = context.get('current_topic')
90
-
91
- # Build system prompt
92
- system_prompt = """You are an expert tutor helping students learn.
93
- Give clear, step-by-step explanations with examples.
94
- Focus on the current topic if specified."""
95
-
96
- if current_topic and current_topic != "All Topics":
97
- system_prompt += f"\nYou are currently tutoring about {current_topic}."
98
-
99
- # Generate response
100
- response = self.client.messages.create(
101
- model="claude-3-opus-20240229",
102
- temperature=0.7,
103
- max_tokens=1024,
104
- system=system_prompt,
105
- messages=[{
106
- "role": "user",
107
- "content": user_input
108
- }]
109
- )
110
-
111
- # Get response text
112
- response_text = response.content[0].text
113
-
114
- # Update metrics
115
- self.update_engagement_metrics(user_input, response_text)
116
-
117
- return response_text
118
-
119
- except anthropic.APIError as e:
120
- st.error(f"API Error: {str(e)}")
121
- return "I encountered an API error. Please try again in a moment."
122
- except anthropic.APIConnectionError as e:
123
- st.error(f"Connection Error: {str(e)}")
124
- return "I'm having trouble connecting to my API. Please check your internet connection."
125
- except Exception as e:
126
- st.error(f"Unexpected error: {str(e)}")
127
- return "I encountered an unexpected error. Please try again."
128
-
129
- def update_engagement_metrics(self, user_input: str, response: str):
130
- """Update engagement metrics"""
131
- if 'tutor_context' not in st.session_state:
132
- st.session_state.tutor_context = {
133
- 'engagement_metrics': []
134
- }
135
-
136
- metrics = st.session_state.tutor_context['engagement_metrics']
137
- metrics.append({
138
- 'timestamp': datetime.now().isoformat(),
139
- 'sentiment_score': min(1.0, len(user_input) / 100.0),
140
- 'interaction_length': len(user_input)
141
- })
142
 
143
  class AITutor:
144
  def __init__(self):
@@ -151,15 +13,13 @@ class AITutor:
151
  # Voice controls with TTS mode indicator
152
  col1, col2 = st.columns([3, 2])
153
  with col1:
154
- st.write("Voice features not implemented yet.")
155
- # if self.voice_enabled:
156
- # voice_active = st.toggle("Enable Voice", value=False, key="voice_active")
157
- # else:
158
- # voice_active = False
159
  with col2:
160
- st.write("TTS mode not implemented yet.")
161
- # if self.tts_mode:
162
- # st.info(f"Using {self.tts_mode.upper()} TTS")
163
 
164
  # Display avatar
165
  self.service.display_avatar(state='neutral')
@@ -186,9 +46,9 @@ class AITutor:
186
  st.write(message["content"])
187
  if message["role"] == "assistant":
188
  self.service.display_avatar(state='happy')
189
- # if voice_active and message.get('speak', True):
190
- # self.speak(message["content"])
191
- # message['speak'] = False
192
 
193
  # Chat input
194
  if prompt := st.text_input("Ask your question...", key="chat_input"):
@@ -216,25 +76,5 @@ class AITutor:
216
  "speak": True
217
  })
218
 
219
- # Show happy avatar and rerun
220
- self.service.display_avatar(state='happy')
221
- st.experimental_rerun()
222
-
223
- def get_tutor_context() -> Dict:
224
- """Get or initialize tutor context"""
225
- if 'tutor_context' not in st.session_state:
226
- st.session_state.tutor_context = {
227
- 'current_topic': None,
228
- 'chat_history': []
229
- }
230
- return st.session_state.tutor_context
231
-
232
- def main():
233
- """Main Streamlit application entry point"""
234
- st.set_page_config(page_title="EduAI Platform", page_icon="🎓")
235
-
236
- ai_tutor = AITutor()
237
- ai_tutor.display_chat_interface()
238
-
239
- if __name__ == "__main__":
240
- main()
 
1
  import streamlit as st
2
+ from src.services.ai_service import AITutorService
3
+ from src.utils.session import get_tutor_context
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  class AITutor:
6
  def __init__(self):
 
13
  # Voice controls with TTS mode indicator
14
  col1, col2 = st.columns([3, 2])
15
  with col1:
16
+ if self.service.voice_enabled:
17
+ voice_active = st.toggle("Enable Voice", value=False, key="voice_active")
18
+ else:
19
+ voice_active = False
 
20
  with col2:
21
+ if self.service.tts_mode:
22
+ st.info(f"Using {self.service.tts_mode.upper()} TTS")
 
23
 
24
  # Display avatar
25
  self.service.display_avatar(state='neutral')
 
46
  st.write(message["content"])
47
  if message["role"] == "assistant":
48
  self.service.display_avatar(state='happy')
49
+ if voice_active and message.get('speak', True):
50
+ self.service.speak(message["content"])
51
+ message['speak'] = False
52
 
53
  # Chat input
54
  if prompt := st.text_input("Ask your question...", key="chat_input"):
 
76
  "speak": True
77
  })
78
 
79
+ # Show happy avatar
80
+ self.service.display_avatar(state='happy')