Skip to content

khizerarain/SCRIBE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SCRIBE

AI Content Generation Engine — turn a single topic into a publish-ready blog post, then repurpose it for SEO and social media.

Python License Status

A production-quality Python CLI that goes from topicmarkdown in one command, with built-in SEO scoring, tone rewrites, and social-media repurposing. Built to demonstrate clean architecture, prompt engineering discipline, and UX polish.


Why this exists

Most "AI blog generator" demos stop at "ask the model for a post." SCRIBE goes further:

  • Real SEO scoring, not AI-hallucinated numbers — readability via textstat, keyword density from actual counts, structure heuristics. The model only fills the qualitative gaps.
  • Single-responsibility modules behind one API wrapper, so swapping OpenAI for Anthropic is a one-file change.
  • A real CLI with Rich panels, spinners, tables, and a --no-export escape hatch — not a notebook.
  • Typed tone rewrites with a Typer enum that rejects bad input before the API call.

It's a portfolio piece: the code is the resume.


Features

  • scribe title — generate n varied title candidates (list / how-to / question / contrarian angles)
  • scribe outline — produce a structured [{section, description}, ...] outline
  • scribe generate — full pipeline: title → outline → draft → export to Markdown with YAML frontmatter
  • scribe seo — real computed score (readability 40% / keyword density 30% / structure 30%) + AI meta description + 3 suggestions
  • scribe improve — rewrite for clarity, flow, and engagement; renders a unified diff
  • scribe tone <professional|casual|witty|technical|persuasive> — tone-shift rewrites with a Typer enum
  • scribe social — LinkedIn post, X/Twitter thread (1/, 2/, ...), Facebook post — three Rich panels; --save writes each to output/social/
  • scribe history — Rich table of past generations
  • Friendly errors (Rich panels, no stack traces) for missing keys, empty topics, bad tones, API hiccups

Install

git clone https://github.com/<you>/scribe.git
cd scribe
python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# edit .env and set OPENAI_API_KEY

Windows users: set PYTHONIOENCODING=utf-8 once per shell to keep Typer's Rich help (it uses ) from crashing the legacy cp1252 stdout.


Usage

scribe title --topic "AI startup ideas" --count 5
scribe outline --topic "AI startup ideas" --sections 6
scribe generate --topic "AI startup ideas" --tone casual --length 1500
scribe generate --topic "AI startup ideas" --no-export   # print only
scribe seo --file output/ai-startup-ideas.md --keywords "AI startup, founder"
scribe improve --file output/ai-startup-ideas.md
scribe tone casual --file output/ai-startup-ideas.md
scribe tone technical --text "Paste draft here..."
scribe social --file output/ai-startup-ideas.md
scribe social --file output/ai-startup-ideas.md --save    # write to output/social/
scribe history
scribe --version

If you run scribe with no args you get a small ASCII banner and a quick-start hint.

Example output

   ____  ___  ____ ___ ___  __  __
  / ___|| _ \/ ___|_ _|_ _||  \/  |
  \___ \|  _/\___ \| | | | | |\/| |
   ___) | |  ___) | | | | | |  | |
  |____/|_| |____/___|___| |_|  |_|

  SCRIBE v0.1.0 · AI content generation engine

Architecture

Every module has one job. Every API call goes through client.py so swapping providers is a single-file change.

Module Responsibility
main.py Typer app, command registration, banner, error panels
client.py OpenAI wrapper (chat_completion() w/ exponential backoff) — the only module that talks to the API
prompts.py All system/user prompt templates — no API calls live here
generator.py generate_titles(), generate_draft()
outlines.py generate_outline()
seo.py analyze_seo() — computed score + AI-suggested meta/suggestions
improver.py improve_content(), change_tone()
social.py generate_social_posts(){linkedin, twitter_thread, facebook}
exporter.py export_markdown() — YAML frontmatter + slugified filename
config.py Env loading, defaults, paths
utils.py Shared Rich console, with_spinner(), slugify, history I/O

SEO scoring formula

score = round(
    readability_score  * 0.40
  + keyword_score      * 0.30    (skipped if no --keywords; weight redistributed)
  + structure_score    * 0.30
)
  • Readability (40%): textstat.flesch_reading_ease(text) — clamped to 0-100
  • Keyword density (30%): per-keyword count / total_words * 100; 1-2% ideal, 0.5-1% or 2-3% acceptable, <0.5% low, >3% stuffed
  • Structure (30%): H2 headings + intro paragraph + conclusion section + paragraph-length distribution

The AI is asked for exactly two qualitative outputs: a meta description (150-160 chars) and three concrete improvement suggestions. It is never asked for the score.


Configuration

Env var Default Purpose
OPENAI_API_KEY (required) Your OpenAI API key
SCRIBE_MODEL gpt-4o-mini Any chat-completions-compatible model

.env is gitignored. If the key is missing, SCRIBE prints a Rich error panel and exits 1 — never a stack trace.


Error handling

Situation Behavior
Missing OPENAI_API_KEY Rich red panel with setup steps, exit 1
Empty / too-short --topic Friendly yellow panel asking for more detail, exit 1
Invalid --tone Typer auto-rejects with valid options listed, exit 2
OpenAI rate-limit / network error Retried 3× with exponential backoff (client.py); clear Rich panel if all fail
AI returns malformed JSON for SEO suggestions Falls back to a deterministic truncated meta; the score (computed) is unaffected

Roadmap (v2 — seams are in place, not implemented)

  • SQLite history with full-text search, tags, and per-topic stats
  • LangChain orchestration for prompt chaining and tool use
  • Vector DB style-matching — pull the top 3 past posts in a similar tone and use them as few-shot examples
  • Template library — load user-defined prompt templates from disk
  • Streaming responses for live diff rendering in improve and tone
  • Concurrent social generation with bounded concurrency (3 calls today run sequentially)

Development

# Verify the CLI
python -m scribe.main --help
python -m scribe.main version --help   # not a thing; use --version

# Manual smoke test of a single command without hitting the API
PYTHONIOENCODING=utf-8 python -m scribe.main seo --file output/<some>.md

The v2 hook: comments in config.py, prompts.py, and client.py mark the seams where new pieces slot in.


License

MIT — see LICENSE.


Sample output

The .gitignore excludes output/*.md by default so generated content doesn't pollute commits. To produce a real screenshot for the README, run something like:

scribe generate --topic "Starting an AI business in 2026" --tone professional --length 1500
scribe seo --file output/starting-an-ai-business-in-2026.md --keywords "AI business"

Then commit the resulting .md file manually with git add -f output/<file>.md for the portfolio screenshot.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages