# cphos/ai_scoring architecture

> Architecture diagram of the GitHub repository cphos/ai_scoring, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-29). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/cphos/ai_scoring
- Repository: https://github.com/cphos/ai_scoring

## Overview

CPHOS AI is a command-line handwritten physics-answer transcription and grading system. Its principal workflow accepts answer images or PDFs and a TeX rubric, then runs a mode-specific pipeline: recognize transcribes handwriting, judge parses the rubric and scores a transcription, while direct scores images without an intermediate transcription. Results are rendered as Markdown; batch modes also summarize per-file outcomes. The README documents these capabilities, while sampled handlers confirm pipeline dispatch and model calls; unsampled subsystem wiring is shown only where documented.

Main entry points: [`src/pipeline/handlers.py`](https://github.com/cphos/ai_scoring/blob/main/src/pipeline/handlers.py) (Stage Handlers), [`src/pipeline/pipeline.py`](https://github.com/cphos/ai_scoring/blob/main/src/pipeline/pipeline.py) (Mode Pipeline), [`src/client/openrouter.py`](https://github.com/cphos/ai_scoring/blob/main/src/client/openrouter.py) (OpenRouter Client), [`src/app/cli.py`](https://github.com/cphos/ai_scoring/blob/main/src/app/cli.py) (Command Router)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_entry["CLI and Pipeline"]
  node_cli["Command Router<br/>[cli.py]"]
  node_pipeline["Mode Pipeline<br/>[pipeline.py]"]
  node_handlers["Stage Handlers<br/>[handlers.py]"]
  node_context["Pipeline Context<br/>[context.py]"]
  node_states["Mode Transitions<br/>[states.py]"]
end

subgraph group_recognition["Recognition"]
  node_recognition_service["Recognition Service<br/>[service.py]"]
  node_input_processing["Image/PDF Loading"]
  node_recognition_prompt["Transcription Prompt<br/>[prompt_builder.py]"]
  node_recognition_yaml["Recognition Template<br/>[recognize.yaml]"]
  node_recognition_result["Transcription Result<br/>[output.py]"]
end

subgraph group_grading["Rubric and Grading"]
  node_grading_service["Grading Service<br/>[service.py]"]
  node_rubric_parser["Rubric Parser<br/>[answer_parser.py]"]
  node_rubric["Scoring Rubric<br/>[types.py]"]
  node_judge_prompt["Scoring Prompt<br/>[prompt_builder.py]"]
  node_judge_yaml["Judge Template<br/>[judge.yaml]"]
  node_judge_parser["Score Response Parser<br/>[response_parser.py]"]
  node_grading_result["Scoring Result<br/>[output.py]"]
end

subgraph group_services["Model Services"]
  node_settings["Model Settings<br/>[settings.py]"]
  node_openrouter["OpenRouter Client<br/>[openrouter.py]"]
end

node_operator(("CLI User"))
node_answer_files["Answer Images/PDFs"]
node_rubric_file["TeX Answer Key"]
node_openrouter_api{{"OpenRouter API"}}
node_markdown_output["Markdown Results"]

node_operator -->|"invokes"| node_cli
node_cli -->|"dispatches"| node_recognition_service
node_cli -->|"dispatches"| node_grading_service
node_recognition_service -->|"runs mode"| node_pipeline
node_grading_service -->|"runs mode"| node_pipeline
node_pipeline -->|"dispatches stages"| node_handlers
node_pipeline -->|"selects transitions"| node_states
node_pipeline -->|"updates state"| node_context
node_answer_files -->|"supplies files"| node_input_processing
node_handlers -->|"loads inputs"| node_input_processing
node_handlers -->|"builds prompt"| node_recognition_prompt
node_recognition_yaml -->|"provides template"| node_recognition_prompt
node_handlers -->|"requests transcription"| node_openrouter
node_handlers -->|"parses rubric"| node_rubric_parser
node_rubric_file -->|"supplies TeX"| node_rubric_parser
node_rubric_parser -->|"produces rubric"| node_rubric
node_handlers -->|"builds scoring prompt"| node_judge_prompt
node_judge_yaml -->|"provides template"| node_judge_prompt
node_handlers -->|"requests scoring"| node_openrouter
node_openrouter -->|"uses configuration"| node_settings
node_openrouter -->|"sends requests"| node_openrouter_api
node_openrouter_api -->|"returns responses"| node_openrouter
node_handlers -->|"parses scores"| node_judge_parser
node_handlers -->|"creates transcription"| node_recognition_result
node_handlers -->|"creates scores"| node_grading_result
node_recognition_service -->|"renders transcription"| node_markdown_output
node_grading_service -->|"renders scores"| node_markdown_output

click node_cli "https://github.com/cphos/ai_scoring/blob/main/src/app/cli.py"
click node_recognition_service "https://github.com/cphos/ai_scoring/blob/main/src/recognize/service.py"
click node_grading_service "https://github.com/cphos/ai_scoring/blob/main/src/judge/service.py"
click node_pipeline "https://github.com/cphos/ai_scoring/blob/main/src/pipeline/pipeline.py"
click node_handlers "https://github.com/cphos/ai_scoring/blob/main/src/pipeline/handlers.py"
click node_context "https://github.com/cphos/ai_scoring/blob/main/src/pipeline/context.py"
click node_states "https://github.com/cphos/ai_scoring/blob/main/src/pipeline/states.py"
click node_input_processing "https://github.com/cphos/ai_scoring/blob/main/src/recognize/input_processing.py"
click node_recognition_prompt "https://github.com/cphos/ai_scoring/blob/main/src/recognize/prompt_builder.py"
click node_recognition_yaml "https://github.com/cphos/ai_scoring/blob/main/src/prompts/recognize.yaml"
click node_recognition_result "https://github.com/cphos/ai_scoring/blob/main/src/recognize/output.py"
click node_rubric_parser "https://github.com/cphos/ai_scoring/blob/main/src/judge/answer_parser.py"
click node_rubric "https://github.com/cphos/ai_scoring/blob/main/src/judge/types.py"
click node_judge_prompt "https://github.com/cphos/ai_scoring/blob/main/src/judge/prompt_builder.py"
click node_judge_yaml "https://github.com/cphos/ai_scoring/blob/main/src/prompts/judge.yaml"
click node_judge_parser "https://github.com/cphos/ai_scoring/blob/main/src/judge/response_parser.py"
click node_grading_result "https://github.com/cphos/ai_scoring/blob/main/src/judge/output.py"
click node_settings "https://github.com/cphos/ai_scoring/blob/main/src/config/settings.py"
click node_openrouter "https://github.com/cphos/ai_scoring/blob/main/src/client/openrouter.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_cli,node_pipeline,node_handlers,node_context,node_states,node_operator toneBlue
class node_recognition_service,node_input_processing,node_recognition_prompt,node_recognition_yaml,node_recognition_result toneAmber
class node_grading_service,node_rubric_parser,node_rubric,node_judge_prompt,node_judge_yaml,node_judge_parser,node_grading_result,node_openrouter_api toneMint
class node_settings,node_openrouter toneRose
class node_answer_files,node_rubric_file,node_markdown_output toneIndigo
```

## Components

### CLI and Pipeline

- [Command Router](https://github.com/cphos/ai_scoring/blob/main/src/app/cli.py): `src/app/cli.py`
- [Mode Pipeline](https://github.com/cphos/ai_scoring/blob/main/src/pipeline/pipeline.py): `src/pipeline/pipeline.py`
- [Stage Handlers](https://github.com/cphos/ai_scoring/blob/main/src/pipeline/handlers.py): `src/pipeline/handlers.py`
- [Pipeline Context](https://github.com/cphos/ai_scoring/blob/main/src/pipeline/context.py): `src/pipeline/context.py`
- [Mode Transitions](https://github.com/cphos/ai_scoring/blob/main/src/pipeline/states.py): `src/pipeline/states.py`

### Recognition

- [Recognition Service](https://github.com/cphos/ai_scoring/blob/main/src/recognize/service.py): `src/recognize/service.py`
- [Image/PDF Loading](https://github.com/cphos/ai_scoring/blob/main/src/recognize/input_processing.py): `src/recognize/input_processing.py`
- [Transcription Prompt](https://github.com/cphos/ai_scoring/blob/main/src/recognize/prompt_builder.py): `src/recognize/prompt_builder.py`
- [Recognition Template](https://github.com/cphos/ai_scoring/blob/main/src/prompts/recognize.yaml): `src/prompts/recognize.yaml`
- [Transcription Result](https://github.com/cphos/ai_scoring/blob/main/src/recognize/output.py): `src/recognize/output.py`

### Rubric and Grading

- [Grading Service](https://github.com/cphos/ai_scoring/blob/main/src/judge/service.py): `src/judge/service.py`
- [Rubric Parser](https://github.com/cphos/ai_scoring/blob/main/src/judge/answer_parser.py): `src/judge/answer_parser.py`
- [Scoring Rubric](https://github.com/cphos/ai_scoring/blob/main/src/judge/types.py): `src/judge/types.py`
- [Scoring Prompt](https://github.com/cphos/ai_scoring/blob/main/src/judge/prompt_builder.py): `src/judge/prompt_builder.py`
- [Judge Template](https://github.com/cphos/ai_scoring/blob/main/src/prompts/judge.yaml): `src/prompts/judge.yaml`
- [Score Response Parser](https://github.com/cphos/ai_scoring/blob/main/src/judge/response_parser.py): `src/judge/response_parser.py`
- [Scoring Result](https://github.com/cphos/ai_scoring/blob/main/src/judge/output.py): `src/judge/output.py`

### Model Services

- [Model Settings](https://github.com/cphos/ai_scoring/blob/main/src/config/settings.py): `src/config/settings.py`
- [OpenRouter Client](https://github.com/cphos/ai_scoring/blob/main/src/client/openrouter.py): `src/client/openrouter.py`

### Other components

- **CLI User**
- **Answer Images/PDFs**
- **TeX Answer Key**
- **OpenRouter API**
- **Markdown Results**

## Connections

- CLI User → Command Router: invokes
- Command Router → Recognition Service: dispatches
- Command Router → Grading Service: dispatches
- Recognition Service → Mode Pipeline: runs mode
- Grading Service → Mode Pipeline: runs mode
- Mode Pipeline → Stage Handlers: dispatches stages
- Mode Pipeline → Mode Transitions: selects transitions
- Mode Pipeline → Pipeline Context: updates state
- Answer Images/PDFs → Image/PDF Loading: supplies files
- Stage Handlers → Image/PDF Loading: loads inputs
- Stage Handlers → Transcription Prompt: builds prompt
- Recognition Template → Transcription Prompt: provides template
- Stage Handlers → OpenRouter Client: requests transcription
- Stage Handlers → Rubric Parser: parses rubric
- TeX Answer Key → Rubric Parser: supplies TeX
- Rubric Parser → Scoring Rubric: produces rubric
- Stage Handlers → Scoring Prompt: builds scoring prompt
- Judge Template → Scoring Prompt: provides template
- Stage Handlers → OpenRouter Client: requests scoring
- OpenRouter Client → Model Settings: uses configuration
- OpenRouter Client → OpenRouter API: sends requests
- OpenRouter API → OpenRouter Client: returns responses
- Stage Handlers → Score Response Parser: parses scores
- Stage Handlers → Transcription Result: creates transcription
- Stage Handlers → Scoring Result: creates scores
- Recognition Service → Markdown Results: renders transcription
- Grading Service → Markdown Results: renders scores
