第15章(2)------项目十三:使用Gradio MCP与Apps SDK构建ChatGPT应用------提亮图像
-
- [15.6 项目十三:使用Gradio MCP与Apps SDK构建ChatGPT应用------提亮图像](#15.6 项目十三:使用Gradio MCP与Apps SDK构建ChatGPT应用——提亮图像)
15.6 项目十三:使用Gradio MCP与Apps SDK构建ChatGPT应用------提亮图像
ChatGPT应用(🖇️链接15-4)让用户能够在熟悉的聊天界面中,通过对话形式直接体验机器学习模型或其他应用。OpenAI已发布Apps SDK(🖇️链接15-5)供开发者构建完整的应用程序,但借助Gradio MCP服务器,开发者可以基于Gradio极为快速地搭建ChatGPT应用。另外,Gradio内置的分享链接让构建ChatGPT应用极为便利。使用Gradio构建ChatGPT应用需要完成两项任务:
- 构建一个至少暴露一个工具的Gradio MCP服务器。
- 使用HTML、JavaScript和CSS构建一个自定义界面,当工具被调用时显示该界面,并将其作为MCP资源暴露。
接下来构建ChatGPT图像增强应用,该应用包含一个"提亮"按钮,用户可以直接通过应用界面调用该工具。该应用如代码15-10所示:
代码15-10
py
import gradio as gr
import tempfile
from PIL import Image
import numpy as np
def power_law_image(input_path: str, gamma: float = 0.5) -> str:
"""Applies a power-law (gamma) transformation to an image file and saves
the result to a temporary file.
Args:
input_path (str): Path to the input image.
gamma (float): Power-law exponent. <1 brightens, >1 darkens.
Returns:
str: Path to the saved temporary output image."""
img = Image.open(input_path).convert("RGB")
arr = np.array(img, dtype=np.float32) / 255.0
arr = np.power(arr, gamma)
arr = np.clip(arr * 255, 0, 255).astype(np.uint8)
out_img = Image.fromarray(arr)
tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
out_img.save(tmp_file.name)
tmp_file.close()
return tmp_file.name
@gr.mcp.tool(
_meta={"openai/outputTemplate": "ui://widget/app.html",
"openai/resultCanProduceWidget": True,
"openai/widgetAccessible": True})
@gr.mcp.resource("ui://widget/app.html", mime_type="text/html+skybridge")
def app_html():
visual = """
<style>
#image-container {position: relative;
display: inline-block;
max-width: 100%;}
...
</style>
<div id="image-container">
<img id="image-display" alt="Processed image" />
<button id="brighten-btn">Brighten</button>
</div>
<script>
const imageEl = document.getElementById('image-display');
const btnEl = document.getElementById('brighten-btn');
function extractImageUrl(data) {
if (data?.text?.startsWith('Image URL: ')) {
return data.text.substring('Image URL: '.length).trim();}
if (data?.content) {
for (const item of data.content) {
if (item.type === 'text' && item.text?.startsWith('Image URL: ')) {
return item.text.substring('Image URL: '.length).trim();}}}}
function render() {
const url = extractImageUrl(window.openai?.toolOutput);
if (url) imageEl.src = url;}
async function brightenImage() {
btnEl.disabled = true;
btnEl.textContent = 'Brightening...';
const result = await window.openai.callTool('power_law_image', {
input_path: imageEl.src});
const newUrl = extractImageUrl(result);
if (newUrl) imageEl.src = newUrl;
btnEl.disabled = false;
btnEl.textContent = 'Brighten';}
btnEl.addEventListener('click', brightenImage);
window.addEventListener("openai:set_globals", (event) => {
if (event.detail?.globals?.toolOutput) render();
}, { passive: true });
render();
</script>
"""
return visual
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
original_image = gr.Image(label="Original Image", type="filepath")
btn = gr.Button("Brighten Image")
with gr.Column():
output_image = gr.Image(label="Output Image", type="filepath")
html = gr.Code(language="html", max_lines=20)
btn.click(power_law_image, inputs=original_image, outputs=original_image)
btn.click(app_html, outputs=html)
if __name__ == "__main__":
demo.launch(mcp_server=True, share=True)
代码实现了一个完整的MCP应用,结合Gradio UI、图像处理工具和交互式前端组件。核心亮点是将图像处理工具暴露为MCP工具,并通过Skybridge协议实现前端交互。详细拆解如下:
(1)Gamma校正。函数使用Gamma校正使图像变暗或变量,通过幂律变换,当gamma< 1时提高亮度,当gamma>1时降低亮度。
(2)为MCP工具添加_meta属性,将创建的MCP工具与为应用创建的UI关联起来。关键点是"openai/outputTemplate" 必须与创建的MCP资源的URI保持一致。
(3)gr.mcp.resource提供了一个URI:ui://widget/app.html,与_meta的属性保持一致。同时将资源的MIME类型指定为mime_type="text/html+skybridge"。请注意,在JavaScript的最后为"openai:set_globals"添加了一个事件监听器,控制小部件在每次触发新的工具调用时进行更新页面。
(4)为ChatGPT应用创建UI,并将其作为资源暴露。使用前端代码HTML、Javascript和CSS创建图像显示页面,window.openai对象由ChatGPT自动插入,其中包含了用户工具调用的数据(imageEl.src)。通过window.openai.callTool()直接通过按钮btnEl调用MCP工具,无需经过ChatGPT调用。返回结果content数组保存在window.openai?.toolOutput,需要extractImageUrl()提取数据。
(5)在Gradio应用中创建一个与资源函数对应的事件。这一步非常必要,因为Gradio应用只有在MCP工具、资源、提示等与Gradio事件关联时才会识别它们。通常的做法是将MCP资源的代码直接显示在一个gr.Code组件中。
重新启动Gradio应用并开启共享功能,终端打印出的MCP服务器URL,例如https://xxx.gradio.live/gradio_api/mcp/。Gradio运行界面如图15-7所示:

图15-7
设置为ChatGPT应用 。现在,进入ChatGPT(https://chat.com/)。如前所述,您需要在 ChatGPT 中开启"developer mode",路径为:Settings → Apps & Connectors → Advanced settings。然后,进入Settings → Apps & Connectors,点击"Create"按钮。为连接器设置肖像、名称、描述(可选),并粘贴终端中打印出的MCP服务器URL,选择"No authentication"后完成创建。效果如图15-8所示:

图15-8
大功告成!连接器创建完成后,就可以向其上传照片并可持续变亮。本项目展示了如何构建简单的响应式小部件,以及能够直接从界面调用工具的更高级交互式应用。结合Gradio的MCP服务器能力与OpenAI的Apps SDK,可以创建更丰富的ChatGPT集成,通过自定义可视化来提升用户交互的对话体验。