Nymbo commited on
Commit
aa2cd6e
·
verified ·
1 Parent(s): e0d9a09

Adding HF inference image generation to MCP tools (Flux Krea by default)

Browse files
Files changed (1) hide show
  1. app.py +129 -3
app.py CHANGED
@@ -9,6 +9,8 @@ from __future__ import annotations
9
  import re
10
  import json
11
  import sys
 
 
12
  from io import StringIO
13
  from typing import List, Dict, Tuple, Annotated
14
 
@@ -18,6 +20,8 @@ from bs4 import BeautifulSoup
18
  from readability import Document
19
  from urllib.parse import urljoin, urldefrag, urlparse
20
  from duckduckgo_search import DDGS
 
 
21
 
22
  # Optional imports for Kokoro TTS (loaded lazily)
23
  import numpy as np
@@ -626,7 +630,7 @@ CSS_STYLES = """
626
  }
627
  /* Default: add subtitle under titles */
628
  .gradio-container h1::after {
629
- content: "Fetch Webpage | Search DuckDuckGo | Code Interpreter | Kokoro TTS";
630
  display: block;
631
  font-size: 1rem;
632
  font-weight: 500;
@@ -660,14 +664,136 @@ kokoro_interface = gr.Interface(
660
  allow_flagging="never",
661
  )
662
 
663
- # Build tabbed app including Kokoro
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
664
  demo = gr.TabbedInterface(
665
- interface_list=[fetch_interface, concise_interface, code_interface, kokoro_interface],
666
  tab_names=[
667
  "Fetch Webpage",
668
  "DuckDuckGo Search",
669
  "Python Code Executor",
670
  "Kokoro TTS",
 
671
  ],
672
  title="Tools MCP",
673
  theme="Nymbo/Nymbo_Theme",
 
9
  import re
10
  import json
11
  import sys
12
+ import os
13
+ import random
14
  from io import StringIO
15
  from typing import List, Dict, Tuple, Annotated
16
 
 
20
  from readability import Document
21
  from urllib.parse import urljoin, urldefrag, urlparse
22
  from duckduckgo_search import DDGS
23
+ from PIL import Image
24
+ from huggingface_hub import InferenceClient
25
 
26
  # Optional imports for Kokoro TTS (loaded lazily)
27
  import numpy as np
 
630
  }
631
  /* Default: add subtitle under titles */
632
  .gradio-container h1::after {
633
+ content: "Fetch Webpage | Search DuckDuckGo | Code Interpreter | Kokoro TTS | Flux Krea (Serverless)";
634
  display: block;
635
  font-size: 1rem;
636
  font-weight: 500;
 
664
  allow_flagging="never",
665
  )
666
 
667
+ # ==========================
668
+ # Flux Krea (Serverless)
669
+ # ==========================
670
+
671
+ HF_API_TOKEN = os.getenv("HF_READ_TOKEN")
672
+
673
+
674
+ def Flux_Krea_Generate( # <-- MCP tool #5 (Flux Krea - Serverless)
675
+ prompt: Annotated[str, "Text description of the image to generate."],
676
+ negative_prompt: Annotated[str, "What should NOT appear in the image." ] = (
677
+ "(deformed, distorted, disfigured), poorly drawn, bad anatomy, wrong anatomy, extra limb, "
678
+ "missing limb, floating limbs, (mutated hands and fingers), disconnected limbs, mutation, "
679
+ "mutated, ugly, disgusting, blurry, amputation, misspellings, typos"
680
+ ),
681
+ steps: Annotated[int, "Number of denoising steps (1–100). Higher = slower, potentially higher quality."] = 35,
682
+ cfg_scale: Annotated[float, "Classifier-free guidance scale (1–20). Higher = follow the prompt more closely."] = 7.0,
683
+ sampler: Annotated[str, "Sampling method label (UI only). Common options: 'DPM++ 2M Karras', 'DPM++ SDE Karras', 'Euler', 'Euler a', 'Heun', 'DDIM'."] = "DPM++ 2M Karras",
684
+ seed: Annotated[int, "Random seed for reproducibility. Use -1 for a random seed per call."] = -1,
685
+ width: Annotated[int, "Output width in pixels (64–1216, multiple of 32 recommended)."] = 1024,
686
+ height: Annotated[int, "Output height in pixels (64–1216, multiple of 32 recommended)."] = 1024,
687
+ ) -> Image.Image:
688
+ """
689
+ Generate a single image from a text prompt using the black-forest-labs/FLUX.1-Krea-dev
690
+ model via Hugging Face Inference (serverless). Returns a PIL image.
691
+
692
+ Notes (MCP):
693
+ - Per the latest Gradio MCP docs, images returned from tools are handled by the server and
694
+ converted to file URLs automatically for MCP clients. Ensure type hints and this docstring
695
+ "Args:" block are present so the tool schema is accurate.
696
+
697
+ Args:
698
+ prompt (str): Text description of the image to generate.
699
+ negative_prompt (str): What should NOT appear in the image.
700
+ steps (int): Number of denoising steps (1–100). Higher can improve quality.
701
+ cfg_scale (float): Guidance scale (1–20). Higher = follow the prompt more closely.
702
+ sampler (str): Sampling method label for UI; not all providers expose this control.
703
+ seed (int): Random seed. Use -1 to randomize on each call.
704
+ width (int): Output width in pixels (64–1216; multiples of 32 recommended).
705
+ height (int): Output height in pixels (64–1216; multiples of 32 recommended).
706
+
707
+ Returns:
708
+ PIL.Image.Image: The generated image.
709
+
710
+ Error modes:
711
+ - Raises gr.Error with a user-friendly message on auth/model/load errors.
712
+ """
713
+ if not prompt or not prompt.strip():
714
+ raise gr.Error("Please provide a non-empty prompt.")
715
+
716
+ # Slightly enhance prompt for quality (kept consistent with Serverless space)
717
+ enhanced_prompt = f"{prompt} | ultra detail, ultra elaboration, ultra quality, perfect."
718
+
719
+ # Try multiple providers for resilience
720
+ providers = ["auto", "replicate", "fal-ai"]
721
+ last_error: Exception | None = None
722
+
723
+ for provider in providers:
724
+ try:
725
+ client = InferenceClient(api_key=HF_API_TOKEN, provider=provider)
726
+ image = client.text_to_image(
727
+ prompt=enhanced_prompt,
728
+ negative_prompt=negative_prompt,
729
+ model="black-forest-labs/FLUX.1-Krea-dev",
730
+ width=width,
731
+ height=height,
732
+ num_inference_steps=steps,
733
+ guidance_scale=cfg_scale,
734
+ seed=seed if seed != -1 else random.randint(1, 1_000_000_000),
735
+ )
736
+ return image
737
+ except Exception as e: # try next provider, transform last one to friendly error
738
+ last_error = e
739
+ continue
740
+
741
+ # If we reach here, all providers failed
742
+ msg = str(last_error) if last_error else "Unknown error"
743
+ if "404" in msg:
744
+ raise gr.Error("Model not found. Ensure 'FLUX.1-Krea-dev' is accessible with your HF token.")
745
+ if "503" in msg:
746
+ raise gr.Error("The model is warming up. Please try again shortly.")
747
+ if "401" in msg or "403" in msg:
748
+ raise gr.Error("Authentication failed. Set HF_READ_TOKEN environment variable with access to the model.")
749
+ raise gr.Error(f"Image generation failed: {msg}")
750
+
751
+
752
+ flux_krea_interface = gr.Interface(
753
+ fn=Flux_Krea_Generate,
754
+ inputs=[
755
+ gr.Textbox(label="Prompt", placeholder="Enter a prompt", lines=2),
756
+ gr.Textbox(
757
+ label="Negative Prompt",
758
+ value=(
759
+ "(deformed, distorted, disfigured), poorly drawn, bad anatomy, wrong anatomy, extra limb, "
760
+ "missing limb, floating limbs, (mutated hands and fingers), disconnected limbs, mutation, "
761
+ "mutated, ugly, disgusting, blurry, amputation, misspellings, typos"
762
+ ),
763
+ lines=2,
764
+ ),
765
+ gr.Slider(minimum=1, maximum=100, value=35, step=1, label="Steps"),
766
+ gr.Slider(minimum=1.0, maximum=20.0, value=7.0, step=0.1, label="CFG Scale"),
767
+ gr.Radio(label="Sampler", value="DPM++ 2M Karras", choices=[
768
+ "DPM++ 2M Karras", "DPM++ SDE Karras", "Euler", "Euler a", "Heun", "DDIM"
769
+ ]),
770
+ gr.Slider(minimum=-1, maximum=1_000_000_000, value=-1, step=1, label="Seed (-1 = random)"),
771
+ gr.Slider(minimum=64, maximum=1216, value=1024, step=32, label="Width"),
772
+ gr.Slider(minimum=64, maximum=1216, value=1024, step=32, label="Height"),
773
+ ],
774
+ outputs=gr.Image(label="Generated Image"),
775
+ title="Flux Krea (Serverless)",
776
+ description=(
777
+ "<div style=\"text-align:center\">Generate images with FLUX.1-Krea-dev via Hugging Face Inference. "
778
+ "No input image required. 'Strength' is omitted. Set HF_READ_TOKEN as needed.</div>"
779
+ ),
780
+ api_description=(
781
+ "Generate a single image from a text prompt using black-forest-labs/FLUX.1-Krea-dev on Hugging Face Inference. "
782
+ "Parameters: prompt (str), negative_prompt (str), steps (int, 1–100), cfg_scale (float, 1–20), "
783
+ "sampler (str, label only), seed (int, -1=random), width/height (int, 64–1216). Returns a PIL.Image."
784
+ ),
785
+ allow_flagging="never",
786
+ )
787
+
788
+ # Build tabbed app including Flux Krea
789
  demo = gr.TabbedInterface(
790
+ interface_list=[fetch_interface, concise_interface, code_interface, kokoro_interface, flux_krea_interface],
791
  tab_names=[
792
  "Fetch Webpage",
793
  "DuckDuckGo Search",
794
  "Python Code Executor",
795
  "Kokoro TTS",
796
+ "Flux Krea (Serverless)",
797
  ],
798
  title="Tools MCP",
799
  theme="Nymbo/Nymbo_Theme",