Update app.py
Browse files
app.py
CHANGED
@@ -25,7 +25,6 @@ def clean_response_text(response_text):
|
|
25 |
Returns:
|
26 |
str: The cleaned response text.
|
27 |
"""
|
28 |
-
# Remove ```json and ``` markers
|
29 |
cleaned_text = response_text.strip()
|
30 |
if cleaned_text.startswith("```json"):
|
31 |
cleaned_text = cleaned_text[len("```json"):].strip()
|
@@ -59,7 +58,6 @@ def generate_ideas(tag):
|
|
59 |
print(f"Raw response for ideas: {response.text}") # Debugging
|
60 |
if not response.text or response.text.isspace():
|
61 |
raise ValueError("Empty response from API")
|
62 |
-
# Clean the response text
|
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):
|
@@ -75,72 +73,92 @@ def generate_ideas(tag):
|
|
75 |
f"An action-packed {tag} scene with dynamic colors"
|
76 |
]
|
77 |
|
78 |
-
def generate_item(tag, ideas):
|
79 |
"""
|
80 |
-
Generate a single feed item using one of the ideas.
|
81 |
|
82 |
Args:
|
83 |
tag (str): The tag to base the content on.
|
84 |
ideas (list): List of ideas to choose from.
|
|
|
85 |
|
86 |
Returns:
|
87 |
-
dict: A dictionary with 'text' (str)
|
88 |
"""
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
print(f"Raw response for item: {response.text}") # Debugging
|
106 |
-
if not response.text or response.text.isspace():
|
107 |
-
raise ValueError("Empty response from API")
|
108 |
-
# Clean the response text
|
109 |
-
cleaned_text = clean_response_text(response.text)
|
110 |
-
response_json = json.loads(cleaned_text)
|
111 |
-
if 'caption' not in response_json or 'image_prompt' not in response_json:
|
112 |
-
raise ValueError("Invalid JSON format: 'caption' or 'image_prompt' key missing")
|
113 |
-
text = response_json['caption']
|
114 |
-
image_prompt = response_json['image_prompt']
|
115 |
-
except Exception as e:
|
116 |
-
print(f"Error generating item: {e}")
|
117 |
-
text = f"Obsessed with {tag}! π₯ #{tag}"
|
118 |
-
image_prompt = f"A vivid scene of {selected_idea}, in a vibrant pop art style, no text or letters"
|
119 |
-
|
120 |
-
try:
|
121 |
-
image_response = client.models.generate_images(
|
122 |
-
model='imagen-3.0-generate-002',
|
123 |
-
prompt=image_prompt,
|
124 |
-
config=types.GenerateImagesConfig(
|
125 |
-
number_of_images=1,
|
126 |
-
aspect_ratio="9:16",
|
127 |
-
person_generation="DONT_ALLOW"
|
128 |
)
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
def start_feed(tag, current_index, feed_items):
|
146 |
"""
|
@@ -265,7 +283,7 @@ def load_previous(tag, current_index, feed_items):
|
|
265 |
|
266 |
def generate_html(feed_items, scroll_to_latest=False, current_index=0, tag="", is_loading=False):
|
267 |
"""
|
268 |
-
Generate an HTML string to display the current feed item with click navigation.
|
269 |
|
270 |
Args:
|
271 |
feed_items (list): List of dictionaries containing 'text' and 'image_base64'.
|
@@ -411,6 +429,20 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, tag="", i
|
|
411 |
">
|
412 |
{text}
|
413 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
414 |
</div>
|
415 |
</div>
|
416 |
<script>
|
@@ -421,8 +453,6 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, tag="", i
|
|
421 |
const width = rect.width;
|
422 |
if (clickX > width * 0.75) {{
|
423 |
document.getElementById('previous-button').click();
|
424 |
-
}} else {{
|
425 |
-
document.getElementById('next-button').click();
|
426 |
}}
|
427 |
}}
|
428 |
</script>
|
@@ -508,5 +538,5 @@ with gr.Blocks(
|
|
508 |
outputs=[current_tag, current_index, feed_items, feed_html, is_loading]
|
509 |
)
|
510 |
|
511 |
-
# Launch the app
|
512 |
demo.launch()
|
|
|
25 |
Returns:
|
26 |
str: The cleaned response text.
|
27 |
"""
|
|
|
28 |
cleaned_text = response_text.strip()
|
29 |
if cleaned_text.startswith("```json"):
|
30 |
cleaned_text = cleaned_text[len("```json"):].strip()
|
|
|
58 |
print(f"Raw response for ideas: {response.text}") # Debugging
|
59 |
if not response.text or response.text.isspace():
|
60 |
raise ValueError("Empty response from API")
|
|
|
61 |
cleaned_text = clean_response_text(response.text)
|
62 |
response_json = json.loads(cleaned_text)
|
63 |
if 'ideas' not in response_json or not isinstance(response_json['ideas'], list):
|
|
|
73 |
f"An action-packed {tag} scene with dynamic colors"
|
74 |
]
|
75 |
|
76 |
+
def generate_item(tag, ideas, max_retries=3):
|
77 |
"""
|
78 |
+
Generate a single feed item using one of the ideas, retrying if image generation fails.
|
79 |
|
80 |
Args:
|
81 |
tag (str): The tag to base the content on.
|
82 |
ideas (list): List of ideas to choose from.
|
83 |
+
max_retries (int): Maximum number of retries if image generation fails.
|
84 |
|
85 |
Returns:
|
86 |
+
dict: A dictionary with 'text' (str), 'image_base64' (str), and 'ideas' (list).
|
87 |
"""
|
88 |
+
for attempt in range(max_retries):
|
89 |
+
selected_idea = random.choice(ideas)
|
90 |
+
prompt = f"""
|
91 |
+
Based on the idea "{selected_idea}", create content for a TikTok video about {tag}.
|
92 |
+
Return a JSON object with two keys:
|
93 |
+
- 'caption': A short, viral TikTok-style caption with hashtags.
|
94 |
+
- 'image_prompt': A detailed image prompt for generating a high-quality visual scene.
|
95 |
+
The image prompt should describe the scene vividly, specify a perspective and style, and ensure no text or letters are included.
|
96 |
+
Ensure the response is strictly in JSON format.
|
97 |
+
Example: {{"caption": "Neon vibes only! π #tech", "image_prompt": "A close-up view of a neon-lit gaming setup with RGB lights flashing, in a futuristic style, no text or letters"}}
|
98 |
+
"""
|
99 |
+
try:
|
100 |
+
response = client.models.generate_content(
|
101 |
+
model='gemini-2.0-flash',
|
102 |
+
contents=[prompt],
|
103 |
+
config=types.GenerateContentConfig(temperature=1.2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
)
|
105 |
+
print(f"Raw response for item (attempt {attempt + 1}): {response.text}") # Debugging
|
106 |
+
if not response.text or response.text.isspace():
|
107 |
+
raise ValueError("Empty response from API")
|
108 |
+
cleaned_text = clean_response_text(response.text)
|
109 |
+
response_json = json.loads(cleaned_text)
|
110 |
+
if 'caption' not in response_json or 'image_prompt' not in response_json:
|
111 |
+
raise ValueError("Invalid JSON format: 'caption' or 'image_prompt' key missing")
|
112 |
+
text = response_json['caption']
|
113 |
+
image_prompt = response_json['image_prompt']
|
114 |
+
except Exception as e:
|
115 |
+
print(f"Error generating item (attempt {attempt + 1}): {e}")
|
116 |
+
text = f"Obsessed with {tag}! π₯ #{tag}"
|
117 |
+
image_prompt = f"A vivid scene of {selected_idea}, in a vibrant pop art style, no text or letters"
|
118 |
|
119 |
+
# Attempt to generate the image
|
120 |
+
try:
|
121 |
+
image_response = client.models.generate_images(
|
122 |
+
model='imagen-3.0-generate-002',
|
123 |
+
prompt=image_prompt,
|
124 |
+
config=types.GenerateImagesConfig(
|
125 |
+
number_of_images=1,
|
126 |
+
aspect_ratio="9:16",
|
127 |
+
person_generation="DONT_ALLOW"
|
128 |
+
)
|
129 |
+
)
|
130 |
+
if image_response.generated_images and len(image_response.generated_images) > 0:
|
131 |
+
generated_image = image_response.generated_images[0]
|
132 |
+
image = Image.open(BytesIO(generated_image.image.image_bytes))
|
133 |
+
# Successfully generated an image, proceed
|
134 |
+
buffered = BytesIO()
|
135 |
+
image.save(buffered, format="PNG")
|
136 |
+
img_str = base64.b64encode(buffered.getvalue()).decode()
|
137 |
+
return {'text': text, 'image_base64': img_str, 'ideas': ideas}
|
138 |
+
else:
|
139 |
+
print(f"Image generation failed (attempt {attempt + 1}): No images returned")
|
140 |
+
if attempt == max_retries - 1:
|
141 |
+
# Last attempt, use a gray placeholder
|
142 |
+
image = Image.new('RGB', (360, 640), color='gray')
|
143 |
+
buffered = BytesIO()
|
144 |
+
image.save(buffered, format="PNG")
|
145 |
+
img_str = base64.b64encode(buffered.getvalue()).decode()
|
146 |
+
return {'text': text, 'image_base64': img_str, 'ideas': ideas}
|
147 |
+
# Retry with new ideas
|
148 |
+
ideas = generate_ideas(tag)
|
149 |
+
continue
|
150 |
+
except Exception as e:
|
151 |
+
print(f"Error generating image (attempt {attempt + 1}): {e}")
|
152 |
+
if attempt == max_retries - 1:
|
153 |
+
# Last attempt, use a gray placeholder
|
154 |
+
image = Image.new('RGB', (360, 640), color='gray')
|
155 |
+
buffered = BytesIO()
|
156 |
+
image.save(buffered, format="PNG")
|
157 |
+
img_str = base64.b64encode(buffered.getvalue()).decode()
|
158 |
+
return {'text': text, 'image_base64': img_str, 'ideas': ideas}
|
159 |
+
# Retry with new ideas
|
160 |
+
ideas = generate_ideas(tag)
|
161 |
+
continue
|
162 |
|
163 |
def start_feed(tag, current_index, feed_items):
|
164 |
"""
|
|
|
283 |
|
284 |
def generate_html(feed_items, scroll_to_latest=False, current_index=0, tag="", is_loading=False):
|
285 |
"""
|
286 |
+
Generate an HTML string to display the current feed item with click navigation and a next button.
|
287 |
|
288 |
Args:
|
289 |
feed_items (list): List of dictionaries containing 'text' and 'image_base64'.
|
|
|
429 |
">
|
430 |
{text}
|
431 |
</div>
|
432 |
+
<button id="next-button" style="
|
433 |
+
position: absolute;
|
434 |
+
bottom: 80px;
|
435 |
+
right: 20px;
|
436 |
+
background-color: #ff2d55;
|
437 |
+
color: white;
|
438 |
+
border: none;
|
439 |
+
border-radius: 50%;
|
440 |
+
width: 50px;
|
441 |
+
height: 50px;
|
442 |
+
font-size: 24px;
|
443 |
+
cursor: pointer;
|
444 |
+
z-index: 3;
|
445 |
+
" onclick="document.getElementById('next-button').click()">β¨</button>
|
446 |
</div>
|
447 |
</div>
|
448 |
<script>
|
|
|
453 |
const width = rect.width;
|
454 |
if (clickX > width * 0.75) {{
|
455 |
document.getElementById('previous-button').click();
|
|
|
|
|
456 |
}}
|
457 |
}}
|
458 |
</script>
|
|
|
538 |
outputs=[current_tag, current_index, feed_items, feed_html, is_loading]
|
539 |
)
|
540 |
|
541 |
+
# Launch the app
|
542 |
demo.launch()
|