mjpsm's picture
Deploy MyVillage Activity Generation API
9c9ef1d verified
|
Raw History Blame Contribute Delete
7.96 kB
metadata
title: MyVillage Activity Generation API
emoji: 🌱
colorFrom: green
colorTo: blue
sdk: docker
app_port: 7860
pinned: false

MyVillage Activity Generation API

One lightweight FastAPI wrapper around three separately deployed Hugging Face Spaces:

  1. Progression: what the villager needs to do next.
  2. Composition: activity title and description from the progression plan.
  3. Instruction: step-by-step instructions from the progression and composition results.

Only the final title, description and instructions leave this API. No Qwen weights, GGUF files, Transformers, or GPU are needed in this Space.

Endpoint

POST /generate-activity with this JSON body:

{
  "version": "v1",
  "knowledge_submission": "I reviewed 25 saved chatbot conversations. I noticed the refund responses sometimes contradicted the policy, but I have not systematically documented the errors.",
  "wisdom": {
    "content": "Testing systems requires comparing observations with expected outcomes.",
    "chapterTitle": "Testing With Purpose",
    "BookTypeName": "Personal Records",
    "BookType": "personal_record"
  },
  "village_goal": "Build and evaluate a reliable customer support chatbot",
  "previous_activity_title": "Test Chatbot Conversations"
}

Response shape (generated text varies):

{
  "output": {
    "activity_title": "Evaluate Chatbot Response Accuracy",
    "activity_description": "Review saved chatbot conversations to identify recurring errors in responses.",
    "instructions": [
      "Review the 25 saved chatbot conversations.",
      "Compare responses with expected answers.",
      "List recurring errors by category."
    ]
  }
}

Input wisdom uses the exact existing field names content, chapterTitle, BookTypeName, BookType. The wrapper does not synthesize wisdom from the current knowledge submission. Progression fields are passed through: no success_evidence field is fabricated or required.

Other endpoints: GET /health (liveness), GET /docs (Swagger), GET /openapi.json.

Deploy on Hugging Face Spaces (Docker)

  1. Create a Docker Space named e.g. mjpsm/activity-generation-api.
  2. Copy the entire repository content into that Space (including Dockerfile, app/, requirements.txt, and this README.md).
  3. Under Settings → Variables and secrets, set the three *_API_URL variables if needed, and optionally set API_KEY as a secret. Set HF_TOKEN as a secret only if the upstream Spaces require authentication.
  4. Wait for Space status Running, then open https://mjpsm-activity-generation-api.hf.space/docs (assuming that is the Space name you selected).
  5. Use Try it out for POST /generate-activity, or issue the cURL request below.

Important: Live contract verification

The three Space repository identities have been checked, but their live OpenAPI JSON could not be fetched during development. This project does not claim the live POST paths or exact intermediate request bodies were verified. To avoid inventing endpoint paths, each default API URL points to its base; on first use, the wrapper asks that Space for /openapi.json and automatically selects the POST route when unambiguous.

If the upstream Space has multiple POST routes, set its URL to the full POST endpoint from that Space's /docs, such as https://...hf.space/<actual-post-path> (not /docs).

Intermediate request body contract

By default, this wrapper uses:

  • Progression request: original input JSON as sent to /generate-activity.
  • Composition request: {"progression": <unwrapped progression object>}.
  • Instruction request: {"progression": <unwrapped progression object>, "composition": {"activity_title": "...", "activity_description": "..."}}.

Common response envelopes {"output": ...} and {"progression": ...} are unwrapped before forwarding. Composition requires non-empty activity_title and activity_description. Instruction requires a nonempty array of nonblank strings in instructions.

If a deployed Space's actual request schema nests its inputs differently, use the corresponding Variables (no code edits needed):

Variable Value Request body
COMPOSITION_INPUT_STYLE direct (default) {"progression": {...}}
input {"input": {"progression": {...}}}
bare progression object directly
INSTRUCTION_INPUT_STYLE direct (default) {"progression": {...}, "composition": {"activity_title": "...", "activity_description": "..."}}
nested_output {"progression": {...}, "composition": {"output": {"activity_title": "...", "activity_description": "..."}}}
input wraps the direct request in {"input": ...}
input_nested_output wraps the nested_output request in {"input": ...}

A 502 upstream_http_error with HTTP 422 often indicates a request shape mismatch; check the upstream Swagger docs and change the applicable variable. Avoid silently retrying arbitrary alternate bodies or hiding schema mismatches.

Calling your wrapper

curl -X POST 'http://localhost:7860/generate-activity' \
  -H 'Content-Type: application/json' \
  -d '{
    "version": "v1",
    "knowledge_submission": "I tested the chatbot in 25 conversations but have not documented its recurring errors.",
    "wisdom": {
      "content": "Compare actual outputs against expectations when testing.",
      "chapterTitle": "Test With Purpose",
      "BookTypeName": "Personal Records",
      "BookType": "personal_record"
    },
    "village_goal": "Build a reliable customer service chatbot",
    "previous_activity_title": "Test Chatbot Conversations"
  }'

If you set the API_KEY secret, also include -H 'X-API-Key: your-secret-key' in client calls. Treat this like a server-side key; don't embed it in public web frontend JavaScript.

Run locally

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt
cp .env.example .env  # optional reference; configure env vars in shell to apply them
uvicorn app.main:app --reload --port 7860

Note: This template intentionally does not load .env automatically, to avoid another dependency. To use .env locally, export the file's values into your shell or use a runner that reads dotenv files.

Run tests:

pytest -q

The tests mock all upstream model APIs. They validate orchestration, payload shapes, retries/errors, and output validation without inference costs. They are not live end-to-end verification.

Error handling and safety

  • Input validation returns 422 before calling any model.
  • Upstream errors return 502/503, and exhausted timeouts return 504. The error contains the failing stage and a short code, but not submitted knowledge or model output.
  • Each model call is sequential; the wrapper stops on any error (no partial activities).
  • Transient 429/502/503/504, timeouts, and network failures are retried once by default; HTTP 422 contract errors are not retried.
  • Set READ_TIMEOUT_SECONDS for cold Spaces; default 240s. MAX_ATTEMPTS defaults to 2.
  • Logs include stage names, timing and a request identifier, not user input.
  • GET /health only checks the wrapper. It does not prove the three upstream Spaces are awake.
  • Configure API_KEY and keep upstream HF_TOKEN secrets private before production use.

Check the live APIs before your first end-to-end test

On a machine with internet access, run:

python scripts/inspect_upstreams.py

This performs read-only GET requests to the three Spaces' OpenAPI documents. It shows their actual POST URLs, top-level request properties, and required properties without making inference calls. Compare its output with the COMPOSITION_INPUT_STYLE and INSTRUCTION_INPUT_STYLE settings above. You can set the three service URLs in the shell if they have changed.