Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| import os | |
| from fastmcp import FastMCP, Context | |
| from starlette.responses import FileResponse | |
| from huggingface_hub import InferenceClient | |
| from typing_extensions import TypedDict | |
| # --- Config (same as your Gradio app) ---------------------------------------- | |
| HF_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN", "") | |
| HF_MODEL = os.getenv("HF_MODEL_ID", "meta-llama/Llama-3.1-8B-Instruct") | |
| # Single HF client, chat-only | |
| hf = InferenceClient(model=HF_MODEL, token=(HF_TOKEN or None)) | |
| # --- Minimal sampling fallback (server-side) --------------------------------- | |
| def sampling_handler(messages, params, ctx): | |
| msgs = [ | |
| { | |
| "role": getattr(m, "role", "user"), | |
| "content": getattr(m.content, "text", str(m.content)), | |
| } | |
| for m in messages | |
| ] | |
| r = hf.chat.completions.create(messages=msgs, temperature=1, max_tokens=150) | |
| out = r.choices[0].message.content | |
| return ( | |
| "".join(p.get("text", "") for p in out) | |
| if isinstance(out, list) | |
| else out.strip() | |
| ) | |
| # --- FastMCP app ------------------------------------------------------------- | |
| mcp = FastMCP( | |
| "MemeOps 🚀", | |
| sampling_handler=sampling_handler, | |
| sampling_handler_behavior="fallback", | |
| ) | |
| def ship_meme_for_commit(commit_id: str, git_diff_content: str) -> str: | |
| return ( | |
| "You are a release assistant for memes.\n" | |
| "Given the commit and its git diff, CALL the tool `memes_render_for_commit`.\n" | |
| f"commit_id: {commit_id}\n" | |
| f"git_diff:\n{git_diff_content}\n" | |
| "Return the whole tool response." | |
| ) | |
| def git_diff(commit_id: str, ctx: Context) -> str: | |
| return f"""--- MOCK DIFF for {commit_id} | |
| --- a/main.py | |
| +++ b/main.py | |
| @@ -5,7 +5,6 @@ | |
| def process(data): | |
| - result = data.strip().lower() | |
| - return result | |
| + return data | |
| """ | |
| def get_config() -> str: | |
| """Static configuration data""" | |
| return "App configuration here" | |
| class MemeResponse(TypedDict): | |
| commit_id: str | |
| caption: str | |
| meme_name: str | |
| image_url: str | |
| async def render_meme_for_commit(commit_id: str, ctx: Context) -> MemeResponse: | |
| res = await ctx.read_resource(f"gitdiff://{commit_id}") | |
| diff_text = getattr(res, "text", "") | |
| # Caption via sampling (handled by our server fallback) | |
| cap = await ctx.sample( | |
| f"Write ONE short funny caption that can be linked to a bad commit, use the commit name for it :\n{diff_text} \n\n Write ONLY the funny caption!" | |
| ) | |
| caption = getattr(cap, "text", str(cap)).strip() | |
| # Pick a meme via sampling too (kept simple) | |
| meme_list = "- 61579 : One Does Not Simply\n- 181913649 : Drake Hotline Bling\n- 112126428 : Distracted Boyfriend" | |
| choice = await ctx.sample( | |
| f'Caption: "{caption}"\nPick best meme id from:\n{meme_list}\nReply ONLY the id' | |
| ) | |
| meme_id = getattr(choice, "text", str(choice)).strip() | |
| name_map = { | |
| "61579": "One Does Not Simply", | |
| "181913649": "Drake Hotline Bling", | |
| "112126428": "Distracted Boyfriend", | |
| } | |
| url_map = { | |
| "61579": "https://i.imgflip.com/1bij.jpg", | |
| "181913649": "https://i.imgflip.com/30b1gx.jpg", | |
| "112126428": "https://i.imgflip.com/1ur9b0.jpg", | |
| } | |
| meme_name = name_map.get(meme_id, "One Does Not Simply") | |
| image_url = url_map.get(meme_id, "https://i.imgflip.com/1bij.jpg") | |
| return { | |
| "commit_id": commit_id, | |
| "caption": caption, | |
| "meme_name": meme_name, | |
| "image_url": image_url, | |
| } | |
| # Optional: serve a simple page at / | |
| async def root(_): | |
| return FileResponse("index.html") # put a static file next to server.py, or remove | |
| if __name__ == "__main__": | |
| mcp.run( | |
| transport="streamable-http", | |
| host="0.0.0.0", | |
| port=int(os.getenv("PORT", "7860")), | |
| path="/mcp", | |
| ) | |