cwattsnogueira commited on
Commit
9fed4f0
Β·
verified Β·
1 Parent(s): 56a3648

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -145
app.py CHANGED
@@ -1,146 +1,146 @@
1
- import os
2
- import asyncio
3
- import google.generativeai as genai
4
-
5
- from google.adk.agents import Agent
6
- from google.adk.models.google_llm import Gemini
7
- from google.adk.runners import InMemoryRunner
8
- from google.adk.tools import google_search
9
- from google.genai import types
10
-
11
- from google.cloud import texttospeech
12
- from pydub import AudioSegment
13
- import gradio as gr
14
-
15
- # --- Configure API Keys ---
16
- GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
17
- if not GOOGLE_API_KEY:
18
- raise RuntimeError("❌ Missing GOOGLE_API_KEY environment variable.")
19
- genai.configure(api_key=GOOGLE_API_KEY)
20
-
21
- SERVICE_ACCOUNT_JSON = os.getenv("GCP_VI_SERVICE_ACCOUNT_JSON")
22
- if not SERVICE_ACCOUNT_JSON:
23
- raise RuntimeError("❌ Missing GCP_VI_SERVICE_ACCOUNT_JSON environment variable.")
24
-
25
- with open("tinytutor-tss-agent.json", "w") as f:
26
- f.write(SERVICE_ACCOUNT_JSON)
27
-
28
- os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "tinytutor-tss-agent.json"
29
- tts_client = texttospeech.TextToSpeechClient()
30
-
31
- # --- Retry Options ---
32
- retry_config = types.HttpRetryOptions(
33
- attempts=5,
34
- exp_base=7,
35
- initial_delay=1,
36
- http_status_codes=[429, 500, 503, 504]
37
- )
38
-
39
- # --- Pedagogy Agent ---
40
- pedagogy_agent = Agent(
41
- name="PedagogyAgent",
42
- model=Gemini(model="gemini-2.5-flash-lite", retry_options=retry_config),
43
- description="Explains topics in simple ELI5 style.",
44
- instruction="Explain the topic like I'm 5. Use google_search if needed.",
45
- tools=[google_search],
46
- )
47
- runner = InMemoryRunner(agent=pedagogy_agent)
48
-
49
- async def run_pedagogy_async(topic: str) -> str:
50
- response = await runner.run_debug(topic)
51
- return response[0].content.parts[0].text
52
-
53
- # --- ScriptWriter Agent ---
54
- SCRIPTWRITER_SYSTEM_PROMPT = """
55
- You are a Teacher.
56
- ... (same as your original prompt) ...
57
- """
58
-
59
- def run_scriptwriter(explanation: str) -> str:
60
- model = genai.GenerativeModel(
61
- model_name="gemini-2.5-flash",
62
- system_instruction=SCRIPTWRITER_SYSTEM_PROMPT
63
- )
64
- response = model.generate_content(
65
- f"Write a children's story based on this:\n{explanation}",
66
- generation_config=genai.GenerationConfig(
67
- temperature=0.9,
68
- max_output_tokens=4096
69
- )
70
- )
71
- try:
72
- return response.text
73
- except Exception:
74
- try:
75
- return response.candidates[0].content.parts[0].text
76
- except Exception:
77
- return "⚠️ ScriptWriter failed."
78
-
79
- # --- Audio Generator ---
80
- def chunk_text(text, max_chars=4500):
81
- text = text.strip()
82
- if len(text) <= max_chars:
83
- return [text]
84
- chunks = []
85
- while len(text) > max_chars:
86
- cut = text.rfind(". ", 0, max_chars)
87
- if cut == -1:
88
- cut = max_chars
89
- chunks.append(text[:cut+1])
90
- text = text[cut+1:].strip()
91
- chunks.append(text)
92
- return chunks
93
-
94
- def tts_segment(text):
95
- synthesis_input = texttospeech.SynthesisInput(text=text)
96
- voice = texttospeech.VoiceSelectionParams(
97
- language_code="en-US",
98
- name="en-US-Journey-F"
99
- )
100
- audio_cfg = texttospeech.AudioConfig(
101
- audio_encoding=texttospeech.AudioEncoding.MP3,
102
- speaking_rate=0.94,
103
- pitch=0.0,
104
- volume_gain_db=0.0
105
- )
106
- response = tts_client.synthesize_speech(
107
- input=synthesis_input,
108
- voice=voice,
109
- audio_config=audio_cfg
110
- )
111
- return response.audio_content
112
-
113
- def audio_writer(script_text: str, out="story.mp3"):
114
- chunks = chunk_text(script_text)
115
- audio = AudioSegment.silent(200)
116
- for i, chunk in enumerate(chunks, 1):
117
- path = f"seg_{i}.mp3"
118
- with open(path, "wb") as f:
119
- f.write(tts_segment(chunk))
120
- audio += AudioSegment.from_mp3(path)
121
- audio += AudioSegment.silent(150)
122
- audio.export(out, format="mp3")
123
- return out
124
-
125
- # --- Full Pipeline ---
126
- async def full_pipeline(topic: str):
127
- eli5 = await run_pedagogy_async(topic)
128
- script = run_scriptwriter(eli5)
129
- audio_path = audio_writer(script, "story.mp3")
130
- return eli5, script, audio_path
131
-
132
- # --- Gradio App ---
133
- app = gr.Interface(
134
- fn=full_pipeline,
135
- inputs=gr.Textbox(label="Your Topic"),
136
- outputs=[
137
- gr.Textbox(label="ELI5 Explanation", lines=8),
138
- gr.Textbox(label="Generated Story Script", lines=20),
139
- gr.Audio(label="Generated Audio")
140
- ],
141
- title="🎧 TinyTutor β€” Full Pipeline",
142
- css=".gradio-container { min-height: 1200px !important; }"
143
- )
144
-
145
- if __name__ == "__main__":
146
  app.launch()
 
1
+ import os
2
+ import asyncio
3
+ import google.generativeai as genai
4
+
5
+ from google.adk.agents import Agent
6
+ from google.adk.models.google_llm import Gemini
7
+ from google.adk.runners import InMemoryRunner
8
+ from google.adk.tools import google_search
9
+ from google.genai import types
10
+
11
+ from google.cloud import texttospeech
12
+ from pydub import AudioSegment
13
+ import gradio as gr
14
+
15
+ # --- Configure API Keys ---
16
+ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
17
+ if not GOOGLE_API_KEY:
18
+ raise RuntimeError("❌ Missing GOOGLE_API_KEY environment variable.")
19
+ genai.configure(api_key=GOOGLE_API_KEY)
20
+
21
+ SERVICE_ACCOUNT_JSON = os.getenv("GCP_VI_SERVICE_ACCOUNT_JSON")
22
+ if not SERVICE_ACCOUNT_JSON:
23
+ raise RuntimeError("❌ Missing GCP_VI_SERVICE_ACCOUNT_JSON environment variable.")
24
+
25
+ with open("tinytutor-tss-agent.json", "w") as f:
26
+ f.write(SERVICE_ACCOUNT_JSON)
27
+
28
+ os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "tinytutor-tss-agent.json"
29
+ tts_client = texttospeech.TextToSpeechClient()
30
+
31
+ # --- Retry Options ---
32
+ retry_config = types.HttpRetryOptions(
33
+ attempts=5,
34
+ exp_base=7,
35
+ initial_delay=1,
36
+ http_status_codes=[429, 500, 503, 504]
37
+ )
38
+
39
+ # --- Pedagogy Agent ---
40
+ pedagogy_agent = Agent(
41
+ name="PedagogyAgent",
42
+ model=Gemini(model="gemini-2.5-flash-lite", retry_options=retry_config),
43
+ description="Explains topics in simple ELI5 style.",
44
+ instruction="Explain the topic like I'm 5. Use google_search if needed.",
45
+ tools=[google_search],
46
+ )
47
+ runner = InMemoryRunner(agent=pedagogy_agent)
48
+
49
+ async def run_pedagogy_async(topic: str) -> str:
50
+ response = await runner.run_debug(topic)
51
+ return response[0].content.parts[0].text
52
+
53
+ # --- ScriptWriter Agent ---
54
+ SCRIPTWRITER_SYSTEM_PROMPT = """
55
+ You are a Teacher.
56
+ Your role is to take a simplified explanation created by the Pedagogy Agent and turn it into a clear, friendly teaching script suitable for a young child around the age of 5.
57
+ ... (keep the rest of your original prompt here) ...
58
+ """
59
+
60
+ def run_scriptwriter(explanation: str) -> str:
61
+ model = genai.GenerativeModel(
62
+ model_name="gemini-2.5-flash",
63
+ system_instruction=SCRIPTWRITER_SYSTEM_PROMPT
64
+ )
65
+ response = model.generate_content(
66
+ f"Write a children's story based on this:\n{explanation}",
67
+ generation_config=genai.GenerationConfig(
68
+ temperature=0.9,
69
+ max_output_tokens=4096
70
+ )
71
+ )
72
+ try:
73
+ return response.text
74
+ except Exception:
75
+ try:
76
+ return response.candidates[0].content.parts[0].text
77
+ except Exception:
78
+ return "⚠️ ScriptWriter failed."
79
+
80
+ # --- Audio Generator ---
81
+ def chunk_text(text, max_chars=4500):
82
+ text = text.strip()
83
+ if len(text) <= max_chars:
84
+ return [text]
85
+ chunks = []
86
+ while len(text) > max_chars:
87
+ cut = text.rfind(". ", 0, max_chars)
88
+ if cut == -1:
89
+ cut = max_chars
90
+ chunks.append(text[:cut+1])
91
+ text = text[cut+1:].strip()
92
+ chunks.append(text)
93
+ return chunks
94
+
95
+ def tts_segment(text):
96
+ synthesis_input = texttospeech.SynthesisInput(text=text)
97
+ voice = texttospeech.VoiceSelectionParams(
98
+ language_code="en-US",
99
+ name="en-US-Journey-F"
100
+ )
101
+ audio_cfg = texttospeech.AudioConfig(
102
+ audio_encoding=texttospeech.AudioEncoding.MP3,
103
+ speaking_rate=0.94,
104
+ pitch=0.0,
105
+ volume_gain_db=0.0
106
+ )
107
+ response = tts_client.synthesize_speech(
108
+ input=synthesis_input,
109
+ voice=voice,
110
+ audio_config=audio_cfg
111
+ )
112
+ return response.audio_content
113
+
114
+ def audio_writer(script_text: str, out="story.mp3"):
115
+ chunks = chunk_text(script_text)
116
+ audio = AudioSegment.silent(200)
117
+ for i, chunk in enumerate(chunks, 1):
118
+ path = f"seg_{i}.mp3"
119
+ with open(path, "wb") as f:
120
+ f.write(tts_segment(chunk))
121
+ audio += AudioSegment.from_mp3(path)
122
+ audio += AudioSegment.silent(150)
123
+ audio.export(out, format="mp3")
124
+ return out
125
+
126
+ # --- Full Pipeline ---
127
+ async def full_pipeline(topic: str):
128
+ eli5 = await run_pedagogy_async(topic)
129
+ script = run_scriptwriter(eli5)
130
+ audio_path = audio_writer(script, "story.mp3")
131
+ return eli5, script, audio_path
132
+
133
+ # --- Gradio App ---
134
+ app = gr.Interface(
135
+ fn=full_pipeline,
136
+ inputs=gr.Textbox(label="Your Topic"),
137
+ outputs=[
138
+ gr.Textbox(label="ELI5 Explanation", lines=8),
139
+ gr.Textbox(label="Generated Story Script", lines=20),
140
+ gr.Audio(label="Generated Audio")
141
+ ],
142
+ title="🎧 TinyTutor β€” Full Pipeline"
143
+ )
144
+
145
+ if __name__ == "__main__":
146
  app.launch()