Update app.py
Browse files
app.py
CHANGED
|
@@ -173,11 +173,31 @@ def clean_generated_script(script: str, prompt: str) -> str:
|
|
| 173 |
r'ONLY RETURN THE SCRIPT CONTENT.*?(\n\n|$)',
|
| 174 |
r'IMPORTANT: ONLY generate.*?(\n\n|$)',
|
| 175 |
r'BEGIN SCRIPT:.*?(\n\n|$)',
|
|
|
|
|
|
|
| 176 |
]
|
| 177 |
|
| 178 |
for pattern in patterns_to_remove:
|
| 179 |
script = re.sub(pattern, '', script, flags=re.DOTALL | re.IGNORECASE)
|
| 180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
# Remove multiple empty lines
|
| 182 |
script = re.sub(r'\n\s*\n', '\n\n', script)
|
| 183 |
|
|
@@ -193,25 +213,41 @@ def generate_script(topic: str) -> str:
|
|
| 193 |
clean_topic = topic.strip().strip("['").strip("']").strip('"').strip("'")
|
| 194 |
logger.info(f"🎯 Generating script for: '{clean_topic}'")
|
| 195 |
|
| 196 |
-
#
|
| 197 |
prompt = (
|
| 198 |
-
f"IMPORTANT:
|
| 199 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
|
| 201 |
-
"SCRIPT
|
| 202 |
-
"[0:00-0:08] VISUAL: [visual
|
| 203 |
-
"VOICEOVER: [
|
| 204 |
|
| 205 |
-
"[0:08-0:45] VISUAL: [
|
| 206 |
-
"VOICEOVER: [
|
| 207 |
|
| 208 |
-
"[0:45-0:55] VISUAL: [visual
|
| 209 |
-
"VOICEOVER: [
|
| 210 |
|
| 211 |
-
"[0:55-1:00] VISUAL: [visual
|
| 212 |
-
"VOICEOVER: [
|
| 213 |
|
| 214 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
)
|
| 216 |
|
| 217 |
inputs = generator.tokenizer(
|
|
@@ -242,13 +278,15 @@ def generate_script(topic: str) -> str:
|
|
| 242 |
|
| 243 |
# If cleaning removed too much, fallback to basic extraction
|
| 244 |
if not script_content or len(script_content) < 50:
|
| 245 |
-
if "
|
| 246 |
-
script_content = full_output.split("BEGIN SCRIPT:")[-1].strip()
|
| 247 |
-
elif "SCRIPT:" in full_output:
|
| 248 |
script_content = full_output.split("SCRIPT:")[-1].strip()
|
| 249 |
else:
|
| 250 |
script_content = full_output.replace(prompt, "").strip()
|
| 251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
logger.info(f"📝 Generated {len(script_content)} characters")
|
| 253 |
return script_content
|
| 254 |
|
|
@@ -292,7 +330,7 @@ async def process_job(job_id: str, topics_input: Union[str, List[str]], callback
|
|
| 292 |
"job_id": job_id,
|
| 293 |
"status": "complete",
|
| 294 |
"result": script,
|
| 295 |
-
"topic": generated_topic,
|
| 296 |
"script_length": len(script),
|
| 297 |
"formatted": True,
|
| 298 |
"original_topics": topics
|
|
@@ -460,7 +498,7 @@ async def root():
|
|
| 460 |
return JSONResponse({
|
| 461 |
"message": "Video Script Generator API",
|
| 462 |
"version": "2.0",
|
| 463 |
-
"features": "Generates viral topics from trends and creates video scripts",
|
| 464 |
"endpoints": {
|
| 465 |
"submit_job": "POST /api/submit (with 'topics' array)",
|
| 466 |
"check_status": "GET /api/status/{job_id}",
|
|
|
|
| 173 |
r'ONLY RETURN THE SCRIPT CONTENT.*?(\n\n|$)',
|
| 174 |
r'IMPORTANT: ONLY generate.*?(\n\n|$)',
|
| 175 |
r'BEGIN SCRIPT:.*?(\n\n|$)',
|
| 176 |
+
r'NO PROMOTIONAL CONTENT.*?(\n\n|$)',
|
| 177 |
+
r'FOCUS ON EDUCATIONAL VALUE.*?(\n\n|$)',
|
| 178 |
]
|
| 179 |
|
| 180 |
for pattern in patterns_to_remove:
|
| 181 |
script = re.sub(pattern, '', script, flags=re.DOTALL | re.IGNORECASE)
|
| 182 |
|
| 183 |
+
# Remove promotional content (apps, websites, products)
|
| 184 |
+
promotional_patterns = [
|
| 185 |
+
r'visit our (website|app|page)',
|
| 186 |
+
r'download (the|our) app',
|
| 187 |
+
r'check out our (product|service)',
|
| 188 |
+
r'buy now',
|
| 189 |
+
r'sign up',
|
| 190 |
+
r'click the link',
|
| 191 |
+
r'in the description below',
|
| 192 |
+
r'link in bio',
|
| 193 |
+
r'use code.*?',
|
| 194 |
+
r'promo code',
|
| 195 |
+
r'discount code',
|
| 196 |
+
]
|
| 197 |
+
|
| 198 |
+
for pattern in promotional_patterns:
|
| 199 |
+
script = re.sub(pattern, '', script, flags=re.IGNORECASE)
|
| 200 |
+
|
| 201 |
# Remove multiple empty lines
|
| 202 |
script = re.sub(r'\n\s*\n', '\n\n', script)
|
| 203 |
|
|
|
|
| 213 |
clean_topic = topic.strip().strip("['").strip("']").strip('"').strip("'")
|
| 214 |
logger.info(f"🎯 Generating script for: '{clean_topic}'")
|
| 215 |
|
| 216 |
+
# IMPROVED PROMPT - Focus on informative content, no promotions
|
| 217 |
prompt = (
|
| 218 |
+
f"IMPORTANT: Create a purely informative 60-second YouTube/TikTok video script about: {clean_topic}\n\n"
|
| 219 |
+
"CRITICAL REQUIREMENTS:\n"
|
| 220 |
+
"- Total duration: 60 seconds exactly with clear timestamps\n"
|
| 221 |
+
"- Each scene must have BOTH visual description AND voiceover text\n"
|
| 222 |
+
"- Visual descriptions should be specific, searchable keywords for stock videos\n"
|
| 223 |
+
"- Voiceover should be conversational, educational, and engaging\n"
|
| 224 |
+
"- NO personal introductions ('I'm...', 'My name is...')\n"
|
| 225 |
+
"- NO promotional content (no apps, websites, products, or services)\n"
|
| 226 |
+
"- NO calls to action (no 'visit our', 'download', 'buy now', 'sign up')\n"
|
| 227 |
+
"- Focus on educational value and useful information only\n"
|
| 228 |
+
"- Provide practical tips, facts, or insights that viewers can use immediately\n\n"
|
| 229 |
|
| 230 |
+
"SCRIPT STRUCTURE:\n"
|
| 231 |
+
"[0:00-0:08] VISUAL: [Attention-grabbing visual - dramatic/curious imagery]\n"
|
| 232 |
+
"VOICEOVER: [8-second hook that creates curiosity and grabs attention]\n\n"
|
| 233 |
|
| 234 |
+
"[0:08-0:45] VISUAL: [Action-oriented visuals demonstrating the topic]\n"
|
| 235 |
+
"VOICEOVER: [37-second valuable content with key insights, facts, and practical tips]\n\n"
|
| 236 |
|
| 237 |
+
"[0:45-0:55] VISUAL: [Transformation/result visual showing benefits]\n"
|
| 238 |
+
"VOICEOVER: [10-second summary of key benefits and value]\n\n"
|
| 239 |
|
| 240 |
+
"[0:55-1:00] VISUAL: [Inspiring visual that reinforces the main message]\n"
|
| 241 |
+
"VOICEOVER: [5-second inspiring closing thought]\n\n"
|
| 242 |
|
| 243 |
+
"VOICEOVER GUIDELINES:\n"
|
| 244 |
+
"- Focus on viewer benefits and valuable information\n"
|
| 245 |
+
"- Include surprising facts, statistics, or insights\n"
|
| 246 |
+
"- Use conversational, engaging tone\n"
|
| 247 |
+
"- End with an inspiring thought, not a call to action\n\n"
|
| 248 |
+
|
| 249 |
+
"NOW CREATE A PURELY INFORMATIVE SCRIPT FOR: {clean_topic}\n\n"
|
| 250 |
+
"SCRIPT:\n"
|
| 251 |
)
|
| 252 |
|
| 253 |
inputs = generator.tokenizer(
|
|
|
|
| 278 |
|
| 279 |
# If cleaning removed too much, fallback to basic extraction
|
| 280 |
if not script_content or len(script_content) < 50:
|
| 281 |
+
if "SCRIPT:" in full_output:
|
|
|
|
|
|
|
| 282 |
script_content = full_output.split("SCRIPT:")[-1].strip()
|
| 283 |
else:
|
| 284 |
script_content = full_output.replace(prompt, "").strip()
|
| 285 |
|
| 286 |
+
# Final cleanup to ensure no promotional content
|
| 287 |
+
script_content = re.sub(r'(visit|download|buy|sign up|check out).*?\.', '', script_content, flags=re.IGNORECASE)
|
| 288 |
+
script_content = re.sub(r'link (in|below).*?', '', script_content, flags=re.IGNORECASE)
|
| 289 |
+
|
| 290 |
logger.info(f"📝 Generated {len(script_content)} characters")
|
| 291 |
return script_content
|
| 292 |
|
|
|
|
| 330 |
"job_id": job_id,
|
| 331 |
"status": "complete",
|
| 332 |
"result": script,
|
| 333 |
+
"topic": generated_topic,
|
| 334 |
"script_length": len(script),
|
| 335 |
"formatted": True,
|
| 336 |
"original_topics": topics
|
|
|
|
| 498 |
return JSONResponse({
|
| 499 |
"message": "Video Script Generator API",
|
| 500 |
"version": "2.0",
|
| 501 |
+
"features": "Generates viral topics from trends and creates informative video scripts",
|
| 502 |
"endpoints": {
|
| 503 |
"submit_job": "POST /api/submit (with 'topics' array)",
|
| 504 |
"check_status": "GET /api/status/{job_id}",
|