HumanifyAI helps writers inspect stiff or overly formal English prose, apply selected editing rules, and compare the result with the original. It combines a FastAPI service with a responsive browser workspace and does not require an external LLM API.
The project deliberately separates two concerns:
- Analysis extracts 15 linguistic measurements and scores 12 of them against documented writing-style ranges.
- Transformation applies opt-in rules for contractions, formal phrasing, sentence variety, and selected passive constructions.
The Human-Likeness score is a hand-tuned writing heuristic. It is not a trained AI detector, cannot prove authorship, and should not be used for academic-integrity or employment decisions.
- Before/after comparison with score delta, word count, sentence count, and actionable suggestions.
- Twelve scored signals including sentence-length variance, lexical diversity, contraction rate, passive-voice rate, and first-person usage.
- Four independent rewrite controls so users can review the effect of each transformation pass.
- Deterministic API output: identical text and options produce identical rewrites.
- Input validation from 10 to 10,000 characters.
- In-memory processing with
Cache-Control: no-storeon API responses. - Per-client sliding-window rate limiting and explicit CORS origins.
- Security headers, restrictive script CSP, and DOM rendering through
textContent/form values. - Keyboard-accessible controls, live error states, mobile layout, and reduced-motion support.
- OpenAPI documentation at
/api/docs.
The analyzer calculates raw measurements such as average sentence length, sentence-length variance, punctuation density, lexical diversity, contraction rate, question rate, hedging, first-person language, conjunction-led sentences, passive voice, syllable density, and uncommon-word rate.
Each scored signal has a target interval and weight. Values inside the interval receive the full component score; values outside it decay based on their distance from the interval. The final 0–100 result is the weighted average of those component scores.
This design makes the output inspectable and fast, but it also means the score reflects the project’s editorial assumptions—not a universal definition of human writing.
Transformations run in a fixed order:
- Direct voice replaces a curated set of impersonal constructions with clearer alternatives.
- Formal simplification shortens verbose phrases and substitutes plainer wording.
- Contractions converts common expanded forms into conversational contractions.
- Sentence variety changes selected repetitive openings in longer passages.
Every pass is optional. HumanifyAI returns both versions so the user remains the final editor.
git clone https://github.com/evan-william/humanifyai.git
cd humanifyai
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS/Linux
source .venv/bin/activate
pip install -r requirements.txt
uvicorn main:app --reloadOpen:
- Dashboard:
http://localhost:8000 - OpenAPI UI:
http://localhost:8000/api/docs - Health check:
http://localhost:8000/api/health
For production, copy .env.example to .env, replace the default secret, and configure explicit allowed origins.
POST /api/v1/analyze
Content-Type: application/json{
"text": "Honestly, I think the team should start small and adjust as it learns."
}The response contains the composite score, grade, counts, component scores, and editing suggestions.
POST /api/v1/transform
Content-Type: application/json{
"text": "It can be seen that the utilization of this method is important.",
"options": {
"use_contractions": true,
"simplify_formal": true,
"vary_sentences": true,
"rewrite_passive": true
}
}The response preserves the original text and returns the transformed text, before/after analyses, and score delta.
.
├── main.py # FastAPI app and middleware wiring
├── api/
│ ├── middleware/ # Rate limiting and response headers
│ ├── models/schemas.py # Validated request/response contracts
│ └── routers/ # Analyze, transform, health, dashboard
├── core/
│ ├── analyzer.py # Feature extraction and heuristic scoring
│ ├── transformer.py # Four-pass rule engine
│ └── config.py # Environment-backed settings
├── dashboard/
│ ├── templates/index.html # Accessible server-rendered shell
│ └── static/ # Product CSS and dependency-free JS
└── tests/
├── unit/ # Analyzer and transformer behavior
└── integration/ # API, dashboard, headers, and CSP
| Variable | Default | Purpose |
|---|---|---|
ENVIRONMENT |
development |
Runtime mode |
MAX_TEXT_LENGTH |
10000 |
Maximum request characters |
RATE_LIMIT_REQUESTS |
60 |
Requests allowed per client/window |
RATE_LIMIT_WINDOW |
60 |
Window length in seconds |
ALLOWED_ORIGINS |
localhost only | Explicit CORS origins |
LOG_LEVEL |
INFO |
Application logging level |
The in-memory limiter is suitable for a single-process deployment. Use a shared store such as Redis when running multiple workers or replicas.
pytest -qCurrent local verification: 54 tests passing, covering the analyzer, transform rules, option behavior, deterministic output, validation, API contracts, security headers, CSP, and dashboard rendering.
- English-only rules and target ranges.
- Regex-based sentence and passive-voice detection can miss complex grammar.
- Phrase substitutions cannot fully preserve intent in every domain.
- A higher heuristic score does not guarantee better writing.
- The service does not detect plagiarism, factual errors, or whether text was generated by AI.
- The default rate limiter is process-local.
MIT — see LICENSE.
