Ad-hoc scoring API for SeeClickFix issues. Give it an issue ID, get back interaction and outcome sentiment scores powered by GPT-4o-mini.
Built to back a browser extension that displays scores directly on SeeClickFix issue pages.
- You send a SeeClickFix issue ID (e.g.
18326635fromseeclickfix.com/.../issues/18326635) - The API fetches the issue details and full comment thread from the SeeClickFix v2 API
- It identifies city employees, flags auto-generated comments, and sends the thread to GPT-4o-mini
- The LLM scores two dimensions:
- Interaction — how did city staff communicate with residents?
- Outcome — was the reported problem actually resolved?
- Results are cached in SQLite. Subsequent requests return instantly.
GET /api/issues/{issue_id}
Fetches, scores, and returns results. First call hits the SeeClickFix API + LLM (a few seconds). Cached calls return in ~30ms.
| Parameter | Type | Default | Description |
|---|---|---|---|
issue_id |
path | required | SeeClickFix issue ID |
force |
query | false |
Re-fetch and re-score even if cached |
curl https://scfs-api.hackjc.org/api/issues/18326635{
"issue_id": 18326635,
"status": "Open",
"summary": "Construction on Street/Sidewalk",
"description": "There is construction at this address that has been ...",
"address": "123 Example St, Jersey City, NJ",
"request_type": "Building and Streets",
"department": "Code Compliance",
"html_url": "https://seeclickfix.com/issues/18326635",
"created_at": "2025-02-14T12:00:00-05:00",
"closed_at": null,
"interaction": {
"label": "negative",
"confidence": 0.9,
"reasoning": "Residents expressed frustration with the city's responses, indicating a lack of effective communication and resolution."
},
"outcome": {
"label": "negative",
"confidence": 0.9,
"reasoning": "The issue remains unresolved despite multiple complaints and follow-ups from residents."
},
"employees": [
{
"commenter_id": 12345,
"name_raw": "Code Compliance Inspector - Brian",
"name_parsed": "Brian",
"title_parsed": "Code Compliance Inspector",
"department": "Code Compliance"
}
],
"comments": [
{
"id": 67890,
"comment": "Thank you for reporting an issue to the City of Jersey City...",
"created_at": "2025-02-14T14:00:00-05:00",
"commenter_name": "Code Compliance Inspector - Brian",
"commenter_role": "Verified Official",
"is_auto_generated": false
}
],
"cached": false
}The cached field tells you whether this was a fresh score (false) or served from cache (true).
curl https://scfs-api.hackjc.org/api/issues/18326635?force=true| Status | Meaning |
|---|---|
404 |
Issue not found on SeeClickFix |
500 |
LLM or internal error |
GET /up
Returns "ok" with status 200.
GET /docs
Interactive Swagger UI with request/response schemas.
Both interaction and outcome use the same label set:
| Label | Interaction meaning | Outcome meaning |
|---|---|---|
positive |
Staff were responsive, helpful, professional | Problem was fixed, action was taken |
negative |
Staff were dismissive, confrontational, unresponsive | Issue ignored, closed without resolution |
neutral |
No resident interaction to evaluate | Unclear resolution, in progress, jurisdictional |
mixed |
Some good, some bad exchanges | Partial resolution or conflicting signals |
Each label comes with a confidence score (0.0–1.0) and a one-sentence reasoning.
- Python 3.11+
- OpenAI API key
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
export OPENAI_API_KEY=sk-...
python -m src.entrypointServer starts on http://localhost:8000.
| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY |
required | OpenAI API key |
OPENAI_MODEL |
gpt-4o-mini |
Model for scoring |
LLM_BACKEND |
openai |
openai or ollama |
OLLAMA_URL |
http://localhost:11434 |
Ollama server URL |
OLLAMA_MODEL |
llama3.1:8b |
Ollama model name |
DATA_DIR |
./data |
SQLite database directory |
WEB_HOST |
0.0.0.0 |
Bind address |
WEB_PORT |
8000 |
Bind port |
CORS_ORIGINS |
* |
Allowed CORS origins (comma-separated) |
Uses Kamal to deploy to scfs-api.hackjc.org:
kamal setup # first time
kamal deploy # subsequent deploysRequires KAMAL_REGISTRY_PASSWORD and OPENAI_API_KEY env vars.