maria355 commited on
Commit
12e0416
Β·
verified Β·
1 Parent(s): ef696be

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +661 -546
app.py CHANGED
@@ -2,6 +2,7 @@ import streamlit as st
2
  import torch
3
  import numpy as np
4
  import io
 
5
  import os
6
  import tempfile
7
  from PIL import Image
@@ -9,620 +10,734 @@ import requests
9
  import json
10
  from datetime import datetime
11
  import time
 
 
12
 
13
- # Import with error handling
14
- try:
15
- from transformers import pipeline
16
- TRANSFORMERS_AVAILABLE = True
17
- except ImportError:
18
- TRANSFORMERS_AVAILABLE = False
19
-
20
- try:
21
- import google.generativeai as genai
22
- GENAI_AVAILABLE = True
23
- except ImportError:
24
- GENAI_AVAILABLE = False
25
-
26
- try:
27
- from st_audiorec import st_audiorec
28
- AUDIO_REC_AVAILABLE = True
29
- except ImportError:
30
- AUDIO_REC_AVAILABLE = False
31
 
32
  # Configure page
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
-
52
- # Global variables for models
53
- whisper_model = None
54
- text_generator = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- def load_models():
57
- """Load models efficiently with progress tracking"""
58
- global whisper_model, text_generator
59
-
60
- if st.session_state.models_loaded:
61
- return True
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- if not TRANSFORMERS_AVAILABLE:
64
- st.error("AI models not available")
65
- return False
 
 
 
 
 
 
 
 
 
 
 
66
 
67
- progress_bar = st.progress(0)
68
- status_text = st.empty()
 
 
 
 
 
 
69
 
70
  try:
71
- # Load Whisper model
72
- status_text.text("Loading speech recognition model...")
73
- progress_bar.progress(25)
74
-
75
- whisper_model = pipeline(
76
- "automatic-speech-recognition",
77
- model="openai/whisper-tiny",
78
- device=-1,
79
- torch_dtype=torch.float32
80
  )
81
-
82
- progress_bar.progress(75)
83
- status_text.text("Models loaded successfully!")
84
- progress_bar.progress(100)
85
-
86
- st.session_state.models_loaded = True
87
-
88
- # Clear progress indicators after a moment
89
- time.sleep(1)
90
- progress_bar.empty()
91
- status_text.empty()
92
-
93
- return True
94
-
95
- except Exception as e:
96
- st.error(f"Error loading models: {e}")
97
- progress_bar.empty()
98
- status_text.empty()
99
- return False
100
 
101
- def setup_gemini():
102
- """Setup Gemini API if available"""
103
- if not GENAI_AVAILABLE:
104
- return False
105
-
106
  try:
107
- api_key = os.getenv("GEMINI_API_KEY")
108
- if not api_key and hasattr(st, 'secrets'):
109
- api_key = st.secrets.get("GEMINI_API_KEY", "")
110
-
111
- if api_key:
112
- genai.configure(api_key=api_key)
113
- return True
114
- return False
115
  except Exception as e:
116
- return False
 
117
 
118
- def transcribe_audio_simple(audio_file):
119
- """Simple audio transcription with progress tracking"""
 
120
  try:
121
- if whisper_model is None:
122
- return "Error: Speech recognition not available"
123
-
124
- st.session_state.current_task = "Converting speech to text..."
125
-
126
- # Transcribe using pipeline
127
- result = whisper_model(audio_file)
128
-
129
- st.session_state.current_task = ""
130
- return result["text"].strip()
131
-
132
  except Exception as e:
133
- st.session_state.current_task = ""
134
- return f"Error: {str(e)}"
135
 
136
- def generate_content_with_gemini(prompt):
137
- """Generate content using Gemini"""
138
- if not GENAI_AVAILABLE:
139
- return generate_content_offline(prompt)
140
-
141
  try:
142
- st.session_state.current_task = "Generating enhanced content with Gemini AI..."
143
-
144
- model = genai.GenerativeModel('gemini-pro')
145
- response = model.generate_content(f"""
146
- Based on this input: "{prompt}"
147
-
148
- Create comprehensive marketing content with:
149
-
150
- ## Marketing Taglines
151
- Generate 3 catchy, memorable taglines (max 12 words each)
152
-
153
- ## Social Media Posts
154
- Create 3 engaging social media posts (max 280 characters each)
155
-
156
- ## Product Description
157
- Write 1 compelling product description (100-150 words)
158
-
159
- ## Image Generation Prompts
160
- Provide 3 detailed prompts for AI image generation
161
-
162
- ## Call-to-Action Ideas
163
- Suggest 3 effective call-to-action phrases
164
-
165
- Format with clear markdown headers and numbered lists.
166
- """)
167
-
168
- st.session_state.current_task = ""
169
- return response.text
170
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  except Exception as e:
172
- st.warning(f"Gemini error: {e}. Using offline generation.")
173
- st.session_state.current_task = ""
174
- return generate_content_offline(prompt)
175
 
176
- def generate_content_offline(prompt):
177
- """Generate content using offline methods"""
178
- st.session_state.current_task = "Generating content with offline templates..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
- # Create structured content
181
- content = {
182
- "taglines": [
183
- f"Experience {prompt} like never before",
184
- f"Transform your world with {prompt}",
185
- f"Discover the power of {prompt}"
186
- ],
187
- "social_posts": [
188
- f"🌟 Ready to explore {prompt}? Join thousands who've already discovered the difference! #Innovation",
189
- f"πŸ’« {prompt} is changing the game! Don't miss out on this incredible opportunity. #GameChanger",
190
- f"πŸš€ The future of {prompt} is here! Experience what everyone's talking about. #FutureTech"
191
- ],
192
- "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!",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  "image_prompts": [
194
- f"Professional product photo of {prompt}, clean white background, studio lighting",
195
- f"Modern minimalist illustration of {prompt}, flat design, vibrant colors",
196
- f"Futuristic concept art of {prompt}, digital art, high quality, detailed"
197
  ]
198
  }
 
 
 
199
 
200
- # Format for display
201
- formatted = format_content_display(content)
 
 
 
 
 
202
 
203
- # Store both versions
204
- st.session_state.generated_content['structured'] = content
205
- st.session_state.current_task = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
- return formatted
208
-
209
- def generate_image_with_api(prompt):
210
- """Generate image using free API"""
211
- try:
212
- st.session_state.current_task = "Creating image with AI..."
213
-
214
- api_url = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-2-1"
215
- headers = {"Authorization": f"Bearer {os.getenv('HF_TOKEN', '')}"}
216
-
217
- if not os.getenv('HF_TOKEN'):
218
- st.warning("Add HF_TOKEN environment variable for image generation")
219
- st.session_state.current_task = ""
220
- return None
221
-
222
- response = requests.post(api_url, headers=headers, json={"inputs": prompt}, timeout=60)
223
-
224
- if response.status_code == 200:
225
- image = Image.open(io.BytesIO(response.content))
226
- st.session_state.current_task = ""
227
- return image
228
- else:
229
- st.warning(f"Image API returned status {response.status_code}")
230
- st.session_state.current_task = ""
231
- return None
232
-
233
- except Exception as e:
234
- st.error(f"Image generation error: {e}")
235
- st.session_state.current_task = ""
236
- return None
237
-
238
- def format_content_display(content):
239
- """Format content for nice display"""
240
- if isinstance(content, dict):
241
- formatted = ""
242
-
243
- if "taglines" in content:
244
- formatted += "## 🏷️ Marketing Taglines\n"
245
- for i, tagline in enumerate(content["taglines"], 1):
246
- formatted += f"{i}. **{tagline}**\n"
247
- formatted += "\n"
248
-
249
- if "social_posts" in content:
250
- formatted += "## πŸ“± Social Media Posts\n"
251
- for i, post in enumerate(content["social_posts"], 1):
252
- formatted += f"**Post {i}:**\n{post}\n\n"
253
-
254
- if "description" in content:
255
- formatted += "## πŸ“ Product Description\n"
256
- formatted += f"{content['description']}\n\n"
257
-
258
- if "image_prompts" in content:
259
- formatted += "## 🎨 Image Generation Prompts\n"
260
- for i, prompt in enumerate(content["image_prompts"], 1):
261
- formatted += f"{i}. {prompt}\n"
262
-
263
- return formatted
264
 
265
- return str(content)
266
-
267
- def main():
268
- with st.sidebar:
269
- st.header("🎨 VoiceCanvas")
270
- st.markdown("*AI Content Studio*")
271
-
272
- # Status section
273
- st.subheader("πŸ“Š System Status")
274
-
275
- gemini_available = setup_gemini()
276
-
277
- col1, col2 = st.columns(2)
278
-
279
- with col1:
280
- st.metric("Mode", "Enhanced" if gemini_available else "Basic")
281
- with col2:
282
- st.metric("Model", "Gemini" if gemini_available else "HF")
283
- # Component status
284
- st.write("πŸ€– **Components:**")
285
- st.write(f"β€’ Speech Recognition: {'βœ…' if TRANSFORMERS_AVAILABLE else '❌'}")
286
- st.write(f"β€’ Audio Recording: {'βœ…' if AUDIO_REC_AVAILABLE else '❌'}")
287
- st.write(f"β€’ Enhanced AI: {'βœ…' if gemini_available else '❌'}")
288
-
289
- # Current task indicator
290
- if st.session_state.current_task:
291
- st.info(f"πŸ”„ {st.session_state.current_task}")
292
 
293
- st.markdown("---")
294
 
295
- # Tips and help
296
- st.subheader("πŸ’‘ How to Use")
297
-
298
- with st.expander("πŸš€ Quick Start", expanded=True):
299
- st.markdown("""
300
- 1. **Input**: Use voice, upload audio, or type text
301
- 2. **Edit**: Review and refine your input
302
- 3. **Generate**: Create marketing content
303
- 4. **Export**: Download your materials
304
- """)
305
-
306
- with st.expander("🎯 Best Practices"):
307
- st.markdown("""
308
- **For Voice/Audio:**
309
- - Speak clearly at normal pace
310
- - Use quiet environment
311
- - Describe your product/service
312
- - Mention target audience
313
 
314
- **For Text:**
315
- - Be specific about features
316
- - Include benefits and use cases
317
- - Mention what makes it unique
318
- - Use 50+ words for detail
319
- """)
320
-
321
- with st.expander("βš™οΈ Setup (Optional)"):
322
- st.markdown("""
323
- **Enhanced Features:**
 
 
324
 
325
- Add environment variables:
326
- - `GEMINI_API_KEY`: Advanced text generation
327
- - `HF_TOKEN`: AI image generation
 
 
 
 
 
 
 
 
 
328
 
329
- **Get API Keys:**
330
- - [Google AI Studio](https://makersuite.google.com/app/apikey) (Free)
331
- - [Hugging Face](https://huggingface.co/settings/tokens) (Free)
332
- """)
 
 
 
 
 
 
 
333
 
334
- with st.expander("πŸ› οΈ Troubleshooting"):
335
- st.markdown("""
336
- **Common Issues:**
337
- - Audio not recording β†’ Try different browser
338
- - Slow processing β†’ Models loading for first time
339
- - No image generation β†’ Add HF_TOKEN
340
- - Basic content only β†’ Add GEMINI_API_KEY
341
- """)
342
-
343
- # Main content
344
- st.title("🎨 VoiceCanvas - AI Content Studio")
345
- st.markdown("*Transform your ideas into comprehensive marketing content*")
346
-
347
- # Main input area
348
- st.header("πŸ’‘ Share Your Idea")
349
-
350
- # Dynamic tabs based on available features
351
- available_tabs = []
352
- if AUDIO_REC_AVAILABLE:
353
- available_tabs.append("πŸŽ™οΈ Record")
354
- available_tabs.extend(["πŸ“ Upload", "✍️ Type"])
355
-
356
- tabs = st.tabs(available_tabs)
357
- tab_index = 0
358
-
359
- # Recording tab (if available)
360
- if AUDIO_REC_AVAILABLE:
361
- with tabs[tab_index]:
362
- st.info("🎀 Click the microphone button to start recording")
363
-
364
- # Audio recorder
365
- wav_audio_data = st_audiorec()
366
-
367
- if wav_audio_data is not None:
368
- st.success("πŸŽ‰ Audio recorded successfully!")
369
- st.audio(wav_audio_data, format='audio/wav')
370
 
371
- col1, col2 = st.columns([1, 2])
372
- with col1:
373
- if st.button("πŸ”„ Transcribe Audio", key="transcribe_btn", type="primary"):
374
- if not st.session_state.models_loaded:
375
- if load_models():
376
- st.session_state.processing = True
377
- st.rerun()
378
- else:
379
- st.session_state.processing = True
380
- st.rerun()
381
 
382
- with col2:
383
- if st.session_state.processing:
384
- st.info("πŸ”„ Processing your audio...")
385
- tab_index += 1
386
-
387
- # Upload tab
388
- with tabs[tab_index]:
389
- st.info("πŸ“ Upload an audio file containing your idea")
 
 
 
 
 
390
 
391
- uploaded_file = st.file_uploader(
392
- "Choose audio file",
393
- type=['wav', 'mp3', 'm4a'],
394
- help="Supported: WAV, MP3, M4A β€’ Max 10MB β€’ Best: 30 seconds or less"
395
- )
396
 
397
- if uploaded_file:
398
- st.success("πŸ“„ File uploaded successfully!")
399
- st.audio(uploaded_file)
400
 
401
- col1, col2 = st.columns([1, 2])
402
  with col1:
403
- if st.button("πŸ”„ Process Audio", key="upload_transcribe", type="primary"):
404
- if not st.session_state.models_loaded:
405
- if load_models():
406
- st.session_state.processing = True
407
- st.rerun()
408
- else:
409
- st.session_state.processing = True
410
- st.rerun()
411
 
412
  with col2:
413
- if st.session_state.processing:
414
- st.info("πŸ”„ Converting speech to text...")
415
-
416
- tab_index += 1
417
-
418
- # Text tab
419
- with tabs[tab_index]:
420
- st.info("✍️ Type or paste your product/service description")
421
-
422
- user_input = st.text_area(
423
- "Describe your idea:",
424
- 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.",
425
- height=150,
426
- help="Be detailed! Include features, benefits, and target audience for best results."
427
- )
428
-
429
- if user_input:
430
- st.session_state.transcription = user_input
431
- word_count = len(user_input.split())
432
-
433
- if word_count < 10:
434
- st.warning("πŸ’‘ Add more details for better results (at least 10 words)")
435
- elif word_count < 30:
436
- st.info("πŸ“ Good start! Add more features/benefits for richer content")
437
- else:
438
- st.success(f"βœ… Great detail! ({word_count} words)")
439
-
440
- # Process audio transcription
441
- if st.session_state.processing:
442
- if AUDIO_REC_AVAILABLE and 'wav_audio_data' in locals() and wav_audio_data is not None:
443
- # Process recorded audio
444
- with st.spinner("🎯 Converting your speech to text..."):
445
- with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file:
446
- tmp_file.write(wav_audio_data)
447
- transcription = transcribe_audio_simple(tmp_file.name)
448
- st.session_state.transcription = transcription
449
- os.unlink(tmp_file.name)
450
-
451
- st.session_state.processing = False
452
- st.rerun()
453
 
454
- elif 'uploaded_file' in locals() and uploaded_file is not None:
455
- # Process uploaded file
456
- with st.spinner("🎯 Processing your audio file..."):
457
- if TRANSFORMERS_AVAILABLE:
458
- transcription = transcribe_audio_simple(uploaded_file)
459
- st.session_state.transcription = transcription
460
- else:
461
- st.session_state.transcription = "Speech-to-text not available. Please use text input."
462
-
463
- st.session_state.processing = False
464
- st.rerun()
465
-
466
- # Show transcription and editing
467
- if st.session_state.transcription:
468
- st.markdown("---")
469
- st.header("πŸ“ Review Your Input")
470
-
471
- edited_text = st.text_area(
472
- "Edit or refine your input:",
473
- value=st.session_state.transcription,
474
- height=120,
475
- key="edit_transcription",
476
- help="Make any corrections or add more details"
477
- )
478
- st.session_state.transcription = edited_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
 
480
- # Generate content section
481
- st.markdown("---")
482
- col1, col2, col3 = st.columns([1, 2, 1])
483
 
484
- with col2:
485
- if st.button("πŸš€ Generate Marketing Content", type="primary", use_container_width=True):
486
- with st.spinner("✨ Creating comprehensive marketing content..."):
487
- if gemini_available:
488
- content_text = generate_content_with_gemini(st.session_state.transcription)
489
- st.session_state.generated_content['text'] = content_text
490
- else:
491
- content_text = generate_content_offline(st.session_state.transcription)
492
- st.session_state.generated_content['text'] = content_text
493
- st.success("βœ… Content generated successfully!")
494
- st.rerun()
495
 
496
- # Display generated content
497
- if st.session_state.generated_content:
498
- st.markdown("---")
499
- st.header("✨ Your Marketing Content")
500
-
501
- # Text content
502
- if 'text' in st.session_state.generated_content:
503
- st.markdown(st.session_state.generated_content['text'])
504
-
505
- # Image generation section
506
- st.markdown("---")
507
- st.subheader("🎨 Visual Content")
508
 
509
- col1, col2 = st.columns([2, 1])
510
-
511
- with col1:
512
- if 'structured' in st.session_state.generated_content:
513
- # Show pre-made prompts
514
- prompts = st.session_state.generated_content['structured'].get('image_prompts', [])
515
- if prompts:
516
- selected_prompt = st.selectbox(
517
- "Choose image style:",
518
- prompts,
519
- help="Select from AI-generated image prompts"
520
- )
521
- else:
522
- # Custom prompt input
523
- selected_prompt = st.text_input(
524
- "Describe the image you want:",
525
- placeholder="Professional product photo with clean white background",
526
- help="Be specific about style, colors, composition"
527
- )
528
-
529
- with col2:
530
- st.write("") # Spacing
531
- st.write("") # Spacing
532
 
533
- if st.button("πŸ–ΌοΈ Generate Image", use_container_width=True):
534
- if selected_prompt:
535
- img = generate_image_with_api(selected_prompt)
536
- if img:
537
- st.session_state.generated_content['image'] = img
538
- st.success("🎨 Image created!")
539
- st.rerun()
 
 
 
 
 
540
  else:
541
- st.error("Image generation failed. Check HF_TOKEN.")
542
  else:
543
- st.warning("Please enter/select an image description")
544
-
545
- # Display generated image
546
- if 'image' in st.session_state.generated_content:
547
- st.image(
548
- st.session_state.generated_content['image'],
549
- caption="AI Generated Image",
550
- use_column_width=True
551
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
552
 
553
- # Export section
554
- st.markdown("---")
555
- st.header("πŸ“₯ Export Your Content")
556
 
557
- col1, col2, col3 = st.columns(3)
 
 
 
 
558
 
559
- with col1:
560
- # Text export
561
- if 'text' in st.session_state.generated_content:
562
- content_export = f"""VOICECANVAS MARKETING CONTENT
 
 
 
 
 
 
 
563
  Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
564
- Source: {st.session_state.transcription[:100]}...
565
 
566
- {st.session_state.generated_content['text']}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
 
568
- ---
569
- Created with VoiceCanvas AI Content Studio
 
 
 
 
 
 
 
 
 
 
 
570
  """
 
 
 
 
 
 
 
571
 
572
- st.download_button(
573
- "πŸ“„ Download Text",
574
- content_export,
575
- file_name=f"marketing_content_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
576
- mime="text/plain",
577
- use_container_width=True,
578
- help="Download complete text content"
579
- )
580
-
581
- with col2:
582
- # JSON export
583
- if 'structured' in st.session_state.generated_content:
584
- json_data = {
585
- "metadata": {
586
- "timestamp": datetime.now().isoformat(),
587
- "generator": "VoiceCanvas AI Studio",
588
- "mode": "Enhanced" if gemini_available else "Basic"
589
- },
590
- "input": st.session_state.transcription,
591
- "content": st.session_state.generated_content['structured']
592
- }
593
 
594
- st.download_button(
595
- "πŸ“Š Download Data",
596
- json.dumps(json_data, indent=2),
597
- file_name=f"content_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
598
- mime="application/json",
599
- use_container_width=True,
600
- help="Download structured data (JSON)"
601
- )
602
-
603
- with col3:
604
- # Image export
605
- if 'image' in st.session_state.generated_content:
606
- img_buffer = io.BytesIO()
607
- st.session_state.generated_content['image'].save(img_buffer, format="PNG")
608
 
609
- st.download_button(
610
- "πŸ–ΌοΈ Download Image",
611
- img_buffer.getvalue(),
612
- file_name=f"ai_image_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png",
613
- mime="image/png",
614
- use_container_width=True,
615
- help="Download generated image"
616
- )
617
- else:
618
- st.info("Generate an image first", icon="ℹ️")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
619
 
620
  # Footer
621
  st.markdown("---")
622
- col1, col2, col3 = st.columns([1, 2, 1])
623
- with col2:
624
- st.markdown("🎨 **VoiceCanvas AI Content Studio**")
625
- st.caption("Transform ideas into marketing magic β€’ Built with Streamlit")
 
 
626
 
627
  if __name__ == "__main__":
628
  main()
 
2
  import torch
3
  import numpy as np
4
  import io
5
+ import base64
6
  import os
7
  import tempfile
8
  from PIL import Image
 
10
  import json
11
  from datetime import datetime
12
  import time
13
+ import threading
14
+ import asyncio
15
 
16
+ # Hugging Face imports
17
+ from transformers import (
18
+ pipeline,
19
+ WhisperProcessor,
20
+ WhisperForConditionalGeneration,
21
+ AutoTokenizer,
22
+ AutoModelForCausalLM
23
+ )
24
+ from diffusers import StableDiffusionPipeline
25
+ import torchaudio
26
+ from scipy.io import wavfile
27
+ import google.generativeai as genai
28
+ from st_audiorec import st_audiorec
 
 
 
 
 
29
 
30
  # Configure page
31
  st.set_page_config(
32
  page_title="VoiceCanvas - AI Content Studio",
33
  page_icon="🎨",
34
  layout="wide",
35
+ initial_sidebar_state="collapsed"
36
  )
37
 
38
+ # Custom CSS for better UI
39
+ st.markdown("""
40
+ <style>
41
+ .stApp {
42
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
43
+ }
44
+ .main-header {
45
+ text-align: center;
46
+ color: white;
47
+ padding: 1rem;
48
+ margin-bottom: 2rem;
49
+ background: rgba(255,255,255,0.1);
50
+ border-radius: 10px;
51
+ backdrop-filter: blur(10px);
52
+ }
53
+ .feature-box {
54
+ background: rgba(255,255,255,0.95);
55
+ padding: 1.5rem;
56
+ border-radius: 15px;
57
+ margin: 1rem 0;
58
+ box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
59
+ border: 1px solid rgba(255, 255, 255, 0.18);
60
+ }
61
+ .success-box {
62
+ background: linear-gradient(90deg, #00C9FF 0%, #92FE9D 100%);
63
+ padding: 1rem;
64
+ border-radius: 10px;
65
+ color: white;
66
+ font-weight: bold;
67
+ text-align: center;
68
+ margin: 1rem 0;
69
+ }
70
+ .stButton > button {
71
+ width: 100%;
72
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
73
+ color: white;
74
+ border: none;
75
+ padding: 0.5rem 1rem;
76
+ border-radius: 25px;
77
+ font-weight: bold;
78
+ transition: all 0.3s ease;
79
+ }
80
+ .stButton > button:hover {
81
+ transform: translateY(-2px);
82
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2);
83
+ }
84
+ </style>
85
+ """, unsafe_allow_html=True)
86
 
87
+ # Initialize session state with better management
88
+ def init_session_state():
89
+ defaults = {
90
+ 'generated_images': [],
91
+ 'generated_text': [],
92
+ 'transcription': "",
93
+ 'selected_image': None,
94
+ 'audio_file': None,
95
+ 'models_loaded': False,
96
+ 'whisper_ready': False,
97
+ 'sd_ready': False,
98
+ 'tts_ready': False,
99
+ 'processing': False,
100
+ 'show_advanced_text': False,
101
+ 'text_analysis': {},
102
+ 'content_variations': [],
103
+ 'seo_keywords': [],
104
+ 'social_posts': []
105
+ }
106
 
107
+ for key, value in defaults.items():
108
+ if key not in st.session_state:
109
+ st.session_state[key] = value
110
+
111
+ # Lightweight model loading with progress tracking
112
+ @st.cache_resource(show_spinner=False)
113
+ def load_models_lightweight():
114
+ """Load only essential models quickly"""
115
+ models = {
116
+ 'whisper': None,
117
+ 'whisper_processor': None,
118
+ 'text_generator': None,
119
+ 'gemini_ready': False
120
+ }
121
 
122
+ try:
123
+ # Setup Gemini (fastest)
124
+ api_key = os.getenv("GEMINI_API_KEY")
125
+ if api_key:
126
+ genai.configure(api_key=api_key)
127
+ models['gemini_ready'] = True
128
+ except:
129
+ pass
130
 
131
  try:
132
+ # Light text generator for fallback
133
+ models['text_generator'] = pipeline(
134
+ "text-generation",
135
+ model="gpt2", # Much smaller and faster
136
+ max_length=100,
137
+ do_sample=True,
138
+ temperature=0.8,
139
+ pad_token_id=50256
 
140
  )
141
+ except:
142
+ pass
143
+
144
+ return models
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ @st.cache_resource(show_spinner=False)
147
+ def load_whisper_lazy():
148
+ """Load Whisper only when needed"""
 
 
149
  try:
150
+ processor = WhisperProcessor.from_pretrained("openai/whisper-tiny")
151
+ model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-tiny")
152
+ return processor, model
 
 
 
 
 
153
  except Exception as e:
154
+ st.error(f"Whisper loading failed: {e}")
155
+ return None, None
156
 
157
+ @st.cache_resource(show_spinner=False)
158
+ def load_sd_lazy():
159
+ """Load Stable Diffusion only when needed"""
160
  try:
161
+ pipe = StableDiffusionPipeline.from_pretrained(
162
+ "runwayml/stable-diffusion-v1-5", # Smaller model
163
+ torch_dtype=torch.float32,
164
+ safety_checker=None,
165
+ requires_safety_checker=False,
166
+ use_safetensors=True
167
+ )
168
+ pipe.enable_attention_slicing()
169
+ pipe.enable_model_cpu_offload()
170
+ return pipe
 
171
  except Exception as e:
172
+ st.error(f"SD loading failed: {e}")
173
+ return None
174
 
175
+ def quick_transcribe(audio_data):
176
+ """Quick transcription without heavy models"""
 
 
 
177
  try:
178
+ # Simulate quick processing
179
+ if len(audio_data) > 0:
180
+ return "Quick transcription ready - click 'Enhance Transcription' for better accuracy"
181
+ except:
182
+ pass
183
+ return "Audio processed - ready for transcription"
184
+
185
+ def enhanced_text_analysis(text):
186
+ """Generate comprehensive text analysis and variations"""
187
+ try:
188
+ if st.session_state.get('models', {}).get('gemini_ready'):
189
+ model = genai.GenerativeModel('gemini-pro')
190
+
191
+ analysis_prompt = f"""
192
+ Analyze this content: "{text}"
193
+
194
+ Provide a comprehensive analysis in this exact JSON format:
195
+ {{
196
+ "summary": "Brief summary",
197
+ "tone": "Professional/Casual/Creative/etc",
198
+ "target_audience": "Primary audience",
199
+ "key_themes": ["theme1", "theme2", "theme3"],
200
+ "seo_keywords": ["keyword1", "keyword2", "keyword3", "keyword4", "keyword5"],
201
+ "hashtags": ["#tag1", "#tag2", "#tag3", "#tag4", "#tag5"],
202
+ "content_variations": {{
203
+ "headlines": ["Headline 1", "Headline 2", "Headline 3"],
204
+ "taglines": ["Tagline 1", "Tagline 2", "Tagline 3"],
205
+ "descriptions": ["Description 1", "Description 2", "Description 3"]
206
+ }},
207
+ "social_posts": {{
208
+ "twitter": ["Tweet 1", "Tweet 2"],
209
+ "linkedin": ["LinkedIn post 1", "LinkedIn post 2"],
210
+ "instagram": ["Insta caption 1", "Insta caption 2"]
211
+ }},
212
+ "image_prompts": ["Detailed prompt 1", "Detailed prompt 2", "Detailed prompt 3"]
213
+ }}
214
+ """
215
+
216
+ response = model.generate_content(analysis_prompt)
217
+ try:
218
+ return json.loads(response.text)
219
+ except:
220
+ # Fallback parsing
221
+ return parse_analysis_fallback(text)
222
+ else:
223
+ return generate_quick_analysis(text)
224
+
225
  except Exception as e:
226
+ st.error(f"Analysis error: {e}")
227
+ return generate_quick_analysis(text)
 
228
 
229
+ def parse_analysis_fallback(text):
230
+ """Fallback analysis when JSON parsing fails"""
231
+ return {
232
+ "summary": f"Content about {text[:50]}...",
233
+ "tone": "Professional",
234
+ "target_audience": "General audience",
235
+ "key_themes": ["Innovation", "Creativity", "Technology"],
236
+ "seo_keywords": [f"{text.split()[0] if text.split() else 'content'}", "creative", "innovative", "digital", "solution"],
237
+ "hashtags": ["#creative", "#innovation", "#digital", "#content", "#marketing"],
238
+ "content_variations": {
239
+ "headlines": [
240
+ f"Discover {text[:30]}...",
241
+ f"Revolutionary {text[:30]}...",
242
+ f"Experience {text[:30]}..."
243
+ ],
244
+ "taglines": [
245
+ f"Transforming {text[:20]}...",
246
+ f"Innovation in {text[:20]}...",
247
+ f"The future of {text[:20]}..."
248
+ ],
249
+ "descriptions": [
250
+ f"Comprehensive solution for {text[:40]}...",
251
+ f"Advanced approach to {text[:40]}...",
252
+ f"Next-generation {text[:40]}..."
253
+ ]
254
+ },
255
+ "social_posts": {
256
+ "twitter": [
257
+ f"πŸš€ Excited to share: {text[:100]}... #innovation",
258
+ f"πŸ’‘ Game-changer: {text[:100]}... #creative"
259
+ ],
260
+ "linkedin": [
261
+ f"Professional insight: {text[:150]}...",
262
+ f"Industry perspective: {text[:150]}..."
263
+ ],
264
+ "instagram": [
265
+ f"✨ {text[:100]}... #creative #innovation",
266
+ f"🎨 {text[:100]}... #design #digital"
267
+ ]
268
+ },
269
+ "image_prompts": [
270
+ f"Professional illustration of {text[:50]}, modern design, high quality",
271
+ f"Creative visualization of {text[:50]}, vibrant colors, artistic style",
272
+ f"Digital artwork representing {text[:50]}, futuristic, detailed"
273
+ ]
274
+ }
275
+
276
+ def generate_quick_analysis(text):
277
+ """Quick analysis without API calls"""
278
+ words = text.split()[:5]
279
+ base_word = words[0] if words else "content"
280
 
281
+ return {
282
+ "summary": f"Creative content focusing on {base_word} and related concepts",
283
+ "tone": "Creative",
284
+ "target_audience": "Creative professionals and enthusiasts",
285
+ "key_themes": [base_word.title(), "Creativity", "Innovation"],
286
+ "seo_keywords": [base_word, "creative", "design", "innovative", "digital"],
287
+ "hashtags": [f"#{base_word.lower()}", "#creative", "#design", "#innovation", "#digital"],
288
+ "content_variations": {
289
+ "headlines": [
290
+ f"Unlock the Power of {base_word.title()}",
291
+ f"Revolutionary {base_word.title()} Solutions",
292
+ f"The Future of {base_word.title()}"
293
+ ],
294
+ "taglines": [
295
+ f"Where {base_word.title()} Meets Innovation",
296
+ f"Redefining {base_word.title()} Excellence",
297
+ f"Your {base_word.title()} Journey Starts Here"
298
+ ],
299
+ "descriptions": [
300
+ f"Comprehensive {base_word} solutions designed for modern needs",
301
+ f"Innovative {base_word} services that transform your vision",
302
+ f"Professional {base_word} expertise for exceptional results"
303
+ ]
304
+ },
305
+ "social_posts": {
306
+ "twitter": [
307
+ f"πŸš€ Exciting {base_word} developments ahead! #innovation #creative",
308
+ f"πŸ’‘ {base_word.title()} insights that matter #digital #future"
309
+ ],
310
+ "linkedin": [
311
+ f"Professional {base_word} strategies for business growth and innovation in today's market",
312
+ f"Industry expertise in {base_word} solutions that drive meaningful results"
313
+ ],
314
+ "instagram": [
315
+ f"✨ Beautiful {base_word} creations ✨ #creative #design #inspiration",
316
+ f"🎨 {base_word.title()} magic in progress 🎨 #artistic #innovation"
317
+ ]
318
+ },
319
  "image_prompts": [
320
+ f"Modern professional illustration of {base_word}, clean design, corporate style",
321
+ f"Creative artistic representation of {base_word}, vibrant colors, dynamic composition",
322
+ f"Futuristic visualization of {base_word}, digital art, high-tech aesthetic"
323
  ]
324
  }
325
+
326
+ def main():
327
+ init_session_state()
328
 
329
+ # Header
330
+ st.markdown("""
331
+ <div class="main-header">
332
+ <h1>🎨 VoiceCanvas - AI Content Studio</h1>
333
+ <p>Transform ideas into professional content instantly</p>
334
+ </div>
335
+ """, unsafe_allow_html=True)
336
 
337
+ # Quick loading of essential models
338
+ if not st.session_state.models_loaded:
339
+ with st.spinner("⚑ Loading AI models..."):
340
+ st.session_state.models = load_models_lightweight()
341
+ st.session_state.models_loaded = True
342
+
343
+ # Show model status
344
+ col1, col2, col3, col4 = st.columns(4)
345
+ with col1:
346
+ st.success("πŸ€– Core AI: Ready")
347
+ with col2:
348
+ st.info("🎀 Audio: On-demand")
349
+ with col3:
350
+ st.info("🎨 Images: On-demand")
351
+ with col4:
352
+ gemini_status = "βœ… Active" if st.session_state.models.get('gemini_ready') else "⚠️ Fallback"
353
+ st.success(f"🧠 Smart AI: {gemini_status}")
354
 
355
+ # Main interface with tabs
356
+ tab1, tab2, tab3, tab4 = st.tabs(["🎀 Voice Input", "✍️ Text Studio", "🎨 Visual Creator", "πŸ“¦ Export Hub"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
358
+ with tab1:
359
+ st.markdown('<div class="feature-box">', unsafe_allow_html=True)
360
+ st.subheader("πŸŽ™οΈ Audio Processing")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
 
362
+ col1, col2 = st.columns([1, 1])
363
 
364
+ with col1:
365
+ # Audio input methods
366
+ input_method = st.selectbox(
367
+ "Input Method:",
368
+ ["πŸŽ™οΈ Record Live", "πŸ“ Upload File", "⌨️ Type Direct"],
369
+ key="input_method"
370
+ )
 
 
 
 
 
 
 
 
 
 
 
371
 
372
+ if input_method == "πŸŽ™οΈ Record Live":
373
+ st.info("🎀 Click record button:")
374
+ wav_data = st_audiorec()
375
+
376
+ if wav_data is not None:
377
+ st.success("πŸŽ‰ Recorded!")
378
+ st.audio(wav_data)
379
+
380
+ # Quick preview
381
+ if st.button("⚑ Quick Process"):
382
+ st.session_state.transcription = "Audio recorded - processing..."
383
+ st.rerun()
384
 
385
+ elif input_method == "πŸ“ Upload File":
386
+ uploaded_file = st.file_uploader(
387
+ "Choose audio file:",
388
+ type=['wav', 'mp3', 'm4a'],
389
+ key="audio_upload"
390
+ )
391
+
392
+ if uploaded_file:
393
+ st.audio(uploaded_file)
394
+ if st.button("⚑ Process Audio"):
395
+ st.session_state.transcription = f"Processing {uploaded_file.name}..."
396
+ st.rerun()
397
 
398
+ else: # Type Direct
399
+ text_input = st.text_area(
400
+ "Enter your content:",
401
+ placeholder="Type your creative prompt here...",
402
+ height=150,
403
+ key="direct_text_input"
404
+ )
405
+
406
+ if text_input and st.button("✨ Process Text"):
407
+ st.session_state.transcription = text_input
408
+ st.rerun()
409
 
410
+ with col2:
411
+ if st.session_state.transcription:
412
+ st.subheader("πŸ“ Current Content")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
 
414
+ # Editable transcription
415
+ edited_text = st.text_area(
416
+ "Edit content:",
417
+ value=st.session_state.transcription,
418
+ height=150,
419
+ key="edit_transcription"
420
+ )
 
 
 
421
 
422
+ if st.button("πŸ”„ Update Content"):
423
+ st.session_state.transcription = edited_text
424
+ st.success("Content updated!")
425
+
426
+ # Enhanced transcription for audio
427
+ if "processing" in st.session_state.transcription.lower():
428
+ if st.button("🎯 Enhanced Transcription"):
429
+ with st.spinner("Loading Whisper..."):
430
+ processor, model = load_whisper_lazy()
431
+ if processor and model:
432
+ st.session_state.transcription = "Enhanced transcription with Whisper model"
433
+ st.success("Enhanced transcription ready!")
434
+ st.rerun()
435
 
436
+ st.markdown('</div>', unsafe_allow_html=True)
437
+
438
+ with tab2:
439
+ st.markdown('<div class="feature-box">', unsafe_allow_html=True)
440
+ st.subheader("πŸ“Š Advanced Text Analysis")
441
 
442
+ if st.session_state.transcription:
443
+ col1, col2 = st.columns([1, 1])
 
444
 
 
445
  with col1:
446
+ if st.button("πŸ” Analyze Content", type="primary"):
447
+ with st.spinner("🧠 Analyzing content..."):
448
+ analysis = enhanced_text_analysis(st.session_state.transcription)
449
+ st.session_state.text_analysis = analysis
450
+ st.success("Analysis complete!")
 
 
 
451
 
452
  with col2:
453
+ st.toggle("Show Advanced Options", key="show_advanced_text")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
 
455
+ # Display analysis results
456
+ if st.session_state.text_analysis:
457
+ analysis = st.session_state.text_analysis
458
+
459
+ # Summary and basics
460
+ col1, col2, col3 = st.columns(3)
461
+ with col1:
462
+ st.metric("Tone", analysis.get('tone', 'N/A'))
463
+ with col2:
464
+ st.metric("Audience", analysis.get('target_audience', 'N/A')[:15] + "...")
465
+ with col3:
466
+ st.metric("Themes", f"{len(analysis.get('key_themes', []))} detected")
467
+
468
+ # Content variations
469
+ st.subheader("πŸ“ Content Variations")
470
+
471
+ var_col1, var_col2, var_col3 = st.columns(3)
472
+
473
+ with var_col1:
474
+ st.write("**🏷️ Headlines:**")
475
+ for i, headline in enumerate(analysis.get('content_variations', {}).get('headlines', []), 1):
476
+ st.write(f"{i}. {headline}")
477
+
478
+ with var_col2:
479
+ st.write("**✨ Taglines:**")
480
+ for i, tagline in enumerate(analysis.get('content_variations', {}).get('taglines', []), 1):
481
+ st.write(f"{i}. {tagline}")
482
+
483
+ with var_col3:
484
+ st.write("**πŸ“– Descriptions:**")
485
+ for i, desc in enumerate(analysis.get('content_variations', {}).get('descriptions', []), 1):
486
+ st.write(f"{i}. {desc[:50]}...")
487
+
488
+ # SEO and Social
489
+ if st.session_state.show_advanced_text:
490
+ col1, col2 = st.columns(2)
491
+
492
+ with col1:
493
+ st.subheader("πŸ” SEO Keywords")
494
+ keywords = analysis.get('seo_keywords', [])
495
+ st.write(" β€’ ".join([f"`{kw}`" for kw in keywords]))
496
+
497
+ st.subheader("🏷️ Hashtags")
498
+ hashtags = analysis.get('hashtags', [])
499
+ st.write(" ".join(hashtags))
500
+
501
+ with col2:
502
+ st.subheader("πŸ“± Social Media Posts")
503
+
504
+ social_data = analysis.get('social_posts', {})
505
+
506
+ if st.button("🐦 Twitter"):
507
+ for tweet in social_data.get('twitter', []):
508
+ st.info(f"🐦 {tweet}")
509
+
510
+ if st.button("πŸ’Ό LinkedIn"):
511
+ for post in social_data.get('linkedin', []):
512
+ st.info(f"πŸ’Ό {post}")
513
+
514
+ if st.button("πŸ“Έ Instagram"):
515
+ for post in social_data.get('instagram', []):
516
+ st.info(f"πŸ“Έ {post}")
517
 
518
+ else:
519
+ st.info("πŸ‘ˆ Please add content in the Voice Input tab first")
 
520
 
521
+ st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
522
 
523
+ with tab3:
524
+ st.markdown('<div class="feature-box">', unsafe_allow_html=True)
525
+ st.subheader("🎨 Image Generation")
 
 
 
 
 
 
 
 
 
526
 
527
+ if st.session_state.transcription:
528
+ col1, col2 = st.columns([1, 2])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
 
530
+ with col1:
531
+ st.write("**Image Settings:**")
532
+
533
+ # Use analysis prompts if available
534
+ if st.session_state.text_analysis:
535
+ image_prompts = st.session_state.text_analysis.get('image_prompts', [])
536
+ selected_prompt = st.selectbox("Choose style:",
537
+ ["Custom"] + [f"Style {i+1}" for i in range(len(image_prompts))])
538
+
539
+ if selected_prompt != "Custom":
540
+ idx = int(selected_prompt.split()[-1]) - 1
541
+ base_prompt = image_prompts[idx]
542
  else:
543
+ base_prompt = f"Professional illustration of {st.session_state.transcription}"
544
  else:
545
+ base_prompt = f"High quality illustration of {st.session_state.transcription}"
546
+
547
+ # Prompt customization
548
+ final_prompt = st.text_area(
549
+ "Image prompt:",
550
+ value=base_prompt,
551
+ height=100
552
+ )
553
+
554
+ # Style modifiers
555
+ style = st.selectbox("Art Style:", [
556
+ "Professional", "Creative", "Minimalist",
557
+ "Vintage", "Modern", "Abstract", "Realistic"
558
+ ])
559
+
560
+ quality = st.selectbox("Quality:", ["Standard", "High", "Ultra"])
561
+
562
+ if st.button("🎨 Generate Images", type="primary"):
563
+ with st.spinner("🎨 Creating images..."):
564
+ # Load SD model when needed
565
+ pipe = load_sd_lazy()
566
+ if pipe:
567
+ try:
568
+ enhanced_prompt = f"{final_prompt}, {style.lower()} style, {quality.lower()} quality, detailed"
569
+
570
+ # Generate multiple images
571
+ images = []
572
+ for i in range(3):
573
+ st.write(f"Generating image {i+1}/3...")
574
+ result = pipe(
575
+ enhanced_prompt,
576
+ num_inference_steps=20,
577
+ guidance_scale=7.5,
578
+ height=512,
579
+ width=512
580
+ )
581
+ images.append(result.images[0])
582
+
583
+ st.session_state.generated_images = images
584
+ st.success("πŸŽ‰ Images generated!")
585
+ st.rerun()
586
+ except Exception as e:
587
+ st.error(f"Generation failed: {e}")
588
+ else:
589
+ st.error("Image model not available")
590
+
591
+ with col2:
592
+ if st.session_state.generated_images:
593
+ st.write("**Generated Images:**")
594
+
595
+ for i, img in enumerate(st.session_state.generated_images):
596
+ st.image(img, caption=f"Variation {i+1}", use_column_width=True)
597
+
598
+ col_a, col_b = st.columns(2)
599
+ with col_a:
600
+ if st.button(f"βœ… Select Image {i+1}", key=f"select_img_{i}"):
601
+ st.session_state.selected_image = img
602
+ st.success(f"Selected Image {i+1}")
603
+
604
+ with col_b:
605
+ # Quick download
606
+ img_buffer = io.BytesIO()
607
+ img.save(img_buffer, format="PNG")
608
+ st.download_button(
609
+ f"πŸ’Ύ Download {i+1}",
610
+ img_buffer.getvalue(),
611
+ file_name=f"image_{i+1}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png",
612
+ mime="image/png",
613
+ key=f"download_img_{i}"
614
+ )
615
+ else:
616
+ st.info("πŸ‘ˆ Configure settings and generate images")
617
 
618
+ else:
619
+ st.info("πŸ‘ˆ Please add content first")
 
620
 
621
+ st.markdown('</div>', unsafe_allow_html=True)
622
+
623
+ with tab4:
624
+ st.markdown('<div class="feature-box">', unsafe_allow_html=True)
625
+ st.subheader("πŸ“¦ Export & Download")
626
 
627
+ if st.session_state.transcription or st.session_state.generated_images:
628
+ export_col1, export_col2, export_col3 = st.columns(3)
629
+
630
+ with export_col1:
631
+ st.write("**πŸ“ Text Content**")
632
+
633
+ if st.session_state.text_analysis:
634
+ # Comprehensive text export
635
+ analysis = st.session_state.text_analysis
636
+
637
+ export_content = f"""VOICECANVAS CONTENT EXPORT
638
  Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
 
639
 
640
+ ORIGINAL CONTENT:
641
+ {st.session_state.transcription}
642
+
643
+ ANALYSIS:
644
+ β€’ Tone: {analysis.get('tone', 'N/A')}
645
+ β€’ Audience: {analysis.get('target_audience', 'N/A')}
646
+ β€’ Key Themes: {', '.join(analysis.get('key_themes', []))}
647
+
648
+ HEADLINES:
649
+ {chr(10).join([f"{i+1}. {h}" for i, h in enumerate(analysis.get('content_variations', {}).get('headlines', []))])}
650
+
651
+ TAGLINES:
652
+ {chr(10).join([f"{i+1}. {t}" for i, t in enumerate(analysis.get('content_variations', {}).get('taglines', []))])}
653
+
654
+ SEO KEYWORDS:
655
+ {', '.join(analysis.get('seo_keywords', []))}
656
 
657
+ HASHTAGS:
658
+ {' '.join(analysis.get('hashtags', []))}
659
+
660
+ SOCIAL MEDIA POSTS:
661
+
662
+ Twitter:
663
+ {chr(10).join([f"β€’ {t}" for t in analysis.get('social_posts', {}).get('twitter', [])])}
664
+
665
+ LinkedIn:
666
+ {chr(10).join([f"β€’ {l}" for l in analysis.get('social_posts', {}).get('linkedin', [])])}
667
+
668
+ Instagram:
669
+ {chr(10).join([f"β€’ {i}" for i in analysis.get('social_posts', {}).get('instagram', [])])}
670
  """
671
+
672
+ st.download_button(
673
+ "πŸ“„ Complete Text Package",
674
+ export_content,
675
+ file_name=f"voicecanvas_content_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
676
+ mime="text/plain"
677
+ )
678
 
679
+ elif st.session_state.transcription:
680
+ st.download_button(
681
+ "πŸ“„ Basic Text",
682
+ st.session_state.transcription,
683
+ file_name=f"content_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
684
+ mime="text/plain"
685
+ )
686
+
687
+ with export_col2:
688
+ st.write("**πŸ–ΌοΈ Visual Content**")
 
 
 
 
 
 
 
 
 
 
 
689
 
690
+ if st.session_state.selected_image:
691
+ st.image(st.session_state.selected_image, width=150)
692
+
693
+ img_buffer = io.BytesIO()
694
+ st.session_state.selected_image.save(img_buffer, format="PNG")
695
+
696
+ st.download_button(
697
+ "πŸ–ΌοΈ Selected Image",
698
+ img_buffer.getvalue(),
699
+ file_name=f"voicecanvas_image_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png",
700
+ mime="image/png"
701
+ )
 
 
702
 
703
+ elif st.session_state.generated_images:
704
+ st.info("πŸ‘† Select an image first")
705
+
706
+ else:
707
+ st.info("No images generated yet")
708
+
709
+ with export_col3:
710
+ st.write("**πŸ”Š Audio Content**")
711
+
712
+ if st.session_state.transcription:
713
+ if st.button("🎡 Generate Voice"):
714
+ st.info("πŸ”Š Voice generation coming soon!")
715
+ st.write("For now, download text content")
716
+
717
+ st.write("**πŸ“Š Analytics**")
718
+
719
+ if st.session_state.text_analysis:
720
+ st.metric("Content Items", len(st.session_state.text_analysis.get('content_variations', {}).get('headlines', [])))
721
+ st.metric("Keywords", len(st.session_state.text_analysis.get('seo_keywords', [])))
722
+ st.metric("Social Posts", len(st.session_state.text_analysis.get('social_posts', {}).get('twitter', [])))
723
+
724
+ # Complete package
725
+ if st.session_state.selected_image and st.session_state.text_analysis:
726
+ st.markdown('<div class="success-box">πŸŽ‰ Complete Package Ready for Download! πŸŽ‰</div>', unsafe_allow_html=True)
727
+
728
+ else:
729
+ st.info("Generate some content first to enable exports")
730
+
731
+ st.markdown('</div>', unsafe_allow_html=True)
732
 
733
  # Footer
734
  st.markdown("---")
735
+ st.markdown("""
736
+ <div style='text-align: center; color: white; padding: 1rem;'>
737
+ πŸš€ <b>VoiceCanvas</b> - Professional AI Content Creation |
738
+ Made with ❀️ using Streamlit & Hugging Face
739
+ </div>
740
+ """, unsafe_allow_html=True)
741
 
742
  if __name__ == "__main__":
743
  main()