Spaces:
Sleeping
Sleeping
File size: 6,745 Bytes
bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 36177f4 bdf8af1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | """
AI Engine β uses Groq (free tier) for LLM calls + gTTS for audio.
Setup on Hugging Face Spaces:
Settings β Repository secrets β Add:
Name : GROQ_API_KEY
Value: your key from https://console.groq.com (free, no credit card)
Free Groq model used: llama-3.3-70b-versatile
"""
import os
import json
import re
from groq import Groq
# ββ Client βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def get_client() -> Groq:
api_key = os.environ.get("GROQ_API_KEY", "")
if not api_key:
raise ValueError(
"GROQ_API_KEY secret not set.\n"
"Go to: Space Settings β Repository secrets β add GROQ_API_KEY\n"
"Get a free key at: https://console.groq.com"
)
return Groq(api_key=api_key)
def _chat(prompt: str, max_tokens: int = 1024) -> str:
"""Single-turn chat with llama-3.3-70b on Groq."""
client = get_client()
resp = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role": "user", "content": prompt}],
max_tokens=max_tokens,
temperature=0.7,
)
return resp.choices[0].message.content
# ββ Experiment Explanation ββββββββββββββββββββββββββββββββββββββββββββββββββββ
def generate_experiment_explanation(exp: dict) -> str:
prompt = f"""You are an enthusiastic science teacher for Class 10 students (age ~15).
Experiment: {exp['title']}
Materials: {exp['materials']}
Steps: {exp['steps']}
Outcome: {exp['outcome']}
Write a clear, engaging explanation (250β350 words) covering:
1. **What is happening scientifically** β the core concept
2. **Why it works** β the chemistry/biology/physics behind it
3. **Real-world connection** β where students see this in daily life
4. **Key formula or equation** if applicable (use simple notation)
Use friendly, enthusiastic language suitable for a 15-year-old."""
return _chat(prompt, max_tokens=700)
# ββ Quiz Generator ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def generate_quiz_questions(exp: dict) -> list:
prompt = f"""You are a science quiz creator for Class 10 students.
Experiment: {exp['title']}
Materials: {exp['materials']}
Steps: {exp['steps']}
Outcome: {exp['outcome']}
Generate exactly 5 multiple-choice questions testing understanding of this experiment.
Return ONLY a valid JSON array β no markdown fences, no extra text β in this exact format:
[
{{
"question": "Question text here?",
"options": ["A) Option 1", "B) Option 2", "C) Option 3", "D) Option 4"],
"answer": "A) Option 1",
"explanation": "Brief reason why this answer is correct."
}}
]
Cover: observation, concept, reasoning, safety, and real-world application."""
raw = _chat(prompt, max_tokens=1400)
raw = re.sub(r"```json|```", "", raw).strip()
# Find the JSON array inside the response
match = re.search(r"\[.*\]", raw, re.DOTALL)
if match:
raw = match.group(0)
try:
questions = json.loads(raw)
if isinstance(questions, list) and questions:
return questions
except json.JSONDecodeError:
pass
# Fallback single question
return [{
"question": f"What is the main observation in '{exp['title']}'?",
"options": [
f"A) {exp['outcome'][:70]}",
"B) No reaction takes place",
"C) The mixture turns blue",
"D) Heat is always absorbed",
],
"answer": f"A) {exp['outcome'][:70]}",
"explanation": exp["outcome"],
}]
# ββ Video Script Generator ββββββββββββββββββββββββββββββββββββββββββββββββββββ
def generate_video_script(exp: dict) -> str:
prompt = f"""You are a scriptwriter creating a 2-minute science video for Class 10 students.
Experiment: {exp['title']}
Materials: {exp['materials']}
Procedure: {exp['steps']}
Safety: {exp['safety']}
Outcome: {exp['outcome']}
Write a complete VIDEO SCRIPT with these six scenes:
π¬ SCENE 1 β HOOK (0:00β0:15)
[Camera/action]
Narrator: "..."
π¬ SCENE 2 β MATERIALS (0:15β0:30)
[Visual: each material shown]
Narrator: "..."
π¬ SCENE 3 β SAFETY BRIEFING (0:30β0:40)
[Safety icons / lab coat]
Narrator: "..."
π¬ SCENE 4 β STEP-BY-STEP PROCEDURE (0:40β1:20)
[Camera angle + action per step]
Narrator: "..."
π¬ SCENE 5 β OBSERVATION & RESULT (1:20β1:45)
[Close-up of the change/outcome]
Narrator: "..."
π¬ SCENE 6 β SCIENCE EXPLANATION (1:45β2:00)
[Animation or diagram]
Narrator: "..."
Include [ANIMATION: ...], [CLOSE-UP: ...], and [TEXT ON SCREEN: ...] cues.
Narrator text must be enthusiastic and clear for 15-year-old students."""
return _chat(prompt, max_tokens=1200)
# ββ Text-to-Speech ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def text_to_speech_explanation(exp: dict, script: str = None):
"""
Converts narrator lines from the script to MP3 using gTTS (free, no API key).
Returns the path to the MP3 file, or None on failure.
"""
try:
from gtts import gTTS
import tempfile
if script:
lines = []
for line in script.split("\n"):
line = line.strip()
if line.lower().startswith("narrator:"):
text = line[9:].strip().strip('"').strip("'")
if text:
lines.append(text)
audio_text = " ".join(lines) if lines else script
else:
audio_text = (
f"Welcome to the AI Science Lab. Today we explore: {exp['title']}. "
f"Materials needed: {exp['materials']}. "
f"Procedure: {exp['steps']}. "
f"Safety: {exp['safety']}. "
f"Expected outcome: {exp['outcome']}."
)
audio_text = audio_text[:3000] # gTTS limit
tts = gTTS(text=audio_text, lang="en", slow=False)
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
tts.save(tmp.name)
return tmp.name
except ImportError:
return None
except Exception as e:
print(f"TTS error: {e}")
return None |