Update app.py
Browse files
app.py
CHANGED
@@ -45,11 +45,19 @@ def generate_ideas(user_input):
|
|
45 |
list: A list of ideas as strings.
|
46 |
"""
|
47 |
prompt = f"""
|
48 |
-
The user has provided the concept: "{user_input}".
|
49 |
-
Each idea
|
|
|
50 |
Return the response as a JSON object with a single key 'ideas' containing a list of 5 ideas.
|
51 |
Ensure the response is strictly in JSON format.
|
52 |
-
Example
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
"""
|
54 |
try:
|
55 |
response = client.models.generate_content(
|
@@ -62,9 +70,22 @@ def generate_ideas(user_input):
|
|
62 |
raise ValueError("Empty response from API")
|
63 |
cleaned_text = clean_response_text(response.text)
|
64 |
response_json = json.loads(cleaned_text)
|
65 |
-
if 'ideas' not in response_json or not isinstance(response_json['ideas'], list):
|
66 |
-
raise ValueError("Invalid JSON format: 'ideas' key missing
|
67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
except Exception as e:
|
69 |
print(f"Error generating ideas: {e}")
|
70 |
return [
|
@@ -161,7 +182,6 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
161 |
number_of_videos=2,
|
162 |
duration_seconds=8,
|
163 |
negative_prompt="blurry, low quality, text, letters"
|
164 |
-
# Removed enhance_prompt=True since it's the default
|
165 |
)
|
166 |
)
|
167 |
# Wait for videos to generate
|
@@ -183,10 +203,19 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
183 |
raise ValueError(f"Video {n} is invalid or missing video data")
|
184 |
fname = f'with_image_input{n}.mp4'
|
185 |
print(f"Generated video: {fname}")
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
video_base64_list.append(video_base64)
|
191 |
except Exception as e:
|
192 |
print(f"Error generating video: {e}")
|
@@ -476,9 +505,10 @@ def generate_share_links(image_base64, video_base64_list, caption):
|
|
476 |
def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_input="", is_loading=False):
|
477 |
"""
|
478 |
Generate an HTML string to display the current feed item with click navigation.
|
|
|
479 |
|
480 |
Args:
|
481 |
-
feed_items (list): List of dictionaries containing 'text' and '
|
482 |
scroll_to_latest (bool): Whether to auto-scroll to the latest item (not used here).
|
483 |
current_index (int): The index of the item to display.
|
484 |
user_input (str): The user's input concept or idea for loading messages.
|
@@ -576,7 +606,37 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_inpu
|
|
576 |
"""
|
577 |
|
578 |
item = feed_items[current_index]
|
579 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
580 |
<div id="feed-container" style="
|
581 |
display: flex;
|
582 |
flex-direction: column;
|
@@ -599,15 +659,7 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_inpu
|
|
599 |
overflow: hidden;
|
600 |
cursor: pointer;
|
601 |
" onclick="handleClick(event)">
|
602 |
-
|
603 |
-
width: 100%;
|
604 |
-
height: 100%;
|
605 |
-
object-fit: cover;
|
606 |
-
position: absolute;
|
607 |
-
top: 0;
|
608 |
-
left: 0;
|
609 |
-
z-index: 1;
|
610 |
-
">
|
611 |
<div style="
|
612 |
position: relative;
|
613 |
z-index: 2;
|
@@ -619,14 +671,14 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_inpu
|
|
619 |
font-weight: bold;
|
620 |
text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
|
621 |
">
|
622 |
-
{text}
|
623 |
</div>
|
624 |
</div>
|
625 |
</div>
|
626 |
<script>
|
627 |
function handleClick(event) {{
|
628 |
-
const
|
629 |
-
const rect =
|
630 |
const clickX = event.clientX - rect.left;
|
631 |
const width = rect.width;
|
632 |
if (clickX > width * 0.75) {{
|
@@ -635,8 +687,7 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_inpu
|
|
635 |
}}
|
636 |
</script>
|
637 |
<button id="previous-button" style="display: none;" onclick="document.getElementById('previous-button').click()"></button>
|
638 |
-
"""
|
639 |
-
|
640 |
return html_str
|
641 |
|
642 |
# Define the Gradio interface
|
|
|
45 |
list: A list of ideas as strings.
|
46 |
"""
|
47 |
prompt = f"""
|
48 |
+
The user has provided the concept: "{user_input}". You must generate 5 diverse and creative ideas for a TikTok video that are directly and explicitly related to "{user_input}".
|
49 |
+
Each idea must clearly incorporate and focus on the core theme of "{user_input}" without deviating into unrelated topics.
|
50 |
+
Each idea should be a short sentence describing a specific scene or concept.
|
51 |
Return the response as a JSON object with a single key 'ideas' containing a list of 5 ideas.
|
52 |
Ensure the response is strictly in JSON format.
|
53 |
+
Example for "blindfolded Rubik's Cube challenge":
|
54 |
+
{{"ideas": [
|
55 |
+
"A blindfolded speedcubing competition with dramatic music",
|
56 |
+
"A close-up of a person solving a Rubik's Cube blindfolded under a spotlight",
|
57 |
+
"A time-lapse of a blindfolded Rubik's Cube solve with colorful lighting",
|
58 |
+
"A blindfolded Rubik's Cube challenge in a futuristic setting",
|
59 |
+
"A split-screen of two people racing to solve a Rubik's Cube blindfolded"
|
60 |
+
]}}
|
61 |
"""
|
62 |
try:
|
63 |
response = client.models.generate_content(
|
|
|
70 |
raise ValueError("Empty response from API")
|
71 |
cleaned_text = clean_response_text(response.text)
|
72 |
response_json = json.loads(cleaned_text)
|
73 |
+
if 'ideas' not in response_json or not isinstance(response_json['ideas'], list) or len(response_json['ideas']) != 5:
|
74 |
+
raise ValueError("Invalid JSON format: 'ideas' key missing, not a list, or incorrect length")
|
75 |
+
|
76 |
+
# Validate that ideas are related to user_input
|
77 |
+
ideas = response_json['ideas']
|
78 |
+
for idea in ideas:
|
79 |
+
if user_input.lower() not in idea.lower():
|
80 |
+
print(f"Warning: Idea '{idea}' does not seem related to '{user_input}'. Falling back to default ideas.")
|
81 |
+
return [
|
82 |
+
f"A dramatic {user_input} scene with cinematic lighting",
|
83 |
+
f"A close-up of {user_input} in a futuristic setting",
|
84 |
+
f"A high-energy {user_input} moment with vibrant colors",
|
85 |
+
f"A serene {user_input} scene with soft focus",
|
86 |
+
f"An action-packed {user_input} challenge with dynamic angles"
|
87 |
+
]
|
88 |
+
return ideas
|
89 |
except Exception as e:
|
90 |
print(f"Error generating ideas: {e}")
|
91 |
return [
|
|
|
182 |
number_of_videos=2,
|
183 |
duration_seconds=8,
|
184 |
negative_prompt="blurry, low quality, text, letters"
|
|
|
185 |
)
|
186 |
)
|
187 |
# Wait for videos to generate
|
|
|
203 |
raise ValueError(f"Video {n} is invalid or missing video data")
|
204 |
fname = f'with_image_input{n}.mp4'
|
205 |
print(f"Generated video: {fname}")
|
206 |
+
# Download the video and get the raw bytes
|
207 |
+
video_data = client.files.download(file=video.video)
|
208 |
+
# Ensure video_data is in bytes
|
209 |
+
if isinstance(video_data, bytes):
|
210 |
+
video_bytes = video_data
|
211 |
+
else:
|
212 |
+
# If video_data is a file-like object, read the bytes
|
213 |
+
video_buffer = BytesIO()
|
214 |
+
for chunk in video_data:
|
215 |
+
video_buffer.write(chunk)
|
216 |
+
video_bytes = video_buffer.getvalue()
|
217 |
+
# Encode the video bytes as base64
|
218 |
+
video_base64 = base64.b64encode(video_bytes).decode()
|
219 |
video_base64_list.append(video_base64)
|
220 |
except Exception as e:
|
221 |
print(f"Error generating video: {e}")
|
|
|
505 |
def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_input="", is_loading=False):
|
506 |
"""
|
507 |
Generate an HTML string to display the current feed item with click navigation.
|
508 |
+
Displays a video if available, otherwise falls back to the image.
|
509 |
|
510 |
Args:
|
511 |
+
feed_items (list): List of dictionaries containing 'text', 'image_base64', and 'video_base64_list'.
|
512 |
scroll_to_latest (bool): Whether to auto-scroll to the latest item (not used here).
|
513 |
current_index (int): The index of the item to display.
|
514 |
user_input (str): The user's input concept or idea for loading messages.
|
|
|
606 |
"""
|
607 |
|
608 |
item = feed_items[current_index]
|
609 |
+
# Check if there are videos to display; if so, show the first video
|
610 |
+
if item['video_base64_list']:
|
611 |
+
media_element = f"""
|
612 |
+
<video id="feed-video" controls style="
|
613 |
+
width: 100%;
|
614 |
+
height: 100%;
|
615 |
+
object-fit: cover;
|
616 |
+
position: absolute;
|
617 |
+
top: 0;
|
618 |
+
left: 0;
|
619 |
+
z-index: 1;
|
620 |
+
">
|
621 |
+
<source src="data:video/mp4;base64,{item['video_base64_list'][0]}" type="video/mp4">
|
622 |
+
Your browser does not support the video tag.
|
623 |
+
</video>
|
624 |
+
"""
|
625 |
+
else:
|
626 |
+
# Fallback to image if no video is available
|
627 |
+
media_element = f"""
|
628 |
+
<img id="feed-image" src="data:image/png;base64,{item['image_base64']}" style="
|
629 |
+
width: 100%;
|
630 |
+
height: 100%;
|
631 |
+
object-fit: cover;
|
632 |
+
position: absolute;
|
633 |
+
top: 0;
|
634 |
+
left: 0;
|
635 |
+
z-index: 1;
|
636 |
+
">
|
637 |
+
"""
|
638 |
+
|
639 |
+
html_str = f"""
|
640 |
<div id="feed-container" style="
|
641 |
display: flex;
|
642 |
flex-direction: column;
|
|
|
659 |
overflow: hidden;
|
660 |
cursor: pointer;
|
661 |
" onclick="handleClick(event)">
|
662 |
+
{media_element}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
663 |
<div style="
|
664 |
position: relative;
|
665 |
z-index: 2;
|
|
|
671 |
font-weight: bold;
|
672 |
text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
|
673 |
">
|
674 |
+
{item['text']}
|
675 |
</div>
|
676 |
</div>
|
677 |
</div>
|
678 |
<script>
|
679 |
function handleClick(event) {{
|
680 |
+
const media = document.getElementById('feed-video') || document.getElementById('feed-image');
|
681 |
+
const rect = media.getBoundingClientRect();
|
682 |
const clickX = event.clientX - rect.left;
|
683 |
const width = rect.width;
|
684 |
if (clickX > width * 0.75) {{
|
|
|
687 |
}}
|
688 |
</script>
|
689 |
<button id="previous-button" style="display: none;" onclick="document.getElementById('previous-button').click()"></button>
|
690 |
+
"""
|
|
|
691 |
return html_str
|
692 |
|
693 |
# Define the Gradio interface
|