Gyan.AI / src /services /ai_service.py
cryogenic22's picture
Update src/services/ai_service.py
b6624e5 verified
import streamlit as st
from datetime import datetime
import anthropic
import os
import tempfile
class AITutorService:
def __init__(self):
self._client = None
self.initialize_client()
self.voice_enabled = False
self.tts_mode = None
self.openai_enabled = False
@property
def client(self):
"""Property to safely access the Anthropic client"""
if self._client is None:
raise ValueError("Anthropic client not properly initialized")
return self._client
def initialize_client(self):
"""Initialize Anthropic client with better error handling"""
try:
api_key = st.secrets.get("ANTHROPIC_API_KEY") or os.getenv('ANTHROPIC_API_KEY')
if not api_key:
st.error("ANTHROPIC_API_KEY not found in secrets or environment variables")
return
self._client = anthropic.Anthropic(api_key=api_key)
self.voice_enabled = True
self.tts_mode = 'openai'
self.openai_enabled = True
except Exception as e:
st.error(f"Failed to initialize Anthropic client: {str(e)}")
self._client = None
self.voice_enabled = False
self.tts_mode = None
self.openai_enabled = False
def generate_response(self, user_input: str, current_topic: str = None) -> str:
"""Generate response using Claude with better error handling"""
if not self.client:
return "I apologize, but I'm not properly connected right now. Please check the API configuration."
try:
# Build system prompt
system_prompt = """You are an expert tutor helping students learn.
Give clear, step-by-step explanations with examples."""
if current_topic and current_topic != "All Topics":
system_prompt += f"\nYou are currently tutoring about {current_topic}."
# Generate response
response = self.client.messages.create(
model="claude-3-opus-20240229",
temperature=0.7,
max_tokens=1024,
system=system_prompt,
messages=[{
"role": "user",
"content": user_input
}]
)
# Get response text
response_text = response.content[0].text
# Update metrics
self.update_engagement_metrics(user_input, response_text)
return response_text
except anthropic.APIError as e:
st.error(f"API Error: {str(e)}")
return "I encountered an API error. Please try again in a moment."
except anthropic.APIConnectionError as e:
st.error(f"Connection Error: {str(e)}")
return "I'm having trouble connecting to my API. Please check your internet connection."
except Exception as e:
st.error(f"Unexpected error: {str(e)}")
return "I encountered an unexpected error. Please try again."
def speak(self, text: str):
"""Make the AI tutor speak using available TTS method"""
if not self.voice_enabled:
return
if self.tts_mode == 'openai':
if self.openai_enabled:
self.speak_with_openai(text)
else:
st.warning("OpenAI TTS is not available. Voice output is disabled.")
self.tts_mode = None
self.voice_enabled = False
else:
st.warning("Local TTS is not implemented yet.")
def speak_with_openai(self, text: str):
"""Generate speech using OpenAI's TTS"""
try:
# Generate speech using OpenAI
response = self.client.audio.speech.create(
model="tts-1",
voice="alloy", # or "nova", "shimmer", "echo", "fable"
input=text
)
# Create a temporary file to store the audio
with tempfile.NamedTemporaryFile(delete=False, suffix='.mp3') as tmp_file:
response.stream_to_file(tmp_file.name)
# Create audio player in Streamlit
audio_file = open(tmp_file.name, 'rb')
audio_bytes = audio_file.read()
st.audio(audio_bytes, format='audio/mp3')
# Clean up
audio_file.close()
os.unlink(tmp_file.name)
except Exception as e:
st.error(f"Error during OpenAI speech synthesis: {e}")
def update_engagement_metrics(self, user_input: str, response: str):
"""Update engagement metrics"""
if 'tutor_context' not in st.session_state:
st.session_state.tutor_context = {
'engagement_metrics': []
}
metrics = st.session_state.tutor_context['engagement_metrics']
metrics.append({
'timestamp': datetime.now().isoformat(),
'sentiment_score': min(1.0, len(user_input) / 100.0),
'interaction_length': len(user_input)
})