{"id":46902823,"url":"https://github.com/jamditis/hawk-translation-api","last_synced_at":"2026-03-11T00:12:09.305Z","repository":{"id":339492699,"uuid":"1162163165","full_name":"jamditis/hawk-translation-api","owner":"jamditis","description":"REST API for translating journalism content into 10 languages — built for NJ News Commons partner newsrooms","archived":false,"fork":false,"pushed_at":"2026-03-04T23:09:16.000Z","size":2038,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-05T04:52:27.378Z","etag":null,"topics":["celery","deepl","fastapi","journalism","newsroom","postgresql","python","translation"],"latest_commit_sha":null,"homepage":"https://jamditis.github.io/hawk-translation-api/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamditis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-19T23:54:14.000Z","updated_at":"2026-03-04T23:09:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jamditis/hawk-translation-api","commit_stats":null,"previous_names":["jamditis/hawk-translation-api"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jamditis/hawk-translation-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamditis%2Fhawk-translation-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamditis%2Fhawk-translation-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamditis%2Fhawk-translation-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamditis%2Fhawk-translation-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamditis","download_url":"https://codeload.github.com/jamditis/hawk-translation-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamditis%2Fhawk-translation-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30363007,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"ssl_error","status_checked_at":"2026-03-10T21:40:59.357Z","response_time":106,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["celery","deepl","fastapi","journalism","newsroom","postgresql","python","translation"],"created_at":"2026-03-11T00:12:09.029Z","updated_at":"2026-03-11T00:12:09.294Z","avatar_url":"https://github.com/jamditis.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hawk News Service translation API\n\n[![Tests](https://github.com/jamditis/hawk-translation-api/actions/workflows/tests.yml/badge.svg)](https://github.com/jamditis/hawk-translation-api/actions/workflows/tests.yml)\n[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)\n[![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-orange)](https://jamditis.github.io/hawk-translation-api/)\n\nA human translator-centered REST API for translating journalism content into 10 languages. Machine translation and AI quality scoring produce a first draft; professional human translators review, edit, and certify the final output. Built for the [Center for Cooperative Media](https://centerforcooperativemedia.org)'s Spanish Translation News Service (STNS) and NJ News Commons partner newsrooms.\n\n**Docs:** [jamditis.github.io/hawk-translation-api](https://jamditis.github.io/hawk-translation-api/) — how it works, interface mockups, Spanish style guide, and term glossary.\n\n---\n\n## How it works\n\nEvery translation passes through a pipeline designed to support human translators, not replace them. Machine translation generates a first draft, AI scoring highlights problem areas, and human translators make the final call on quality.\n\n```\nPOST /v1/translate\n    → validate API key\n    → check quota\n    → create job record\n    → enqueue pipeline task\n    → return 202 + job_id\n\nPipeline (machine draft)\n    → segment HTML (BeautifulSoup4)\n    → apply NJ journalism glossary (proper nouns, gov titles, place names)\n    → generate machine draft via claude -p subprocess\n    → reassemble HTML\n    → AI quality scoring flags segments for human attention\n\nHuman translator review\n    → reviewer assigned by language pair + availability\n    → side-by-side editor: machine draft vs. source\n    → AI scores highlight segments that need the most attention\n    → translator edits, approves, or rewrites segments\n    → certified tier: second translator verifies\n\nDelivery\n    → webhook fires when human-approved translation is ready\n    → result available at GET /v1/translate/{job_id}\n```\n\n### Translation tiers\n\n| Tier | What happens |\n|---|---|\n| **Instant** | Machine draft + AI scoring. Fast turnaround, no human review. Suitable for time-sensitive content where speed matters most. |\n| **Reviewed** | Machine draft + AI scoring + **one human translator** reviews and edits. The standard for publication-quality journalism translation. |\n| **Certified** | Machine draft + AI scoring + **human translator reviews** + **second translator certifies**. Full audit trail of edits. For content requiring the highest accuracy. |\n\n## Stack\n\n| Component | Technology |\n|---|---|\n| **Human translators** | Professional bilingual journalists and translators matched by language pair |\n| API server | FastAPI + uvicorn (port 8091) |\n| Task queue | Celery 5.3 + Redis |\n| Database | PostgreSQL 15 + SQLAlchemy 2.0 + Alembic |\n| Machine draft | `claude -p` subprocess — all 10 languages via Claude subscription |\n| AI quality scoring | `claude -p` subprocess — flags segments for human translator attention |\n\n## Languages\n\n| Language | Code | Status |\n|---|---|---|\n| Spanish | `es` | Supported |\n| Portuguese | `pt` | Supported |\n| Chinese (Simplified) | `zh` | Supported |\n| Korean | `ko` | Supported |\n| Arabic | `ar` | Supported |\n| French | `fr` | Supported |\n| Polish | `pl` | Supported |\n| Haitian Creole | `ht` | Limited |\n| Hindi | `hi` | Limited |\n| Urdu | `ur` | Limited |\n\n## Local dev\n\n```bash\npython3 -m venv venv \u0026\u0026 source venv/bin/activate\npip install -r requirements.txt -r requirements-dev.txt\ncp .env.example .env  # fill in real values\nalembic upgrade head\nuvicorn api.main:app --host 0.0.0.0 --port 8091 --reload\ncelery -A workers.celery_app worker --loglevel=info  # separate terminal\n```\n\nRequires: PostgreSQL and Redis running locally.\n\n## Tests\n\n```bash\n# Unit tests (97+ tests, no live services needed)\npytest -v\n\n# Acceptance tests (requires live API + Claude CLI logged in)\nHAWK_API_KEY=hawk_test_xxx HAWK_API_BASE_URL=http://localhost:8091 pytest tests/acceptance/ -v -s\n```\n\n## API\n\n### Submit a translation job\n\n```http\nPOST /v1/translate\nAuthorization: Bearer hawk_live_\u003ckey\u003e\nContent-Type: application/json\n\n{\n  \"content\": \"\u003cp\u003eYour article HTML here\u003c/p\u003e\",\n  \"source_language\": \"en\",\n  \"target_language\": \"es\",\n  \"tier\": \"reviewed\",\n  \"callback_url\": \"https://yoursite.com/webhook\"\n}\n```\n\nThe `tier` field controls how much human translator involvement your job gets:\n- `\"instant\"` — machine draft + AI scoring only (no human review)\n- `\"reviewed\"` — machine draft reviewed and edited by a human translator\n- `\"certified\"` — reviewed by one translator, certified by a second\n\nReturns `202 Accepted` with a `job_id`.\n\n### Check job status\n\n```http\nGET /v1/translate/{job_id}\nAuthorization: Bearer hawk_live_\u003ckey\u003e\n```\n\n### List supported languages\n\n```http\nGET /v1/languages\n```\n\n## Deployment\n\nRun directly on houseofjawn (the API runs there — no SSH needed):\n\n```bash\n# First time\n./scripts/deploy-houseofjawn.sh --install\n\n# Subsequent deploys\n./scripts/deploy-houseofjawn.sh\n```\n\nThe deploy script installs deps, runs `alembic upgrade head`, and restarts `hawk-api` and `hawk-worker` systemd services.\n\n---\n\n## Philosophy\n\nMachine translation is a tool, not a replacement for human expertise. The Hawk News Service exists because NJ's diverse communities deserve journalism translated by people who understand the language, the culture, and the local context. Every piece of technology in this pipeline — Claude-powered machine drafts, AI quality scoring, the glossary system — exists to make human translators faster and more effective, not to cut them out of the process.\n\n---\n\nBuilt by [Joe Amditis](https://github.com/jamditis) for the Center for Cooperative Media, Montclair State University.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamditis%2Fhawk-translation-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamditis%2Fhawk-translation-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamditis%2Fhawk-translation-api/lists"}