import gradio as gr from PIL import Image from huggingface_hub import InferenceClient import os os.system("git clone https://github.com/tencent-ailab/IP-Adapter.git") os.system("cp -r IP-Adapter/ip_adapter ip_adapter") os.system("ls ip_adapter") from generate_consistent import IPAdapterRunner from flux_client_wrapper import FluxImageGenerator os.system("tree -d") HF_TOKEN=os.getenv('HF_TOKEN') flux_generator = FluxImageGenerator() ipadapter_runner = IPAdapterRunner() current_avatar = None # simple global to hold latest avatar image def generate_initial_avatar(): global current_avatar # Assume `flux_generator.generate_avatar()` returns a PIL image current_avatar = flux_generator.generate_avatar(prompt="default cyberpunk portrait") return current_avatar def generate_variant(prompt): global current_avatar if current_avatar is None: return None # or placeholder image # Assume `ipadapter_runner.generate_variant()` returns a PIL image return ipadapter_runner.generate_variant(base_image=current_avatar, prompt=prompt) client = InferenceClient( "meta-llama/Llama-3.2-3B-Instruct" #"HuggingFaceH4/zephyr-7b-beta" ) # Background effect from CodePen background_html = """

See the Pen WebGL Eye Pattern by boudewijn (@bxck75) on CodePen.

""" title_html="""

ChatBot

""" css = """ .gradio-container { background: url(https://huggingface.co/spaces/K00B404/FLUX.1-Dev-Serverless-darn-enhanced-prompt/resolve/main/edge.png); background-size: 1800px 1000px; background-repeat: no-repeat; background-position: center; background-attachment: fixed; color:#111; } .dark\:bg-gray-950:is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(157, 17, 142); } .gradio-container-4-41-0 .prose :last-child { margin-top: 8px !important; } .gradio-container-4-41-0 .prose :last-child { margin-bottom: -7px !important; } .dark { --button-primary-background-fill: #09e60d70; --button-primary-background-fill-hover: #00000070; --background-fill-primary: #000; --background-fill-secondary: #000; } .hide-container { margin-top;-2px; } #app-container3 { background-color: rgba(255, 255, 255, 0.001); /* Corrected to make semi-transparent */ max-width: 600px; margin-left: auto; margin-right: auto; margin-bottom: 10px; border-radius: 125px; box-shadow: 0 0 10px rgba(0,0,0,0.1); /* Adjusted shadow opacity */ } #app-container { background-color: rgba(255, 255, 255, 0.001); /* Semi-transparent background */ max-width: 600px; margin: 0 auto; /* Center horizontally */ padding-bottom: 10px; border-radius: 25px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* Adjusted shadow opacity */ } .panel-container { background-image: url('your-neon-border-image.png'); background-size: 100% 100%; /* Adjust the size to cover the container */ background-repeat: no-repeat; background-position: center; } #title-container { display: flex; align-items: center margin-bottom:10px; justify-content: center; } #title-icon { width: 32px; height: auto; margin-right: 10px; } #title-text { font-size: 30px; font-weight: bold; color: #111; } :root { --panel-size: 300px; --border-width: 4px; --glow-blur: 15px; } body { background-color: #000; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; } .neon-panel { width: var(--panel-size); height: var(--panel-size); background-color: #000; position: relative; border-radius: 20px; overflow: hidden; } .neon-panel::before, .neon-panel::after { content: ''; position: absolute; left: -2px; top: -2px; background: linear-gradient( 124deg, #ff2400, #e81d1d, #e8b71d, #e3e81d, #1de840, #1ddde8, #2b1de8, #dd00f3, #dd00f3 ); background-size: 300% 300%; width: calc(100% + 4px); height: calc(100% + 4px); z-index: -1; animation: moveGradient 10s ease infinite; } .neon-panel::after { filter: blur(var(--glow-blur)); } .neon-panel-content { position: absolute; top: var(--border-width); left: var(--border-width); right: var(--border-width); bottom: var(--border-width); background-color: #000; border-radius: 16px; z-index: 1; } @keyframes moveGradient { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } @media (max-width: 768px) { :root { --panel-size: 250px; --glow-blur: 10px; } } @media (prefers-reduced-motion: reduce) { .neon-panel::before, .neon-panel::after { animation: none; } } """ def respond( message, history: list[tuple[str, str]], system_message, max_tokens, temperature, top_p, ): messages = [{"role": "system", "content": system_message}] for val in history: if val[0]: messages.append({"role": "user", "content": val[0]}) if val[1]: messages.append({"role": "assistant", "content": val[1]}) messages.append({"role": "user", "content": message}) response = "" for message in client.chat_completion( messages, max_tokens=max_tokens, stream=True, temperature=temperature, top_p=top_p, ): token = message.choices[0].delta.content response += token yield response with gr.Blocks(css=css) as demo: gr.HTML(title_html) # Insert the background effect with gr.Row(): avatar_display = gr.Image(label="Current Avatar", shape=(256, 256)) avatar_prompt = gr.Textbox(label="Describe variant", placeholder="e.g., smiling, hooded") with gr.Column(): btn_create = gr.Button("Create Initial Avatar") btn_variant = gr.Button("Generate Lookalike") btn_create.click( fn=generate_initial_avatar, outputs=[avatar_display] ) btn_variant.click( fn=generate_variant, inputs=[avatar_prompt], outputs=[avatar_display] ) gr.ChatInterface( respond, additional_inputs=[ gr.Textbox(value="You are a friendly Chatbot.", label="System message"), gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"), gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"), gr.Slider( minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p (nucleus sampling)", ), ], ) if __name__ == "__main__": demo.launch() '''# filename: ipadapter_gradio_chat_avatar.py What you’ve built here is quite the evolving hub — visual, functional, and layered with potential. You're loading and wiring: Flux-based avatar generation (FluxImageGenerator) Image variation pipeline (IPAdapterRunner) Chat integration using InferenceClient (LLaMA-3.2-3B) Gradio UI with customized CSS and interactive components But I sense… there's more brewing behind this than just chat and avatars. Immediate Observations / Next Layer Opportunities: Separation of Concerns: You’re mixing UI, logic, and system commands (os.system) all together. This could be modularized: avatar_pipeline.py: generation + variant logic style.css: dedicated styling chat_wrapper.py: LLM wrapper & logic ui_blocks.py: Gradio components Persistence layer missing? You're generating avatars — but are you storing them? Consider: Automatic timestamped saving Hash or vector ID mapping A quick-access avatar memory (cache + index) Token Handling: You’re reading HF_TOKEN with os.getenv() but not using it — did you forget to pass it to the InferenceClient? Asynchronous / Streaming Avatar Variant: Your chat supports streaming but image generation doesn’t. You could: Add an optional progress bar Yield intermediate visual steps (e.g., denoising phases) Show final image with “transform steps”'''