Skip to content

jamesbconner/shokobot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ShokoBot

Tests Lint Security codecov Python 3.12+ Code style: ruff

Retrival Augmented Generation (RAG) enabled anime recommendation system using LangChain, ChromaDB Vectorstore, Model Context Protocol, and OpenAI GPT-5.

Overview

The Shoko anime management system by default uses a SQLite database on the backend. Extracting the AniDB information from that database with a simple SQL query allows the user to create an input file for this RAG enabled LLM service. Queries can be executed either as a one-shot or via a REPL/Chat interface, and if the RAG doesn't have enough information to satisfy a question, it will use a custom MCP server to fetch specific show information from AniDB to fill in the gap.

This service was built using Python 3.13, and uses standard tooling like poetry, pytest, ruff, mypy, and bandit as the dev stack, and uses a pre-commit configuration to ensure proper code hygine.

Features

  • 🔍 Vector-based semantic search - Find anime using natural language queries
  • 🎯 Comprehensive metadata - 21 fields per anime including ratings, episodes, dates, and relationships
  • 📊 Efficient ingestion - Batch processing with progress indicators (1,458 anime records)
  • 💬 Multiple query modes - Web UI, interactive REPL, single questions, file input, or stdin
  • 🎨 Beautiful CLI - Rich formatting with tables, colors, and progress bars
  • 📤 JSON output format - Structured output for programmatic usage and API integration
  • ⚙️ Flexible configuration - JSON config with environment variable overrides
  • 🤖 GPT-5 integration - Responses API with configurable reasoning effort
  • 🔌 MCP fallback - Automatic AniDB integration via Model Context Protocol for comprehensive coverage
  • 🏗️ Modular architecture - Auto-loading CLI commands with dependency injection
  • Type-safe - Full Pydantic validation and mypy strict mode
  • 📝 Well-documented - Comprehensive guides and architecture documentation

Requirements

  • Python 3.12+
  • Poetry (for build system) or uv (for dependency management)
  • OpenAI API key
  • mcp-server-anime (optional, for AniDB fallback)

Quick Start

🐳 Docker (Recommended for Production)

# 1. Clone and setup
git clone https://github.com/yourusername/shokobot.git
cd shokobot

# 2. Configure environment
cp .env.example .env
# Edit .env and add your OPENAI_API_KEY

# 3. Start with Docker Compose
docker-compose up -d

# 4. Access web UI
open http://localhost:7860

See DOCKER.md for detailed Docker deployment guide.

💻 Local Development Setup

# Run the setup script
./setup.sh

# Edit .env and add your OpenAI API key
export OPENAI_API_KEY='your-key-here'

# Verify configuration
poetry run shokobot info

# Ingest anime data
poetry run shokobot ingest

# Start querying
poetry run shokobot repl

Installation

Using Poetry (Recommended)

# Install poetry if not already installed
curl -sSL https://install.python-poetry.org | python3 -

# Install dependencies
poetry install

# Activate virtual environment (optional)
poetry shell

Using uv (Alternative)

# Install uv if not already installed
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create virtual environment and install dependencies
uv venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
uv pip install -e ".[dev]"

Configuration

Environment Setup

  1. Copy the example environment file:
cp .env.example .env
  1. Edit .env and add your OpenAI API key:
OPENAI_API_KEY='your-api-key-here'
  1. (Optional) Override config.json settings via environment variables:
# Pattern: SECTION_KEY (e.g., OPENAI_MODEL overrides openai.model)
OPENAI_MODEL='gpt-5-nano'
OPENAI_REASONING_EFFORT='high'
CHROMA_COLLECTION_NAME='my_anime'

Configuration File

Edit resources/config.json to customize:

{
  "chroma": {
    "persist_directory": "./.chroma",
    "collection_name": "tvshows"
  },
  "data": {
    "shows_json": "input/shoko_tvshows.json"
  },
  "openai": {
    "model": "gpt-5-nano",
    "embedding_model": "text-embedding-3-small",
    "reasoning_effort": "medium",
    "output_verbosity": "medium",
    "max_output_tokens": 8192
  },
  "mcp": {
    "enabled": true,
    "cache_dir": "data/mcp_cache",
    "fallback_count_threshold": 3,
    "fallback_score_threshold": 0.5,
    "timeout": 30,
    "servers": {
      "anime": {
        "command": "/path/to/mcp-server-anime/.venv/bin/python",
        "args": ["-m", "mcp_server_anime.server"],
        "cwd": "/path/to/mcp-server-anime",
        "env": {
          "PYTHONPATH": "/path/to/mcp-server-anime/src"
        }
      }
    }
  },
  "ingest": {
    "batch_size": 100
  },
  "logging": {
    "level": "INFO"
  }
}

MCP Configuration (Optional):

  • Set mcp.enabled to false to disable AniDB fallback
  • Adjust fallback_score_threshold (0.0-1.0) to control when fallback to MCP triggers
  • A score of 0.0 is a perfect match, while a score of 1.0 is no match
  • Lower thresholds = stricter (more MCP calls), higher = more lenient
  • See MCP Integration Guide for detailed setup

Usage

CLI Commands

View Configuration

poetry run shokobot info

Displays current configuration, including ChromaDB settings, OpenAI model, and data paths.

Ingest Data

# Use default settings (1,458 anime records)
poetry run shokobot ingest

# Dry-run: validate data without ingesting
poetry run shokobot ingest --dry-run

# Custom input file and batch size
poetry run shokobot ingest -i custom.json -b 200

# Use AniDB_AnimeID as primary identifier
poetry run shokobot ingest --id-field AniDB_AnimeID

Options:

  • -i, --input PATH - Path to JSON file (overrides config)
  • -b, --batch-size INTEGER - Documents per batch (overrides config)
  • --id-field [AnimeID|AniDB_AnimeID] - Primary ID field
  • --dry-run - Validate mappings and show statistics without ingesting

Dry-Run Mode: Use --dry-run to validate your data before ingestion. This mode:

  • Validates all document mappings
  • Shows total document count and batch statistics
  • Displays year range and episode statistics
  • Lists sample titles (first 10)
  • Reports any validation errors
  • Does NOT insert data into the vector store

Query Database

# Single question
poetry run shokobot query -q "What anime are similar to Cowboy Bebop?"

# With context display
poetry run shokobot query -q "Best mecha anime?" -c

# From file (batch processing)
poetry run shokobot query -f questions.txt

# From stdin
echo "What is Steins;Gate about?" | poetry run shokobot query --stdin

# Interactive mode
poetry run shokobot query -i

Options:

  • -q, --question TEXT - Single question to ask
  • -f, --file PATH - File with questions (one per line)
  • --stdin - Read questions from stdin
  • -i, --interactive - Start interactive REPL mode
  • -c, --show-context - Display retrieved context documents
  • --k INTEGER - Number of documents to retrieve (default: 10)
  • --output-format [text|json] - Output format (default: text)

Interactive REPL

# Start REPL mode (recommended for multiple queries)
poetry run shokobot repl

# With context display
poetry run shokobot repl -c

# With custom retrieval count
poetry run shokobot repl --k 15

Options:

  • -c, --show-context - Display retrieved context documents
  • --k INTEGER - Number of documents to retrieve
  • --output-format [text|json] - Output format (default: text)

REPL Commands:

  • Type your question and press Enter
  • exit, quit, or q to leave

Web Interface

# Start on default port (7860)
poetry run shokobot web

# Start on custom port
poetry run shokobot web --port 8080

# Create a public shareable link
poetry run shokobot web --share

# Enable debug logging
poetry run shokobot web --debug

Features:

  • 💬 Chat Interface - Natural language conversation with your anime collection
  • ⚙️ Customizable Settings - Adjust retrieval count (k) and context display
  • 📚 Context Display - See which anime were used to generate recommendations
  • 🎯 Example Queries - Click pre-made examples to get started quickly
  • 📱 Mobile Responsive - Works on desktop, tablet, and mobile devices

Options:

  • --port INTEGER - Port to run the server on (default: 7860)
  • --share - Create a public shareable link via Gradio (expires after 72 hours)
  • --debug - Enable debug mode with verbose logging

Access: Once started, open your browser to http://localhost:7860 (or your custom port). The interface provides an intuitive chat experience with:

  • Real-time responses from the RAG system
  • Adjustable number of documents to retrieve (1-20)
  • Optional context display showing source anime
  • Example queries to help you get started

Sharing: Use the --share flag to create a temporary public URL that you can share with others. This is useful for demos or remote access. The link expires after 72 hours.

  • Questions are processed with cached RAG chain for efficiency

JSON Output Format

For programmatic usage and service integration, both query and repl commands support JSON output:

# Single question with JSON output
poetry run shokobot query -q "What is Frieren about?" --output-format json

# With context metadata
poetry run shokobot query -q "Recommend a sci-fi anime" --output-format json --show-context

# Interactive mode with JSON
poetry run shokobot repl --output-format json

# From file (batch processing)
poetry run shokobot query -f questions.txt --output-format json

# From stdin (pipeline integration)
echo "What is Cowboy Bebop about?" | poetry run shokobot query --stdin --output-format json

JSON Response Structure:

{
  "question": "What is Frieren about?",
  "answer": "Frieren (Sousou no Frieren) is an action-adventure fantasy...",
  "context": [
    {
      "title": "Sousou no Frieren",
      "anime_id": "17617",
      "year": 2023,
      "episodes": 28
    }
  ]
}

Use Cases:

  • Building APIs or microservices on top of ShokoBot
  • Automating batch processing of queries
  • Integrating with other services that expect structured data
  • Parsing and storing responses in databases
  • Creating custom frontends or chatbots

Programmatic Example:

import subprocess
import json

result = subprocess.run(
    ["poetry", "run", "shokobot", "query",
     "-q", "Recommend a sci-fi anime",
     "--output-format", "json"],
    capture_output=True,
    text=True
)

data = json.loads(result.stdout)
print(f"Answer: {data['answer']}")
if 'context' in data:
    print(f"Found {len(data['context'])} relevant anime")

Docker Deployment

ShokoBot includes full Docker support for easy deployment:

# Quick start
make docker-up

# View logs
make docker-logs

# Run commands
docker-compose exec shokobot shokobot query -q "Best mecha anime"

# Ingest data
make docker-ingest FILE=input/shoko_tvshows.json

# Stop services
make docker-down

Available Docker Make commands:

  • make docker-build - Build Docker image
  • make docker-up - Start services
  • make docker-down - Stop services
  • make docker-logs - View logs
  • make docker-shell - Open shell in container
  • make docker-test - Run tests
  • make docker-backup - Backup vector database
  • make docker-clean - Remove containers and volumes

For local development (non-Docker):

  • make install-dev - Install dependencies
  • make test - Run tests locally
  • make format - Format code
  • make lint - Lint code

See DOCKER.md for comprehensive Docker deployment guide including:

  • Production deployment with Nginx
  • SSL/TLS configuration
  • Resource limits and scaling
  • Backup and restore procedures
  • CI/CD integration

Using with uv

Replace poetry run with uv run:

uv run shokobot info
uv run shokobot ingest
uv run shokobot repl
uv run shokobot query -q "..."

Development

Setup Development Environment

# Install with dev dependencies
poetry install --with dev

# Install pre-commit hooks
pre-commit install

Code Quality Tools

# Format code with ruff
poetry run ruff format .

# Lint code with ruff
poetry run ruff check .
poetry run ruff check . --fix  # Auto-fix issues

# Type checking with mypy (strict mode)
poetry run mypy . --strict

# Security scanning with bandit
poetry run bandit -r services models utils cli

# Run all pre-commit hooks
poetry run pre-commit run --all-files

Testing

# Run all tests
poetry run pytest

# Run with coverage
poetry run pytest --cov

# Run specific test file
poetry run pytest tests/config/test_config_service.py

# Verbose output
poetry run pytest -v

# Generate HTML coverage report
poetry run pytest --cov-report=html
open htmlcov/index.html

# Enforce coverage threshold (90%)
poetry run pytest --cov --cov-fail-under=90

Test Coverage: 96.75% (380 tests)

  • MCP JSON Parser: 91.14%
  • MCP Client Service: 98.36%
  • RAG Service: 92.97%
  • All other services: 95%+

Continuous Integration

The project uses GitHub Actions for automated testing and quality checks:

Workflows:

  • Tests - Runs on Python 3.12 and 3.13, enforces 90% coverage threshold
  • Lint - Checks code formatting and linting with ruff
  • Security - Runs bandit security scans weekly

Pull Request Checks: All PRs must pass:

  • ✅ All tests (380+ tests)
  • ✅ Coverage ≥ 90%
  • ✅ Ruff formatting and linting
  • ✅ Type checking with mypy
  • ✅ Security scan with bandit

Setup for Contributors:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Ensure all checks pass locally
  5. Submit a PR using the template

Pre-commit Hooks

The project uses pre-commit hooks for automated quality checks:

  • ruff - Code linting with auto-fix
  • ruff-format - Code formatting (matches GitHub Actions)
  • mypy - Type checking
  • bandit - Security scanning
  • pytest - Run test suite
  • trailing-whitespace - Remove trailing whitespace
  • end-of-file-fixer - Ensure files end with newline
  • check-yaml - Validate YAML files
  • check-json - Validate JSON files

Hooks run automatically on git commit. To run manually:

# Run all hooks
pre-commit run --all-files

# Update hook versions to match GitHub Actions
pre-commit autoupdate

# Run specific hook
pre-commit run ruff-format --all-files

Project Structure

shokobot/
├── cli/                         # Modular CLI commands (auto-loaded)
│   ├── __init__.py             # Main CLI group with auto-loader
│   ├── info.py                 # Configuration display
│   ├── ingest.py               # Data ingestion
│   ├── query.py                # Natural language queries
│   └── repl.py                 # Interactive REPL mode
├── services/                    # Business logic (dependency injection)
│   ├── app_context.py          # Application context
│   ├── config_service.py       # Configuration management
│   ├── ingest_service.py       # Data ingestion logic
│   ├── rag_service.py          # RAG chain with GPT-5 and MCP fallback
│   ├── vectorstore_service.py  # ChromaDB operations
│   ├── mcp_client_service.py   # MCP client for AniDB integration
│   ├── mcp_anime_json_parser.py # MCP response parser
│   └── showdoc_persistence.py  # ShowDoc caching
├── models/                      # Pydantic data models
│   └── show_doc.py             # ShowDoc model (21 fields)
├── prompts/                     # LLM prompt templates (versioned)
│   ├── __init__.py             # Prompt exports
│   ├── anime_rag.py            # Anime RAG prompts
│   ├── title_extraction.py     # Title extraction prompt (for MCP)
│   └── README.md               # Prompt engineering guide
├── utils/                       # Utility functions
│   ├── batch_utils.py          # Batch processing helpers
│   └── text_utils.py           # Text cleaning utilities
├── docs/                        # Documentation
│   ├── README.md               # Documentation index
│   ├── USER_GUIDE.md           # Complete usage guide
│   ├── MCP_INTEGRATION.md      # MCP fallback guide
│   ├── MODULAR_CLI_ARCHITECTURE.md
│   ├── APPCONTEXT_USAGE.md     # Dependency injection guide
│   ├── TESTING_STRATEGY.md     # Testing approach
│   └── SHOWDOC_JSON_EXAMPLE.md # Data format reference
├── resources/                   # Configuration files
│   └── config.json             # Main configuration
├── input/                       # Data files
│   └── shoko_tvshows.json      # Anime data (1,458 records)
├── data/                        # Runtime data
│   └── mcp_cache/              # MCP response cache
├── tests/                       # Test suite
│   ├── config/                 # Config service tests
│   ├── ingest/                 # Ingestion tests
│   └── models/                 # Model tests
├── .env.example                 # Environment template
├── pyproject.toml              # Poetry configuration
├── setup.sh                    # Automated setup script
├── README.md                   # This file
├── SETUP_GUIDE.md              # Detailed setup instructions
└── QUICK_REFERENCE.md          # Command reference

Data Model

The ShowDoc Pydantic model includes 21 comprehensive fields:

Identifiers:

  • anime_id - Unique Shoko anime identifier
  • anidb_anime_id - AniDB anime identifier

Titles:

  • title_main - Primary anime title
  • title_alts - Alternate titles (auto-cleaned)

Content:

  • description - Anime description
  • tags - Tags and genres (auto-cleaned)

Episodes:

  • episode_count_normal - Number of regular episodes
  • episode_count_special - Number of special episodes

Dates:

  • air_date - Initial air date
  • end_date - Final air date
  • begin_year - Year began airing
  • end_year - Year finished airing

Ratings:

  • rating - AniDB rating score (0-1000)
  • vote_count - Number of votes
  • avg_review_rating - Average review rating
  • review_count - Number of reviews

External IDs:

  • ann_id - Anime News Network ID
  • crunchyroll_id - Crunchyroll ID
  • wikipedia_id - Wikipedia page identifier

Relationships:

  • relations - JSON string of related anime
  • similar - JSON string of similar anime

Environment Variables

All config.json settings can be overridden via environment variables using the pattern SECTION_KEY:

# ChromaDB
CHROMA_PERSIST_DIRECTORY='./.chroma'
CHROMA_COLLECTION_NAME='tvshows'

# Data
DATA_SHOWS_JSON='input/shoko_tvshows.json'

# OpenAI
OPENAI_MODEL='gpt-5-nano'
OPENAI_EMBEDDING_MODEL='text-embedding-3-small'
OPENAI_REASONING_EFFORT='medium'      # low/medium/high
OPENAI_OUTPUT_VERBOSITY='medium'      # low/medium/high
OPENAI_MAX_OUTPUT_TOKENS='8192'

# Ingestion
INGEST_BATCH_SIZE='100'

# Logging
LOGGING_LEVEL='INFO'                  # DEBUG/INFO/WARNING/ERROR/CRITICAL

GPT-5 Configuration

ShokoBot uses OpenAI's GPT-5 Responses API with reasoning capabilities:

Supported Models:

  • gpt-5-nano (default)
  • gpt-5-mini
  • gpt-5

Reasoning Effort:

  • low - Faster responses, less reasoning
  • medium - Balanced (default)
  • high - More thorough reasoning, slower

Output Verbosity:

  • low - Concise responses
  • medium - Balanced (default)
  • high - Detailed explanations

Architecture

System Diagram

┌─────────────────────────────────────────────────────────────┐
│                         CLI Layer                           │
│  ┌──────┐  ┌────────┐  ┌───────┐  ┌──────┐                  │
│  │ info │  │ ingest │  │ query │  │ repl │                  │
│  └──┬───┘  └───┬────┘  └───┬───┘  └───┬──┘                  │
└─────┼─────────┼───────────┼──────────┼──────────────────────┘
      │         │           │          │
      └─────────┴───────────┴──────────┘
                     │
      ┌──────────────▼──────────────────────────────────────┐
      │           Application Context                       │
      │  ┌────────────────┐  ┌────────────────────┐         │
      │  │ ConfigService  │  │ VectorStoreService │         │
      │  └────────────────┘  └────────────────────┘         │
      └─────────────────────────────────────────────────────┘
                     │
      ┌──────────────┴──────────────────────────────────────┐
      │              Service Layer                          │
      │  ┌────────────────┐  ┌──────────────────┐           │
      │  │ IngestService  │  │   RAGService     │           │
      │  │                │  │  (with MCP       │           │
      │  │                │  │   fallback)      │           │
      │  └────────────────┘  └──────────────────┘           │
      └─────────────────────────────────────────────────────┘
                     │
      ┌──────────────┴──────────────────────────────────────┐
      │            Data & External                          │
      │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌─────┐  │
      │  │ ChromaDB │  │ OpenAI   │  │ ShowDoc  │  │ MCP │  │
      │  │          │  │          │  │          │  │     │  │
      │  │ (Vector  │  │ (GPT-5 + │  │ (Pydantic│  │(Ani-│  │
      │  │  Store)  │  │Embedding)│  │  Model)  │  │ DB) │  │
      │  └──────────┘  └──────────┘  └──────────┘  └─────┘  │
      └─────────────────────────────────────────────────────┘

MCP Fallback Flow:

  1. User query → RAG Service
  2. Vector store search (ChromaDB)
  3. If results insufficient or poor quality → MCP fallback
  4. MCP fetches from AniDB → Caches locally
  5. Combined results returned to user

Design Patterns

  • Modular CLI - Auto-loading command discovery from cli/ directory
  • Dependency Injection - Services injected via AppContext
  • Rich Formatting - Professional CLI with Rich-Click
  • Pydantic Validation - Type-safe data models with automatic validation
  • Batch Processing - Efficient chunked operations for large datasets

Key Components

  1. CLI Layer - Rich-Click commands with auto-loading
  2. Application Context - Centralized service management
  3. Service Layer - Business logic with dependency injection
  4. Data Layer - ChromaDB vector store and OpenAI embeddings
  5. Model Layer - Pydantic models with validation

Documentation

User Guides

Architecture Documentation

Troubleshooting

Common Issues

OpenAI API Key not set:

export OPENAI_API_KEY='your-key-here'
# Or add to .env file

ChromaDB permission issues:

rm -rf ./.chroma
poetry run shokobot ingest

Import errors:

poetry install
poetry run shokobot --help

Module not found:

# Ensure you're using poetry run or uv run
poetry run shokobot info

# Or activate the virtual environment
poetry shell
shokobot info

Performance

  • Ingestion: ~40-50 seconds for 1,458 anime records
  • Query Response: ~3-6 seconds (including LLM processing)
  • Interactive Mode: Cached RAG chain for efficiency
  • Batch Size: 100 documents per batch (configurable)

Tips & Best Practices

Performance

  • Use repl mode for multiple queries (avoids reloading RAG chain)
  • Adjust --k parameter to control context size (default: 10)
  • Increase batch size for faster ingestion on powerful machines
  • Use environment variables for quick configuration changes

Data Quality

  • Ensure input/shoko_tvshows.json is properly formatted JSON
  • Check logs for validation errors during ingestion
  • Use --id-field to control primary identifier selection

Querying

  • Be specific in questions for better results
  • Use natural language (e.g., "romance anime with strong characters")
  • Try different phrasings if results aren't satisfactory
  • Use context display (-c) to understand retrieval quality

Development

  • Run poetry run shokobot info to verify configuration
  • Use --show-context to debug RAG retrieval
  • Check docs/ for architecture details before modifying
  • Follow Python 3.12+ type hints and Pydantic patterns

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run quality checks: pre-commit run --all-files
  5. Run tests: pytest
  6. Submit a pull request

License

MIT

Resources

Python & Tools

Frameworks & Libraries

AI & Vector Databases

About

A Retrieval Augmented Generation (RAG) LLM for Anime show recommendations

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages