from fastapi import APIRouter from fastapi.responses import HTMLResponse router = APIRouter() @router.get("/api-docs", include_in_schema=False) async def custom_api_docs() -> HTMLResponse: return HTMLResponse(_DOCS_HTML) _DOCS_HTML = r""" LockedIn AI Service API Docs
Production API documentation

Generate clear learning roadmaps from one API request.

LockedIn turns a learner's goal into a structured roadmap with phases, learning nodes, curated free resources, practical projects, stable backend IDs, and metadata your frontend can render immediately.

What This API Does

A focused backend for generating beginner-friendly learning plans. The frontend sends a skill and optional preferences; the API handles search, model generation, validation, IDs, caching, and safe error responses.

Curates free resources

The service searches Tavily and YouTube, filters paid-looking or invalid links, and only allows generated roadmaps to use known candidate URLs.

Returns frontend-ready JSON

Responses include stable IDs, normalized skill names, phases, nodes, project details, resources, source metadata, and cache status.

Keeps production errors safe

Users receive clean messages and a request ID. Detailed stack traces stay in container logs so developers can diagnose failures without leaking internals.

Quick Start

The smallest valid request only needs a skill. Defaults fill in learner level, goals, time commitment, preferred resource types, and language.

curl
curl -X POST https://jaykay73-lockedin.hf.space/api/v1/roadmaps/generate \
  -H "Content-Type: application/json" \
  -d '{"skill":"Learn Python"}'
JavaScript fetch
const response = await fetch(
  "https://jaykay73-lockedin.hf.space/api/v1/roadmaps/generate",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ skill: "Learn Python" })
  }
);

const body = await response.json();

if (!response.ok || body.success === false) {
  throw new Error(body.error?.message ?? "Roadmap generation failed");
}

console.log(body.data);

Endpoint Reference

The generation endpoint is asynchronous from the client perspective: send one POST request and wait for a validated roadmap response.

POST /api/v1/roadmaps/generate
Returns JSON

Generates a complete learning roadmap for a requested skill. The API searches for free resources, asks the model to produce a roadmap using only those resources, validates the final schema, assigns IDs, and caches valid results.

Roadmaps AI generation Validated schema Cached results

Request Body

Send only skill for the default experience, or include optional fields to tailor the roadmap to a learner's level, goals, time, format preferences, and language.

Field
Description
Required
skill
The skill or topic to learn. Example: Learn Python.
Required
user_level
Current learner level. Default: complete beginner.
Optional
goal
The learner's outcome. Default: learn step by step and build practical confidence.
Optional
time_commitment
Expected study time. Default: 3 to 5 hours per week.
Optional
preferred_resource_types
Defaults to all supported formats: youtube_video, article, free_course, documentation, free_book, interactive_practice.
Optional
language
Preferred output language. Default: English.
Optional
Full request example
{
  "skill": "Learn Python",
  "user_level": "complete beginner",
  "goal": "build small automation projects",
  "time_commitment": "5 hours per week",
  "preferred_resource_types": [
    "youtube_video",
    "article",
    "free_course",
    "documentation",
    "free_book",
    "interactive_practice"
  ],
  "language": "English"
}

Successful Response

A successful response returns success: true and a roadmap object designed for direct rendering in your frontend.

Roadmap structure

  • Exactly 3 phases.
  • Each phase has exactly 3 learning nodes.
  • Each node has 2 to 4 free resources.
  • Each phase includes one practical project.
  • Top-level projects mirrors phase projects for easy UI rendering.

Metadata

  • model_used shows the generation model or fallback.
  • resource_sources shows providers such as Tavily and YouTube.
  • generated_at is an ISO timestamp.
  • cached tells the frontend whether the response came from cache.
Response shape
{
  "success": true,
  "data": {
    "roadmap_id": "roadmap_python_599569",
    "skill": "Learn Python",
    "normalized_skill": "python",
    "overview": "A beginner-friendly overview...",
    "estimated_total_duration": "6-8 weeks",
    "phases": [
      {
        "id": "phase_1",
        "title": "Getting Started",
        "level": "beginner",
        "goal": "Learn the foundations.",
        "estimated_duration": "2 weeks",
        "nodes": [],
        "project": {}
      }
    ],
    "projects": [],
    "metadata": {
      "model_used": "deepseek-v4-flash",
      "resource_sources": ["tavily", "youtube"],
      "generated_at": "2026-04-30T20:18:18.238214Z",
      "cached": false,
      "fallback": false
    }
  }
}

Error Handling

The API uses real HTTP status codes. Production responses stay safe for users, while the backend logs detailed exceptions with the same request_id.

Status
Meaning
Retry?
200
Roadmap generated successfully.
No
422
Invalid request body, such as a blank skill or unsupported resource type.
Fix request
500
Unexpected backend error.
Maybe
502
The model returned malformed or schema-invalid output.
Yes
503
Generation, model provider, search provider, or validation workflow failed.
Yes
Error response
{
  "success": false,
  "error": {
    "code": "ROADMAP_GENERATION_FAILED",
    "message": "We could not generate this roadmap right now. Please try again.",
    "retryable": true,
    "request_id": "2e4d4e8fd3f049d28e1a7fd04ef63c8a"
  }
}

Frontend Integration Pattern

Keep API keys on the backend. The frontend only calls LockedIn, handles loading states, checks response.ok, and logs request IDs for failed calls.

1

Collect the skill

Ask the learner what they want to learn. Optional controls can collect level, goal, time, language, and preferred resource types.

2

POST to the API

Send JSON to /api/v1/roadmaps/generate. Show a loading state because provider calls can take several seconds.

3

Render or recover

If successful, render phases, nodes, resources, and projects. If failed, show a friendly message and log the request_id.

Operational Notes

These details help keep the Hugging Face Spaces deployment stable and debuggable.

Secrets

Set DEEPSEEK_API_KEY, TAVILY_API_KEY, and YOUTUBE_API_KEY as Space secrets. Never expose them in frontend code.

CORS

Set CORS_ALLOWED_ORIGINS to your frontend domain. During testing, a broad value may work, but production should use explicit origins.

Health

Use /health to verify the service is running. It does not prove external providers are healthy; it only checks the app process.

"""