Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files
README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
app_file:
|
| 9 |
pinned: false
|
|
|
|
| 10 |
---
|
| 11 |
-
|
| 12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
+
|
| 2 |
---
|
| 3 |
+
title: mcp_image_app
|
| 4 |
+
emoji: 🔥
|
| 5 |
+
colorFrom: indigo
|
| 6 |
+
colorTo: indigo
|
| 7 |
sdk: gradio
|
| 8 |
+
sdk_version: 6.0.0
|
| 9 |
+
app_file: run.py
|
| 10 |
pinned: false
|
| 11 |
+
hf_oauth: true
|
| 12 |
---
|
|
|
|
|
|
run.ipynb
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: mcp_image_app"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import tempfile\n", "from PIL import Image\n", "import numpy as np\n", "\n", "\n", "@gr.mcp.tool(\n", " _meta={\n", " \"openai/outputTemplate\": \"ui://widget/app.html\",\n", " \"openai/resultCanProduceWidget\": True,\n", " \"openai/widgetAccessible\": True,\n", " }\n", ")\n", "\n", "def power_law_image(input_path: str, gamma: float = 0.5) -> str:\n", " \"\"\"\n", " Applies a power-law (gamma) transformation to an image file and saves\n", " the result to a temporary file.\n", "\n", " Args:\n", " input_path (str): Path to the input image.\n", " gamma (float): Power-law exponent. <1 brightens, >1 darkens.\n", "\n", " Returns:\n", " str: Path to the saved temporary output image.\n", " \"\"\"\n", " img = Image.open(input_path).convert(\"RGB\")\n", " arr = np.array(img, dtype=np.float32) / 255.0\n", " arr = np.power(arr, gamma)\n", " arr = np.clip(arr * 255, 0, 255).astype(np.uint8)\n", " out_img = Image.fromarray(arr)\n", "\n", " tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=\".png\")\n", " out_img.save(tmp_file.name)\n", " tmp_file.close()\n", "\n", " return tmp_file.name\n", "\n", "\n", "@gr.mcp.resource(\"ui://widget/app.html\", mime_type=\"text/html+skybridge\")\n", "def app_html():\n", " visual = \"\"\"\n", " <style>\n", " #image-container {\n", " position: relative;\n", " display: inline-block;\n", " max-width: 100%;\n", " }\n", " #image-display {\n", " max-width: 100%;\n", " height: auto;\n", " display: block;\n", " border-radius: 8px;\n", " }\n", " #brighten-btn {\n", " position: absolute;\n", " bottom: 16px;\n", " right: 26px;\n", " padding: 12px 24px;\n", " background: #1a1a1a;\n", " color: white;\n", " border: none;\n", " border-radius: 8px;\n", " font-weight: 600;\n", " cursor: pointer;\n", " box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n", " }\n", " #brighten-btn:hover {\n", " background: #000000;\n", " }\n", " </style>\n", " <div id=\"image-container\">\n", " <img id=\"image-display\" alt=\"Processed image\" />\n", " <button id=\"brighten-btn\">Brighten</button>\n", " </div>\n", " <script>\n", " const imageEl = document.getElementById('image-display');\n", " const btnEl = document.getElementById('brighten-btn');\n", "\n", " function extractImageUrl(data) {\n", " if (data?.text?.startsWith('Image URL: ')) {\n", " return data.text.substring('Image URL: '.length).trim();\n", " }\n", " if (data?.content) {\n", " for (const item of data.content) {\n", " if (item.type === 'text' && item.text?.startsWith('Image URL: ')) {\n", " return item.text.substring('Image URL: '.length).trim();\n", " }\n", " }\n", " }\n", " }\n", "\n", " function render() {\n", " const url = extractImageUrl(window.openai?.toolOutput);\n", " if (url) imageEl.src = url;\n", " }\n", "\n", " async function brightenImage() {\n", " btnEl.disabled = true;\n", " btnEl.textContent = 'Brightening...';\n", " const result = await window.openai.callTool('power_law_image', {\n", " input_path: imageEl.src\n", " });\n", " const newUrl = extractImageUrl(result);\n", " if (newUrl) imageEl.src = newUrl;\n", " btnEl.disabled = false;\n", " btnEl.textContent = 'Brighten';\n", " }\n", "\n", " btnEl.addEventListener('click', brightenImage);\n", " window.addEventListener(\"openai:set_globals\", (event) => {\n", " if (event.detail?.globals?.toolOutput) render();\n", " }, { passive: true });\n", "\n", " render();\n", " </script>\n", " \"\"\"\n", " return visual\n", "\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " with gr.Column():\n", " original_image = gr.Image(label=\"Original Image\", type=\"filepath\")\n", " btn = gr.Button(\"Brighten Image\")\n", " with gr.Column():\n", " output_image = gr.Image(label=\"Output Image\", type=\"filepath\")\n", " html = gr.Code(language=\"html\", max_lines=20)\n", "\n", " btn.click(power_law_image, inputs=original_image, outputs=original_image)\n", " btn.click(app_html, outputs=html)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch(mcp_server=True, share=True)\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
run.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import tempfile
|
| 3 |
+
from PIL import Image
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
@gr.mcp.tool(
|
| 8 |
+
_meta={
|
| 9 |
+
"openai/outputTemplate": "ui://widget/app.html",
|
| 10 |
+
"openai/resultCanProduceWidget": True,
|
| 11 |
+
"openai/widgetAccessible": True,
|
| 12 |
+
}
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
def power_law_image(input_path: str, gamma: float = 0.5) -> str:
|
| 16 |
+
"""
|
| 17 |
+
Applies a power-law (gamma) transformation to an image file and saves
|
| 18 |
+
the result to a temporary file.
|
| 19 |
+
|
| 20 |
+
Args:
|
| 21 |
+
input_path (str): Path to the input image.
|
| 22 |
+
gamma (float): Power-law exponent. <1 brightens, >1 darkens.
|
| 23 |
+
|
| 24 |
+
Returns:
|
| 25 |
+
str: Path to the saved temporary output image.
|
| 26 |
+
"""
|
| 27 |
+
img = Image.open(input_path).convert("RGB")
|
| 28 |
+
arr = np.array(img, dtype=np.float32) / 255.0
|
| 29 |
+
arr = np.power(arr, gamma)
|
| 30 |
+
arr = np.clip(arr * 255, 0, 255).astype(np.uint8)
|
| 31 |
+
out_img = Image.fromarray(arr)
|
| 32 |
+
|
| 33 |
+
tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
|
| 34 |
+
out_img.save(tmp_file.name)
|
| 35 |
+
tmp_file.close()
|
| 36 |
+
|
| 37 |
+
return tmp_file.name
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
@gr.mcp.resource("ui://widget/app.html", mime_type="text/html+skybridge")
|
| 41 |
+
def app_html():
|
| 42 |
+
visual = """
|
| 43 |
+
<style>
|
| 44 |
+
#image-container {
|
| 45 |
+
position: relative;
|
| 46 |
+
display: inline-block;
|
| 47 |
+
max-width: 100%;
|
| 48 |
+
}
|
| 49 |
+
#image-display {
|
| 50 |
+
max-width: 100%;
|
| 51 |
+
height: auto;
|
| 52 |
+
display: block;
|
| 53 |
+
border-radius: 8px;
|
| 54 |
+
}
|
| 55 |
+
#brighten-btn {
|
| 56 |
+
position: absolute;
|
| 57 |
+
bottom: 16px;
|
| 58 |
+
right: 26px;
|
| 59 |
+
padding: 12px 24px;
|
| 60 |
+
background: #1a1a1a;
|
| 61 |
+
color: white;
|
| 62 |
+
border: none;
|
| 63 |
+
border-radius: 8px;
|
| 64 |
+
font-weight: 600;
|
| 65 |
+
cursor: pointer;
|
| 66 |
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
| 67 |
+
}
|
| 68 |
+
#brighten-btn:hover {
|
| 69 |
+
background: #000000;
|
| 70 |
+
}
|
| 71 |
+
</style>
|
| 72 |
+
<div id="image-container">
|
| 73 |
+
<img id="image-display" alt="Processed image" />
|
| 74 |
+
<button id="brighten-btn">Brighten</button>
|
| 75 |
+
</div>
|
| 76 |
+
<script>
|
| 77 |
+
const imageEl = document.getElementById('image-display');
|
| 78 |
+
const btnEl = document.getElementById('brighten-btn');
|
| 79 |
+
|
| 80 |
+
function extractImageUrl(data) {
|
| 81 |
+
if (data?.text?.startsWith('Image URL: ')) {
|
| 82 |
+
return data.text.substring('Image URL: '.length).trim();
|
| 83 |
+
}
|
| 84 |
+
if (data?.content) {
|
| 85 |
+
for (const item of data.content) {
|
| 86 |
+
if (item.type === 'text' && item.text?.startsWith('Image URL: ')) {
|
| 87 |
+
return item.text.substring('Image URL: '.length).trim();
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
function render() {
|
| 94 |
+
const url = extractImageUrl(window.openai?.toolOutput);
|
| 95 |
+
if (url) imageEl.src = url;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
async function brightenImage() {
|
| 99 |
+
btnEl.disabled = true;
|
| 100 |
+
btnEl.textContent = 'Brightening...';
|
| 101 |
+
const result = await window.openai.callTool('power_law_image', {
|
| 102 |
+
input_path: imageEl.src
|
| 103 |
+
});
|
| 104 |
+
const newUrl = extractImageUrl(result);
|
| 105 |
+
if (newUrl) imageEl.src = newUrl;
|
| 106 |
+
btnEl.disabled = false;
|
| 107 |
+
btnEl.textContent = 'Brighten';
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
btnEl.addEventListener('click', brightenImage);
|
| 111 |
+
window.addEventListener("openai:set_globals", (event) => {
|
| 112 |
+
if (event.detail?.globals?.toolOutput) render();
|
| 113 |
+
}, { passive: true });
|
| 114 |
+
|
| 115 |
+
render();
|
| 116 |
+
</script>
|
| 117 |
+
"""
|
| 118 |
+
return visual
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
with gr.Blocks() as demo:
|
| 122 |
+
with gr.Row():
|
| 123 |
+
with gr.Column():
|
| 124 |
+
original_image = gr.Image(label="Original Image", type="filepath")
|
| 125 |
+
btn = gr.Button("Brighten Image")
|
| 126 |
+
with gr.Column():
|
| 127 |
+
output_image = gr.Image(label="Output Image", type="filepath")
|
| 128 |
+
html = gr.Code(language="html", max_lines=20)
|
| 129 |
+
|
| 130 |
+
btn.click(power_law_image, inputs=original_image, outputs=original_image)
|
| 131 |
+
btn.click(app_html, outputs=html)
|
| 132 |
+
|
| 133 |
+
if __name__ == "__main__":
|
| 134 |
+
demo.launch(mcp_server=True, share=True)
|