maria355 commited on
Commit
a05bba7
Β·
verified Β·
1 Parent(s): 1a33031

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +536 -286
app.py CHANGED
@@ -5,10 +5,10 @@ import io
5
  import os
6
  import tempfile
7
  from PIL import Image, ImageDraw, ImageFont
 
8
  import json
9
  from datetime import datetime
10
- import re
11
- import random
12
 
13
  # Import with error handling
14
  try:
@@ -16,7 +16,6 @@ try:
16
  TRANSFORMERS_AVAILABLE = True
17
  except ImportError:
18
  TRANSFORMERS_AVAILABLE = False
19
- st.error("Install transformers: pip install transformers")
20
 
21
  try:
22
  import google.generativeai as genai
@@ -34,437 +33,688 @@ except ImportError:
34
  st.set_page_config(
35
  page_title="VoiceCanvas - AI Content Studio",
36
  page_icon="🎨",
37
- layout="wide"
 
38
  )
39
 
40
  # Initialize session state
41
- def init_session_state():
42
- defaults = {
43
- 'generated_content': {},
44
- 'transcription': "",
45
- 'models_loaded': False,
46
- 'whisper_model': None,
47
- 'processing': False
48
- }
49
- for key, value in defaults.items():
50
- if key not in st.session_state:
51
- st.session_state[key] = value
52
-
53
- init_session_state()
 
54
 
55
- @st.cache_resource
56
- def load_whisper_model():
57
- """Load Whisper model with caching"""
 
 
 
58
  if not TRANSFORMERS_AVAILABLE:
59
- return None
 
 
 
 
60
 
61
  try:
62
- model = pipeline(
 
 
 
 
 
63
  "automatic-speech-recognition",
64
  model="openai/whisper-tiny",
65
- device=-1,
66
  torch_dtype=torch.float32,
67
  return_timestamps=False
68
  )
69
- return model
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  except Exception as e:
71
- st.error(f"Model loading error: {e}")
72
- return None
 
 
 
73
 
74
  def setup_gemini():
75
- """Setup Gemini API"""
76
  if not GENAI_AVAILABLE:
77
  return False
78
-
79
- api_key = os.getenv("GEMINI_API_KEY") or st.secrets.get("GEMINI_API_KEY", "") if hasattr(st, 'secrets') else ""
80
-
81
- if api_key:
82
- genai.configure(api_key=api_key)
83
- return True
84
- return False
85
-
86
- def transcribe_audio(audio_input):
87
- """Transcribe audio to text"""
88
  try:
89
- model = load_whisper_model()
90
- if not model:
91
- return "Error: Speech recognition not available"
92
 
93
- result = model(audio_input)
94
- return result.get("text", "").strip() if isinstance(result, dict) else str(result).strip()
95
-
 
96
  except Exception as e:
97
- return f"Transcription error: {str(e)}"
98
-
99
- def extract_keywords(text):
100
- """Extract key terms from user input"""
101
- # Remove common words
102
- stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were', 'will', 'would', 'could', 'should', 'can', 'may', 'might', 'this', 'that', 'these', 'those'}
103
- words = re.findall(r'\b[a-zA-Z]{3,}\b', text.lower())
104
- keywords = [word for word in words if word not in stop_words]
105
- return list(set(keywords))[:10] # Top 10 unique keywords
106
 
107
- def generate_dynamic_content(user_input):
108
- """Generate dynamic content based on user input"""
109
- keywords = extract_keywords(user_input)
110
- input_words = user_input.split()
111
-
112
- # Extract potential product/service name (first significant noun)
113
- product_name = next((word for word in input_words if len(word) > 4 and word.lower() not in ['that', 'with', 'this', 'your', 'their', 'could', 'would', 'should']), "your product")
114
-
115
- # Dynamic taglines based on user input
116
- tagline_templates = [
117
- f"Revolutionize your {keywords[0] if keywords else 'experience'} with {product_name}",
118
- f"{product_name.title()}: Where {keywords[1] if len(keywords) > 1 else 'innovation'} meets {keywords[2] if len(keywords) > 2 else 'excellence'}",
119
- f"Transform {keywords[0] if keywords else 'your world'} - Choose {product_name.title()}"
120
- ]
121
-
122
- # Dynamic social media posts
123
- hashtags = ['#' + word.title() for word in keywords[:3]]
124
- social_posts = [
125
- f"πŸš€ Ready to experience {product_name}? Discover how it's changing {keywords[0] if keywords else 'everything'}! Join thousands already benefiting. {' '.join(hashtags[:2])}",
126
- f"πŸ’‘ What makes {product_name} special? It's all about {keywords[1] if len(keywords) > 1 else 'innovation'} and {keywords[2] if len(keywords) > 2 else 'quality'}. See the difference today! {' '.join(hashtags[1:3])}",
127
- f"✨ {product_name.title()} users report amazing results with {keywords[0] if keywords else 'their experience'}. Don't miss out on this opportunity! {hashtags[0] if hashtags else '#Innovation'}"
128
- ]
129
-
130
- # Dynamic product description
131
- description = f"Introducing {product_name.title()}, the game-changing solution for {keywords[0] if keywords else 'modern needs'}. "
132
- if len(keywords) > 1:
133
- description += f"Our advanced approach to {keywords[1]} ensures you get the best {keywords[2] if len(keywords) > 2 else 'results'}. "
134
- description += f"Whether you're looking for {keywords[0] if keywords else 'quality'} or {keywords[1] if len(keywords) > 1 else 'reliability'}, {product_name} delivers exceptional performance. "
135
- description += f"Join the growing community of users who've discovered the power of {product_name} and see why it's becoming the preferred choice for {keywords[0] if keywords else 'success'}."
136
-
137
- # Dynamic CTAs
138
- cta_ideas = [
139
- f"Experience {product_name.title()} Today!",
140
- f"Start Your {keywords[0].title() if keywords else 'Success'} Journey Now",
141
- f"Get {product_name.title()} - Transform Your {keywords[1].title() if len(keywords) > 1 else 'Experience'}"
142
- ]
143
-
144
- # Dynamic image prompts
145
- image_prompts = [
146
- f"Professional product photography of {product_name}, focused on {keywords[0] if keywords else 'quality'}, clean modern style",
147
- f"Lifestyle image showing {product_name} in use, emphasizing {keywords[1] if len(keywords) > 1 else 'convenience'}, natural lighting",
148
- f"Minimalist design featuring {product_name} with {keywords[2] if len(keywords) > 2 else 'elegant'} aesthetic, premium look"
149
- ]
150
-
151
- return {
152
- "taglines": tagline_templates,
153
- "social_posts": social_posts,
154
- "description": description,
155
- "cta_ideas": cta_ideas,
156
- "image_prompts": image_prompts,
157
- "keywords": keywords
158
- }
159
 
160
- def generate_with_gemini(user_input):
161
- """Generate enhanced content with Gemini"""
 
 
 
162
  try:
 
 
163
  model = genai.GenerativeModel('gemini-pro')
 
 
 
 
 
 
 
 
 
 
164
 
165
- prompt = f"""
166
- Create detailed marketing content for: "{user_input}"
167
 
168
- Generate:
169
- 1. Three unique, catchy taglines (max 12 words each)
170
- 2. Three detailed social media posts (200-280 characters each) with relevant hashtags
171
- 3. One comprehensive product description (150-200 words)
172
- 4. Three compelling call-to-action phrases
173
- 5. Three specific image generation prompts
174
 
175
- Make everything highly relevant to the specific product/service described.
176
- Format with clear markdown headers.
177
- """
178
 
179
- response = model.generate_content(prompt)
 
 
 
180
  return response.text
181
 
182
  except Exception as e:
183
- st.warning(f"Gemini AI unavailable: {e}")
184
- return format_dynamic_content(generate_dynamic_content(user_input))
 
185
 
186
- def format_dynamic_content(content):
187
- """Format structured content for display"""
188
- formatted = "## 🏷️ Marketing Taglines\n"
189
- for i, tagline in enumerate(content["taglines"], 1):
190
- formatted += f"{i}. **{tagline}**\n"
191
-
192
- formatted += "\n## πŸ“± Social Media Posts\n"
193
- for i, post in enumerate(content["social_posts"], 1):
194
- formatted += f"**Post {i}:**\n{post}\n\n"
195
 
196
- formatted += "## πŸ“ Product Description\n"
197
- formatted += f"{content['description']}\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
 
199
- formatted += "## 🎯 Call-to-Action Ideas\n"
200
- for i, cta in enumerate(content["cta_ideas"], 1):
201
- formatted += f"{i}. {cta}\n"
202
 
203
- formatted += "\n## 🎨 Image Generation Prompts\n"
204
- for i, prompt in enumerate(content["image_prompts"], 1):
205
- formatted += f"{i}. {prompt}\n"
206
 
207
  return formatted
208
 
209
- def create_dynamic_flowchart(content_data, user_input):
210
- """Create flowchart based on actual user content"""
211
  try:
 
212
  width, height = 800, 600
213
  image = Image.new('RGB', (width, height), 'white')
214
  draw = ImageDraw.Draw(image)
215
 
216
- # Use default font
217
  try:
218
- font_title = ImageFont.truetype("arial.ttf", 18)
219
  font_text = ImageFont.truetype("arial.ttf", 14)
220
  font_small = ImageFont.truetype("arial.ttf", 12)
221
  except:
222
- font_title = font_text = font_small = ImageFont.load_default()
 
 
223
 
224
  # Colors
225
- colors = ["#2E86AB", "#A23B72", "#F18F01", "#C73E1D"]
226
-
227
- # Extract product name from input
228
- words = user_input.split()
229
- product = next((word for word in words if len(word) > 4), "Product")
230
-
231
- # Title with actual product
232
- title = f"Marketing Strategy: {product.title()}"
233
- draw.text((50, 20), title, fill="#333", font=font_title)
234
-
235
- # Dynamic sections based on content
236
- sections = [
237
- ("🏷️ Brand Message", content_data.get('taglines', ['Message'])[0][:40] + "..."),
238
- ("πŸ“± Social Strategy", content_data.get('social_posts', ['Strategy'])[0][:40] + "..."),
239
- ("πŸ“ Core Value", content_data.get('description', user_input)[:50] + "..."),
240
- ("🎯 Action Plan", content_data.get('cta_ideas', ['Action'])[0])
241
- ]
242
-
243
- # Draw sections
244
- y = 80
245
- for i, (title, content) in enumerate(sections):
246
- color = colors[i % len(colors)]
247
-
248
- # Box
249
- draw.rectangle([50, y, 750, y + 80], outline=color, width=2)
250
-
251
- # Title
252
- draw.text((60, y + 10), title, fill=color, font=font_text)
253
-
254
- # Content
255
- draw.text((60, y + 35), content, fill="#333", font=font_small)
256
-
257
- # Connect to next (except last)
258
- if i < len(sections) - 1:
259
- draw.line([(400, y + 80), (400, y + 100)], fill="#666", width=2)
260
- draw.polygon([(395, y + 95), (405, y + 95), (400, y + 100)], fill="#666")
261
-
262
- y += 100
263
-
264
- # Add keywords if available
265
- if 'keywords' in content_data and content_data['keywords']:
266
- keywords_text = f"Key Terms: {', '.join(content_data['keywords'][:5])}"
267
- draw.text((50, height - 50), keywords_text, fill="#666", font=font_small)
268
-
269
- draw.text((50, height - 30), f"Generated for: {user_input[:30]}...", fill="#999", font=font_small)
 
 
270
 
271
  return image
272
-
273
  except Exception as e:
274
- st.error(f"Flowchart error: {e}")
275
  return None
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  def main():
278
- # Sidebar
279
  with st.sidebar:
280
  st.header("🎨 VoiceCanvas")
281
  st.markdown("*AI Content Studio*")
282
 
283
- # Status
284
- st.subheader("πŸ“Š Status")
 
 
 
 
 
 
 
 
 
 
 
 
285
 
286
- gemini_status = setup_gemini()
 
 
 
 
287
 
288
- st.write(f"πŸ€– Speech Recognition: {'βœ…' if TRANSFORMERS_AVAILABLE else '❌'}")
289
- st.write(f"πŸŽ™οΈ Audio Recording: {'βœ…' if AUDIO_REC_AVAILABLE else '❌'}")
290
- st.write(f"πŸš€ Enhanced AI: {'βœ…' if gemini_status else '❌'}")
 
 
 
 
 
 
291
 
292
  st.markdown("---")
293
 
294
- # Instructions
295
- with st.expander("πŸ“– How to Use"):
 
 
296
  st.markdown("""
297
- 1. **Input your idea** via voice, audio upload, or text
298
- 2. **Review and edit** your input
299
- 3. **Generate content** with one click
300
- 4. **Download** your marketing materials
 
 
301
  """)
302
 
303
- with st.expander("πŸ’‘ Tips"):
304
  st.markdown("""
305
- - Be specific about your product/service
 
 
 
306
  - Mention target audience
307
- - Include key features and benefits
308
- - Use 30+ words for better results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  """)
310
 
311
  # Main content
312
  st.title("🎨 VoiceCanvas - AI Content Studio")
313
- st.markdown("*Transform your ideas into marketing content*")
 
 
 
 
314
 
315
- # Input tabs
316
- tabs = st.tabs(["πŸŽ™οΈ Record", "πŸ“ Upload", "✍️ Type"] if AUDIO_REC_AVAILABLE else ["πŸ“ Upload", "✍️ Type"])
317
 
318
- # Recording tab
 
319
  if AUDIO_REC_AVAILABLE:
320
- with tabs[0]:
321
- st.info("🎀 Record your idea")
 
 
 
 
 
 
 
 
322
 
 
323
  wav_audio_data = st_audiorec()
324
 
325
- if wav_audio_data and st.button("πŸ”„ Transcribe", type="primary"):
326
- with st.spinner("Converting speech to text..."):
327
- with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file:
328
- tmp_file.write(wav_audio_data)
329
- st.session_state.transcription = transcribe_audio(tmp_file.name)
330
- os.unlink(tmp_file.name)
331
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
 
333
  # Upload tab
334
- tab_idx = 1 if AUDIO_REC_AVAILABLE else 0
335
- with tabs[tab_idx]:
336
- st.info("πŸ“ Upload audio file")
337
 
338
- uploaded_file = st.file_uploader("Choose audio file", type=['wav', 'mp3', 'm4a'])
 
 
 
 
339
 
340
- if uploaded_file and st.button("πŸ”„ Process Audio", type="primary"):
341
- with st.spinner("Processing audio..."):
342
- st.session_state.transcription = transcribe_audio(uploaded_file)
343
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
 
345
  # Text tab
346
- tab_idx = 2 if AUDIO_REC_AVAILABLE else 1
347
- with tabs[tab_idx]:
348
- st.info("✍️ Describe your product/service")
349
 
350
  user_input = st.text_area(
351
- "Your idea:",
352
- placeholder="Example: A smart fitness tracker that monitors sleep, heart rate, and stress levels for busy professionals...",
353
- height=120
 
354
  )
355
 
356
  if user_input:
357
  st.session_state.transcription = user_input
 
 
 
 
 
 
 
 
358
 
359
- # Review and edit
360
  if st.session_state.transcription:
361
  st.markdown("---")
362
- st.subheader("πŸ“ Review Your Input")
363
 
364
  edited_text = st.text_area(
365
- "Edit your input:",
366
  value=st.session_state.transcription,
367
- height=100
 
 
368
  )
 
369
 
370
- # Generate content button
 
371
  col1, col2, col3 = st.columns([1, 2, 1])
 
372
  with col2:
373
  if st.button("πŸš€ Generate Marketing Content", type="primary", use_container_width=True):
374
-
375
- with st.spinner("✨ Creating your marketing content..."):
376
- if setup_gemini():
377
- content = generate_with_gemini(edited_text)
378
- st.session_state.generated_content = {
379
- 'text': content,
380
- 'structured': generate_dynamic_content(edited_text)
381
- }
382
- else:
383
- structured_content = generate_dynamic_content(edited_text)
384
- formatted_content = format_dynamic_content(structured_content)
385
- st.session_state.generated_content = {
386
- 'text': formatted_content,
387
- 'structured': structured_content
388
- }
389
-
390
- st.success("βœ… Content generated!")
391
- st.rerun()
392
 
393
- # Display results
394
  if st.session_state.generated_content:
395
  st.markdown("---")
396
  st.header("✨ Your Marketing Content")
397
 
398
- # Show content
399
  if 'text' in st.session_state.generated_content:
400
  st.markdown(st.session_state.generated_content['text'])
401
 
402
- # Flowchart section
403
  st.markdown("---")
404
- st.subheader("πŸ“Š Strategy Visualization")
405
-
406
- if st.button("πŸ“Š Generate Strategy Flowchart", type="secondary"):
407
- with st.spinner("Creating flowchart..."):
408
- if 'structured' in st.session_state.generated_content:
409
- flowchart = create_dynamic_flowchart(
410
- st.session_state.generated_content['structured'],
411
- st.session_state.transcription
412
- )
413
- if flowchart:
414
- st.session_state.generated_content['flowchart'] = flowchart
415
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
 
 
417
  if 'flowchart' in st.session_state.generated_content:
418
- st.image(st.session_state.generated_content['flowchart'], use_column_width=True)
 
 
 
 
419
 
420
- # Download section
421
  st.markdown("---")
422
- st.subheader("πŸ“₯ Download Content")
423
 
424
  col1, col2, col3 = st.columns(3)
425
 
426
  with col1:
 
427
  if 'text' in st.session_state.generated_content:
428
- content_file = f"""VoiceCanvas Marketing Content
429
- Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}
430
-
431
- Input: {st.session_state.transcription}
432
 
433
  {st.session_state.generated_content['text']}
 
 
 
434
  """
 
435
  st.download_button(
436
  "πŸ“„ Download Text",
437
- content_file,
438
- f"marketing_content_{datetime.now().strftime('%Y%m%d_%H%M')}.txt",
439
- use_container_width=True
 
 
440
  )
441
 
442
  with col2:
 
443
  if 'structured' in st.session_state.generated_content:
444
  json_data = {
445
- "timestamp": datetime.now().isoformat(),
 
 
 
 
446
  "input": st.session_state.transcription,
447
  "content": st.session_state.generated_content['structured']
448
  }
 
449
  st.download_button(
450
  "πŸ“Š Download Data",
451
  json.dumps(json_data, indent=2),
452
- f"content_data_{datetime.now().strftime('%Y%m%d_%H%M')}.json",
453
  mime="application/json",
454
- use_container_width=True
 
455
  )
456
 
457
  with col3:
 
458
  if 'flowchart' in st.session_state.generated_content:
459
  img_buffer = io.BytesIO()
460
  st.session_state.generated_content['flowchart'].save(img_buffer, format="PNG")
 
461
  st.download_button(
462
  "πŸ“Š Download Flowchart",
463
  img_buffer.getvalue(),
464
- f"flowchart_{datetime.now().strftime('%Y%m%d_%H%M')}.png",
465
  mime="image/png",
466
- use_container_width=True
 
467
  )
 
 
 
 
 
 
 
 
 
468
 
469
  if __name__ == "__main__":
470
  main()
 
5
  import os
6
  import tempfile
7
  from PIL import Image, ImageDraw, ImageFont
8
+ import requests
9
  import json
10
  from datetime import datetime
11
+ import time
 
12
 
13
  # Import with error handling
14
  try:
 
16
  TRANSFORMERS_AVAILABLE = True
17
  except ImportError:
18
  TRANSFORMERS_AVAILABLE = False
 
19
 
20
  try:
21
  import google.generativeai as genai
 
33
  st.set_page_config(
34
  page_title="VoiceCanvas - AI Content Studio",
35
  page_icon="🎨",
36
+ layout="wide",
37
+ initial_sidebar_state="expanded"
38
  )
39
 
40
  # Initialize session state
41
+ if 'generated_content' not in st.session_state:
42
+ st.session_state.generated_content = {}
43
+ if 'transcription' not in st.session_state:
44
+ st.session_state.transcription = ""
45
+ if 'processing' not in st.session_state:
46
+ st.session_state.processing = False
47
+ if 'current_task' not in st.session_state:
48
+ st.session_state.current_task = ""
49
+ if 'models_loaded' not in st.session_state:
50
+ st.session_state.models_loaded = False
51
+ if 'whisper_model' not in st.session_state:
52
+ st.session_state.whisper_model = None
53
+ if 'button_clicked' not in st.session_state:
54
+ st.session_state.button_clicked = False
55
 
56
+ def load_models():
57
+ """Load models efficiently with progress tracking"""
58
+
59
+ if st.session_state.models_loaded and st.session_state.whisper_model is not None:
60
+ return True
61
+
62
  if not TRANSFORMERS_AVAILABLE:
63
+ st.error("❌ Transformers library not available. Please install: pip install transformers")
64
+ return False
65
+
66
+ progress_bar = st.progress(0)
67
+ status_text = st.empty()
68
 
69
  try:
70
+ # Load Whisper model
71
+ status_text.text("Loading speech recognition model...")
72
+ progress_bar.progress(25)
73
+
74
+ # Use session state to store the model
75
+ st.session_state.whisper_model = pipeline(
76
  "automatic-speech-recognition",
77
  model="openai/whisper-tiny",
78
+ device=-1, # Use CPU
79
  torch_dtype=torch.float32,
80
  return_timestamps=False
81
  )
82
+
83
+ progress_bar.progress(75)
84
+ status_text.text("Models loaded successfully!")
85
+ progress_bar.progress(100)
86
+
87
+ st.session_state.models_loaded = True
88
+
89
+ # Clear progress indicators after a moment
90
+ time.sleep(1)
91
+ progress_bar.empty()
92
+ status_text.empty()
93
+
94
+ return True
95
+
96
  except Exception as e:
97
+ st.error(f"❌ Error loading models: {str(e)}")
98
+ st.error("Try installing additional dependencies: pip install librosa soundfile")
99
+ progress_bar.empty()
100
+ status_text.empty()
101
+ return False
102
 
103
  def setup_gemini():
104
+ """Setup Gemini API if available"""
105
  if not GENAI_AVAILABLE:
106
  return False
107
+
 
 
 
 
 
 
 
 
 
108
  try:
109
+ api_key = os.getenv("GEMINI_API_KEY")
110
+ if not api_key and hasattr(st, 'secrets'):
111
+ api_key = st.secrets.get("GEMINI_API_KEY", "")
112
 
113
+ if api_key:
114
+ genai.configure(api_key=api_key)
115
+ return True
116
+ return False
117
  except Exception as e:
118
+ return False
 
 
 
 
 
 
 
 
119
 
120
+ def transcribe_audio_simple(audio_file):
121
+ """Simple audio transcription with progress tracking"""
122
+ try:
123
+ # Check if model is loaded
124
+ if st.session_state.whisper_model is None:
125
+ st.error("❌ Speech recognition model not loaded. Please try loading models first.")
126
+ return "Error: Speech recognition model not available"
127
+
128
+ st.session_state.current_task = "Converting speech to text..."
129
+
130
+ # Handle different input types
131
+ if isinstance(audio_file, str):
132
+ # File path
133
+ audio_input = audio_file
134
+ else:
135
+ # File-like object
136
+ audio_input = audio_file
137
+
138
+ # Transcribe using pipeline
139
+ result = st.session_state.whisper_model(audio_input)
140
+
141
+ st.session_state.current_task = ""
142
+
143
+ # Handle different result formats
144
+ if isinstance(result, dict) and "text" in result:
145
+ return result["text"].strip()
146
+ elif isinstance(result, str):
147
+ return result.strip()
148
+ else:
149
+ return str(result).strip()
150
+
151
+ except Exception as e:
152
+ st.session_state.current_task = ""
153
+ error_msg = f"Transcription error: {str(e)}"
154
+ st.error(error_msg)
155
+
156
+ # Provide troubleshooting suggestions
157
+ if "librosa" in str(e).lower() or "soundfile" in str(e).lower():
158
+ st.error("πŸ”§ Missing audio processing libraries. Install with:")
159
+ st.code("pip install librosa soundfile")
160
+
161
+ return f"Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
162
 
163
+ def generate_content_with_gemini(prompt):
164
+ """Generate content using Gemini"""
165
+ if not GENAI_AVAILABLE:
166
+ return generate_content_offline(prompt)
167
+
168
  try:
169
+ st.session_state.current_task = "Generating enhanced content with Gemini AI..."
170
+
171
  model = genai.GenerativeModel('gemini-pro')
172
+ response = model.generate_content(f"""
173
+ Based on this input: "{prompt}"
174
+
175
+ Create comprehensive marketing content with:
176
+
177
+ ## Marketing Taglines
178
+ Generate 3 catchy, memorable taglines (max 12 words each)
179
+
180
+ ## Social Media Posts
181
+ Create 3 engaging social media posts (max 280 characters each)
182
 
183
+ ## Product Description
184
+ Write 1 compelling product description (100-150 words)
185
 
186
+ ## Image Generation Prompts
187
+ Provide 3 detailed prompts for AI image generation
 
 
 
 
188
 
189
+ ## Call-to-Action Ideas
190
+ Suggest 3 effective call-to-action phrases
 
191
 
192
+ Format with clear markdown headers and numbered lists.
193
+ """)
194
+
195
+ st.session_state.current_task = ""
196
  return response.text
197
 
198
  except Exception as e:
199
+ st.warning(f"Gemini error: {e}. Using offline generation.")
200
+ st.session_state.current_task = ""
201
+ return generate_content_offline(prompt)
202
 
203
+ def generate_content_offline(prompt):
204
+ """Generate content using offline methods"""
205
+ st.session_state.current_task = "Generating content with offline templates..."
 
 
 
 
 
 
206
 
207
+ # Create structured content
208
+ content = {
209
+ "taglines": [
210
+ f"Experience {prompt} like never before",
211
+ f"Transform your world with {prompt}",
212
+ f"Discover the power of {prompt}"
213
+ ],
214
+ "social_posts": [
215
+ f"🌟 Ready to explore {prompt}? Join thousands who've already discovered the difference! #Innovation",
216
+ f"πŸ’« {prompt} is changing the game! Don't miss out on this incredible opportunity. #GameChanger",
217
+ f"πŸš€ The future of {prompt} is here! Experience what everyone's talking about. #FutureTech"
218
+ ],
219
+ "description": f"Discover the revolutionary world of {prompt}. Our innovative approach combines cutting-edge technology with user-friendly design to deliver an unmatched experience. Perfect for both beginners and experts, this solution transforms how you interact with {prompt}. Join thousands of satisfied users today!",
220
+ "image_prompts": [
221
+ f"Professional product photo of {prompt}, clean white background, studio lighting",
222
+ f"Modern minimalist illustration of {prompt}, flat design, vibrant colors",
223
+ f"Futuristic concept art of {prompt}, digital art, high quality, detailed"
224
+ ],
225
+ "cta_ideas": [
226
+ f"Get Started with {prompt} Today!",
227
+ f"Transform Your Experience Now",
228
+ f"Join the {prompt} Revolution"
229
+ ]
230
+ }
231
 
232
+ # Format for display
233
+ formatted = format_content_display(content)
 
234
 
235
+ # Store both versions
236
+ st.session_state.generated_content['structured'] = content
237
+ st.session_state.current_task = ""
238
 
239
  return formatted
240
 
241
+ def create_flowchart_image(content_data):
242
+ """Create a simple flowchart visualization of the content"""
243
  try:
244
+ # Create image
245
  width, height = 800, 600
246
  image = Image.new('RGB', (width, height), 'white')
247
  draw = ImageDraw.Draw(image)
248
 
249
+ # Try to use a basic font, fall back to default if not available
250
  try:
251
+ font_title = ImageFont.truetype("arial.ttf", 20)
252
  font_text = ImageFont.truetype("arial.ttf", 14)
253
  font_small = ImageFont.truetype("arial.ttf", 12)
254
  except:
255
+ font_title = ImageFont.load_default()
256
+ font_text = ImageFont.load_default()
257
+ font_small = ImageFont.load_default()
258
 
259
  # Colors
260
+ primary_color = "#2E86AB"
261
+ secondary_color = "#A23B72"
262
+ accent_color = "#F18F01"
263
+ text_color = "#333333"
264
+
265
+ # Title
266
+ draw.text((width//2 - 150, 20), "Marketing Content Strategy", fill=text_color, font=font_title)
267
+
268
+ # Draw boxes and content
269
+ y_offset = 80
270
+ box_height = 80
271
+ box_width = 180
272
+
273
+ # Row 1: Taglines and Social Media
274
+ draw.rectangle([50, y_offset, 50 + box_width, y_offset + box_height], outline=primary_color, width=2)
275
+ draw.text((60, y_offset + 10), "🏷️ Taglines", fill=primary_color, font=font_text)
276
+ draw.text((60, y_offset + 35), f"β€’ {content_data.get('taglines', ['Sample tagline'])[0][:25]}...", fill=text_color, font=font_small)
277
+
278
+ draw.rectangle([width//2 + 50, y_offset, width//2 + 50 + box_width, y_offset + box_height], outline=secondary_color, width=2)
279
+ draw.text((width//2 + 60, y_offset + 10), "πŸ“± Social Media", fill=secondary_color, font=font_text)
280
+ draw.text((width//2 + 60, y_offset + 35), f"β€’ {content_data.get('social_posts', ['Sample post'])[0][:25]}...", fill=text_color, font=font_small)
281
+
282
+ # Row 2: Description
283
+ y_offset += 120
284
+ draw.rectangle([width//4, y_offset, width*3//4, y_offset + box_height], outline=accent_color, width=2)
285
+ draw.text((width//4 + 10, y_offset + 10), "πŸ“ Product Description", fill=accent_color, font=font_text)
286
+ desc_text = content_data.get('description', 'Product description goes here')[:50] + "..."
287
+ draw.text((width//4 + 10, y_offset + 35), desc_text, fill=text_color, font=font_small)
288
+
289
+ # Row 3: CTAs and Image Ideas
290
+ y_offset += 120
291
+ draw.rectangle([50, y_offset, 50 + box_width, y_offset + box_height], outline=primary_color, width=2)
292
+ draw.text((60, y_offset + 10), "🎯 Call-to-Actions", fill=primary_color, font=font_text)
293
+ draw.text((60, y_offset + 35), f"β€’ {content_data.get('cta_ideas', ['Sample CTA'])[0]}", fill=text_color, font=font_small)
294
+
295
+ draw.rectangle([width//2 + 50, y_offset, width//2 + 50 + box_width, y_offset + box_height], outline=secondary_color, width=2)
296
+ draw.text((width//2 + 60, y_offset + 10), "🎨 Visual Ideas", fill=secondary_color, font=font_text)
297
+ draw.text((width//2 + 60, y_offset + 35), "β€’ Professional photos", fill=text_color, font=font_small)
298
+ draw.text((width//2 + 60, y_offset + 50), "β€’ Minimalist design", fill=text_color, font=font_small)
299
+
300
+ # Draw connecting lines
301
+ draw.line([(width//2, 80 + box_height), (width//2, 200)], fill=text_color, width=2)
302
+ draw.line([(width//4 + box_width//2, 200 + box_height), (width//2, 320)], fill=text_color, width=2)
303
+ draw.line([(width*3//4 - box_width//2, 200 + box_height), (width//2, 320)], fill=text_color, width=2)
304
+
305
+ # Add footer
306
+ draw.text((width//2 - 100, height - 30), "Generated by VoiceCanvas AI Studio", fill=text_color, font=font_small)
307
 
308
  return image
309
+
310
  except Exception as e:
311
+ st.error(f"Error creating flowchart: {e}")
312
  return None
313
 
314
+ def format_content_display(content):
315
+ """Format content for nice display"""
316
+ if isinstance(content, dict):
317
+ formatted = ""
318
+
319
+ if "taglines" in content:
320
+ formatted += "## 🏷️ Marketing Taglines\n"
321
+ for i, tagline in enumerate(content["taglines"], 1):
322
+ formatted += f"{i}. **{tagline}**\n"
323
+ formatted += "\n"
324
+
325
+ if "social_posts" in content:
326
+ formatted += "## πŸ“± Social Media Posts\n"
327
+ for i, post in enumerate(content["social_posts"], 1):
328
+ formatted += f"**Post {i}:**\n{post}\n\n"
329
+
330
+ if "description" in content:
331
+ formatted += "## πŸ“ Product Description\n"
332
+ formatted += f"{content['description']}\n\n"
333
+
334
+ if "cta_ideas" in content:
335
+ formatted += "## 🎯 Call-to-Action Ideas\n"
336
+ for i, cta in enumerate(content["cta_ideas"], 1):
337
+ formatted += f"{i}. {cta}\n"
338
+ formatted += "\n"
339
+
340
+ if "image_prompts" in content:
341
+ formatted += "## 🎨 Image Generation Prompts\n"
342
+ for i, prompt in enumerate(content["image_prompts"], 1):
343
+ formatted += f"{i}. {prompt}\n"
344
+
345
+ return formatted
346
+
347
+ return str(content)
348
+
349
+ def handle_button_click(button_key):
350
+ """Handle button clicks to prevent multiple clicks"""
351
+ if not st.session_state.get(f'{button_key}_clicked', False):
352
+ st.session_state[f'{button_key}_clicked'] = True
353
+ return True
354
+ return False
355
+
356
+ def reset_button_state(button_key):
357
+ """Reset button state"""
358
+ if f'{button_key}_clicked' in st.session_state:
359
+ st.session_state[f'{button_key}_clicked'] = False
360
+
361
  def main():
362
+ # Sidebar with tips and status
363
  with st.sidebar:
364
  st.header("🎨 VoiceCanvas")
365
  st.markdown("*AI Content Studio*")
366
 
367
+ # Load models button
368
+ if not st.session_state.models_loaded:
369
+ if st.button("πŸš€ Load AI Models", type="primary", use_container_width=True):
370
+ if handle_button_click("load_models"):
371
+ with st.spinner("Loading AI models..."):
372
+ success = load_models()
373
+ reset_button_state("load_models")
374
+ if success:
375
+ st.rerun()
376
+
377
+ # Status section
378
+ st.subheader("πŸ“Š System Status")
379
+
380
+ gemini_available = setup_gemini()
381
 
382
+ col1, col2 = st.columns(2)
383
+ with col1:
384
+ st.metric("Mode", "Enhanced" if gemini_available else "Basic")
385
+ with col2:
386
+ st.metric("Status", "Ready" if not st.session_state.processing else "Working")
387
 
388
+ # Component status
389
+ st.write("πŸ€– **Components:**")
390
+ st.write(f"β€’ Speech Recognition: {'βœ…' if st.session_state.models_loaded else '❌'}")
391
+ st.write(f"β€’ Audio Recording: {'βœ…' if AUDIO_REC_AVAILABLE else '❌'}")
392
+ st.write(f"β€’ Enhanced AI: {'βœ…' if gemini_available else '❌'}")
393
+
394
+ # Current task indicator
395
+ if st.session_state.current_task:
396
+ st.info(f"πŸ”„ {st.session_state.current_task}")
397
 
398
  st.markdown("---")
399
 
400
+ # Tips and help
401
+ st.subheader("πŸ’‘ How to Use")
402
+
403
+ with st.expander("πŸš€ Quick Start", expanded=True):
404
  st.markdown("""
405
+ 1. **Load Models**: Click "Load AI Models" button first
406
+ 2. **Input**: Use voice, upload audio, or type text
407
+ 3. **Edit**: Review and refine your input
408
+ 4. **Generate**: Create marketing content
409
+ 5. **Visualize**: Generate flowchart of your strategy
410
+ 6. **Export**: Download your materials
411
  """)
412
 
413
+ with st.expander("🎯 Best Practices"):
414
  st.markdown("""
415
+ **For Voice/Audio:**
416
+ - Speak clearly at normal pace
417
+ - Use quiet environment
418
+ - Describe your product/service
419
  - Mention target audience
420
+
421
+ **For Text:**
422
+ - Be specific about features
423
+ - Include benefits and use cases
424
+ - Mention what makes it unique
425
+ - Use 50+ words for detail
426
+ """)
427
+
428
+ with st.expander("βš™οΈ Setup (Optional)"):
429
+ st.markdown("""
430
+ **Enhanced Features:**
431
+
432
+ Add environment variables:
433
+ - `GEMINI_API_KEY`: Advanced text generation
434
+
435
+ **Get API Key:**
436
+ - [Google AI Studio](https://makersuite.google.com/app/apikey) (Free)
437
+ """)
438
+
439
+ with st.expander("πŸ› οΈ Troubleshooting"):
440
+ st.markdown("""
441
+ **Common Issues:**
442
+ - "Speech recognition not available" β†’ Click "Load AI Models"
443
+ - Audio processing errors β†’ Install: `pip install librosa soundfile`
444
+ - Button not responding β†’ Wait for processing to complete
445
+ - Slow processing β†’ Models loading for first time
446
+ - Basic content only β†’ Add GEMINI_API_KEY
447
  """)
448
 
449
  # Main content
450
  st.title("🎨 VoiceCanvas - AI Content Studio")
451
+ st.markdown("*Transform your ideas into comprehensive marketing content*")
452
+
453
+ # Show model loading status
454
+ if not st.session_state.models_loaded:
455
+ st.warning("⚠️ AI models not loaded yet. Click 'Load AI Models' in the sidebar to enable speech recognition.")
456
 
457
+ # Main input area
458
+ st.header("πŸ’‘ Share Your Idea")
459
 
460
+ # Dynamic tabs based on available features
461
+ available_tabs = []
462
  if AUDIO_REC_AVAILABLE:
463
+ available_tabs.append("πŸŽ™οΈ Record")
464
+ available_tabs.extend(["πŸ“ Upload", "✍️ Type"])
465
+
466
+ tabs = st.tabs(available_tabs)
467
+ tab_index = 0
468
+
469
+ # Recording tab (if available)
470
+ if AUDIO_REC_AVAILABLE:
471
+ with tabs[tab_index]:
472
+ st.info("🎀 Click the microphone button to start recording")
473
 
474
+ # Audio recorder
475
  wav_audio_data = st_audiorec()
476
 
477
+ if wav_audio_data is not None:
478
+ st.success("πŸŽ‰ Audio recorded successfully!")
479
+ st.audio(wav_audio_data, format='audio/wav')
480
+
481
+ col1, col2 = st.columns([1, 2])
482
+ with col1:
483
+ if st.button("πŸ”„ Transcribe Audio", key="transcribe_btn", type="primary"):
484
+ if not st.session_state.models_loaded:
485
+ st.error("Please load AI models first using the sidebar button.")
486
+ else:
487
+ if handle_button_click("transcribe"):
488
+ st.session_state.processing = True
489
+ # Process immediately
490
+ with st.spinner("🎯 Converting your speech to text..."):
491
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file:
492
+ tmp_file.write(wav_audio_data)
493
+ transcription = transcribe_audio_simple(tmp_file.name)
494
+ st.session_state.transcription = transcription
495
+ os.unlink(tmp_file.name)
496
+ st.session_state.processing = False
497
+ reset_button_state("transcribe")
498
+ st.rerun()
499
+
500
+ with col2:
501
+ if st.session_state.processing:
502
+ st.info("πŸ”„ Processing your audio...")
503
+ tab_index += 1
504
 
505
  # Upload tab
506
+ with tabs[tab_index]:
507
+ st.info("πŸ“ Upload an audio file containing your idea")
 
508
 
509
+ uploaded_file = st.file_uploader(
510
+ "Choose audio file",
511
+ type=['wav', 'mp3', 'm4a'],
512
+ help="Supported: WAV, MP3, M4A β€’ Max 10MB β€’ Best: 30 seconds or less"
513
+ )
514
 
515
+ if uploaded_file:
516
+ st.success("πŸ“„ File uploaded successfully!")
517
+ st.audio(uploaded_file)
518
+
519
+ col1, col2 = st.columns([1, 2])
520
+ with col1:
521
+ if st.button("πŸ”„ Process Audio", key="upload_transcribe", type="primary"):
522
+ if not st.session_state.models_loaded:
523
+ st.error("Please load AI models first using the sidebar button.")
524
+ else:
525
+ if handle_button_click("upload_process"):
526
+ st.session_state.processing = True
527
+ # Process immediately
528
+ with st.spinner("🎯 Processing your audio file..."):
529
+ transcription = transcribe_audio_simple(uploaded_file)
530
+ st.session_state.transcription = transcription
531
+ st.session_state.processing = False
532
+ reset_button_state("upload_process")
533
+ st.rerun()
534
+
535
+ with col2:
536
+ if st.session_state.processing:
537
+ st.info("πŸ”„ Converting speech to text...")
538
+
539
+ tab_index += 1
540
 
541
  # Text tab
542
+ with tabs[tab_index]:
543
+ st.info("✍️ Type or paste your product/service description")
 
544
 
545
  user_input = st.text_area(
546
+ "Describe your idea:",
547
+ placeholder="Example: A smart fitness tracker that monitors sleep patterns, heart rate, and stress levels. It provides personalized workout recommendations for busy professionals who want to maintain their health despite hectic schedules.",
548
+ height=150,
549
+ help="Be detailed! Include features, benefits, and target audience for best results."
550
  )
551
 
552
  if user_input:
553
  st.session_state.transcription = user_input
554
+ word_count = len(user_input.split())
555
+
556
+ if word_count < 10:
557
+ st.warning("πŸ’‘ Add more details for better results (at least 10 words)")
558
+ elif word_count < 30:
559
+ st.info("πŸ“ Good start! Add more features/benefits for richer content")
560
+ else:
561
+ st.success(f"βœ… Great detail! ({word_count} words)")
562
 
563
+ # Show transcription and editing
564
  if st.session_state.transcription:
565
  st.markdown("---")
566
+ st.header("πŸ“ Review Your Input")
567
 
568
  edited_text = st.text_area(
569
+ "Edit or refine your input:",
570
  value=st.session_state.transcription,
571
+ height=120,
572
+ key="edit_transcription",
573
+ help="Make any corrections or add more details"
574
  )
575
+ st.session_state.transcription = edited_text
576
 
577
+ # Generate content section
578
+ st.markdown("---")
579
  col1, col2, col3 = st.columns([1, 2, 1])
580
+
581
  with col2:
582
  if st.button("πŸš€ Generate Marketing Content", type="primary", use_container_width=True):
583
+ if handle_button_click("generate_content"):
584
+ with st.spinner("✨ Creating comprehensive marketing content..."):
585
+ if setup_gemini():
586
+ content_text = generate_content_with_gemini(st.session_state.transcription)
587
+ st.session_state.generated_content['text'] = content_text
588
+ else:
589
+ content_text = generate_content_offline(st.session_state.transcription)
590
+ st.session_state.generated_content['text'] = content_text
591
+ reset_button_state("generate_content")
592
+ st.success("βœ… Content generated successfully!")
593
+ st.rerun()
 
 
 
 
 
 
 
594
 
595
+ # Display generated content
596
  if st.session_state.generated_content:
597
  st.markdown("---")
598
  st.header("✨ Your Marketing Content")
599
 
600
+ # Text content
601
  if 'text' in st.session_state.generated_content:
602
  st.markdown(st.session_state.generated_content['text'])
603
 
604
+ # Visual content section
605
  st.markdown("---")
606
+ st.subheader("🎨 Visual Content")
607
+
608
+ col1, col2 = st.columns([1, 1])
609
+
610
+ with col1:
611
+ if st.button("πŸ“Š Generate Strategy Flowchart", use_container_width=True, type="secondary"):
612
+ if handle_button_click("generate_flowchart"):
613
+ with st.spinner("🎨 Creating strategy flowchart..."):
614
+ if 'structured' in st.session_state.generated_content:
615
+ flowchart_img = create_flowchart_image(st.session_state.generated_content['structured'])
616
+ if flowchart_img:
617
+ st.session_state.generated_content['flowchart'] = flowchart_img
618
+ else:
619
+ # Create basic flowchart from text content
620
+ basic_data = {
621
+ 'taglines': ['Key message from your content'],
622
+ 'social_posts': ['Social media strategy'],
623
+ 'description': st.session_state.transcription[:100],
624
+ 'cta_ideas': ['Call to action'],
625
+ 'image_prompts': ['Visual elements']
626
+ }
627
+ flowchart_img = create_flowchart_image(basic_data)
628
+ if flowchart_img:
629
+ st.session_state.generated_content['flowchart'] = flowchart_img
630
+ reset_button_state("generate_flowchart")
631
+ st.success("πŸ“Š Flowchart created!")
632
+ st.rerun()
633
+
634
+ with col2:
635
+ st.info("πŸ’‘ Generate a visual flowchart of your marketing strategy to better understand content relationships and flow.")
636
 
637
+ # Display generated flowchart
638
  if 'flowchart' in st.session_state.generated_content:
639
+ st.image(
640
+ st.session_state.generated_content['flowchart'],
641
+ caption="Marketing Strategy Flowchart",
642
+ use_column_width=True
643
+ )
644
 
645
+ # Export section
646
  st.markdown("---")
647
+ st.header("πŸ“₯ Export Your Content")
648
 
649
  col1, col2, col3 = st.columns(3)
650
 
651
  with col1:
652
+ # Text export
653
  if 'text' in st.session_state.generated_content:
654
+ content_export = f"""VOICECANVAS MARKETING CONTENT
655
+ Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
656
+ Source: {st.session_state.transcription[:100]}...
 
657
 
658
  {st.session_state.generated_content['text']}
659
+
660
+ ---
661
+ Created with VoiceCanvas AI Content Studio
662
  """
663
+
664
  st.download_button(
665
  "πŸ“„ Download Text",
666
+ content_export,
667
+ file_name=f"marketing_content_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
668
+ mime="text/plain",
669
+ use_container_width=True,
670
+ help="Download complete text content"
671
  )
672
 
673
  with col2:
674
+ # JSON export
675
  if 'structured' in st.session_state.generated_content:
676
  json_data = {
677
+ "metadata": {
678
+ "timestamp": datetime.now().isoformat(),
679
+ "generator": "VoiceCanvas AI Studio",
680
+ "mode": "Enhanced" if setup_gemini() else "Basic"
681
+ },
682
  "input": st.session_state.transcription,
683
  "content": st.session_state.generated_content['structured']
684
  }
685
+
686
  st.download_button(
687
  "πŸ“Š Download Data",
688
  json.dumps(json_data, indent=2),
689
+ file_name=f"content_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
690
  mime="application/json",
691
+ use_container_width=True,
692
+ help="Download structured data (JSON)"
693
  )
694
 
695
  with col3:
696
+ # Flowchart export
697
  if 'flowchart' in st.session_state.generated_content:
698
  img_buffer = io.BytesIO()
699
  st.session_state.generated_content['flowchart'].save(img_buffer, format="PNG")
700
+
701
  st.download_button(
702
  "πŸ“Š Download Flowchart",
703
  img_buffer.getvalue(),
704
+ file_name=f"strategy_flowchart_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png",
705
  mime="image/png",
706
+ use_container_width=True,
707
+ help="Download strategy flowchart"
708
  )
709
+ else:
710
+ st.info("Generate flowchart first", icon="ℹ️")
711
+
712
+ # Footer
713
+ st.markdown("---")
714
+ col1, col2, col3 = st.columns([1, 2, 1])
715
+ with col2:
716
+ st.markdown("🎨 **VoiceCanvas AI Content Studio**")
717
+ st.caption("Transform ideas into marketing magic β€’ Built with Streamlit")
718
 
719
  if __name__ == "__main__":
720
  main()