Spaces:
Sleeping
Sleeping
| """ | |
| Shami's Multi-Agent System β FastAPI server for HuggingFace Spaces. | |
| 5 purpose-built agents, each with custom tools: | |
| - Job Search: find, evaluate, draft cover letters | |
| - Research: multi-source research with structured reports | |
| - Code Review: GitHub PR analysis | |
| - Upwork Proposals: tailored proposal drafting | |
| - n8n Handler: freelance message analysis + reply drafting | |
| All powered by Groq (free, fast) with Tavily web search. | |
| """ | |
| import os | |
| import json | |
| from datetime import datetime | |
| from contextlib import asynccontextmanager | |
| from pathlib import Path | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.responses import HTMLResponse, FileResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from pydantic import BaseModel, Field | |
| from agents.engine import run_agent | |
| from agents.definitions import AGENTS | |
| # ββ App setup ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def lifespan(app: FastAPI): | |
| print(f"[{datetime.now().isoformat()}] Starting Shami's Agent System") | |
| print(f" GROQ_API_KEY: {'SET' if os.environ.get('GROQ_API_KEY') else 'MISSING'}") | |
| print(f" TAVILY_API_KEY: {'SET' if os.environ.get('TAVILY_API_KEY') else 'MISSING'}") | |
| print(f" Agents: {', '.join(AGENTS.keys())}") | |
| yield | |
| print("Shutting down.") | |
| app = FastAPI( | |
| title="Shami's Agent System", | |
| description="Multi-agent AI system β job search, research, code review, proposals, freelance messaging", | |
| lifespan=lifespan, | |
| ) | |
| # ββ Request/Response models ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class AgentRequest(BaseModel): | |
| message: str = Field(..., description="The goal or task for the agent") | |
| conversation_id: str = Field(default="default", description="Conversation ID for context") | |
| class AgentResponse(BaseModel): | |
| agent: str | |
| result: str | |
| tool_calls_made: int | |
| tools_used: list[str] | |
| iterations: int | |
| conversation_id: str | |
| timestamp: str | |
| class N8nWebhookRequest(BaseModel): | |
| message: str = Field(..., description="The incoming freelance message") | |
| platform: str = Field(default="unknown", description="Source platform (upwork/fiverr/email)") | |
| sender: str = Field(default="", description="Sender name or username") | |
| # ββ Agent endpoints ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def run_agent_endpoint(agent_type: str, req: AgentRequest): | |
| """Run a specific agent with a goal.""" | |
| if agent_type not in AGENTS: | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"Unknown agent: {agent_type}. Available: {list(AGENTS.keys())}", | |
| ) | |
| agent_def = AGENTS[agent_type] | |
| result = await run_agent( | |
| goal=req.message, | |
| system_prompt=agent_def["prompt"], | |
| tools=agent_def["tools"], | |
| conversation_id=req.conversation_id, | |
| ) | |
| return AgentResponse( | |
| agent=agent_def["name"], | |
| result=result["result"], | |
| tool_calls_made=result["tool_calls_made"], | |
| tools_used=result["tools_used"], | |
| iterations=result["iterations"], | |
| conversation_id=result["conversation_id"], | |
| timestamp=datetime.now().isoformat(), | |
| ) | |
| async def n8n_webhook(req: N8nWebhookRequest): | |
| """n8n webhook endpoint β receives freelance messages, returns analysis + draft reply.""" | |
| agent_def = AGENTS["n8n"] | |
| goal = f"Platform: {req.platform}\nSender: {req.sender}\n\nMessage:\n{req.message}" | |
| result = await run_agent( | |
| goal=goal, | |
| system_prompt=agent_def["prompt"], | |
| tools=agent_def["tools"], | |
| conversation_id=f"n8n-{datetime.now().strftime('%Y%m%d-%H%M')}", | |
| ) | |
| return AgentResponse( | |
| agent=agent_def["name"], | |
| result=result["result"], | |
| tool_calls_made=result["tool_calls_made"], | |
| tools_used=result["tools_used"], | |
| iterations=result["iterations"], | |
| conversation_id=result["conversation_id"], | |
| timestamp=datetime.now().isoformat(), | |
| ) | |
| # ββ Utility endpoints ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def health(): | |
| return { | |
| "status": "ok", | |
| "agents": {k: {"name": v["name"], "tools": [t.__name__ for t in v["tools"]]} for k, v in AGENTS.items()}, | |
| "model": "groq/llama-3.3-70b-versatile", | |
| "timestamp": datetime.now().isoformat(), | |
| } | |
| async def list_agents(): | |
| """List all available agents with their descriptions.""" | |
| return { | |
| "agents": [ | |
| { | |
| "id": k, | |
| "name": v["name"], | |
| "description": v["description"], | |
| "icon": v["icon"], | |
| "tools": [t.__name__ for t in v["tools"]], | |
| "endpoint": f"/agent/{k}", | |
| } | |
| for k, v in AGENTS.items() | |
| ] | |
| } | |
| # ββ Web UI βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def home(): | |
| return (Path(__file__).parent / "static" / "index.html").read_text() | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |