Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import google.generativeai as genai
|
3 |
+
from google.genai import types
|
4 |
+
from PIL import Image
|
5 |
+
from io import BytesIO
|
6 |
+
import base64
|
7 |
+
import os
|
8 |
+
|
9 |
+
# Initialize the Google Generative AI client with the API key from environment variables
|
10 |
+
api_key = os.getenv("GEMINI_API_KEY")
|
11 |
+
genai.configure(api_key=api_key)
|
12 |
+
|
13 |
+
# Initialize the Gemini model for text generation
|
14 |
+
gemini_model = genai.GenerativeModel('gemini-2.5-flash-preview-04-17')
|
15 |
+
|
16 |
+
def generate_item(tag):
|
17 |
+
"""
|
18 |
+
Generate a single feed item consisting of text from Gemini LLM and an image from Imagen.
|
19 |
+
|
20 |
+
Args:
|
21 |
+
tag (str): The tag to base the content on.
|
22 |
+
|
23 |
+
Returns:
|
24 |
+
dict: A dictionary with 'text' (str) and 'image_base64' (str).
|
25 |
+
"""
|
26 |
+
# Generate text using Gemini LLM
|
27 |
+
prompt = f"Generate a short, engaging post about {tag} in the style of a TikTok caption."
|
28 |
+
text_response = gemini_model.generate_content(prompt)
|
29 |
+
text = text_response.text.strip()
|
30 |
+
|
31 |
+
# Generate an image using Imagen based on the generated text
|
32 |
+
image_response = genai.generate_images(
|
33 |
+
model='imagen-3.0-generate-002',
|
34 |
+
prompt=text,
|
35 |
+
config=types.GenerateImagesConfig(
|
36 |
+
number_of_images=1,
|
37 |
+
aspect_ratio="9:16", # TikTok-style vertical video ratio
|
38 |
+
person_generation="DONT_ALLOW" # Avoid generating people
|
39 |
+
)
|
40 |
+
)
|
41 |
+
generated_image = image_response.generated_images[0]
|
42 |
+
image = Image.open(BytesIO(generated_image.image.image_bytes))
|
43 |
+
|
44 |
+
# Convert the image to base64 for HTML display
|
45 |
+
buffered = BytesIO()
|
46 |
+
image.save(buffered, format="PNG")
|
47 |
+
img_str = base64.b64encode(buffered.getvalue()).decode()
|
48 |
+
|
49 |
+
return {'text': text, 'image_base64': img_str}
|
50 |
+
|
51 |
+
def start_feed(tag):
|
52 |
+
"""
|
53 |
+
Start a new feed with the given tag by generating one initial item.
|
54 |
+
|
55 |
+
Args:
|
56 |
+
tag (str): The tag to generate content for.
|
57 |
+
|
58 |
+
Returns:
|
59 |
+
tuple: (current_tag, feed_items, html_content)
|
60 |
+
"""
|
61 |
+
item = generate_item(tag)
|
62 |
+
feed_items = [item]
|
63 |
+
html_content = generate_html(feed_items)
|
64 |
+
return tag, feed_items, html_content
|
65 |
+
|
66 |
+
def load_more(current_tag, feed_items):
|
67 |
+
"""
|
68 |
+
Append a new item to the existing feed using the current tag.
|
69 |
+
|
70 |
+
Args:
|
71 |
+
current_tag (str): The tag currently being used for the feed.
|
72 |
+
feed_items (list): The current list of feed items.
|
73 |
+
|
74 |
+
Returns:
|
75 |
+
tuple: (current_tag, updated_feed_items, updated_html_content)
|
76 |
+
"""
|
77 |
+
new_item = generate_item(current_tag)
|
78 |
+
feed_items.append(new_item)
|
79 |
+
html_content = generate_html(feed_items)
|
80 |
+
return current_tag, feed_items, html_content
|
81 |
+
|
82 |
+
def generate_html(feed_items):
|
83 |
+
"""
|
84 |
+
Generate an HTML string to display the feed items.
|
85 |
+
|
86 |
+
Args:
|
87 |
+
feed_items (list): List of dictionaries containing 'text' and 'image_base64'.
|
88 |
+
|
89 |
+
Returns:
|
90 |
+
str: HTML string representing the feed.
|
91 |
+
"""
|
92 |
+
html_str = '<div style="max-height: 600px; overflow-y: auto; border: 1px solid #ccc; padding: 10px;">'
|
93 |
+
for item in feed_items:
|
94 |
+
html_str += f"""
|
95 |
+
<div style="margin-bottom: 20px; border-bottom: 1px solid #eee; padding-bottom: 20px;">
|
96 |
+
<p style="font-size: 16px; margin-bottom: 10px;">{item['text']}</p>
|
97 |
+
<img src="data:image/png;base64,{item['image_base64']}" style="width: 100%; max-width: 300px; height: auto;">
|
98 |
+
</div>
|
99 |
+
"""
|
100 |
+
html_str += '</div>'
|
101 |
+
return html_str
|
102 |
+
|
103 |
+
# Define the Gradio interface
|
104 |
+
with gr.Blocks(title="TikTok-Style Infinite Feed") as demo:
|
105 |
+
# Header
|
106 |
+
gr.Markdown("# TikTok-Style Infinite Feed Generator")
|
107 |
+
gr.Markdown("Enter a tag or select a suggested one to generate a scrollable feed of AI-generated content!")
|
108 |
+
|
109 |
+
# Input components
|
110 |
+
with gr.Row():
|
111 |
+
suggested_tags = gr.Dropdown(
|
112 |
+
choices=["technology", "nature", "art", "food"],
|
113 |
+
label="Suggested Tags",
|
114 |
+
value="nature" # Default value
|
115 |
+
)
|
116 |
+
tag_input = gr.Textbox(label="Enter a Custom Tag", value="nature")
|
117 |
+
|
118 |
+
# Buttons
|
119 |
+
with gr.Row():
|
120 |
+
start_button = gr.Button("Start Feed")
|
121 |
+
load_more_button = gr.Button("Load More")
|
122 |
+
|
123 |
+
# Output display
|
124 |
+
feed_html = gr.HTML(label="Your Feed")
|
125 |
+
|
126 |
+
# State variables to maintain feed and tag
|
127 |
+
current_tag = gr.State(value="")
|
128 |
+
feed_items = gr.State(value=[])
|
129 |
+
|
130 |
+
# Event handlers
|
131 |
+
def set_tag(selected_tag):
|
132 |
+
"""Update the tag input when a suggested tag is selected."""
|
133 |
+
return selected_tag
|
134 |
+
|
135 |
+
suggested_tags.change(fn=set_tag, inputs=suggested_tags, outputs=tag_input)
|
136 |
+
start_button.click(
|
137 |
+
fn=start_feed,
|
138 |
+
inputs=tag_input,
|
139 |
+
outputs=[current_tag, feed_items, feed_html]
|
140 |
+
)
|
141 |
+
load_more_button.click(
|
142 |
+
fn=load_more,
|
143 |
+
inputs=[current_tag, feed_items],
|
144 |
+
outputs=[current_tag, feed_items, feed_html]
|
145 |
+
)
|
146 |
+
|
147 |
+
# Launch the app
|
148 |
+
demo.launch()
|