Asad235 commited on
Commit
5e068a3
Β·
verified Β·
1 Parent(s): e1a092a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +272 -263
app.py CHANGED
@@ -1,237 +1,211 @@
1
  #!/usr/bin/env python3
2
  """
3
- Complete Working MiniCPM-o-2.6 Voiceover Generator
4
- No Docker needed - Direct Python run
 
5
  """
6
 
7
  import gradio as gr
8
  import torch
 
9
  import tempfile
10
- import os
11
- import subprocess
12
- import sys
13
  from pathlib import Path
14
  import warnings
15
  warnings.filterwarnings('ignore')
16
 
17
  # ============================================================
18
- # CONFIGURATION
19
  # ============================================================
20
- OUTPUT_DIR = Path("./generated_voiceovers")
21
- OUTPUT_DIR.mkdir(exist_ok=True)
22
-
23
- VOICE_STYLES = {
24
- "1": {"name": "Professional Narrator", "emotion": "neutral", "speed": 0.9, "voice": "en-US-JennyNeural"},
25
- "2": {"name": "Enthusiastic YouTuber", "emotion": "happy", "speed": 1.1, "voice": "en-US-GuyNeural"},
26
- "3": {"name": "Calm Teacher", "emotion": "neutral", "speed": 0.8, "voice": "en-GB-SoniaNeural"},
27
- "4": {"name": "Energetic Announcer", "emotion": "happy", "speed": 1.2, "voice": "en-US-DavisNeural"},
28
- "5": {"name": "Deep Documentary Voice", "emotion": "neutral", "speed": 0.75, "voice": "en-US-ChristopherNeural"},
29
- "6": {"name": "Friendly Explainer", "emotion": "happy", "speed": 1.0, "voice": "en-US-AnaNeural"},
30
- }
31
-
32
- # Templates for voiceover text
33
- INTROS = [
34
- "Watch how", "See how", "Discover how", "Learn how",
35
- "Ever wondered how", "Here's how", "This is how",
36
- "Let me show you how", "In this video, see how"
37
- ]
38
-
39
- ACTION_DESCS = {
40
- "increasing torque": ["multiplies rotational force", "boosts pulling power", "enhances mechanical advantage"],
41
- "reducing speed": ["controls motion safely", "slows down rotation", "manages velocity"],
42
- "transferring power": ["sends energy efficiently", "transmits mechanical force", "delivers power smoothly"],
43
- "lifting heavy loads": ["raises massive weights", "hoists heavy objects", "lifts tons with ease"],
44
- "driving conveyor belts": ["moves products along", "keeps production flowing", "transports items efficiently"],
45
- "precise positioning": ["achieves pinpoint accuracy", "places parts exactly", "aligns with perfection"],
46
- }
47
-
48
- OUTROS = [
49
- "That's engineering in action!",
50
- "Simple mechanics, powerful results!",
51
- "That's how industry gets things done!",
52
- "Engineering made simple.",
53
- "Powerful mechanics at work.",
54
- "Now you know how it works!"
55
- ]
56
 
57
  # ============================================================
58
- # GENERATE VOICEOVER TEXT (Template-based - Always Works)
59
  # ============================================================
60
- def generate_voiceover_text(raw_prompt):
61
- """Convert technical prompt to natural voiceover using templates"""
62
-
63
- if not raw_prompt:
64
- return ""
 
65
 
66
- # Parse prompt
67
- if " in " in raw_prompt:
68
- parts = raw_prompt.split(" in ", 1)
69
- mechanism_action = parts[0]
70
- industry = parts[1].split(" -")[0] if " -" in parts[1] else parts[1]
71
- else:
72
- mechanism_action = raw_prompt
73
- industry = "industrial setting"
74
 
75
- words = mechanism_action.split()
76
- mechanism = words[0] if words else "mechanism"
77
- action = " ".join(words[1:]) if len(words) > 1 else "operates"
78
 
79
- # Find action description
80
- import random
81
- action_desc = None
82
- for key, descs in ACTION_DESCS.items():
83
- if key in action.lower():
84
- action_desc = random.choice(descs)
85
- break
86
 
87
- if not action_desc:
88
- action_desc = f"{action} with precision and reliability"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
- intro = random.choice(INTROS)
91
- outro = random.choice(OUTROS)
92
- article = "an" if mechanism[0].lower() in 'aeiou' else "a"
93
 
94
- voiceover = f"{intro} {article} {mechanism} {action} inside {article} {industry}. "
95
- voiceover += f"This clever mechanism {action_desc}. {outro}"
 
 
96
 
97
- return voiceover
 
 
98
 
99
  # ============================================================
100
- # TEXT TO SPEECH (Edge TTS - Always Works)
101
  # ============================================================
102
- def text_to_speech_edge(text, voice_choice, output_path):
103
- """Convert text to speech using Microsoft Edge TTS"""
104
 
105
- import asyncio
106
-
107
- # Check if edge-tts is installed
108
- try:
109
- import edge_tts
110
- except ImportError:
111
- print("πŸ“¦ Installing edge-tts...")
112
- subprocess.check_call([sys.executable, "-m", "pip", "install", "edge-tts"])
113
- import edge_tts
114
-
115
- style = VOICE_STYLES.get(voice_choice, VOICE_STYLES["1"])
116
- voice = style["voice"]
117
 
118
- async def generate():
119
- communicate = edge_tts.Communicate(text, voice)
120
- await communicate.save(output_path)
121
 
122
- asyncio.run(generate())
123
- return output_path
 
 
 
124
 
125
- # ============================================================
126
- # MAIN PROCESS FUNCTION
127
- # ============================================================
128
- def process_prompt(prompt_text, voice_choice, auto_convert):
129
- """Generate voiceover from prompt"""
130
 
131
- if not prompt_text:
132
- return None, "⚠️ Please enter a prompt!", ""
 
 
133
 
134
  try:
135
- # Step 1: Generate natural voiceover text
136
- if auto_convert:
137
- voiceover_text = generate_voiceover_text(prompt_text)
138
- else:
139
- voiceover_text = prompt_text
140
-
141
- # Step 2: Generate audio
142
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
143
- audio_path = text_to_speech_edge(voiceover_text, voice_choice, tmp.name)
144
 
145
- # Info message
146
- word_count = len(voiceover_text.split())
147
- estimated_duration = word_count / 2.5
148
 
149
- info = f"""
150
- βœ… VOICEOVER GENERATED SUCCESSFULLY!
151
-
152
- πŸ“ Original Prompt: {prompt_text}
153
-
154
- πŸŽ™οΈ Voiceover Script:
155
- {voiceover_text}
156
-
157
- 🎭 Voice Style: {VOICE_STYLES[voice_choice]['name']}
158
- πŸ“Š Word Count: {word_count}
159
- ⏱️ Duration: ~{estimated_duration:.1f} seconds
160
- """
161
 
162
- return audio_path, info, voiceover_text
163
 
164
  except Exception as e:
165
- return None, f"❌ Error: {str(e)}", ""
 
166
 
167
  # ============================================================
168
  # BATCH PROCESS FUNCTION
169
  # ============================================================
170
- def batch_process(csv_file, voice_choice, auto_convert):
171
- """Process multiple prompts from CSV"""
172
 
173
- if csv_file is None:
174
- return None, "⚠️ Please upload a CSV file!", ""
175
-
176
- import csv
177
- import io
178
 
179
  try:
180
- # Read CSV
181
- content = csv_file.decode('utf-8')
182
- csv_reader = csv.DictReader(io.StringIO(content))
 
 
 
 
 
 
 
 
 
 
183
 
184
- batch_dir = OUTPUT_DIR / "batch"
185
- batch_dir.mkdir(exist_ok=True)
186
 
 
187
  results = []
188
- success_count = 0
189
 
190
- for idx, row in enumerate(csv_reader, 1):
191
- prompt_text = row.get('prompt', row.get('prompt_text', row.get('text', '')))
192
- if not prompt_text:
193
- continue
194
-
195
- # Generate voiceover text
196
- if auto_convert:
197
- voiceover_text = generate_voiceover_text(prompt_text)
198
- else:
199
- voiceover_text = prompt_text
200
-
201
- # Generate audio
202
- output_path = batch_dir / f"prompt_{idx}.mp3"
203
- text_to_speech_edge(voiceover_text, voice_choice, str(output_path))
204
-
205
- results.append(f"{idx}. {prompt_text[:50]}... β†’ {output_path.name}")
206
- success_count += 1
207
 
208
- info = f"""
 
209
  βœ… BATCH PROCESSING COMPLETE!
210
 
211
- πŸ“Š Total Processed: {success_count}
212
- 🎭 Voice Style: {VOICE_STYLES[voice_choice]['name']}
213
- πŸ“ Output Folder: {batch_dir}
214
 
215
- πŸ“‹ Generated Files:
216
- {chr(10).join(results[:10])}
 
 
 
217
  """
218
 
219
- return str(batch_dir), info, ""
220
 
221
  except Exception as e:
222
- return None, f"❌ Error: {str(e)}", ""
223
 
224
  # ============================================================
225
- # GRADIO INTERFACE
226
  # ============================================================
227
  def create_interface():
228
- with gr.Blocks(title="Voiceover Generator", theme=gr.themes.Soft()) as demo:
229
  gr.Markdown("""
230
- # πŸŽ™οΈ AI Voiceover Generator
 
 
 
 
 
 
 
 
 
231
 
232
- **Turn technical prompts into natural voiceovers - No setup required!**
233
 
234
- Just type a prompt like `"planetary gear increasing torque in automotive plant"` and click generate.
235
  """)
236
 
237
  with gr.Tabs():
@@ -242,49 +216,65 @@ def create_interface():
242
  prompt_input = gr.Textbox(
243
  label="πŸ“ Technical Prompt",
244
  placeholder="Example: planetary gear increasing torque in automotive plant",
245
- lines=3
246
  )
247
 
248
  with gr.Row():
249
- voice_dropdown = gr.Dropdown(
250
- choices=list(VOICE_STYLES.keys()),
251
- label="🎭 Voice Style",
252
- value="1",
253
- info="1=Professional, 2=YouTuber, 3=Teacher, 4=Announcer, 5=Documentary, 6=Friendly"
254
- )
255
-
256
- auto_convert = gr.Checkbox(
257
- label="✨ Auto-convert to natural voiceover",
258
- value=True,
259
- info="Convert technical prompt to engaging script"
260
- )
261
-
262
- with gr.Row():
263
- generate_btn = gr.Button("🎀 Generate Voiceover", variant="primary", size="lg")
264
  clear_btn = gr.Button("πŸ—‘οΈ Clear", size="lg")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
  with gr.Column(scale=1):
267
  gr.Markdown("""
268
- ### 🎭 Voice Style Guide
 
 
 
 
 
269
 
270
- | # | Style | Best For |
271
- |---|-------|----------|
272
- | 1 | Professional | Technical explainers |
273
- | 2 | YouTuber | Engaging shorts |
274
- | 3 | Teacher | Educational |
275
- | 4 | Announcer | High energy |
276
- | 5 | Documentary | Serious topics |
277
- | 6 | Friendly | Casual tutorials |
278
  """)
279
 
280
  with gr.Row():
281
  with gr.Column():
282
- audio_output = gr.Audio(label="🎧 Generated Voiceover", type="filepath")
283
- download_btn = gr.File(label="πŸ“₯ Download Audio", visible=False)
284
-
285
- with gr.Column():
286
- info_output = gr.Textbox(label="πŸ“Š Status", lines=6)
287
- text_output = gr.Textbox(label="πŸ“ Voiceover Script", lines=4)
 
 
 
 
 
 
 
288
 
289
  # Tab 2: Batch Processing
290
  with gr.TabItem("πŸ“ Batch Processing"):
@@ -294,90 +284,114 @@ def create_interface():
294
  label="Upload CSV File",
295
  file_types=[".csv"],
296
  type="binary",
297
- info="CSV should have a 'prompt' column"
298
- )
299
-
300
- batch_voice = gr.Dropdown(
301
- choices=list(VOICE_STYLES.keys()),
302
- label="🎭 Voice Style",
303
- value="1"
304
- )
305
-
306
- batch_auto_convert = gr.Checkbox(
307
- label="✨ Auto-convert prompts",
308
- value=True
309
- )
310
-
311
- batch_max_rows = gr.Slider(
312
- label="Maximum prompts (0 = all)",
313
- minimum=0,
314
- maximum=100,
315
- value=10,
316
- step=1
317
  )
318
 
319
  batch_btn = gr.Button("πŸš€ Start Batch Processing", variant="primary")
320
 
321
  with gr.Column():
322
- batch_output = gr.Textbox(label="πŸ“ Output Folder", lines=2)
323
- batch_info = gr.Textbox(label="πŸ“Š Batch Status", lines=15)
324
 
325
- # Tab 3: Examples
326
- with gr.TabItem("πŸ“‹ Examples"):
327
  gr.Markdown("""
328
- ## πŸ“ Try These Prompts
 
 
 
 
 
329
 
330
- Copy any prompt and paste in the Single Prompt tab:
 
 
 
 
 
 
 
 
 
331
 
 
 
 
332
  ```
333
- planetary gear increasing torque in automotive plant
334
- worm gear reducing speed in steel mill
335
- hydraulic cylinder lifting heavy loads in mining operation
336
- chain drive driving conveyor belts in food processing factory
337
- servo motor precise positioning in warehouse
338
- ball bearing reducing friction in high speed machinery
339
- rack and pinion converting rotary to linear motion
340
- camshaft opening and closing valves in engine
341
- bevel gear transferring power at right angle
342
- clutch assembly engaging and disengaging power
343
  ```
344
 
345
- ## πŸ“ CSV Format for Batch Processing
 
 
 
346
 
347
- Create a CSV file with this structure:
348
 
349
- ```csv
350
- id,prompt
351
- 1,planetary gear increasing torque in automotive plant
352
- 2,worm gear reducing speed in steel mill
353
- 3,hydraulic cylinder lifting heavy loads in mining operation
354
- ```
355
 
356
- ## πŸ’‘ Tips
357
 
358
- - **Auto-convert ON:** Technical prompt automatically becomes natural voiceover
359
- - **Auto-convert OFF:** Use your exact text as voiceover
360
- - First generation may take 2-3 seconds (installing dependencies)
361
- - Audio downloads automatically in MP3 format
 
362
  """)
363
 
364
  # Event handlers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  generate_btn.click(
366
- fn=process_prompt,
367
- inputs=[prompt_input, voice_dropdown, auto_convert],
368
- outputs=[audio_output, info_output, text_output]
369
  )
370
 
371
  clear_btn.click(
372
  fn=lambda: ("", "", ""),
373
- outputs=[prompt_input, info_output, text_output]
 
 
 
 
 
 
374
  )
375
 
376
  batch_btn.click(
377
  fn=batch_process,
378
- inputs=[csv_input, batch_voice, batch_auto_convert],
379
- outputs=[batch_output, batch_info, batch_info]
380
  )
 
 
 
 
 
 
 
 
 
 
 
381
 
382
  return demo
383
 
@@ -386,14 +400,9 @@ def create_interface():
386
  # ============================================================
387
  if __name__ == "__main__":
388
  print("=" * 60)
389
- print("πŸŽ™οΈ AI VOICEOVER GENERATOR")
390
  print("=" * 60)
391
- print("\n✨ Features:")
392
- print(" - Natural voiceover text from technical prompts")
393
- print(" - 6 professional voice styles")
394
- print(" - Batch processing from CSV")
395
- print(" - No GPU required (uses Edge TTS)")
396
- print("\nπŸš€ Starting application...")
397
  print("πŸ“± Access at: http://localhost:7860")
398
  print("=" * 60)
399
 
 
1
  #!/usr/bin/env python3
2
  """
3
+ MiniCPM-o-2.6 Text Generator with Gradio UI
4
+ Convert technical prompts to natural voiceover text
5
+ No TTS - Pure MiniCPM text generation with Web Interface
6
  """
7
 
8
  import gradio as gr
9
  import torch
10
+ import csv
11
  import tempfile
 
 
 
12
  from pathlib import Path
13
  import warnings
14
  warnings.filterwarnings('ignore')
15
 
16
  # ============================================================
17
+ # MONKEY PATCH FOR WHISPER ATTENTION CLASSES (Fix import error)
18
  # ============================================================
19
+ try:
20
+ from transformers.models.whisper.modeling_whisper import WHISPER_ATTENTION_CLASSES
21
+ except ImportError:
22
+ import transformers.models.whisper.modeling_whisper as whisper_module
23
+ if not hasattr(whisper_module, 'WHISPER_ATTENTION_CLASSES'):
24
+ whisper_module.WHISPER_ATTENTION_CLASSES = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  # ============================================================
27
+ # LOAD MINICPM MODEL
28
  # ============================================================
29
+ _model = None
30
+ _tokenizer = None
31
+
32
+ def load_model():
33
+ """Load MiniCPM-o-2.6 model for text generation only"""
34
+ global _model, _tokenizer
35
 
36
+ if _model is not None:
37
+ return _model, _tokenizer
 
 
 
 
 
 
38
 
39
+ print("=" * 60)
40
+ print("πŸ”„ Loading MiniCPM-o-2.6 model...")
41
+ print("=" * 60)
42
 
43
+ from transformers import AutoModel, AutoTokenizer
 
 
 
 
 
 
44
 
45
+ try:
46
+ _model = AutoModel.from_pretrained(
47
+ 'openbmb/MiniCPM-o-2_6',
48
+ trust_remote_code=True,
49
+ torch_dtype=torch.float32,
50
+ low_cpu_mem_usage=True,
51
+ )
52
+ except Exception as e:
53
+ print(f"⚠️ First attempt error: {e}")
54
+ print("πŸ”„ Retrying with dtype='auto'...")
55
+ _model = AutoModel.from_pretrained(
56
+ 'openbmb/MiniCPM-o-2_6',
57
+ trust_remote_code=True,
58
+ torch_dtype='auto',
59
+ low_cpu_mem_usage=True,
60
+ )
61
 
62
+ _model = _model.eval()
63
+ _model = _model.to('cpu')
 
64
 
65
+ _tokenizer = AutoTokenizer.from_pretrained(
66
+ 'openbmb/MiniCPM-o-2_6',
67
+ trust_remote_code=True
68
+ )
69
 
70
+ print("βœ… MiniCPM-o-2.6 loaded successfully on CPU!")
71
+ print("=" * 60)
72
+ return _model, _tokenizer
73
 
74
  # ============================================================
75
+ # GENERATE NATURAL VOICEOVER TEXT
76
  # ============================================================
77
+ def generate_natural_text(prompt_text):
78
+ """Convert technical prompt to natural voiceover text using MiniCPM"""
79
 
80
+ if not prompt_text:
81
+ return "⚠️ Please enter a prompt!"
 
 
 
 
 
 
 
 
 
 
82
 
83
+ model, tokenizer = load_model()
 
 
84
 
85
+ # System prompt
86
+ system_prompt = """You are a professional YouTube Shorts script writer.
87
+ Convert the given technical engineering prompt into a natural, engaging, and educational voiceover script.
88
+ The script should be 30-50 words long, exciting, easy to speak, and suitable for a short video.
89
+ Return ONLY the script text, no explanations, no quotes."""
90
 
91
+ user_message = f"Technical prompt: {prompt_text}\n\nNatural voiceover script:"
 
 
 
 
92
 
93
+ msgs = [
94
+ {'role': 'system', 'content': system_prompt},
95
+ {'role': 'user', 'content': user_message}
96
+ ]
97
 
98
  try:
99
+ response = model.chat(
100
+ msgs=msgs,
101
+ tokenizer=tokenizer,
102
+ sampling=True,
103
+ temperature=0.7,
104
+ max_new_tokens=200,
105
+ )
 
 
106
 
107
+ text = response.strip()
 
 
108
 
109
+ # Clean up
110
+ if text.startswith('"'):
111
+ text = text[1:]
112
+ if text.endswith('"'):
113
+ text = text[:-1]
114
+ if text.lower().startswith('voiceover script:'):
115
+ text = text[16:].strip()
 
 
 
 
 
116
 
117
+ return text
118
 
119
  except Exception as e:
120
+ print(f"❌ Generation error: {e}")
121
+ return f"Watch how {prompt_text}. That's engineering in action!"
122
 
123
  # ============================================================
124
  # BATCH PROCESS FUNCTION
125
  # ============================================================
126
+ def batch_process(file_obj, progress=gr.Progress()):
127
+ """Process multiple prompts from uploaded CSV"""
128
 
129
+ if file_obj is None:
130
+ return "⚠️ Please upload a CSV file!", None
 
 
 
131
 
132
  try:
133
+ # Read uploaded CSV
134
+ content = file_obj.decode('utf-8')
135
+ lines = content.strip().split('\n')
136
+
137
+ # Parse prompts
138
+ prompts = []
139
+ for line in lines[1:]: # Skip header
140
+ if line.strip():
141
+ parts = line.split(',')
142
+ if len(parts) >= 2:
143
+ prompts.append(parts[1].strip().strip('"'))
144
+ elif len(parts) >= 1:
145
+ prompts.append(parts[0].strip().strip('"'))
146
 
147
+ if not prompts:
148
+ return "❌ No prompts found in CSV!", None
149
 
150
+ # Process each prompt
151
  results = []
152
+ progress(0, desc="Starting...")
153
 
154
+ for idx, prompt in enumerate(prompts):
155
+ progress(idx / len(prompts), desc=f"Processing {idx+1}/{len(prompts)}")
156
+ natural_text = generate_natural_text(prompt)
157
+ results.append({
158
+ 'prompt': prompt,
159
+ 'voiceover': natural_text,
160
+ 'words': len(natural_text.split())
161
+ })
162
+
163
+ # Create output CSV
164
+ output_file = tempfile.NamedTemporaryFile(delete=False, suffix='.csv', mode='w', newline='', encoding='utf-8')
165
+ writer = csv.DictWriter(output_file, fieldnames=['prompt', 'voiceover', 'words'])
166
+ writer.writeheader()
167
+ writer.writerows(results)
168
+ output_file.close()
 
 
169
 
170
+ # Create summary
171
+ summary = f"""
172
  βœ… BATCH PROCESSING COMPLETE!
173
 
174
+ πŸ“Š Total Prompts: {len(prompts)}
175
+ πŸ“ Successfully Processed: {len(results)}
 
176
 
177
+ πŸ“‹ Sample Output:
178
+ {'-' * 50}
179
+ {results[0]['prompt'][:60]}...
180
+ β†’ {results[0]['voiceover'][:100]}...
181
+ {'-' * 50}
182
  """
183
 
184
+ return summary, output_file.name
185
 
186
  except Exception as e:
187
+ return f"❌ Error: {str(e)}", None
188
 
189
  # ============================================================
190
+ # CREATE GRADIO INTERFACE
191
  # ============================================================
192
  def create_interface():
193
+ with gr.Blocks(title="MiniCPM Voiceover Text Generator", theme=gr.themes.Soft()) as demo:
194
  gr.Markdown("""
195
+ # πŸŽ™οΈ MiniCPM-o-2.6 Voiceover Text Generator
196
+
197
+ **Convert technical prompts to natural voiceover scripts using MiniCPM**
198
+
199
+ | Feature | Description |
200
+ |---------|-------------|
201
+ | ✍️ Text Generation | Technical prompt β†’ Natural voiceover script |
202
+ | 🎯 Pure MiniCPM | No fallbacks, only MiniCPM-o-2.6 |
203
+ | ⚑ CPU Only | Works on your 16GB RAM / 2 vCPU |
204
+ | πŸ“ Batch Processing | Upload CSV and process multiple prompts |
205
 
206
+ ---
207
 
208
+ **Example:** `"planetary gear increasing torque in automotive plant"`
209
  """)
210
 
211
  with gr.Tabs():
 
216
  prompt_input = gr.Textbox(
217
  label="πŸ“ Technical Prompt",
218
  placeholder="Example: planetary gear increasing torque in automotive plant",
219
+ lines=4
220
  )
221
 
222
  with gr.Row():
223
+ generate_btn = gr.Button("🎀 Generate Voiceover Text", variant="primary", size="lg")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  clear_btn = gr.Button("πŸ—‘οΈ Clear", size="lg")
225
+
226
+ gr.Markdown("""
227
+ ### πŸ’‘ Example Prompts
228
+
229
+ Click any to try:
230
+ """)
231
+
232
+ example_prompts = [
233
+ "planetary gear increasing torque in automotive plant",
234
+ "worm gear reducing speed in steel mill",
235
+ "hydraulic cylinder lifting heavy loads in mining operation",
236
+ "chain drive driving conveyor belts in food processing factory",
237
+ "servo motor precise positioning in warehouse",
238
+ "ball bearing reducing friction in high speed machinery",
239
+ "rack and pinion converting rotary to linear motion",
240
+ "camshaft opening and closing valves in engine"
241
+ ]
242
+
243
+ for ex in example_prompts:
244
+ gr.Markdown(f"- `{ex}`")
245
 
246
  with gr.Column(scale=1):
247
  gr.Markdown("""
248
+ ### 🎯 What MiniCPM Does
249
+
250
+ 1. **Understands** your technical prompt
251
+ 2. **Creates** natural, engaging voiceover script
252
+ 3. **Optimizes** for YouTube Shorts (30-50 words)
253
+ 4. **Returns** ready-to-use script
254
 
255
+ ### πŸ“Š Output Format
256
+
257
+ - Natural, conversational tone
258
+ - Engaging hooks
259
+ - Clear explanations
260
+ - Strong conclusions
 
 
261
  """)
262
 
263
  with gr.Row():
264
  with gr.Column():
265
+ output_text = gr.Textbox(
266
+ label="πŸŽ™οΈ Generated Voiceover Script",
267
+ lines=6,
268
+ interactive=False
269
+ )
270
+
271
+ info_text = gr.Textbox(
272
+ label="πŸ“Š Info",
273
+ lines=3,
274
+ interactive=False
275
+ )
276
+
277
+ copy_btn = gr.Button("πŸ“‹ Copy to Clipboard", size="sm")
278
 
279
  # Tab 2: Batch Processing
280
  with gr.TabItem("πŸ“ Batch Processing"):
 
284
  label="Upload CSV File",
285
  file_types=[".csv"],
286
  type="binary",
287
+ info="CSV should have header: id,prompt or just prompts column"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  )
289
 
290
  batch_btn = gr.Button("πŸš€ Start Batch Processing", variant="primary")
291
 
292
  with gr.Column():
293
+ batch_status = gr.Textbox(label="πŸ“Š Status", lines=10)
294
+ batch_output_file = gr.File(label="πŸ“₯ Download Results", visible=True)
295
 
296
+ # Tab 3: Help
297
+ with gr.TabItem("❓ Help"):
298
  gr.Markdown("""
299
+ ## πŸ“– How to Use
300
+
301
+ ### Single Prompt Mode
302
+ 1. Enter a technical prompt in the text box
303
+ 2. Click "Generate Voiceover Text"
304
+ 3. Copy the generated script for your video
305
 
306
+ ### Batch Mode
307
+ 1. Prepare a CSV file with this format:
308
+ ```csv
309
+ id,prompt
310
+ 1,planetary gear increasing torque in automotive plant
311
+ 2,worm gear reducing speed in steel mill
312
+ ```
313
+ 2. Upload the CSV file
314
+ 3. Click "Start Batch Processing"
315
+ 4. Download results CSV
316
 
317
+ ## 🎯 Prompt Format
318
+
319
+ Best results with this format:
320
  ```
321
+ [mechanism] [action] in [industry]
 
 
 
 
 
 
 
 
 
322
  ```
323
 
324
+ Examples:
325
+ - `planetary gear increasing torque in automotive plant`
326
+ - `worm gear reducing speed in steel mill`
327
+ - `hydraulic cylinder lifting heavy loads in mining`
328
 
329
+ ## βš™οΈ Technical Details
330
 
331
+ - **Model:** MiniCPM-o-2.6 (8B parameters)
332
+ - **Hardware:** CPU only (16GB RAM recommended)
333
+ - **First run:** Downloads model (~8GB, 5-10 minutes)
334
+ - **Subsequent runs:** Instant loading from cache
 
 
335
 
336
+ ## πŸ”§ Troubleshooting
337
 
338
+ | Issue | Solution |
339
+ |-------|----------|
340
+ | Slow first generation | Model downloading in background |
341
+ | Out of memory | Close other applications |
342
+ | Import errors | Use Docker for consistent environment |
343
  """)
344
 
345
  # Event handlers
346
+ def process_and_info(prompt):
347
+ if not prompt:
348
+ return "⚠️ Please enter a prompt!", "❌ No prompt provided"
349
+
350
+ result = generate_natural_text(prompt)
351
+ word_count = len(result.split())
352
+ info = f"""
353
+ βœ… Generated successfully!
354
+
355
+ πŸ“ Original prompt: {prompt[:60]}...
356
+ πŸ“Š Word count: {word_count}
357
+ ⏱️ Estimated duration: ~{word_count / 2.5:.1f} seconds
358
+ πŸ€– Model: MiniCPM-o-2.6
359
+ """
360
+ return result, info
361
+
362
  generate_btn.click(
363
+ fn=process_and_info,
364
+ inputs=[prompt_input],
365
+ outputs=[output_text, info_text]
366
  )
367
 
368
  clear_btn.click(
369
  fn=lambda: ("", "", ""),
370
+ outputs=[prompt_input, output_text, info_text]
371
+ )
372
+
373
+ copy_btn.click(
374
+ fn=lambda: output_text.value,
375
+ outputs=None,
376
+ js="(text) => navigator.clipboard.writeText(text)"
377
  )
378
 
379
  batch_btn.click(
380
  fn=batch_process,
381
+ inputs=[csv_input],
382
+ outputs=[batch_status, batch_output_file]
383
  )
384
+
385
+ # Example prompt click (using JavaScript)
386
+ example_js = """
387
+ function set_example(prompt) {
388
+ document.querySelector('textarea').value = prompt;
389
+ return prompt;
390
+ }
391
+ """
392
+
393
+ for ex in example_prompts[:4]:
394
+ gr.Markdown(f"<button onclick='set_example(\"{ex}\")'>{ex}</button>", elem_id="example-btn")
395
 
396
  return demo
397
 
 
400
  # ============================================================
401
  if __name__ == "__main__":
402
  print("=" * 60)
403
+ print("πŸŽ™οΈ MiniCPM-o-2.6 Voiceover Text Generator")
404
  print("=" * 60)
405
+ print("πŸš€ Starting Gradio Interface...")
 
 
 
 
 
406
  print("πŸ“± Access at: http://localhost:7860")
407
  print("=" * 60)
408