Skip to content

Commit 56d022d

Browse files
StoryTelling Engine
1 parent a2c663d commit 56d022d

28 files changed

+799
-492
lines changed

MindGUI.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
import logging
66
from dotenv import load_dotenv
7-
from src.json_2_video.json_2_video import PyJson2Video # Import the process_video function
7+
from src.json_2_video_engine.json_2_video import PyJson2Video # Import the process_video function
88
import asyncio
99
import uuid
1010

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
system_prompt: |
2+
You are a script generator for YouTube Shorts. The user will provide instructions, and you will generate a script that adheres to their instructions.
3+
4+
**Guidelines:**
5+
6+
- Ensure the script consists solely of the text to be narrated—no titles, character names, actions, or additional formatting. Always verify that the script is exclusively the narration text.
7+
- Create a concise and engaging narrative that aligns with the user’s instructions, as long as they comply with the following guidelines.
8+
- Aim for a length of 120-140 words unless user specified otherwise.
9+
- Start with a captivating hook within the first 5 seconds to engage viewers.
10+
- End the script naturally at the conclusion of the story, avoiding calls to action or prompts to continue watching.
11+
- Use a friendly, conversational tone, as if sharing a personal story with a close friend.
12+
- Jump straight into the narrative—omit any titles, subtitles, or formal wrap-ups.
13+
- Maintain a single voice throughout the narration.
14+
15+
**Output Instructions:**
16+
- Return the result as a JSON object structured as follows:
17+
{
18+
"text_script": "script text here"
19+
}
20+
21+
user_prompt: |
22+
- Generate a new script.
23+
- Script instructions:
File renamed without changes.

src/captions/caption_handler.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ def __init__(self):
1818
self.video_captioner = VideoCaptioner()
1919
self.default_font = "Dacherry.ttf"
2020

21-
async def process(self, audio_file: str, captions_color="white", shadow_color="cyan", font_size=60, font=None):
21+
async def process(self, audio_file: str, captions_color="white", shadow_color="cyan", font_size=60, font=None, width=540):
2222
subtitles_file = await self.subtitle_generator.generate_subtitles(audio_file)
2323
caption_clips = self.video_captioner.generate_captions_to_video(
2424
subtitles_file,
2525
font=font,
2626
captions_color=captions_color,
2727
shadow_color=shadow_color,
28-
font_size=font_size
28+
font_size=font_size,
29+
width=width
2930
)
3031
return subtitles_file, caption_clips

src/captions/video_captioner.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,32 @@ def get_font_path(self, font_name):
1818
logging.warning(f"Font file {font_name} not found. Using default system font.")
1919
return None
2020

21-
def create_shadow_text(self, txt, fontsize, font, color, shadow_color, shadow_offset, blur_color):
21+
def create_shadow_text(self, txt, fontsize, font, color, shadow_color, shadow_offset, blur_color, width):
2222
""" # Create the blurred shadow
2323
blur_size = int(fontsize * 1.08) # 10% larger than the main text
2424
blur_clip = TextClip(txt, fontsize=blur_size, font=font, color=blur_color, size=(1000, None), method='caption')
2525
blur_clip = blur_clip.set_opacity(0.15) # Set the opacity to 15%
2626
"""
27+
2728
# Create the offset shadow
28-
shadow_clip = TextClip(txt, fontsize=fontsize, font=font, color=shadow_color, size=(1000, None), method='caption')
29-
shadow_clip = shadow_clip.set_position((shadow_offset, shadow_offset))
29+
#shadow_clip = TextClip(txt, fontsize=fontsize, font=font, color=shadow_color, size=(width, None), method='caption')
30+
#shadow_clip = shadow_clip.set_position((shadow_offset, shadow_offset))
3031

3132
# Create the main text
32-
text_clip = TextClip(txt, fontsize=fontsize, font=font, color=color, size=(1000, None), method='caption')
33+
text_clip = TextClip(txt, fontsize=fontsize*1.1, font=font, color=color, size=(width*0.8, None), method='caption', stroke_color=shadow_color, stroke_width=fontsize/15)
3334

3435
# Composite all layers
3536
#return CompositeVideoClip([blur_clip, shadow_clip, text_clip])
36-
return CompositeVideoClip([shadow_clip, text_clip])
37+
return CompositeVideoClip([text_clip])
3738

3839
""" Call this function to generate the captions to video """
3940
def generate_captions_to_video(self,
4041
subtitles_path,
4142
font=None,
4243
captions_color='#BA4A00',
4344
shadow_color='white',
44-
font_size=60
45+
font_size=60,
46+
width=540
4547
):
4648
font = self.get_font_path(font) if font else self.default_font
4749
try:
@@ -79,6 +81,7 @@ def generate_captions_to_video(self,
7981
shadow_color=shadow_color,
8082
shadow_offset=shadow_offset,
8183
blur_color='black',
84+
width=width
8285
)
8386

8487
start_seconds = start_time.ordinal / 1000 if hasattr(start_time, 'ordinal') else start_time

src/image_handler.py

+52-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re
66
from openai import OpenAI
77
import math
8+
import time
89

910
from dotenv import load_dotenv # To load environment variables
1011

@@ -19,6 +20,50 @@ def __init__(self, pexels_api_key, openai_api_key):
1920
self.openai = OpenAI(api_key=self.openai_api_key)
2021
self.base_dir = os.path.dirname(os.path.abspath(__file__))
2122

23+
def generate_image_pollinations(self, query, width=1024, height=1024, model=None, seed=None, nologo=False, private=True, enhance=False, timeout=15):
24+
"""Generate an image using Pollinations AI API
25+
26+
Args:
27+
query (str): Text description of the image to generate
28+
width (int, optional): Width of generated image. Defaults to 1024
29+
height (int, optional): Height of generated image. Defaults to 1024
30+
model (str, optional): Model to use for generation
31+
seed (int, optional): Seed for reproducible results
32+
nologo (bool, optional): Turn off logo rendering. Defaults to False
33+
private (bool, optional): Prevent image from appearing in public feed. Defaults to True
34+
enhance (bool, optional): Enable prompt enhancing via LLM. Defaults to False
35+
timeout (int, optional): Maximum time to wait for image generation in seconds. Defaults to 15
36+
37+
Returns:
38+
list: List containing the generated image URL if successful, empty list otherwise
39+
"""
40+
# Build query parameters
41+
params = {
42+
'width': width,
43+
'height': height,
44+
'nologo': str(nologo).lower(),
45+
'private': str(private).lower(),
46+
'enhance': str(enhance).lower()
47+
}
48+
if model:
49+
params['model'] = model
50+
if seed is not None:
51+
params['seed'] = seed
52+
53+
# URL encode the prompt
54+
encoded_query = requests.utils.quote(query)
55+
generate_url = f"https://image.pollinations.ai/prompt/{encoded_query}"
56+
57+
try:
58+
full_url = requests.Request('GET', generate_url, params=params).prepare().url
59+
response = requests.get(full_url, timeout=timeout)
60+
if response.status_code == 200:
61+
return [full_url]
62+
return []
63+
except Exception as e:
64+
logging.error(f"Error generating image URL: {e}")
65+
return []
66+
2267
def search_pexels_images(self, query):
2368
"""Search for images using Pexels API and return the URLs."""
2469
search_url = "https://api.pexels.com/v1/search"
@@ -197,9 +242,14 @@ def get_images_from_subtitles(self, subtitles_file_path, video_context, video_du
197242
logging.info(f"Searching image for keywords: {refined_keyword}")
198243

199244
try:
200-
image_urls = self.search_pexels_images(refined_keyword)
245+
## Search for images using first Pollinations API
246+
image_urls = self.generate_image_pollinations(refined_keyword)
201247
if not image_urls:
202-
image_urls = self.search_pixabay_images(refined_keyword)
248+
## Search for images using Pexels API
249+
image_urls = self.search_pexels_images(refined_keyword)
250+
if not image_urls:
251+
## Search for images using Pixabay API
252+
image_urls = self.search_pixabay_images(refined_keyword)
203253
logging.info(f"No images found on Pexels, searching on Pixabay: {image_urls}")
204254
if not image_urls:
205255
logging.info(f"No images found on Pixabay")

0 commit comments

Comments
 (0)