maria355 commited on
Commit
4b37a3b
·
verified ·
1 Parent(s): 12e0416

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +546 -660
app.py CHANGED
@@ -2,7 +2,6 @@ import streamlit as st
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,734 +9,621 @@ import requests
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()
 
2
  import torch
3
  import numpy as np
4
  import io
 
5
  import os
6
  import tempfile
7
  from PIL import Image
 
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
+ # Sidebar with tips and status
269
+ with st.sidebar:
270
+ st.header("🎨 VoiceCanvas")
271
+ st.markdown("*AI Content Studio*")
272
+
273
+ # Status section
274
+ st.subheader("📊 System Status")
275
 
276
+ gemini_available = setup_gemini()
277
 
278
+ col1, col2 = st.columns(2)
279
  with col1:
280
+ st.metric("Mode", "Enhanced" if gemini_available else "Basic")
281
+ with col2:
282
+ st.metric("Status", "Ready" if not st.session_state.processing else "Working")
283
+
284
+ # Component status
285
+ st.write("🤖 **Components:**")
286
+ st.write(f"• Speech Recognition: {'✅' if TRANSFORMERS_AVAILABLE else '❌'}")
287
+ st.write(f"• Audio Recording: {'✅' if AUDIO_REC_AVAILABLE else '❌'}")
288
+ st.write(f"• Enhanced AI: {'✅' if gemini_available else '❌'}")
289
+
290
+ # Current task indicator
291
+ if st.session_state.current_task:
292
+ st.info(f"🔄 {st.session_state.current_task}")
293
+
294
+ st.markdown("---")
295
+
296
+ # Tips and help
297
+ st.subheader("💡 How to Use")
298
+
299
+ with st.expander("🚀 Quick Start", expanded=True):
300
+ st.markdown("""
301
+ 1. **Input**: Use voice, upload audio, or type text
302
+ 2. **Edit**: Review and refine your input
303
+ 3. **Generate**: Create marketing content
304
+ 4. **Export**: Download your materials
305
+ """)
306
+
307
+ with st.expander("🎯 Best Practices"):
308
+ st.markdown("""
309
+ **For Voice/Audio:**
310
+ - Speak clearly at normal pace
311
+ - Use quiet environment
312
+ - Describe your product/service
313
+ - Mention target audience
314
 
315
+ **For Text:**
316
+ - Be specific about features
317
+ - Include benefits and use cases
318
+ - Mention what makes it unique
319
+ - Use 50+ words for detail
320
+ """)
321
+
322
+ with st.expander("⚙️ Setup (Optional)"):
323
+ st.markdown("""
324
+ **Enhanced Features:**
 
 
325
 
326
+ Add environment variables:
327
+ - `GEMINI_API_KEY`: Advanced text generation
328
+ - `HF_TOKEN`: AI image generation
 
 
 
 
 
 
 
 
 
329
 
330
+ **Get API Keys:**
331
+ - [Google AI Studio](https://makersuite.google.com/app/apikey) (Free)
332
+ - [Hugging Face](https://huggingface.co/settings/tokens) (Free)
333
+ """)
 
 
 
 
 
 
 
334
 
335
+ with st.expander("🛠️ Troubleshooting"):
336
+ st.markdown("""
337
+ **Common Issues:**
338
+ - Audio not recording → Try different browser
339
+ - Slow processing → Models loading for first time
340
+ - No image generation → Add HF_TOKEN
341
+ - Basic content only → Add GEMINI_API_KEY
342
+ """)
343
+
344
+ # Main content
345
+ st.title("🎨 VoiceCanvas - AI Content Studio")
346
+ st.markdown("*Transform your ideas into comprehensive marketing content*")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
 
348
+ # Main input area
349
+ st.header("💡 Share Your Idea")
350
+
351
+ # Dynamic tabs based on available features
352
+ available_tabs = []
353
+ if AUDIO_REC_AVAILABLE:
354
+ available_tabs.append("🎙️ Record")
355
+ available_tabs.extend(["📁 Upload", "✍️ Type"])
356
+
357
+ tabs = st.tabs(available_tabs)
358
+ tab_index = 0
359
+
360
+ # Recording tab (if available)
361
+ if AUDIO_REC_AVAILABLE:
362
+ with tabs[tab_index]:
363
+ st.info("🎤 Click the microphone button to start recording")
364
 
365
+ # Audio recorder
366
+ wav_audio_data = st_audiorec()
367
 
368
+ if wav_audio_data is not None:
369
+ st.success("🎉 Audio recorded successfully!")
370
+ st.audio(wav_audio_data, format='audio/wav')
371
 
372
+ col1, col2 = st.columns([1, 2])
 
373
  with col1:
374
+ if st.button("🔄 Transcribe Audio", key="transcribe_btn", type="primary"):
375
+ if not st.session_state.models_loaded:
376
+ if load_models():
377
+ st.session_state.processing = True
378
+ st.rerun()
379
+ else:
380
+ st.session_state.processing = True
381
+ st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
+ with col2:
384
+ if st.session_state.processing:
385
+ st.info("🔄 Processing your audio...")
386
+ tab_index += 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
 
388
+ # Upload tab
389
+ with tabs[tab_index]:
390
+ st.info("📁 Upload an audio file containing your idea")
391
 
392
+ uploaded_file = st.file_uploader(
393
+ "Choose audio file",
394
+ type=['wav', 'mp3', 'm4a'],
395
+ help="Supported: WAV, MP3, M4A • Max 10MB • Best: 30 seconds or less"
396
+ )
397
+
398
+ if uploaded_file:
399
+ st.success("📄 File uploaded successfully!")
400
+ st.audio(uploaded_file)
401
 
402
+ col1, col2 = st.columns([1, 2])
403
  with col1:
404
+ if st.button("🔄 Process Audio", key="upload_transcribe", type="primary"):
405
+ if not st.session_state.models_loaded:
406
+ if load_models():
407
+ st.session_state.processing = True
408
+ st.rerun()
 
 
 
 
 
 
409
  else:
410
+ st.session_state.processing = True
411
+ st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
 
413
  with col2:
414
+ if st.session_state.processing:
415
+ st.info("🔄 Converting speech to text...")
416
+
417
+ tab_index += 1
418
+
419
+ # Text tab
420
+ with tabs[tab_index]:
421
+ st.info("✍️ Type or paste your product/service description")
422
+
423
+ user_input = st.text_area(
424
+ "Describe your idea:",
425
+ 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.",
426
+ height=150,
427
+ help="Be detailed! Include features, benefits, and target audience for best results."
428
+ )
429
+
430
+ if user_input:
431
+ st.session_state.transcription = user_input
432
+ word_count = len(user_input.split())
433
+
434
+ if word_count < 10:
435
+ st.warning("💡 Add more details for better results (at least 10 words)")
436
+ elif word_count < 30:
437
+ st.info("📝 Good start! Add more features/benefits for richer content")
438
+ else:
439
+ st.success(f"✅ Great detail! ({word_count} words)")
440
+
441
+ # Process audio transcription
442
+ if st.session_state.processing:
443
+ if AUDIO_REC_AVAILABLE and 'wav_audio_data' in locals() and wav_audio_data is not None:
444
+ # Process recorded audio
445
+ with st.spinner("🎯 Converting your speech to text..."):
446
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file:
447
+ tmp_file.write(wav_audio_data)
448
+ transcription = transcribe_audio_simple(tmp_file.name)
449
+ st.session_state.transcription = transcription
450
+ os.unlink(tmp_file.name)
451
+
452
+ st.session_state.processing = False
453
+ st.rerun()
454
+
455
+ elif 'uploaded_file' in locals() and uploaded_file is not None:
456
+ # Process uploaded file
457
+ with st.spinner("🎯 Processing your audio file..."):
458
+ if TRANSFORMERS_AVAILABLE:
459
+ transcription = transcribe_audio_simple(uploaded_file)
460
+ st.session_state.transcription = transcription
461
  else:
462
+ st.session_state.transcription = "Speech-to-text not available. Please use text input."
463
+
464
+ st.session_state.processing = False
465
+ st.rerun()
466
+
467
+ # Show transcription and editing
468
+ if st.session_state.transcription:
469
+ st.markdown("---")
470
+ st.header("📝 Review Your Input")
471
 
472
+ edited_text = st.text_area(
473
+ "Edit or refine your input:",
474
+ value=st.session_state.transcription,
475
+ height=120,
476
+ key="edit_transcription",
477
+ help="Make any corrections or add more details"
478
+ )
479
+ st.session_state.transcription = edited_text
480
 
481
+ # Generate content section
482
+ st.markdown("---")
483
+ col1, col2, col3 = st.columns([1, 2, 1])
484
+
485
+ with col2:
486
+ if st.button("🚀 Generate Marketing Content", type="primary", use_container_width=True):
487
+ with st.spinner("✨ Creating comprehensive marketing content..."):
488
+ if gemini_available:
489
+ content_text = generate_content_with_gemini(st.session_state.transcription)
490
+ st.session_state.generated_content['text'] = content_text
491
+ else:
492
+ content_text = generate_content_offline(st.session_state.transcription)
493
+ st.session_state.generated_content['text'] = content_text
494
+ st.success("✅ Content generated successfully!")
495
+ st.rerun()
496
 
497
+ # Display generated content
498
+ if st.session_state.generated_content:
499
+ st.markdown("---")
500
+ st.header("✨ Your Marketing Content")
501
+
502
+ # Text content
503
+ if 'text' in st.session_state.generated_content:
504
+ st.markdown(st.session_state.generated_content['text'])
505
 
506
+ # Image generation section
507
+ st.markdown("---")
508
+ st.subheader("🎨 Visual Content")
509
+
510
+ col1, col2 = st.columns([2, 1])
511
+
512
+ with col1:
513
+ if 'structured' in st.session_state.generated_content:
514
+ # Show pre-made prompts
515
+ prompts = st.session_state.generated_content['structured'].get('image_prompts', [])
516
+ if prompts:
517
+ selected_prompt = st.selectbox(
518
+ "Choose image style:",
519
+ prompts,
520
+ help="Select from AI-generated image prompts"
521
+ )
522
+ else:
523
+ # Custom prompt input
524
+ selected_prompt = st.text_input(
525
+ "Describe the image you want:",
526
+ placeholder="Professional product photo with clean white background",
527
+ help="Be specific about style, colors, composition"
528
+ )
529
+
530
+ with col2:
531
+ st.write("") # Spacing
532
+ st.write("") # Spacing
533
 
534
+ if st.button("🖼️ Generate Image", use_container_width=True):
535
+ if selected_prompt:
536
+ img = generate_image_with_api(selected_prompt)
537
+ if img:
538
+ st.session_state.generated_content['image'] = img
539
+ st.success("🎨 Image created!")
540
+ st.rerun()
541
+ else:
542
+ st.error("Image generation failed. Check HF_TOKEN.")
543
+ else:
544
+ st.warning("Please enter/select an image description")
545
+
546
+ # Display generated image
547
+ if 'image' in st.session_state.generated_content:
548
+ st.image(
549
+ st.session_state.generated_content['image'],
550
+ caption="AI Generated Image",
551
+ use_column_width=True
552
+ )
553
+
554
+ # Export section
555
+ st.markdown("---")
556
+ st.header("📥 Export Your Content")
557
+
558
+ col1, col2, col3 = st.columns(3)
559
+
560
+ with col1:
561
+ # Text export
562
+ if 'text' in st.session_state.generated_content:
563
+ content_export = f"""VOICECANVAS MARKETING CONTENT
564
  Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
565
+ Source: {st.session_state.transcription[:100]}...
566
 
567
+ {st.session_state.generated_content['text']}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
 
569
+ ---
570
+ Created with VoiceCanvas AI Content Studio
 
 
 
 
 
 
 
 
 
 
 
571
  """
 
 
 
 
 
 
 
572
 
573
+ st.download_button(
574
+ "📄 Download Text",
575
+ content_export,
576
+ file_name=f"marketing_content_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
577
+ mime="text/plain",
578
+ use_container_width=True,
579
+ help="Download complete text content"
580
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
 
582
+ with col2:
583
+ # JSON export
584
+ if 'structured' in st.session_state.generated_content:
585
+ json_data = {
586
+ "metadata": {
587
+ "timestamp": datetime.now().isoformat(),
588
+ "generator": "VoiceCanvas AI Studio",
589
+ "mode": "Enhanced" if gemini_available else "Basic"
590
+ },
591
+ "input": st.session_state.transcription,
592
+ "content": st.session_state.generated_content['structured']
593
+ }
594
+
595
+ st.download_button(
596
+ "📊 Download Data",
597
+ json.dumps(json_data, indent=2),
598
+ file_name=f"content_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
599
+ mime="application/json",
600
+ use_container_width=True,
601
+ help="Download structured data (JSON)"
602
+ )
603
 
604
+ with col3:
605
+ # Image export
606
+ if 'image' in st.session_state.generated_content:
607
+ img_buffer = io.BytesIO()
608
+ st.session_state.generated_content['image'].save(img_buffer, format="PNG")
609
+
610
+ st.download_button(
611
+ "🖼️ Download Image",
612
+ img_buffer.getvalue(),
613
+ file_name=f"ai_image_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png",
614
+ mime="image/png",
615
+ use_container_width=True,
616
+ help="Download generated image"
617
+ )
618
+ else:
619
+ st.info("Generate an image first", icon="ℹ️")
620
 
621
  # Footer
622
  st.markdown("---")
623
+ col1, col2, col3 = st.columns([1, 2, 1])
624
+ with col2:
625
+ st.markdown("🎨 **VoiceCanvas AI Content Studio**")
626
+ st.caption("Transform ideas into marketing magic Built with Streamlit")
 
 
627
 
628
  if __name__ == "__main__":
629
  main()