import gradio as gr from google import genai from google.genai import types from PIL import Image from io import BytesIO import base64 import os import json import random # Initialize the Google Generative AI client with the API key from environment variables try: api_key = os.environ['GEMINI_API_KEY'] except KeyError: raise ValueError("Please set the GEMINI_API_KEY environment variable.") client = genai.Client(api_key=api_key) def generate_item(tag, item_index): """ Generate a single feed item with diverse text and image. Args: tag (str): The tag to base the content on. item_index (int): Index of the item to ensure diversity. Returns: dict: A dictionary with 'text' (str) and 'image_base64' (str). """ # Define varied styles for diversity in image generation styles = [ "futuristic neon lighting", "soft pastel tones with a dreamy vibe", "vibrant and colorful pop art style", "minimalist black and white aesthetic", "retro 80s synthwave look", "golden hour sunlight with warm tones" ] perspectives = [ "a close-up view", "a wide-angle shot", "an aerial perspective", "a side profile", "a dynamic angled shot" ] style = random.choice(styles) perspective = random.choice(perspectives) # Generate text with high temperature for diversity prompt = f""" Generate a short, engaging TikTok-style caption about {tag}. Return the response as a JSON object with a single key 'caption' containing the caption text. Example: {{"caption": "Craving this yummy treat! 😍 #foodie"}} Do not include additional commentary or options. Use creative and varied language to ensure uniqueness. """ text_response = client.models.generate_content( model='gemini-2.5-flash-preview-04-17', contents=[prompt], generation_config={"temperature": 1.2} # High temperature for diversity ) # Parse JSON response to extract the caption try: response_json = json.loads(text_response.text.strip()) text = response_json['caption'] except (json.JSONDecodeError, KeyError): text = f"Obsessed with {tag}! 🔥 #{tag}" # Fallback caption # Generate a diverse image based on the tag image_prompt = f""" A high-quality visual scene representing {tag}, designed for a TikTok video. The image should be {perspective} with a {style}. Ensure the image is colorful, engaging, and has no text or letters. """ image_response = client.models.generate_images( model='imagen-3.0-generate-002', prompt=image_prompt, config=types.GenerateImagesConfig( number_of_images=1, aspect_ratio="9:16", person_generation="DONT_ALLOW" ) ) # Check if images were generated if image_response.generated_images and len(image_response.generated_images) > 0: generated_image = image_response.generated_images[0] image = Image.open(BytesIO(generated_image.image.image_bytes)) else: # Fallback to a placeholder image image = Image.new('RGB', (360, 640), color='gray') # 9:16 aspect ratio # Convert the image to base64 buffered = BytesIO() image.save(buffered, format="PNG") img_str = base64.b64encode(buffered.getvalue()).decode() return {'text': text, 'image_base64': img_str} def start_feed(tag): """ Start a new feed with the given tag by generating one initial item. Args: tag (str): The tag to generate content for. Returns: tuple: (current_tag, feed_items, html_content) """ if not tag.strip(): tag = "trending" item = generate_item(tag, 0) feed_items = [item] html_content = generate_html(feed_items) return tag, feed_items, html_content def load_more(current_tag, feed_items): """ Append a new item to the existing feed and scroll to the latest item. Args: current_tag (str): The tag currently being used for the feed. feed_items (list): The current list of feed items. Returns: tuple: (current_tag, updated_feed_items, updated_html_content) """ new_item = generate_item(current_tag, len(feed_items)) feed_items.append(new_item) html_content = generate_html(feed_items, scroll_to_latest=True) return current_tag, feed_items, html_content def generate_html(feed_items, scroll_to_latest=False): """ Generate an HTML string to display the feed items in a TikTok-like carousel. Args: feed_items (list): List of dictionaries containing 'text' and 'image_base64'. scroll_to_latest (bool): Whether to auto-scroll to the latest item. Returns: str: HTML string representing the feed. """ html_str = """