Spaces:
Running
Running
Abid Ali Awan
refactor: Revamp Gradio MCP Connector to enhance performance and user experience by implementing a two-phase chat process with tool resolution and streaming responses, updating the system prompt for clarity, and improving file upload handling.
693bdb2
| """ | |
| Gradio + OpenAI MCP Connector — Clean, Fast, Streaming, With File Upload | |
| """ | |
| import os | |
| import shutil | |
| import gradio as gr | |
| from openai import OpenAI | |
| # --------------------- | |
| # CONFIGURATION | |
| # --------------------- | |
| OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") | |
| MCP_SERVER_URL = "https://mcp-1st-birthday-auto-deployer.hf.space/gradio_api/mcp/" | |
| MODEL_FAST = "gpt-5-mini" # for tool resolution | |
| MODEL_STREAM = "gpt-5.1" # for final streaming reply | |
| client = OpenAI(api_key=OPENAI_API_KEY) | |
| SYSTEM_PROMPT = """ | |
| You are a fast MLOps assistant with access to remote MCP tools. | |
| Use tools only when necessary. | |
| Keep reasoning effort LOW for speed. | |
| After tools run, summarize clearly and concisely. | |
| """ | |
| # --------------------- | |
| # NATIVE MCP CONNECTOR | |
| # --------------------- | |
| TOOLS = [ | |
| { | |
| "type": "mcp", | |
| "server_label": "deploy_tools", | |
| "server_url": MCP_SERVER_URL, | |
| # transport auto-detected; HF space supports HTTP | |
| } | |
| ] | |
| # --------------------- | |
| # FILE UPLOAD HANDLER | |
| # --------------------- | |
| def handle_upload(file_obj, request: gr.Request): | |
| if file_obj is None: | |
| return None | |
| # Ensure file is in a stable path | |
| local_path = file_obj.name | |
| stable_path = os.path.join("/tmp", os.path.basename(local_path)) | |
| try: | |
| shutil.copy(local_path, stable_path) | |
| local_path = stable_path | |
| except Exception: | |
| pass | |
| # Build public Gradio URL | |
| base = str(request.base_url).rstrip("/") | |
| return f"{base}/gradio_api/file={local_path}" | |
| # --------------------- | |
| # MAIN CHAT HANDLER | |
| # --------------------- | |
| def chat_send_stream(user_msg, history, file_url): | |
| """ | |
| 2-phase pipeline: | |
| PHASE 1 ➜ Non-streaming tool resolution using gpt-5-mini | |
| PHASE 2 ➜ Streaming final output using gpt-5 | |
| """ | |
| if history is None: | |
| history = [] | |
| # Build message history for OpenAI | |
| messages = [{"role": "system", "content": SYSTEM_PROMPT}] | |
| for u, a in history: | |
| messages.append({"role": "user", "content": u}) | |
| if a: | |
| messages.append({"role": "assistant", "content": a}) | |
| # Inject file context | |
| if file_url: | |
| user_msg_full = f"[Uploaded CSV file: {file_url}]\n\n{user_msg}" | |
| else: | |
| user_msg_full = user_msg | |
| messages.append({"role": "user", "content": user_msg_full}) | |
| # ----------------------------- | |
| # PHASE 1 — TOOL RESOLUTION | |
| # ----------------------------- | |
| tool_phase = client.responses.create( | |
| model=MODEL_FAST, | |
| reasoning={"effort": "low"}, | |
| tools=TOOLS, | |
| instructions=SYSTEM_PROMPT, | |
| input=messages, | |
| ) | |
| tool_feedback = [] | |
| # Detect tool calls (if any) | |
| if tool_phase.output: | |
| for item in tool_phase.output: | |
| if item.type == "tool_call": | |
| tool_feedback.append(f"🛠️ Used tool `{item.name}`.") | |
| elif item.type == "tool_result": | |
| tool_feedback.append(f"{item.content}") | |
| if not tool_feedback: | |
| tool_feedback.append("No MCP tools needed.") | |
| else: | |
| tool_feedback.append("No MCP tools needed.") | |
| # Append tool results to messages before final generation | |
| messages.append({"role": "assistant", "content": "\n".join(tool_feedback)}) | |
| # Yield intermediate tool feedback to the UI | |
| history.append((user_msg, "\n".join(tool_feedback))) | |
| yield history | |
| # ----------------------------- | |
| # PHASE 2 — STREAMING FINAL ANSWER | |
| # ----------------------------- | |
| stream = client.responses.create( | |
| model=MODEL_STREAM, | |
| reasoning={"effort": "low"}, | |
| instructions=SYSTEM_PROMPT, | |
| input=messages, | |
| stream=True, | |
| ) | |
| final_text = "" | |
| for ev in stream: | |
| if ev.type == "response.output_text.delta": | |
| final_text += ev.delta | |
| history[-1] = (user_msg, "\n".join(tool_feedback) + "\n\n" + final_text) | |
| yield history | |
| elif ev.type == "response.completed": | |
| break | |
| stream.close() | |
| # --------------------- | |
| # GRADIO UI | |
| # --------------------- | |
| with gr.Blocks(title="MCP + GPT-5 — Fast Streaming MLOps Agent") as demo: | |
| gr.Markdown(""" | |
| # 🚀 AI-Driven MLOps Agent (MCP-Powered) | |
| - Upload a CSV file | |
| - Tools resolve instantly | |
| - Final answer streams smoothly | |
| """) | |
| file_state = gr.State() | |
| uploader = gr.File(label="Upload CSV file", type="filepath", file_count="single") | |
| uploader.change(handle_upload, inputs=[uploader], outputs=[file_state]) | |
| chatbot = gr.Chatbot(label="Chat") | |
| msg = gr.Textbox(label="Message") | |
| send = gr.Button("Send") | |
| send.click( | |
| chat_send_stream, | |
| inputs=[msg, chatbot, file_state], | |
| outputs=[chatbot], | |
| ).then(lambda: "", outputs=[msg]) | |
| msg.submit( | |
| chat_send_stream, | |
| inputs=[msg, chatbot, file_state], | |
| outputs=[chatbot], | |
| ).then(lambda: "", outputs=[msg]) | |
| if __name__ == "__main__": | |
| demo.queue().launch( | |
| allowed_paths=["/tmp"], | |
| show_error=True, | |
| quiet=True, | |
| ) | |