Skip to content

Navigation Menu

Sign in
Sign up

Latest commit

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

AI API Debugger

A full-stack tool that classifies API error messages using keyword matching, generates an explanation with the OpenAI API, and stores each analysis in PostgreSQL.


Overview

Problem: When an API call fails, developers have to manually read the error message, guess the likely cause, and search for a fix.

Solution: This project accepts an API name and an error message, matches the message against a small set of predefined error patterns (rate limiting, authentication, server errors, timeouts), returns a likely cause and suggested next steps, and adds a plain-language explanation generated by OpenAI. Every analysis is saved to a PostgreSQL table.

Intended use case: A portfolio/learning project demonstrating a layered FastAPI backend, a React frontend, SQLAlchemy persistence, and a third-party AI API integration — not a production debugging platform.


Key Features

  • Keyword-based classification of API error messages into one of four categories, or Unclassified if nothing matches
  • A confidence percentage based on how many of a category's keywords were matched (see How Confidence Is Calculated — this is not a machine learning or statistical model)
  • AI-generated explanation of the error via the OpenAI API (gpt-3.5-turbo)
  • Persistent storage of every analysis (API name, original error message, category, confidence, AI explanation) in PostgreSQL via SQLAlchemy
  • Single-page React UI to submit an error and view the result

Architecture

flowchart TD
 A[React Frontend] -->|POST /analyze| B[FastAPI Route]
 B --> C[Pydantic Validation - ErrorRequest]
 C --> D[analyze_error_logic]
 D --> E[Keyword Matching against ERROR_PATTERNS]
 E --> F{Match found?}
 F -->|Yes| G[OpenAI API call]
 F -->|No| H[Static Unclassified fallback]
 G --> I[SQLAlchemy - insert DebugSession row]
 H --> I
 I --> J[PostgreSQL]
 I --> K[JSON Response]
 K --> A
Loading

Request flow, in words:

  1. The React form sends api_name and error_message to POST /analyze.
  2. FastAPI validates the payload against the ErrorRequest Pydantic model (both fields are required strings; a missing/invalid field returns HTTP 422 automatically).
  3. analyze_error_logic() lowercases the message into a separate variable (the original casing is preserved for storage) and scores it against each entry in ERROR_PATTERNS by counting matched keywords.
  4. If a category matched at least one keyword, the OpenAI API is called once to generate a short explanation. If nothing matched, a static "Unclassified" result is used and OpenAI is not called — this keeps behavior predictable and avoids spending an API call on a message the app can't categorize.
  5. The result (including the AI explanation) is written to the debug_sessions table. The database session is wrapped in try/except/finally, so a failed write rolls back and the connection still closes.
  6. The full result — category, cause, solutions, confidence score, and AI explanation — is returned as JSON and rendered by the frontend.

Tech Stack

Frontend: React 19, Vite, Tailwind CSS, Axios

Backend: FastAPI, Pydantic

Database: PostgreSQL, SQLAlchemy (no migrations — tables are created via Base.metadata.create_all() on startup)

AI: OpenAI API (gpt-3.5-turbo)

Deployment (as configured, unverified beyond code): The frontend's default backend URL points to a Render deployment, and CORS is scoped to a Vercel origin. There is no Dockerfile, CI configuration, or infrastructure-as-code in this repository.


How It Works

The core logic lives in backend/services/analyze_service.py:

  1. ERROR_PATTERNS (in backend/utils/error_patterns.py) is a hardcoded Python list of four dictionaries, each with a category, a list of keywords, a cause, and a list of solutions.
  2. For each category, the code counts how many of its keywords appear as substrings in the lowercased error message.
  3. The category with the highest keyword-match count is selected as best_match. Ties go to whichever category was checked first.
  4. If no category matched any keyword, the result is Unclassified with a static cause/solutions and no OpenAI call.

How Confidence Is Calculated

confidence = (matched_keywords_in_best_category / total_keywords_in_that_category) * 100

This is a simple ratio, not a probability, not a machine learning prediction, and not a statistical confidence interval. It only reflects how many of one category's predefined keywords happened to appear in the message. A message that happens to contain 2 of a 4-keyword category's terms shows "50%" — that is the entire calculation.


API Endpoints

Method Endpoint Purpose
GET / Health check — returns {"message": "Backend is running successfully"}
POST /analyze Accepts {"api_name": string, "error_message": string}, returns category, cause, solutions, confidence score, and AI explanation

Example request:

{
 "api_name": "Stripe",
 "error_message": "429 Too Many Requests"
}

Example response:

{
 "category": "Rate Limiting",
 "cause": "Too many requests in short time",
 "solutions": [
 "Use retry logic",
 "Reduce request frequency",
 "Add exponential backoff"
 ],
 "confidence_score": "50.0%",
 "ai_explanation": "..."
}

If no keyword matches any category, category is "Unclassified", confidence_score is "0%", and ai_explanation is a static message — OpenAI is not called in this case.


Project Structure

ai-api-debugger/
├── backend/
│ ├── main.py # FastAPI app, CORS, router registration
│ ├── database.py # SQLAlchemy engine/session setup
│ ├── models/
│ │ ├── request_models.py # Pydantic request schema
│ │ └── db_models.py # SQLAlchemy DebugSession table
│ ├── routes/
│ │ └── analyze.py # POST /analyze route
│ ├── services/
│ │ ├── analyze_service.py # Core matching, scoring, persistence logic
│ │ └── ai_service.py # OpenAI API call
│ ├── utils/
│ │ └── error_patterns.py # Hardcoded category/keyword definitions
│ ├── requirements.txt
│ └── .env.example
├── frontend/
│ ├── src/
│ │ ├── App.jsx # Single-page UI: form + result display
│ │ └── main.jsx
│ ├── package.json
│ └── .env.example
└── requirements.txt

Local Setup

Backend

cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # then fill in real values
uvicorn main:app --reload

Frontend

cd frontend
npm install
cp .env.example .env # optional — see below
npm run dev

Environment Variables

backend/.env

DATABASE_URL=your_postgresql_connection_string_here
OPENAI_API_KEY=your_openai_api_key_here

frontend/.env

VITE_API_URL=http://localhost:8000

If VITE_API_URL is not set, the frontend falls back to the deployed production backend URL. Set it to http://localhost:8000 (or wherever the backend is running) for local development.

Database

The app does not include migrations. On startup, Base.metadata.create_all(bind=engine) in main.py creates the debug_sessions table if it doesn't already exist, provided DATABASE_URL points to a reachable PostgreSQL instance.


Engineering Decisions

  • Service layer separated from the route. routes/analyze.py only handles HTTP concerns (path, request/response); all matching, scoring, AI-calling, and persistence logic lives in services/analyze_service.py. This keeps the route trivial to read and the business logic testable independently of FastAPI.
  • AI calls are conditional, not unconditional. OpenAI is only called when a keyword match is found. This was a deliberate choice to keep behavior predictable and avoid calling a paid, network-dependent API for input the app can't meaningfully classify.
  • Matching uses a separate normalized variable. The original error_message string is preserved unmodified for storage; a separate normalized_message (lowercased) is used only for keyword comparison, so stored data reflects what the user actually submitted.
  • Database writes are wrapped in try/except/finally. A failed insert rolls back the transaction and the session is always closed, whether the write succeeds or fails — this is a deliberately minimal error-handling pattern, not a connection pool or retry system.

Limitations

  • Classification is a hardcoded keyword list covering four categories — it is not machine learning, not NLP, and will misclassify or fail to classify any error message that doesn't share vocabulary with ERROR_PATTERNS.
  • The "confidence score" is a simple keyword-match ratio, not a statistically meaningful confidence measure.
  • No authentication — anyone with the API URL can call /analyze and write to the database.
  • No automated tests.
  • No database migrations (schema changes require manual intervention).
  • No rate limiting on the OpenAI call — repeated requests will incur API cost per matched request.
  • No pagination, retrieval, or listing endpoint for past analyses — data is stored but never read back through the API.
  • Single-file React component — fine at this size, but would need to be split up if the UI grew.

Future Improvements

  • Add a GET /sessions endpoint to list past analyses from the database
  • Add automated tests for the keyword-matching logic and the API endpoint
  • Add Alembic migrations instead of create_all()
  • Expand ERROR_PATTERNS to cover more error categories
  • Add basic input length limits and rate limiting on /analyze

Screenshots

Not currently included. To add them, capture:

  • The main form (empty state)
  • A submitted analysis showing category, confidence score, cause, AI explanation, and solutions
  • The /docs Swagger UI page for the /analyze endpoint

and reference them here as assets/dashboard.png, assets/result.png, assets/swagger.png.


Author

Anuman Shailesh Modi

GitHub: https://github.com/anumanmodi

About

Full-stack AI-powered API debugging tool with FastAPI, React, PostgreSQL, and OpenAI API.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

AltStyle によって変換されたページ (->オリジナル) /