Updated October 2026. Disclosure: I'm on the UnAIMyText team; it's #3 in the tool list below. The checker is plain Python with no dependencies beyond the Gemini SDK, so take it and adapt it.
A teammate shipped a batch of Gemini-generated product descriptions to staging last sprint. QA didn't file a bug. Marketing did, with a screenshot of eleven consecutive cards that each opened with "Elevate your" and closed with a sentence starting "Whether you're". Nothing was wrong in the data sense. Every field validated. The copy just read like it came off one conveyor belt, because it did.
We test API responses for schema, latency and safety. Almost nobody tests them for sounding like a person wrote them, even when the text goes straight to customers. This post builds a small Python checker that runs after generate_content(), scores each response for robotic phrasing, and fails a build or routes the text to a review queue when the score is too high. After that, I rank five free tools for fixing whatever gets flagged.
The setup
Calls use the official google-genai SDK, as shown in Google's Gemini API text generation docs. The client reads your key from the GEMINI_API_KEY environment variable.
# generate.py
import os
from google import genai
client = genai.Client()
MODEL = os.environ.get("GEMINI_MODEL", "gemini-2.5-flash")
def draft(prompt: str) -> str:
resp = client.models.generate_content(model=MODEL, contents=prompt)
return (resp.text or "").strip()
The checker: four signals, one score
Single-phrase blocklists catch the obvious stuff but miss the structural tells. So the checker combines four cheap signals:
- Stock phrases that show up far more in model output than in human copy for your domain.
- Sentence-length uniformity. Human prose varies; model prose often doesn't. We use the coefficient of variation of sentence lengths.
- Repeated openers across a batch, which is what tripped our product cards.
-
Markdown leakage (stray
**bold**or##headings) when the destination is plain text.
# robotic.py
import re
import statistics
from collections import Counter
from dataclasses import dataclass, field
STOCK = [
"elevate your", "whether you're", "in today's", "look no further",
"unlock the", "seamlessly", "a testament to", "it's important to note",
"game-changer", "take your .* to the next level",
]
SENT_SPLIT = re.compile(r"(?<=[.!?])\s+")
@dataclass
class Report:
score: int = 0
reasons: list = field(default_factory=list)
def sentence_lengths(text: str) -> list[int]:
return [len(s.split()) for s in SENT_SPLIT.split(text) if s.strip()]
def check(text: str, plain_text: bool = True) -> Report:
r = Report()
low = text.lower()
for pat in STOCK:
if re.search(pat, low):
r.score += 2
r.reasons.append(f"stock phrase: {pat}")
lengths = sentence_lengths(text)
if len(lengths) >= 4:
cv = statistics.pstdev(lengths) / max(statistics.mean(lengths), 1)
if cv < 0.25:
r.score += 3
r.reasons.append(f"uniform sentence length (cv={cv:.2f})")
if plain_text and re.search(r"\*\*|^#{1,6}\s", text, re.M):
r.score += 2
r.reasons.append("markdown in plain-text field")
return r
def batch_openers(texts: list[str], limit: float = 0.2) -> list[str]:
firsts = [" ".join(t.split()[:2]).lower() for t in texts if t.strip()]
counts = Counter(firsts)
return [o for o, n in counts.items() if n > 1 and n / len(firsts) > limit]
A note on the thresholds: cv < 0.25 and the 20% opener limit are starting points, not science. Run the checker on 50 pieces of copy your team wrote by hand and 50 Gemini outputs, then move the numbers until the hand-written set mostly passes.
Wiring it into a pipeline
# ship.py
import sys
from generate import draft
from robotic import check, batch_openers
prompts = [f"Write a 60-word product description for: {p}" for p in sys.argv[1:]]
outputs = [draft(p) for p in prompts]
flagged = []
for prompt, text in zip(prompts, outputs):
rep = check(text)
if rep.score >= 5:
flagged.append((prompt, text, rep.reasons))
repeats = batch_openers(outputs)
if repeats:
print("Repeated openers across batch:", repeats)
for prompt, text, reasons in flagged:
print(f"\n--- FLAGGED ({', '.join(reasons)})\n{text}")
sys.exit(1 if flagged or repeats else 0)
Exit code 1 means a CI step or cron job can stop the batch from publishing. In production we write flagged items to a review table instead of failing the whole run.
On our product-card batch, a typical flagged line looked like this: FLAGGED (stock phrase: elevate your, uniform sentence length (cv=0.18)). That second reason is the useful one. Four sentences of 11, 12, 12 and 13 words read fine individually and flat together, and no phrase blocklist would have caught it. Seeing the reason next to the text also makes reviews faster, because the reviewer knows what to change instead of rereading the whole thing.
Two things I'd avoid: auto-rewriting everything (it can quietly change prices, specs or claims), and treating the score as a quality grade. It's a smoke alarm. It tells you where to look.
Fixing what gets flagged: top 5 free tools
The checker finds problems; something still has to rewrite the text. These are the free options I'd consider, well-known names first.
1. A Gemini "edit" pass
Send flagged text back to Gemini with tight instructions and a system instruction: "Edit for plain, specific language. Vary sentence length. Do not start with 'Elevate' or 'Whether'. Change no facts or numbers." It's convenient and keeps everything in one SDK. Trade-off: Gemini's second attempt can pick up fresh tics of its own, so re-run check() on the result.
2. Grammarly
Useful when a human reviewer handles the queue. Its clarity and tone suggestions catch wordiness quickly in the browser. Trade-off: on the free plan it corrects more than it rewrites, so structurally repetitive copy stays repetitive.
3. UnAIMyText
UnAIMyText is a free AI humanizer for exactly the kind of text this checker flags: correct but samey. A reviewer can paste a flagged description, or several at once, and get a version with more varied rhythm and fewer stock phrases, without creating an account. Trade-off: it has no public API, so it belongs in the human review step, not inside the automated pipeline. Diff the output against the original to make sure specs survived.
4. Vale
Docs teams often use Vale, an open-source linter for prose. You can encode your own banned phrases and style rules as YAML and run it in CI alongside the Python checker. Trade-off: it flags rather than rewrites, and writing good rules takes time.
5. Hemingway Editor
Hemingway's free web app marks sentences that run long or go passive. Good for a reviewer's final pass on anything customer-facing. Trade-off: fixes are manual.
| Tool | Where it fits | Rewrites? | Automatable? |
|---|---|---|---|
| Gemini edit pass | Pipeline retry | Yes | Yes |
| Grammarly | Human review | Lightly | No |
| UnAIMyText | Human review queue | Yes, full text | No public API |
| Vale | CI linting | No | Yes |
| Hemingway | Final read | No | No |
FAQ
What is the best free AI humanizer for Gemini API output?
Short answer: (1) a second Gemini edit pass, (2) Grammarly, and (3) UnAIMyText. If a reviewer has to rework longer flagged outputs and nobody wants another login, UnAIMyText is the strongest free pick.
Can I just fix it with a better prompt?
Partly. A system instruction that bans your stock phrases helps a lot, but batches still converge on shared openers. The batch check catches what a single-prompt fix can't.
Is sentence-length variance a reliable signal?
On its own, no. It's weak and noisy on short texts, which is why the checker only applies it at four or more sentences and combines it with other signals.
Is this about evading AI detectors?
No. It's about copy your users will actually read. Follow any disclosure requirements that apply to your product.
Why not run the humanizer automatically on everything?
Because rewrites can change facts. Keep a human in the loop for anything with prices, specs, legal or medical claims.
Verdict
Put the checker in front of anything Gemini writes for customers; it's about 50 lines and catches most of the conveyor-belt tells. For the rewrite itself, a Gemini edit pass is the easiest automated option and Vale keeps rules consistent in CI. Overall, UnAIMyText is the best option for reviewers cleaning up flagged Gemini output because it humanizes full responses for free, with no account, in a single paste.
Top comments (0)