import os import io import base64 import yaml import tempfile import asyncio from dotenv import load_dotenv load_dotenv() import gradio as gr # Import the updated generate_compliment_and_audio function from compliment import generate_compliment_and_audio # Function to load the configuration def load_config(): if os.path.exists("config.yaml"): with open("config.yaml", "r", encoding="utf-8") as f: config = yaml.safe_load(f) return config else: # Default values if the file doesn't exist return { "vision_model": "meta-llama/llama-4-scout-17b-16e-instruct", "compliment_prompt_de": """Betrachte die Person im Bild und mache einige ehrliche und authentische Komplimente. Konzentriere dich dabei auf positive Merkmale wie ihre Ausstrahlung, ihr Lächeln, ihre Augen, ihre Kleidung oder andere hervorstechende Eigenschaften. Verwende warme, wertschätzende Sprache. Antworte ausschließlich mit den Komplimenten, ohne zusätzliche Erklärungen oder Formatierungen.""", "compliment_prompt_en": """Observe the person in the image and give some honest and authentic compliments. Focus on positive attributes such as their aura, smile, eyes, clothing, or other outstanding features. Use warm, appreciative language. Respond exclusively with the compliments, without any additional explanations or formatting.""", "event_title": "Warmdusche App 🔥🚿", "max_tokens": 300, "temperature": 0.5, "language": "Deutsch" } # Function to save the configuration def save_config(config): with open("config.yaml", "w", encoding="utf-8") as f: yaml.dump(config, f, allow_unicode=True) class SimpleWebcamComplimentAppGradio: def __init__(self): self.config = load_config() self.vision_model = self.config.get("vision_model", "llama-3.2-90b-vision-preview") self.compliment_prompt_de = self.config.get("compliment_prompt_de", "Standard-Prompt auf Deutsch") self.compliment_prompt_en = self.config.get("compliment_prompt_en", "Standard prompt in English") self.event_title = self.config.get("event_title", "Warmdusche App 🔥🚿") self.language = self.config.get("language", "Deutsch") self.max_tokens = self.config.get("max_tokens", 300) self.temperature = self.config.get("temperature", 0.5) def encode_image_to_base64(self, image): """Convert PIL Image to base64 string""" buffered = io.BytesIO() image.save(buffered, format="JPEG") return base64.b64encode(buffered.getvalue()).decode('utf-8') # Initialize the application app = SimpleWebcamComplimentAppGradio() # Create the Gradio interface with gr.Blocks(css=""" .gradio-container tab-wrapper { background-color: #5C9A3A; } h0, h1, h2, h3, h4, h5, h6, p, div, span, label, input, button { color: #4D4D4D; } """, theme=gr.themes.Soft(radius_size=gr.themes.sizes.radius_sm, text_size=gr.themes.sizes.text_md, font=["ui-sans-serif", "system-ui"],), fill_height=True) as demo: with gr.Tabs(): with gr.TabItem("Anwendung"): event_title_markdown = gr.Markdown(f"# {app.event_title}") gr.Markdown(""" Bitte nehmen Sie ein Bild mit Ihrer Kamera auf, um ein persönliches Kompliment zu erhalten. """) with gr.Column(): # Language selection language = gr.Radio(choices=["Deutsch", "English"], label="Sprache / Language", value=app.language) with gr.Row(): # Image component with larger display image_input = gr.Image(label="Mache ein Foto", sources="webcam", type="pil", height=480, width=640) with gr.Row(): clear_button = gr.Button("Bild löschen") clear_button.click(lambda: None, None, image_input) with gr.Row(): compliment_output = gr.Textbox(label="Dein Kompliment") audio_output = gr.Audio(label="Audio-Kompliment", autoplay=True, type="filepath") # Specify type='filepath' # Function to process the image async def process_image(image, language): if image is None: return "Bitte laden Sie ein Bild hoch.", None base64_image = app.encode_image_to_base64(image) if language == "Deutsch": prompt = app.compliment_prompt_de tts_language = "de" else: prompt = app.compliment_prompt_en tts_language = "en" # Generate the compliment and audio compliment, audio_file_path = await generate_compliment_and_audio( base64_image, prompt, model=app.vision_model, max_tokens=app.max_tokens, temperature=app.temperature, tts_language=tts_language ) return compliment, audio_file_path image_input.change(process_image, inputs=[image_input, language], outputs=[compliment_output, audio_output]) with gr.TabItem("Konfiguration"): gr.Markdown("## Einstellungen") # Function to handle the uploaded config.yaml file and update the configuration def upload_config_file(file): if file is not None: with open(file.name, "r", encoding="utf-8") as f: config = yaml.safe_load(f) save_config(config) app.config = config app.vision_model = config.get("vision_model", "meta-llama/llama-4-scout-17b-16e-instruct") app.max_tokens = config.get("max_tokens", 300) app.temperature = config.get("temperature", 0.5) app.compliment_prompt_de = config.get("compliment_prompt_de", "Standard-Prompt auf Deutsch") app.compliment_prompt_en = config.get("compliment_prompt_en", "Standard prompt in English") app.event_title = config.get("event_title", "Warmdusche App 🔥🚿") app.language = config.get("language", "Deutsch") return "Konfiguration hochgeladen und aktualisiert!" else: return "Keine Datei hochgeladen." # Add the upload button and connect it to the upload_config_file function config_upload_button = gr.File(label="Upload config.yaml") upload_confirmation = gr.Textbox(label="", interactive=False) def update_text_fields(): return app.vision_model, app.max_tokens, app.temperature, app.compliment_prompt_de, app.compliment_prompt_en, app.event_title, app.language vision_model_input = gr.Textbox( label="Vision Model", value=app.vision_model, interactive=True ) max_tokens_input = gr.Number(label="Max Tokens", value=app.max_tokens) temperature_input = gr.Slider(label="Temperature", minimum=0.1, maximum=1.0, value=app.temperature) compliment_prompt_de_input = gr.Textbox( label="Kompliment Prompt (Deutsch)", value=app.compliment_prompt_de, lines=10 ) compliment_prompt_en_input = gr.Textbox( label="Compliment Prompt (English)", value=app.compliment_prompt_en, lines=10 ) event_title_input = gr.Textbox( label="Event Titel", value=app.event_title ) language_input = gr.Radio( choices=["Deutsch", "English"], label="Standardsprache", value=app.language ) save_button = gr.Button("Speichern") save_confirmation = gr.Textbox(label="", interactive=False) config_upload_button.change( upload_config_file, inputs=[config_upload_button], outputs=[upload_confirmation] ).then( update_text_fields, inputs=[], outputs=[vision_model_input, max_tokens_input, temperature_input, compliment_prompt_de_input, compliment_prompt_en_input, event_title_input, language_input] ) (vision_model_input.value, max_tokens_input.value, temperature_input.value, compliment_prompt_de_input.value, compliment_prompt_en_input.value, event_title_input.value, language_input.value) = update_text_fields() def update_config(vision_model_value, max_tokens_value, temperature_value, compliment_prompt_de_value, compliment_prompt_en_value, event_title_value, language_value): # Update der Konfiguration app.config['vision_model'] = vision_model_value app.config['max_tokens'] = max_tokens_value app.config['temperature'] = temperature_value app.config['compliment_prompt_de'] = compliment_prompt_de_value app.config['compliment_prompt_en'] = compliment_prompt_en_value app.config['event_title'] = event_title_value app.config['language'] = language_value # Speichern in config.yaml save_config(app.config) # Aktualisierung der App-Attribute app.vision_model = vision_model_value app.max_tokens = max_tokens_value app.temperature = temperature_value app.compliment_prompt_de = compliment_prompt_de_value app.compliment_prompt_en = compliment_prompt_en_value app.event_title = event_title_value app.language = language_value # Aktualisierung des Event Titels in der Markdown-Komponente return "Konfiguration gespeichert!", f"# {event_title_value}" save_button.click( update_config, inputs=[vision_model_input, max_tokens_input, temperature_input, compliment_prompt_de_input, compliment_prompt_en_input, event_title_input, language_input], outputs=[save_confirmation, event_title_markdown] ) def get_config_file(): if os.path.exists("config.yaml"): return "config.yaml" else: return None config_download_button = gr.Button("Download Konfiguration") config_file_output = gr.File(label="Download config.yaml") config_download_button.click( get_config_file, inputs=[], outputs=[config_file_output] ) # Start the application if __name__ == "__main__": demo.queue() demo.launch()