ZereoX commited on
Commit
04a5353
Β·
verified Β·
1 Parent(s): 7c2eb0d

Cancel info from Gradio

Browse files
Files changed (1) hide show
  1. app.py +242 -96
app.py CHANGED
@@ -8,46 +8,67 @@ import gradio as gr
8
  from google import genai
9
  from google.genai import types
10
 
 
 
 
 
11
  # Supported input audio formats
12
  SUPPORTED_AUDIO_EXTS = {".wav", ".mp3", ".m4a"}
13
 
14
- # Default system prompt
 
 
 
 
15
  DEFAULT_SYSTEM_PROMPT = (
16
  """Here are instructions from the user outlining your goals and how you should respond:
17
  You are a tool designed to assist users by enhancing the efficiency and effectiveness of their meeting notes output. You specialize in three primary functions:
18
 
 
19
  Structuring Notes
20
  Objective: Transform unorganized, rough draft notes into a structured, easy-to-navigate document.
21
  Process: Employ NLP and text analysis algorithms to identify key themes, decisions, action items, and insights from the rough notes. Then, organize these elements according to the predefined template that highlights the meeting's objectives, key points, decisions made, action items, and so on.
22
 
 
23
  Synthesizing Transcripts
24
  Objective: Convert lengthy, verbatim meeting transcripts into concise, coherent summaries.
25
  Process: Use advanced summarization techniques to extract the essence of discussions, focusing on outcomes, decisions, and action points. Integration of sentiment analysis could further highlight discussions' tone and areas of agreement or contention.
26
 
 
27
  Develop Downloadable Microsoft Word Documents
28
  Objective: Provide users with a convenient, editable format for the structured notes and synthesized summaries.
29
- Process: After structuring or synthesizing the content, format the output into a Microsoft Word document.
 
30
 
31
  Here is a breakdown of your operational flow:
32
 
33
- Initiation: Each session with the Meeting Notes Assistant begins when a consultant initiates interaction by selecting the "Let's Begin" conversation starter prompt.
34
 
35
- Upon activation, you will print the following text:
 
 
 
 
36
 
37
  "Welcome! Ready to streamline your meeting notes? Here's how I can help:
38
 
 
39
  1. Organize Draft Notes: For structured, coherent notes.
40
  2. Combine Notes: Merge notes from multiple sources into one document.
41
  3. Summarize Transcripts: Get concise summaries of your meetings.
42
  Just reply with 1, 2, or 3 to choose. Let's get started!"
43
 
44
 
 
 
45
  If the user selects 1 (Organize Draft Notes), then the tool responds with:
46
 
 
47
  "Great choice! Let's tidy up those draft notes. To get started, please paste your notes below or upload the file. I'll help structure them for clarity and coherence."
48
 
 
49
  Upon receiving the notes, you will structure the output with the following content. Do not use every piece of this, read the notes and make a decision on the best elements to add. Never use all of them:
50
 
 
51
  Meeting Title: [Automatically extracted or prompted for if unclear.]
52
  Date: [Automatically extracted or prompted for.]
53
  Attendees: [List of participants, extracted from notes or prompted for.]
@@ -59,22 +80,29 @@ Insights and Learnings: [Any notable insights gleaned from the meeting.]
59
  Next Steps: [Detailed actions and responsibilities, clearly outlined for follow-up.]
60
  Formatted Notes: [The structured output, presented in a professional, concise format on no more than one page, focusing on clarity, coherence, and actionable insights.]
61
 
 
62
  You will always print the following question at the end of your note synthesis: "Would you like for me to generate a downloadable Word document of your notes?"
63
 
64
- If the user says anything affirmative like "yes", then use Code Interpretor to generate a downloadable Word document of the content.
 
65
  If the user says anything like "no", then respond with this: "Great! Can I help you with any other notes? Here's how I can help:
66
 
 
67
  1. Organize Draft Notes: For structured, coherent notes.
68
  2. Combine Notes: Merge notes from multiple sources into one document.
69
  3. Summarize Transcripts: Get concise summaries of your meetings.
70
  Just reply with 1, 2, or 3 to choose!"
71
 
 
72
  If the user selects 2 (Combine and Synthesize Notes), then the tool responds with:
73
 
 
74
  "Perfect! Let's merge and synthesize your notes from multiple sources. Please paste the notes below or upload the files, and I'll create a unified, coherent document."
75
 
 
76
  After the user submits their notes, the tool processes and formats the output as follows:
77
 
 
78
  Meeting Title: [Consolidated from provided notes or prompted for if unclear.]
79
  Date(s): [Consolidated dates or prompted for if not provided.]
80
  Attendees: [Compiled list of all participants mentioned across sources.]
@@ -86,22 +114,29 @@ Insights and Learnings: [Notable insights drawn from the synthesis of all notes.
86
  Next Steps: [Consolidated list of detailed actions and responsibilities from all sources.]
87
  Recommendations: [Suggestions for next steps or considerations, based on the synthesized information.]
88
 
 
89
  You will always print the following question at the end of your note synthesis: "Would you like for me to generate a downloadable Word document of your notes?"
90
 
91
- If the user says anything affirmative like "yes", then use Code Interpretor to generate a downloadable Word document of the content.
 
92
  If the user says anything like "no", then respond with this: "Great! Can I help you with any other notes? Here's how I can help:
93
 
 
94
  1. Organize Draft Notes: For structured, coherent notes.
95
  2. Combine Notes: Merge notes from multiple sources into one document.
96
  3. Summarize Transcripts: Get concise summaries of your meetings.
97
  Just reply with 1, 2, or 3 to choose!"
98
 
 
99
  If the user selects 3 (Summarize a Meeting Transcript), then the tool responds with:
100
 
 
101
  "Excellent, let's summarize your meeting transcript. Please upload the transcript file or paste it into the chat window, and I'll distill it into a concise summary, capturing all critical points and actionable insights."
102
 
 
103
  The tool then processes the transcript and structures the output as follows:
104
 
 
105
  Meeting Title: [Title extracted or prompted for if unclear.]
106
  Date: [Date extracted or prompted for.]
107
  Attendees: [List of participants, extracted or prompted for clarification.]
@@ -116,22 +151,35 @@ Next Steps: [Detailed actions and responsibilities, outlined for clarity and acc
116
  Recommendations: [Strategic suggestions based on the meeting's content, aimed to add value and perspective for planning.]
117
  You will always print the following question at the end of your note synthesis: "Would you like for me to generate a downloadable Word document of your notes?"
118
 
119
- If the user says anything affirmative like "yes", then use Code Interpretor to generate a downloadable Word document of the content.
 
120
  If the user says anything like "no", then respond with this: "Great! Can I help you with any other notes? Here's how I can help:
121
 
 
122
  1. Organize Draft Notes: For structured, coherent notes.
123
  2. Combine Notes: Merge notes from multiple sources into one document.
124
  3. Summarize Transcripts: Get concise summaries of your meetings.
125
  Just reply with 1, 2, or 3 to choose!"
126
 
 
127
  You will maintain consistency and apply this approach every time. This approach ensures notes are concise, and actionable, maintaining a professional tone throughout. Your recommendations are provided to enhance strategic outcomes and decision-making processes, always tailored to the context of the discussion."""
128
  )
129
 
 
 
 
130
 
131
- def wave_file(filename: str, pcm: bytes, channels: int = 1,
132
- rate: int = 24000, sample_width: int = 2) -> None:
 
 
 
 
 
 
133
  """
134
  Save raw PCM data as a WAV file.
 
135
  """
136
  with wave.open(filename, "wb") as wf:
137
  wf.setnchannels(channels)
@@ -187,51 +235,77 @@ def normalize_audio_file(audio_path: str) -> str:
187
 
188
 
189
  def generate_text_with_optional_audio(
 
190
  model: str,
191
  prompt: str,
192
  system_prompt: Optional[str] = None,
193
  audio_path: Optional[str] = None,
194
  ) -> str:
195
  """
196
- Call Gemini with text prompt and optional audio file.
 
197
  Returns the model's text response.
198
  """
199
- contents = [prompt]
200
 
201
  if audio_path:
202
  normalized = normalize_audio_file(audio_path)
203
- uploaded_file = genai.upload_file(normalized)
204
  contents.append(uploaded_file)
205
 
206
  effective_system_prompt = system_prompt or DEFAULT_SYSTEM_PROMPT
207
 
208
- model_instance = genai.GenerativeModel(
209
- model_name=model,
210
- system_instruction=effective_system_prompt,
 
 
 
211
  )
212
-
213
- response = model_instance.generate_content(contents)
214
- return response.text
215
 
216
 
217
  def tts_from_text(
 
218
  text: str,
219
- model: str = "gemini-1.5-flash",
220
  voice_name: str = "Kore",
221
  ) -> str:
222
  """
223
- Convert text to speech using Gemini TTS and save to a WAV file.
224
- Returns the path to the generated audio file.
225
- Note: TTS is not yet available in google.generativeai, returning placeholder.
 
 
226
  """
227
- # TTS functionality is not yet available in the standard google.generativeai package
228
- # This is a placeholder that returns None
229
- # Users should use alternative TTS services like Google Cloud TTS or gTTS
230
- raise NotImplementedError(
231
- "TTS is not yet available in google.generativeai. "
232
- "Please disable TTS output or use alternative TTS services."
 
 
 
 
 
 
 
233
  )
234
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
  def process_meeting_notes(
237
  operation_type: str,
@@ -239,187 +313,259 @@ def process_meeting_notes(
239
  audio_input: Optional[str],
240
  enable_tts: bool,
241
  api_key: str,
242
- progress=gr.Progress()
243
  ) -> Tuple[str, Optional[str]]:
244
  """
245
  Main processing function for meeting notes.
246
- Returns (text_output, audio_output_path)
247
  """
248
- if not api_key:
249
- return "❌ Error: Please provide your Gemini API key.", None
250
-
 
 
 
 
 
 
 
251
  if not text_input and not audio_input:
252
  return "❌ Error: Please provide either text input or an audio file.", None
253
-
254
  try:
255
  # Initialize Gemini client
256
  progress(0.1, desc="Initializing Gemini client...")
257
- genai.configure(api_key=api_key)
258
-
259
  # Prepare prompt based on operation type
260
  progress(0.2, desc="Preparing prompt...")
261
  if operation_type == "Organize Draft Notes":
262
- prompt = f"Please organize these draft notes:\n\n{text_input}" if text_input else "Please organize the notes from the audio file."
 
 
 
 
 
 
263
  elif operation_type == "Combine Notes":
264
- prompt = f"Please combine and synthesize these notes:\n\n{text_input}" if text_input else "Please combine and synthesize the notes from the audio file."
265
- else: # Summarize Transcripts
266
- prompt = f"Please summarize this meeting transcript:\n\n{text_input}" if text_input else "Please summarize the meeting transcript from the audio file."
267
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  # Generate text response
269
  progress(0.4, desc="Processing with Gemini...")
270
  text_response = generate_text_with_optional_audio(
271
- model="gemini-1.5-flash",
 
272
  prompt=prompt,
273
  system_prompt=DEFAULT_SYSTEM_PROMPT,
274
  audio_path=audio_input,
275
  )
276
-
277
  progress(0.7, desc="Text processing complete!")
278
-
279
  # Generate TTS if enabled
280
- audio_output = None
281
  if enable_tts:
282
- progress(0.8, desc="Generating audio output...")
283
  try:
284
  audio_output = tts_from_text(
 
285
  text=text_response,
286
- model="gemini-1.5-flash",
287
  voice_name="Kore",
288
  )
289
  progress(1.0, desc="Audio generation complete!")
290
- except NotImplementedError as tts_error:
291
- progress(1.0, desc="Processing complete (TTS unavailable)")
292
- return text_response + "\n\n⚠️ Note: " + str(tts_error), None
 
 
 
 
 
293
  else:
294
  progress(1.0, desc="Processing complete!")
295
-
296
  return text_response, audio_output
297
-
298
  except Exception as e:
299
- return f"❌ Error: {str(e)}", None
 
300
 
 
 
 
301
 
302
- # Create Gradio interface
303
  with gr.Blocks(title="Meeting Notes Assistant", theme=gr.themes.Soft()) as demo:
304
  gr.Markdown(
305
  """
306
  # πŸ“ Meeting Notes Assistant
307
-
308
  Transform your meeting notes with AI-powered organization, synthesis, and summarization.
309
-
310
  **Features:**
311
  - πŸ“‹ Organize Draft Notes
312
  - πŸ”„ Combine Multiple Notes
313
  - πŸ“Š Summarize Transcripts
314
  - 🎀 Audio Input Support (WAV, MP3, M4A)
315
- - πŸ”Š Text-to-Speech Output
316
  """
317
  )
318
-
319
  with gr.Row():
320
  with gr.Column(scale=1):
321
  gr.Markdown("### βš™οΈ Configuration")
322
-
323
  api_key_input = gr.Textbox(
324
- label="Gemini API Key",
325
- placeholder="Enter your Gemini API key",
326
  type="password",
327
- info="Get your API key from Google AI Studio"
328
  )
329
-
 
 
 
 
330
  operation_type = gr.Radio(
331
- choices=["Organize Draft Notes", "Combine Notes", "Summarize Transcripts"],
 
 
 
 
332
  label="Operation Type",
333
  value="Organize Draft Notes",
334
- info="Select the type of operation you want to perform"
335
  )
336
-
 
 
 
 
337
  enable_tts = gr.Checkbox(
338
  label="Enable Text-to-Speech Output",
339
  value=False,
340
- info="Generate audio output of the processed notes"
341
  )
342
-
 
 
 
 
343
  with gr.Column(scale=2):
344
  gr.Markdown("### πŸ“₯ Input")
345
-
346
  text_input = gr.Textbox(
347
  label="Text Input",
348
  placeholder="Paste your meeting notes, transcript, or text here...",
349
  lines=10,
350
- info="Enter your text or leave empty if using audio input"
351
  )
352
-
 
 
 
 
353
  audio_input = gr.Audio(
354
  label="Audio Input (Optional)",
355
  type="filepath",
356
- info="Upload WAV, MP3, or M4A file"
357
  )
358
-
359
- process_btn = gr.Button("πŸš€ Process Notes", variant="primary", size="lg")
360
-
 
 
 
 
361
  gr.Markdown("### πŸ“€ Output")
362
-
363
  with gr.Row():
364
  with gr.Column():
365
  text_output = gr.Textbox(
366
  label="Processed Notes",
367
  lines=15,
368
  show_copy_button=True,
369
- info="Your organized, combined, or summarized notes will appear here"
370
  )
371
-
 
 
 
 
372
  with gr.Column():
373
  audio_output = gr.Audio(
374
  label="Audio Output",
375
  type="filepath",
376
- info="Generated audio (if TTS is enabled)"
377
  )
378
-
 
 
 
 
379
  # Example inputs
380
  gr.Markdown("### πŸ’‘ Examples")
381
  gr.Examples(
382
  examples=[
383
  [
384
  "Organize Draft Notes",
385
- "Meeting with John about Q4 planning. Discussed budget allocation. Need to finalize numbers by Friday. Action items: Sarah to review projections, Mike to update spreadsheet.",
 
 
386
  None,
387
- False
388
  ],
389
  [
390
  "Summarize Transcripts",
391
- "John: We need to discuss the Q4 budget. Sarah: I think we should allocate more to marketing. Mike: I agree, but we need to be careful with spending. John: Let's review the numbers and decide by Friday.",
 
 
392
  None,
393
- False
394
  ],
395
  ],
396
  inputs=[operation_type, text_input, audio_input, enable_tts],
397
  )
398
-
399
  # Connect the process button
400
  process_btn.click(
401
  fn=process_meeting_notes,
402
  inputs=[operation_type, text_input, audio_input, enable_tts, api_key_input],
403
  outputs=[text_output, audio_output],
404
  )
405
-
406
  gr.Markdown(
407
  """
408
  ---
409
  ### πŸ“š How to Use
410
-
411
- 1. **Enter your Gemini API Key** (required)
412
- 2. **Select operation type**: Organize, Combine, or Summarize
413
- 3. **Provide input**: Enter text or upload audio (or both)
414
- 4. **Optional**: Enable TTS for audio output
415
- 5. **Click Process Notes** and wait for results
416
-
417
  ### πŸ”‘ Getting Your API Key
418
-
419
- Visit [Google AI Studio](https://aistudio.google.com/app/apikey) to get your free Gemini API key.
420
  """
421
  )
422
 
423
 
424
  if __name__ == "__main__":
425
- demo.launch()
 
 
8
  from google import genai
9
  from google.genai import types
10
 
11
+ # ------------------------------------------------------------
12
+ # Configuration
13
+ # ------------------------------------------------------------
14
+
15
  # Supported input audio formats
16
  SUPPORTED_AUDIO_EXTS = {".wav", ".mp3", ".m4a"}
17
 
18
+ # Default models (can be overridden via environment variables if desired)
19
+ DEFAULT_TEXT_MODEL = os.getenv("GEMINI_TEXT_MODEL", "gemini-2.0-flash")
20
+ DEFAULT_TTS_MODEL = os.getenv("GEMINI_TTS_MODEL", "gemini-2.5-flash-preview-tts")
21
+
22
+ # Default system prompt used to steer Gemini for meeting-notes behavior.
23
  DEFAULT_SYSTEM_PROMPT = (
24
  """Here are instructions from the user outlining your goals and how you should respond:
25
  You are a tool designed to assist users by enhancing the efficiency and effectiveness of their meeting notes output. You specialize in three primary functions:
26
 
27
+
28
  Structuring Notes
29
  Objective: Transform unorganized, rough draft notes into a structured, easy-to-navigate document.
30
  Process: Employ NLP and text analysis algorithms to identify key themes, decisions, action items, and insights from the rough notes. Then, organize these elements according to the predefined template that highlights the meeting's objectives, key points, decisions made, action items, and so on.
31
 
32
+
33
  Synthesizing Transcripts
34
  Objective: Convert lengthy, verbatim meeting transcripts into concise, coherent summaries.
35
  Process: Use advanced summarization techniques to extract the essence of discussions, focusing on outcomes, decisions, and action points. Integration of sentiment analysis could further highlight discussions' tone and areas of agreement or contention.
36
 
37
+
38
  Develop Downloadable Microsoft Word Documents
39
  Objective: Provide users with a convenient, editable format for the structured notes and synthesized summaries.
40
+ Process: After structuring or synthesizing the content, format the output into a Microsoft Word document.
41
+
42
 
43
  Here is a breakdown of your operational flow:
44
 
 
45
 
46
+ Initiation: Each session with the Meeting Notes Assistant begins when a consultant initiates interaction by selecting the "Let's Begin" conversation starter prompt.
47
+
48
+
49
+ Upon activation, you will print the following text:
50
+
51
 
52
  "Welcome! Ready to streamline your meeting notes? Here's how I can help:
53
 
54
+
55
  1. Organize Draft Notes: For structured, coherent notes.
56
  2. Combine Notes: Merge notes from multiple sources into one document.
57
  3. Summarize Transcripts: Get concise summaries of your meetings.
58
  Just reply with 1, 2, or 3 to choose. Let's get started!"
59
 
60
 
61
+
62
+
63
  If the user selects 1 (Organize Draft Notes), then the tool responds with:
64
 
65
+
66
  "Great choice! Let's tidy up those draft notes. To get started, please paste your notes below or upload the file. I'll help structure them for clarity and coherence."
67
 
68
+
69
  Upon receiving the notes, you will structure the output with the following content. Do not use every piece of this, read the notes and make a decision on the best elements to add. Never use all of them:
70
 
71
+
72
  Meeting Title: [Automatically extracted or prompted for if unclear.]
73
  Date: [Automatically extracted or prompted for.]
74
  Attendees: [List of participants, extracted from notes or prompted for.]
 
80
  Next Steps: [Detailed actions and responsibilities, clearly outlined for follow-up.]
81
  Formatted Notes: [The structured output, presented in a professional, concise format on no more than one page, focusing on clarity, coherence, and actionable insights.]
82
 
83
+
84
  You will always print the following question at the end of your note synthesis: "Would you like for me to generate a downloadable Word document of your notes?"
85
 
86
+
87
+ If the user says anything affirmative like "yes", then use Code Interpretor to generate a downloadable Word document of the content.
88
  If the user says anything like "no", then respond with this: "Great! Can I help you with any other notes? Here's how I can help:
89
 
90
+
91
  1. Organize Draft Notes: For structured, coherent notes.
92
  2. Combine Notes: Merge notes from multiple sources into one document.
93
  3. Summarize Transcripts: Get concise summaries of your meetings.
94
  Just reply with 1, 2, or 3 to choose!"
95
 
96
+
97
  If the user selects 2 (Combine and Synthesize Notes), then the tool responds with:
98
 
99
+
100
  "Perfect! Let's merge and synthesize your notes from multiple sources. Please paste the notes below or upload the files, and I'll create a unified, coherent document."
101
 
102
+
103
  After the user submits their notes, the tool processes and formats the output as follows:
104
 
105
+
106
  Meeting Title: [Consolidated from provided notes or prompted for if unclear.]
107
  Date(s): [Consolidated dates or prompted for if not provided.]
108
  Attendees: [Compiled list of all participants mentioned across sources.]
 
114
  Next Steps: [Consolidated list of detailed actions and responsibilities from all sources.]
115
  Recommendations: [Suggestions for next steps or considerations, based on the synthesized information.]
116
 
117
+
118
  You will always print the following question at the end of your note synthesis: "Would you like for me to generate a downloadable Word document of your notes?"
119
 
120
+
121
+ If the user says anything affirmative like "yes", then use Code Interpretor to generate a downloadable Word document of the content.
122
  If the user says anything like "no", then respond with this: "Great! Can I help you with any other notes? Here's how I can help:
123
 
124
+
125
  1. Organize Draft Notes: For structured, coherent notes.
126
  2. Combine Notes: Merge notes from multiple sources into one document.
127
  3. Summarize Transcripts: Get concise summaries of your meetings.
128
  Just reply with 1, 2, or 3 to choose!"
129
 
130
+
131
  If the user selects 3 (Summarize a Meeting Transcript), then the tool responds with:
132
 
133
+
134
  "Excellent, let's summarize your meeting transcript. Please upload the transcript file or paste it into the chat window, and I'll distill it into a concise summary, capturing all critical points and actionable insights."
135
 
136
+
137
  The tool then processes the transcript and structures the output as follows:
138
 
139
+
140
  Meeting Title: [Title extracted or prompted for if unclear.]
141
  Date: [Date extracted or prompted for.]
142
  Attendees: [List of participants, extracted or prompted for clarification.]
 
151
  Recommendations: [Strategic suggestions based on the meeting's content, aimed to add value and perspective for planning.]
152
  You will always print the following question at the end of your note synthesis: "Would you like for me to generate a downloadable Word document of your notes?"
153
 
154
+
155
+ If the user says anything affirmative like "yes", then use Code Interpretor to generate a downloadable Word document of the content.
156
  If the user says anything like "no", then respond with this: "Great! Can I help you with any other notes? Here's how I can help:
157
 
158
+
159
  1. Organize Draft Notes: For structured, coherent notes.
160
  2. Combine Notes: Merge notes from multiple sources into one document.
161
  3. Summarize Transcripts: Get concise summaries of your meetings.
162
  Just reply with 1, 2, or 3 to choose!"
163
 
164
+
165
  You will maintain consistency and apply this approach every time. This approach ensures notes are concise, and actionable, maintaining a professional tone throughout. Your recommendations are provided to enhance strategic outcomes and decision-making processes, always tailored to the context of the discussion."""
166
  )
167
 
168
+ # ------------------------------------------------------------
169
+ # Utility functions
170
+ # ------------------------------------------------------------
171
 
172
+
173
+ def wave_file(
174
+ filename: str,
175
+ pcm: bytes,
176
+ channels: int = 1,
177
+ rate: int = 24000,
178
+ sample_width: int = 2,
179
+ ) -> None:
180
  """
181
  Save raw PCM data as a WAV file.
182
+ Mirrors the helper used in the official Gemini TTS examples.
183
  """
184
  with wave.open(filename, "wb") as wf:
185
  wf.setnchannels(channels)
 
235
 
236
 
237
  def generate_text_with_optional_audio(
238
+ client: genai.Client,
239
  model: str,
240
  prompt: str,
241
  system_prompt: Optional[str] = None,
242
  audio_path: Optional[str] = None,
243
  ) -> str:
244
  """
245
+ Call Gemini with a text prompt and an optional audio file.
246
+ Uses the modern google-genai Client and models.generate_content API.
247
  Returns the model's text response.
248
  """
249
+ contents: list = [prompt]
250
 
251
  if audio_path:
252
  normalized = normalize_audio_file(audio_path)
253
+ uploaded_file = client.files.upload(file=normalized)
254
  contents.append(uploaded_file)
255
 
256
  effective_system_prompt = system_prompt or DEFAULT_SYSTEM_PROMPT
257
 
258
+ response = client.models.generate_content(
259
+ model=model,
260
+ contents=contents,
261
+ config=types.GenerateContentConfig(
262
+ system_instruction=effective_system_prompt,
263
+ ),
264
  )
265
+
266
+ return response.text or ""
 
267
 
268
 
269
  def tts_from_text(
270
+ client: genai.Client,
271
  text: str,
272
+ model: str = DEFAULT_TTS_MODEL,
273
  voice_name: str = "Kore",
274
  ) -> str:
275
  """
276
+ Convert text to speech using Gemini native TTS (2.5 Flash TTS).
277
+ Uses the official speech-generation pattern with response_modalities=['AUDIO']
278
+ and SpeechConfig / VoiceConfig.
279
+
280
+ Returns the path to a temporary WAV file that Gradio can play.
281
  """
282
+ response = client.models.generate_content(
283
+ model=model,
284
+ contents=text,
285
+ config=types.GenerateContentConfig(
286
+ response_modalities=["AUDIO"],
287
+ speech_config=types.SpeechConfig(
288
+ voice_config=types.VoiceConfig(
289
+ prebuilt_voice_config=types.PrebuiltVoiceConfig(
290
+ voice_name=voice_name
291
+ )
292
+ )
293
+ ),
294
+ ),
295
  )
296
 
297
+ # Inline audio data is returned as raw PCM bytes that we wrap into a .wav file.
298
+ pcm_data = response.candidates[0].content.parts[0].inline_data.data
299
+
300
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp:
301
+ wave_file(tmp.name, pcm_data)
302
+ return tmp.name
303
+
304
+
305
+ # ------------------------------------------------------------
306
+ # Core meeting-notes processing
307
+ # ------------------------------------------------------------
308
+
309
 
310
  def process_meeting_notes(
311
  operation_type: str,
 
313
  audio_input: Optional[str],
314
  enable_tts: bool,
315
  api_key: str,
316
+ progress=gr.Progress(),
317
  ) -> Tuple[str, Optional[str]]:
318
  """
319
  Main processing function for meeting notes.
320
+ Returns (text_output, audio_output_path).
321
  """
322
+ # Determine effective API key: prefer user entry, fall back to env var.
323
+ effective_api_key = (api_key or "").strip() or os.getenv("GEMINI_API_KEY")
324
+
325
+ if not effective_api_key:
326
+ return (
327
+ "❌ Error: Please provide your Gemini API key (textbox) "
328
+ "or set GEMINI_API_KEY in the environment.",
329
+ None,
330
+ )
331
+
332
  if not text_input and not audio_input:
333
  return "❌ Error: Please provide either text input or an audio file.", None
334
+
335
  try:
336
  # Initialize Gemini client
337
  progress(0.1, desc="Initializing Gemini client...")
338
+ client = genai.Client(api_key=effective_api_key)
339
+
340
  # Prepare prompt based on operation type
341
  progress(0.2, desc="Preparing prompt...")
342
  if operation_type == "Organize Draft Notes":
343
+ if text_input:
344
+ prompt = f"Please organize these draft notes:\n\n{text_input}"
345
+ else:
346
+ prompt = (
347
+ "Please listen carefully to this meeting recording and generate "
348
+ "organized draft notes following the system instructions."
349
+ )
350
  elif operation_type == "Combine Notes":
351
+ if text_input:
352
+ prompt = (
353
+ "Please combine and synthesize the following multi-source notes "
354
+ "into one unified, coherent meeting document:\n\n"
355
+ f"{text_input}"
356
+ )
357
+ else:
358
+ prompt = (
359
+ "Please combine and synthesize the notes implied by this audio "
360
+ "input into one coherent document following the system instructions."
361
+ )
362
+ else: # "Summarize Transcripts"
363
+ if text_input:
364
+ prompt = (
365
+ "Please summarize the following meeting transcript into concise, "
366
+ "actionable notes:\n\n" f"{text_input}"
367
+ )
368
+ else:
369
+ prompt = (
370
+ "Please summarize the meeting transcript contained in this audio "
371
+ "file into concise, actionable notes."
372
+ )
373
+
374
  # Generate text response
375
  progress(0.4, desc="Processing with Gemini...")
376
  text_response = generate_text_with_optional_audio(
377
+ client=client,
378
+ model=DEFAULT_TEXT_MODEL,
379
  prompt=prompt,
380
  system_prompt=DEFAULT_SYSTEM_PROMPT,
381
  audio_path=audio_input,
382
  )
383
+
384
  progress(0.7, desc="Text processing complete!")
385
+
386
  # Generate TTS if enabled
387
+ audio_output: Optional[str] = None
388
  if enable_tts:
389
+ progress(0.8, desc="Generating audio output (TTS)...")
390
  try:
391
  audio_output = tts_from_text(
392
+ client=client,
393
  text=text_response,
394
+ model=DEFAULT_TTS_MODEL,
395
  voice_name="Kore",
396
  )
397
  progress(1.0, desc="Audio generation complete!")
398
+ except Exception as tts_error:
399
+ progress(1.0, desc="Processing complete (TTS error)")
400
+ return (
401
+ text_response
402
+ + "\n\n⚠️ Note: TTS generation failed with:\n"
403
+ + str(tts_error),
404
+ None,
405
+ )
406
  else:
407
  progress(1.0, desc="Processing complete!")
408
+
409
  return text_response, audio_output
410
+
411
  except Exception as e:
412
+ return f"❌ Error while processing: {str(e)}", None
413
+
414
 
415
+ # ------------------------------------------------------------
416
+ # Gradio UI
417
+ # ------------------------------------------------------------
418
 
 
419
  with gr.Blocks(title="Meeting Notes Assistant", theme=gr.themes.Soft()) as demo:
420
  gr.Markdown(
421
  """
422
  # πŸ“ Meeting Notes Assistant
423
+
424
  Transform your meeting notes with AI-powered organization, synthesis, and summarization.
425
+
426
  **Features:**
427
  - πŸ“‹ Organize Draft Notes
428
  - πŸ”„ Combine Multiple Notes
429
  - πŸ“Š Summarize Transcripts
430
  - 🎀 Audio Input Support (WAV, MP3, M4A)
431
+ - πŸ”Š Text-to-Speech Output (Gemini 2.5 TTS)
432
  """
433
  )
434
+
435
  with gr.Row():
436
  with gr.Column(scale=1):
437
  gr.Markdown("### βš™οΈ Configuration")
438
+
439
  api_key_input = gr.Textbox(
440
+ label="Gemini API Key (optional)",
441
+ placeholder="Enter your Gemini API key, or leave blank to use GEMINI_API_KEY env var",
442
  type="password",
 
443
  )
444
+ gr.Markdown(
445
+ "πŸ”‘ Get your API key from Google AI Studio and optionally store it "
446
+ "as the GEMINI_API_KEY environment variable on this Space."
447
+ )
448
+
449
  operation_type = gr.Radio(
450
+ choices=[
451
+ "Organize Draft Notes",
452
+ "Combine Notes",
453
+ "Summarize Transcripts",
454
+ ],
455
  label="Operation Type",
456
  value="Organize Draft Notes",
 
457
  )
458
+ gr.Markdown(
459
+ "ℹ️ Choose how you want the assistant to process your input: "
460
+ "organize messy notes, merge multiple notes, or summarize transcripts."
461
+ )
462
+
463
  enable_tts = gr.Checkbox(
464
  label="Enable Text-to-Speech Output",
465
  value=False,
 
466
  )
467
+ gr.Markdown(
468
+ "🎧 When enabled, the assistant will also generate a spoken version "
469
+ "of the processed notes using Gemini TTS."
470
+ )
471
+
472
  with gr.Column(scale=2):
473
  gr.Markdown("### πŸ“₯ Input")
474
+
475
  text_input = gr.Textbox(
476
  label="Text Input",
477
  placeholder="Paste your meeting notes, transcript, or text here...",
478
  lines=10,
 
479
  )
480
+ gr.Markdown(
481
+ "✍️ Enter any text-based notes or transcripts here. "
482
+ "You can also leave this empty and only upload audio."
483
+ )
484
+
485
  audio_input = gr.Audio(
486
  label="Audio Input (Optional)",
487
  type="filepath",
 
488
  )
489
+ gr.Markdown(
490
+ "πŸŽ™οΈ Upload a WAV, MP3, or M4A file. M4A will be converted "
491
+ "to WAV automatically (requires ffmpeg in the environment)."
492
+ )
493
+
494
+ process_btn = gr.Button("πŸš€ Process Notes", variant="primary")
495
+
496
  gr.Markdown("### πŸ“€ Output")
497
+
498
  with gr.Row():
499
  with gr.Column():
500
  text_output = gr.Textbox(
501
  label="Processed Notes",
502
  lines=15,
503
  show_copy_button=True,
 
504
  )
505
+ gr.Markdown(
506
+ "βœ… Your organized, combined, or summarized notes will appear here. "
507
+ "You can copy them with the button in the top-right corner."
508
+ )
509
+
510
  with gr.Column():
511
  audio_output = gr.Audio(
512
  label="Audio Output",
513
  type="filepath",
 
514
  )
515
+ gr.Markdown(
516
+ "πŸ”Š If Text-to-Speech is enabled and succeeds, the generated audio "
517
+ "will appear here for playback or download."
518
+ )
519
+
520
  # Example inputs
521
  gr.Markdown("### πŸ’‘ Examples")
522
  gr.Examples(
523
  examples=[
524
  [
525
  "Organize Draft Notes",
526
+ "Meeting with John about Q4 planning. Discussed budget allocation. "
527
+ "Need to finalize numbers by Friday. Action items: Sarah to review "
528
+ "projections, Mike to update spreadsheet.",
529
  None,
530
+ False,
531
  ],
532
  [
533
  "Summarize Transcripts",
534
+ "John: We need to discuss the Q4 budget. Sarah: I think we should "
535
+ "allocate more to marketing. Mike: I agree, but we need to be careful "
536
+ "with spending. John: Let's review the numbers and decide by Friday.",
537
  None,
538
+ False,
539
  ],
540
  ],
541
  inputs=[operation_type, text_input, audio_input, enable_tts],
542
  )
543
+
544
  # Connect the process button
545
  process_btn.click(
546
  fn=process_meeting_notes,
547
  inputs=[operation_type, text_input, audio_input, enable_tts, api_key_input],
548
  outputs=[text_output, audio_output],
549
  )
550
+
551
  gr.Markdown(
552
  """
553
  ---
554
  ### πŸ“š How to Use
555
+
556
+ 1. **Enter your Gemini API Key** in the box, or configure `GEMINI_API_KEY` in the environment.
557
+ 2. **Select operation type**: Organize, Combine, or Summarize.
558
+ 3. **Provide input**: Enter text and/or upload audio.
559
+ 4. **Optional**: Enable TTS for audio output.
560
+ 5. **Click β€œProcess Notes”** and wait for results.
561
+
562
  ### πŸ”‘ Getting Your API Key
563
+
564
+ Visit Google AI Studio to get your free Gemini API key.
565
  """
566
  )
567
 
568
 
569
  if __name__ == "__main__":
570
+ # Enable queuing so that gr.Progress works correctly in Spaces and other deployments.
571
+ demo.queue().launch()