|
|
|
import streamlit as st |
|
from gradio_client import Client |
|
from groq import Groq |
|
from PIL import Image |
|
import moviepy.editor as mp |
|
from natsort import natsorted |
|
import os |
|
from dotenv import load_dotenv |
|
import json |
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
HF_TOKEN = os.getenv("HF_TOKEN") |
|
GROQ_API_KEY = os.getenv("GROQ_API_KEY") |
|
IMAGE_GENERATION_SPACE_NAME = "stabilityai/stable-diffusion-3.5-large-turbo" |
|
|
|
|
|
groq_client = Groq(api_key=GROQ_API_KEY) |
|
|
|
|
|
LLM_MODELS = { |
|
"Mixtral 8x7B (Groq)": "mixtral-8x7b-32768", |
|
"Mistral 7B (HF)": "mistralai/Mixtral-7B-Instruct-v0.1", |
|
"LLaMA 13B (HF)": "meta-llama/Llama-13b-hf" |
|
} |
|
|
|
|
|
def generate_tutor_output(subject, difficulty, student_input, model): |
|
prompt = f""" |
|
You are an expert tutor in {subject} at the {difficulty} level. |
|
The student has provided the following input: "{student_input}" |
|
|
|
Please generate: |
|
1. A brief, engaging lesson on the topic (2-3 paragraphs) |
|
2. A thought-provoking question to check understanding |
|
3. Constructive feedback on the student's input |
|
|
|
Format your response as a JSON object with keys: "lesson", "question", "feedback" |
|
""" |
|
|
|
if model.startswith("mixtral"): |
|
completion = groq_client.chat.completions.create( |
|
messages=[{ |
|
"role": "system", |
|
"content": f"You are the world's best AI tutor for {subject}, renowned for clear, engaging explanations." |
|
}, { |
|
"role": "user", |
|
"content": prompt |
|
}], |
|
model=model, |
|
max_tokens=1000 |
|
) |
|
return json.loads(completion.choices[0].message.content) |
|
else: |
|
try: |
|
client = Client("https://api-inference.huggingface.co/models/" + model, hf_token=HF_TOKEN) |
|
response = client.predict(prompt, api_name="/generate") |
|
return json.loads(response) |
|
except: |
|
st.warning(f"HF model {model} failed, falling back to Mixtral.") |
|
return generate_tutor_output(subject, difficulty, student_input, "mixtral-8x7b-32768") |
|
|
|
def generate_image(prompt, path='temp_image.png'): |
|
try: |
|
client = Client(IMAGE_GENERATION_SPACE_NAME, hf_token=HF_TOKEN) |
|
result = client.predict( |
|
prompt=prompt, |
|
width=512, |
|
height=512, |
|
api_name="/predict" |
|
) |
|
image = Image.open(result) |
|
image.save(path) |
|
return path |
|
except Exception as e: |
|
st.error(f"Error generating image: {e}") |
|
return None |
|
|
|
def generate_video(images, audio_text, language, speaker, path='temp_video.mp4'): |
|
try: |
|
audio_client = Client("habib926653/Multilingual-TTS") |
|
audio_result = audio_client.predict( |
|
text=audio_text, |
|
language_code=language, |
|
speaker=speaker, |
|
api_name="/text_to_speech_edge" |
|
) |
|
audio_file = audio_result[1] |
|
with open(audio_file, 'rb') as f: |
|
audio_bytes = f.read() |
|
audio_path = "temp_audio.mp3" |
|
with open(audio_path, 'wb') as f: |
|
f.write(audio_bytes) |
|
|
|
audio_clip = mp.AudioFileClip(audio_path) |
|
duration_per_image = audio_clip.duration / len(images) |
|
image_clips = [mp.ImageClip(img).set_duration(duration_per_image) for img in images if img] |
|
video = mp.concatenate_videoclips(image_clips, method="compose").set_audio(audio_clip) |
|
video.write_videofile(path, fps=24, codec='libx264') |
|
return path |
|
except Exception as e: |
|
st.error(f"Error generating video: {e}") |
|
return None |
|
|
|
|
|
def main(): |
|
st.markdown("<h1 style='text-align: center;'>EduAI: Your Interactive Tutor</h1>", unsafe_allow_html=True) |
|
st.markdown("<p style='text-align: center;'>Learn, Ask, Visualize! ❤️</p>", unsafe_allow_html=True) |
|
|
|
subject = st.selectbox("Choose Subject:", ["Math", "Science", "History", "Literature", "Code", "AI"]) |
|
difficulty = st.selectbox("Difficulty Level:", ["Beginner", "Intermediate", "Advanced"]) |
|
model = st.selectbox("Choose LLM Model:", list(LLM_MODELS.keys())) |
|
student_input = st.text_area("Your Question/Input (max 1500 chars):", max_chars=1500) |
|
|
|
if 'tutor_response' not in st.session_state: |
|
st.session_state.tutor_response = None |
|
|
|
if st.button("Generate Answer & Question"): |
|
if student_input: |
|
with st.spinner("Generating your lesson..."): |
|
response = generate_tutor_output(subject, difficulty, student_input, LLM_MODELS[model]) |
|
st.session_state.tutor_response = response |
|
else: |
|
st.warning("Please provide an input!") |
|
|
|
if st.session_state.tutor_response: |
|
st.markdown("### Lesson") |
|
st.write(st.session_state.tutor_response["lesson"]) |
|
st.markdown("### Comprehension Question") |
|
st.write(st.session_state.tutor_response["question"]) |
|
st.markdown("### Feedback") |
|
st.write(st.session_state.tutor_response["feedback"]) |
|
|
|
col1, col2 = st.columns(2) |
|
with col1: |
|
if st.button("Generate Image"): |
|
with st.spinner("Creating image..."): |
|
image_path = generate_image(st.session_state.tutor_response["lesson"]) |
|
if image_path: |
|
st.image(image_path, caption="Visual of your lesson") |
|
with col2: |
|
if st.button("Generate Video"): |
|
with st.spinner("Creating video..."): |
|
audio_client = Client("habib926653/Multilingual-TTS") |
|
speakers_response = audio_client.predict(language="English", api_name="/get_speakers") |
|
speaker = speakers_response["choices"][0][0] |
|
images = [generate_image(st.session_state.tutor_response["lesson"])] |
|
video_path = generate_video(images, st.session_state.tutor_response["lesson"], "English", speaker) |
|
if video_path: |
|
st.video(video_path) |
|
|
|
st.markdown("---") |
|
st.markdown("<p style='text-align: center;'>Built for learning, powered by AI!</p>", unsafe_allow_html=True) |
|
|
|
if __name__ == "__main__": |
|
main() |