{"repo": "bhiv-engineering-exchange/bhiv-prompt-runner01", "files": {"api.py": {"05a52db1e91b6fb60b836dc08885204e5ffad3c4": {"t": 1785674395.6460004, "n": 5242, "h": "38334d68a5f9a111", "c": "\"\"\"\nPrompt Runner - FastAPI Service\n================================\nConverts any user prompt into a structured JSON instruction using the Groq API.\n\nRequired environment variable:\n GROQ_API_KEY=gsk_... (get yours at console.groq.com)\n\nStart:\n uvicorn api:app --host 0.0.0.0 --port 8001\n\nEndpoints:\n POST /generate — prompt structured JSON instruction\n GET /health — Groq availability check\n GET /schema — JSON Schema for the instruction format\n GET /models — list available Groq models\n\"\"\"\n\nfrom typing import Any, Dict, List, Optional\n\nfrom fastapi import FastAPI, HTTPException\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom pydantic import BaseModel, Field\n\nfrom llm_adapter import LLMAdapter, DEFAULT_MODEL\n\n# ---------------------------------------------------------------------------\n# App\n# ---------------------------------------------------------------------------\n\napp = FastAPI(\n title=\"Prompt Runner API\",\n description=\"Converts any user prompt into a deterministic JSON instruction via Groq API.\",\n version=\"5.0.0\",\n)\n\napp.add_middleware(\n CORSMiddleware,\n allow_origins=[\"*\"],\n allow_methods=[\"*\"],\n allow_headers=[\"*\"],\n)\n\n# ---------------------------------------------------------------------------\n# JSON Schema (served at /schema)\n# ---------------------------------------------------------------------------\n\nINSTRUCTION_SCHEMA: Dict[str, Any] = {\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"title\": \"Prompt Runner Instruction\",\n \"type\": \"object\",\n \"properties\": {\n \"prompt\": {\"type\": \"string\"},\n \"module\": {\"type\": \"string\"},\n \"intent\": {\"type\": \"string\"},\n \"topic\": {\"type\": \"string\"},\n \"tasks\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"minItems\": 1},\n \"output_format\": {\"type\": \"string\"},\n \"product_context\": {\"type\": \"string\", \"enum\": [\"creator_core\"]},\n },\n \"required\": [\"prompt\", \"module\", \"intent\", \"topic\", \"tasks\", \"output_format\", \"product_context\"],\n \"additionalProperties\": False,\n}\n\n# ---------------------------------------------------------------------------\n# Singleton adapter\n# ---------------------------------------------------------------------------\n\n_llm: Optional[LLMAdapter] = None\n\n\ndef _get_llm() -> LLMAdapter:\n global _llm\n if _llm is None:\n _llm = LLMAdapter() # reads GROQ_API_KEY from environment / .env.local\n return _llm\n\n\n# ---------------------------------------------------------------------------\n# Pydantic models\n# ---------------------------------------------------------------------------\n\nclass PromptRequest(BaseModel):\n prompt: str = Field(..., min_length=1, description=\"User prompt to interpret\")\n model: Optional[str] = Field(None, description=\"Groq model override\")\n\n\nclass InstructionResponse(BaseModel):\n prompt: str\n module: str\n intent: str\n topic: str\n tasks: List[str]\n output_format: str\n product_context: str = \"creator_core\"\n\n\nclass HealthResponse(BaseModel):\n status: str\n groq_available: bool\n models: List[str]\n\n\n# ---------------------------------------------------------------------------\n# Endpoints\n# ---------------------------------------------------------------------------\n\n@app.get(\"/health\", response_model=HealthResponse, tags=[\"system\"])\ndef health_check():\n \"\"\"Check Groq API availability.\"\"\"\n llm = _get_llm()\n llm.reset_availability_cache()\n return HealthResponse(\n status = \"healthy\",\n groq_available = llm.available,\n models = llm.client.list_models() if llm.available else [],\n )\n\n\n@app.post(\"/generate\", response_model=InstructionResponse, tags=[\"core\"])\ndef generate_instruction(request: PromptRequest):\n \"\"\"\n Convert a user prompt into a structured JSON instruction via Groq API.\n\n Output always contains exactly these 6 keys:\n {\n \"prompt\": \"...\",\n \"module\": \"...\",\n \"intent\": \"...\",\n \"topic\": \"...\",\n \"tasks\": [\"...\", \"...\"],\n \"output_format\": \"...\"\n }\n \"\"\"\n llm = _get_llm()\n\n if not llm.available:\n raise HTTPException(\n status_code=503,\n detail=\"GROQ_API_KEY is not configured. Set it as an environment variable.\",\n )\n\n if request.model:\n llm.client.model = request.model\n llm.reset_availability_cache()\n\n try:\n instruction = llm.generate_instruction(request.prompt)\n return InstructionResponse(**instruction)\n except Exception as exc:\n raise HTTPException(status_code=500, detail=str(exc))\n\n\n@app.get(\"/schema\", tags=[\"system\"])\ndef get_schema():\n \"\"\"Return the JSON Schema for the instruction output format.\"\"\"\n return INSTRUCTION_SCHEMA\n\n\n@app.get(\"/models\", tags=[\"system\"])\ndef list_models():\n \"\"\"List available Groq models.\"\"\"\n llm = _get_llm()\n llm.reset_availability_cache()\n return {\n \"groq_available\": llm.available,\n \"models\": llm.client.list_models() if llm.available else [],\n \"default_model\": DEFAULT_MODEL,\n }\n \n \n \n \n "}}}}