Workflow & Automation

geo-content-optimizer

wangzhuo-coding/geo-content-optimizer · ★ 8

wangzhuo-coding

Turns enterprise source materials into original articles optimized for vector indexing by Doubao, Kimi, DeepSeek, Qwen, GPT, and other LLMs while removing AI-generated traces.

License
MIT
Added
2026-08-23
Maintenance
active
Install kind
github

No manifest check is available; listing does not imply compatibility or security review.

安装

dsh plugin --profile web add github:wangzhuo-coding/geo-content-optimizer

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. Features
  2. Core Capabilities
  3. 6 Usage Modes
  4. Architecture
  5. Quick Start
  6. 1. Install
  7. 2. Configure API Key
  8. 3. Run
  9. User Requirements & Dual Gate (Optional)
  10. Length Auto-calibration (R3)
  11. Runtime Tuning
  12. Structured-Output Degradation
  13. Long-running Deployment & Self-Healing (R7 B6)
  14. Environment Variables
  15. Development Quality Gates
  16. Project Structure
  17. Tech Stack
  18. Contributing
  19. Changelog
  20. License

Python 3.12+ License: MIT CI

中文 | English

Feed enterprise documents → auto-produce high-quality original articles optimized for AI model vector databases (Doubao, Kimi, DeepSeek, Qwen, GPT), with AI-generation traces removed.

GEO (Generative Engine Optimization) content optimization agent — cross-platform, zero platform dependency. Unlike traditional SEO targeting search engine crawlers, GEO targets AI summarizers and answer engines: making AI models "readable, willing to cite, and traceable."


Features

Core Capabilities

Capability Description
📄 Multi-format Document Parsing PDF / Word / Excel / PPT / TXT — extract plain text in one click
🔑 7-type Keyword Mining Core search terms, long-tail scenario terms, geographic entity terms, audience tag terms, problem description terms, brand-specific terms, scenario trigger terms — schema-enforced (Pydantic), ranked by priority formula
✍️ 7-layer Architecture Content Generation EE-A-T authority framework + ACES conclusion-first paradigm + 3-paragraph Hook opening + semantic entity density network
🧹 8-dimension AI Trace Removal Sentence structure / paragraph rhythm / word choice / emotional density / evidence source / perfection / personalization / keyword density — 3-level grading
🛡️ Stage 5 Quality Gate Extreme-word lint, brand traceability density, structural completeness, hallucination guard (claim source verification), optional LLM-as-Judge scoring
📏 Length Auto-calibration LLMs can't count — the pipeline measures length program-side and runs targeted expand/shrink passes until "≥1800字" / "约1500字" / "不超过2000字" requirements land inside the ±10% tolerance band (max 2 passes)
🌐 Web Search Enrichment Tavily / Bing RSS / DuckDuckGo 3-engine auto-switch, works in China
📝 Word Document Export Markdown → formatted Word (.docx), supporting headings / tables / lists / code blocks
🧩 MCP Protocol Integration One-line config to connect Claude Desktop / Claude Code / WorkBuddy and other AI tools
📦 Smart Chunking Auto-split long texts (≤60000 chars/chunk, 500-char overlap), merge before downstream

6 Usage Modes

CLI Interactive Mode  →  Terminal chat, great for quick trials
Command-line Direct   →  --file/--text params, great for batch scripts
Streamlit Web UI      →  Browser-based, great for non-technical users
HTTP API              →  FastAPI service, great for system integration
MCP Server            →  Connect to Claude and other AI tools, conversational invocation
DSH Plugin            →  Native DeepSeek Harness tools (mcp__geo__*), see docs/dsh-integration.md

Architecture

Input Document → [Stage 0 Web Search (optional)] → [Stage 1 Clean & Slice] → [Stage 2 Keyword Extraction] → [Stage 3 Content Generation] → [Stage 4 AI Trace Removal] → [Stage 5 Quality Gate] → Final Article + Word Document
Stage Function Core Method
Stage 0 Web Search (optional) Auto-extract key concepts, 3-engine parallel search enrichment, expand document material
Stage 1 Document Clean & Slice Filter noise, semantic chunking (paragraph/sentence boundaries), extract brand info; long texts chunked in parallel
Stage 2 Keyword Extraction 7 keyword types (schema-enforced via structured output) + priority formula (search volume × relevance × competition) 3-tier ranking
Stage 3 Content Generation EE-A-T authority framework + ACES conclusion-first + 7-layer writing architecture + semantic entity density + FAQ / citation-ready fact block
Stage 4 AI Trace Removal 8-dimension de-AI + 3-level grading (light / medium / deep) + self-check checklist
Stage 5 Quality Gate Extreme-word lint + brand traceability density + structural completeness + hallucination guard + optional LLM-as-Judge scoring (advisory by default, does not block output; with strict=True a sub-threshold article is marked "❌ not publishable" at the top)

Quick Start

1. Install

# Clone the repo
git clone https://github.com/wangzhuo-coding/geo-content-optimizer.git
cd geo-content-optimizer

# Create virtual environment
python -m venv .venv
source .venv/bin/activate  # Linux/macOS
# .venv\Scripts\activate    # Windows

# Install core dependencies
pip install -e .

Optional features (install as needed):

pip install -e ".[mcp]"       # MCP Server (connect to Claude etc.)
pip install -e ".[webui]"     # Streamlit Web UI
pip install -e ".[postgres]"  # PostgreSQL persistence
pip install -e ".[s3]"        # S3 file storage
pip install -e ".[all]"       # All optional features

Windows users: Run setup.bat for one-click install. In China, use a mirror: pip install -e . -i https://pypi.tuna.tsinghua.edu.cn/simple

2. Configure API Key

cp .env.example .env  # Windows: copy .env.example .env

Edit .env and fill in your LLM API Key:

OPENAI_API_KEY=sk-xxx               # Your API Key (required)
OPENAI_BASE_URL=https://api.openai.com/v1   # API endpoint
OPENAI_MODEL_NAME=gpt-4o            # Model name

Compatible API providers:

Provider Base URL Model Examples
OpenAI https://api.openai.com/v1 gpt-4o
DeepSeek https://api.deepseek.com deepseek-chat
Doubao (ByteDance) https://ark.cn-beijing.volces.com/api/v3 doubao-seed-2-0-pro
Qwen (Alibaba) https://dashscope.aliyuncs.com/compatible-mode/v1 qwen-max
Kimi (Moonshot) https://api.moonshot.cn/v1 moonshot-v1-8k

3. Run

Mode 1: CLI Interactive Mode
python -m src          # Simplest
python src/cli.py      # Equivalent
run.bat                # Windows one-click
Mode 2: Command-line Direct Processing
# Input text, auto-save to output/ directory
python src/cli.py --text "Your document content..."

# Process file + brand info
python src/cli.py --file document.pdf --brand "Brand Name, Website URL"

# Enable web search + export Word document
python src/cli.py --file doc.pdf --search --docx

# Full features: file + brand + web search + Word export
python src/cli.py --file doc.pdf --brand "Huawei, https://www.huawei.com" --search --docx
Parameter Description
--text "content" Input text directly
--file path Input file (PDF/Word/Excel/PPT/TXT)
--brand "info" Supplementary brand information
--search Enable web search (adds 1-2 min)
--docx Export Word document (.docx)
--output path Specify Markdown output path
--verbose Show detailed logs
Mode 3: Web UI
pip install -e ".[webui]"
streamlit run src/web_ui.py

Upload files, paste text, toggle web search and Word export, watch real-time progress in the browser.

Mode 4: HTTP API Service
python -m uvicorn src.main:app --host 127.0.0.1 --port 5000
Endpoint Method Description
/run POST Synchronous Agent execution
/stream_run POST SSE streaming execution
/cancel/{run_id} POST Cancel task
/v1/chat/completions POST OpenAI-compatible endpoint
/health GET Health check
/graph_parameter GET Agent graph parameters

Swagger docs: Visit http://127.0.0.1:5000/docs after launch.

Example call:

curl -X POST http://127.0.0.1:5000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "Optimize this document..."}]}'
Mode 5: MCP Server (Connect to Claude and other AI tools)
pip install -e ".[mcp]"

# stdio mode (Claude Desktop / Claude Code / WorkBuddy)
python src/mcp_server.py

# SSE HTTP mode (Web clients)
python src/mcp_server.py --transport sse --port 5001

Configure Claude Desktop (%APPDATA%\Claude\claude_desktop_config.json):

Important: Do NOT use the env field in MCP config to pass API Keys! Claude Code's env overrides the entire environment (including the essential Windows PATH), causing Python to fail loading system DLLs with error code -32000. Configure API Keys in the project .env file instead — MCP Server reads it automatically on startup.

{
  "mcpServers": {
    "geo-content-optimizer": {
      "command": "python",
      "args": ["src/mcp_server.py"],
      "cwd": "/path/to/geo-content-optimizer"
    }
  }
}

Configure WorkBuddy (~/.workbuddy/mcp.json):

{
  "mcpServers": {
    "geo-content-optimizer": {
      "command": "/path/to/geo-content-optimizer/.venv/Scripts/python.exe",
      "args": ["src/mcp_server.py"],
      "cwd": "/path/to/geo-content-optimizer"
    }
  }
}

MCP Tools:

Tool Parameters Description
parse_document file_path: str Parse PDF / Word(.docx) / TXT / CSV / Excel(.xlsx) / PPT(.pptx) files (legacy .doc/.xls/.ppt not guaranteed)
run_geo_pipeline cleaned_text, brand_info="", enable_search=false, user_requirements="", output_docx="" Execute 4-stage GEO pipeline
web_search query: str, max_results=5 Web search
search_and_enrich text: str, brand_info="", max_queries=3 Extract concepts + search + merge

After configuration, invoke by chatting directly in Claude/WorkBuddy:

User: Optimize this Huawei Cloud whitepaper for me
Claude: → Calls parse_document to parse the file
        → Calls run_geo_pipeline to execute 4-stage pipeline
        → Returns the final article
Mode 6: DSH Plugin (native DeepSeek Harness tools)

This project is also a dsh-plugin: the repo ships a dsh-plugin/ package; once installed into a DeepSeek Harness web profile via dsh plugin add, the harness spawns the project's FastMCP server and registers its 4 tools as native model tools mcp__geo__parse_document / run_geo_pipeline / web_search / search_and_enrich (auto-reconnect on crash; long-task timeout preset to 10 minutes).

# Prereqs: install deps and point the working instance at YOUR clone (see dsh-plugin/README.md)
#   python -m venv .venv && .venv\Scripts\python -m pip install -e ".[mcp]"
#   scripts\dsh-plugin-setup.ps1   (Linux/macOS: bash scripts/dsh-plugin-setup.sh)

# Install the plugin (mutually exclusive with a direct mcp-geo row in profiles/web/cordis.patch.yml;
# replace <your-clone> with the actual path)
dsh plugin --profile web add <your-clone>/dsh-plugin
dsh web restart   # after restart, mcp__geo__* tools appear in new sessions

The companion "GEO 创作" agent preset is vendored under dsh-plugin/preset/; install notes, portability, and acceptance checks live in docs/dsh-integration.md and docs/dsh-validation.md. The working instance is chosen by the GEO_PROJECT_ROOT / GEO_PYTHON environment variables (pointed at your clone; startup fails loudly when they are missing instead of silently registering zero tools); API keys are read from the instance's .env (mcp_server.py calls load_dotenv itself).


User Requirements & Dual Gate (Optional)

run_geo_pipeline accepts a user_requirements parameter (content direction / target audience / word count / style / keywords / platform, etc.). When supplied:

  • Writing (Stage 3/4) reconciles user requirements via the three-tier priority: Tier 0 compliance/fact/black-hat red lines -> refuse and give a compliant alternative; Tier 1 GEO floor (EE-A-T/ACES/semantic entity density) -> seek win-win, preserve GEO when forced to choose; Tier 2 other requirements -> maximize satisfaction within constraints
  • Scoring (Stage 5) adds an independent second axis "user-requirement satisfaction" (0-100%); together with the 100-point GEO baseline it forms a dual gate: GEO passes AND satisfaction >= 80% to be publishable; compliance-conflicting requirements are refused + given alternatives and excluded from the satisfaction rate (advisory by default; with run_geo_pipeline(strict=True) a sub-threshold article is explicitly flagged)

Omitting user_requirements leaves behavior unchanged (second axis inactive), consistent with the geo-writer / geo-scorer skills in the ecosystem.

Length Auto-calibration (R3)

LLMs have no stable sense of character counts — the same "≥1800字" request can produce 1200~4700 chars. The pipeline therefore does not trust the model's self-reported length and calibrates program-side instead:

  1. Parse a length target from user_requirements: ≥1800字 (minimum) / 不超过2500字 (maximum) / 约1500字 (around) / 1800-2500字 (range);
  2. After Stage 4 (de-AI rewriting), measure the output with len(text);
  3. When it falls outside the tolerance band (default ±10%, PIPELINE_LENGTH_TOLERANCE), run a targeted expand/shrink pass, up to PIPELINE_MAX_LENGTH_ATTEMPTS (default 2) rounds, stopping as soon as it converges;
  4. If it still misses after the cap, log honestly and accept the residual deviation — no infinite loop.

With no length requirement present, this step is skipped entirely (behavior identical to the previous version).

Runtime Tuning

A single run = 5 sequential LLM stages + optional LLM judge + optional web search. To make runs faster:

  • PIPELINE_QUALITY_JUDGE=false: skip the LLM judge (deterministic lint only, saves one LLM round-trip);
  • PIPELINE_SEARCH_MAX_QUERIES=1: extract only 1 search keyword for web enrichment (default 3);
  • PIPELINE_MAX_LENGTH_ATTEMPTS=1: cap length calibration at 1 correction pass (default 2).

Structured-Output Degradation

If the log shows with_structured_output failed ... response_format type is unavailable now, your model/endpoint does not support native JSON-Schema structured output. The pipeline automatically degrades to "free-form text + Pydantic repair parsing" (functional, but Stage 1/2 schema enforcement is weaker). Prefer a model or OpenAI-compatible endpoint that supports response_format=json_schema.

Long-running Deployment & Self-Healing (R7 B6)

By default the MCP server is spawned per-session by the client (Claude Code, stdio) — no daemon needed. For long-running deployment (servers/dev boxes), use a process supervisor for auto-restart on crash:

  • PM2 (cross-platform): npm i -g pm2 && pm2 start scripts/mcp_pm2.config.js (config: autorestart + exponential backoff + memory-limit restart; pm2 save && pm2 startup for boot persistence). Windows uses .venv/Scripts/python.exe, Linux/macOS change to .venv/bin/python (see comments in the config file).
  • systemd (Linux): sudo cp scripts/mcp_mcp_server.service /etc/systemd/system/ && sudo systemctl enable --now geo-mcp-server (Restart=always, restarts 3s after crash).

Note: after a -32000 Connection closed, auto-reconnect is a client-side behavior (Claude Code retries); server-side responsiveness during long tasks is handled in code via async + asyncio.to_thread (event loop never blocks).

Environment Variables

Variable Required Default Description
OPENAI_API_KEY Yes — LLM API Key
OPENAI_BASE_URL No https://api.openai.com/v1 API endpoint
OPENAI_MODEL_NAME No gpt-4o Model name
AGENT_TEMPERATURE No 0.7 Agent temperature
AGENT_MAX_TOKENS No 32768 Agent max tokens
PIPELINE_MAX_CHUNK_CHARS No 60000 Max chars per chunk (semantic chunking)
PIPELINE_LLM_MAX_RETRIES No 3 LLM retries (transient network/rate-limit only)
PIPELINE_LLM_TIMEOUT No 600 Pipeline LLM call timeout (seconds)
PIPELINE_LLM_MODEL No empty (same as OPENAI_MODEL_NAME) Pipeline-specific model
PIPELINE_MAX_CONCURRENCY No 4 Parallelism for chunk processing / web search
PIPELINE_MAX_INPUT_CHARS No 200000 Upper bound (chars) on pipeline input; oversized text is truncated with a warning. 0 disables (token-cost control)
PIPELINE_STAGE3_MAX_SLICES No 0 Max slices embedded in the Stage-3 prompt (top-K truncation, lowers token cost). 0 = unlimited
PIPELINE_LENGTH_TOLERANCE No 0.10 Character-count calibration tolerance (±10%). When a length requirement is detected in user_requirements (e.g. "≥1800字" / "约1500字"), the pipeline measures length program-side and runs targeted expand/shrink passes until the output lands in the band
PIPELINE_MAX_LENGTH_ATTEMPTS No 2 Max correction passes for length calibration (LLMs can't count; converge via program-side measurement + targeted correction, then accept residual deviation with a warning)
PIPELINE_QUALITY_JUDGE No true Enable Stage 5 LLM scoring (off = deterministic lint only, zero token cost, faster runs)
PIPELINE_QUALITY_THRESHOLD No 80 GEO baseline pass line (default 80, aligned with the project's GEO≥80 publish rule; wired into the judge prompt, and used as the dual-gate GEO gate)
PIPELINE_SEARCH_MAX_QUERIES No 3 Max search queries extracted per text for web enrichment (lower = shorter web-search phase)
PIPELINE_GATE_HARD_DATA No false Optional gate: flag when significant source numbers (>=1000) never appear in the article ("hard-data blurring"; off by default to avoid false positives)
PIPELINE_TEMPERATURE_GEN / PIPELINE_TEMPERATURE_REWRITE No 0.8 / 0.4 Stage 3 generation / Stage 4 rewrite temperature (set 0 for near-deterministic runs)
PIPELINE_REQUIREMENT_SATISFACTION_THRESHOLD No 80 User-requirement satisfaction pass line (dual-gate second-axis gate, active only when user_requirements is supplied)
GEO_API_KEY No empty HTTP write-endpoint auth (requires Authorization: Bearer; binds to 127.0.0.1 by default, prints a startup warning when unset)
TAVILY_API_KEY No - Tavily search key (omit = free engines)
PGDATABASE_URL No — PostgreSQL connection (enables persistence)
S3_* No — S3 storage config
HTTP_PORT No 5000 HTTP service port
HTTP_HOST No 127.0.0.1 HTTP bind address (localhost by default; set 0.0.0.0 + GEO_API_KEY to expose)
MCP_SSE_HOST No 127.0.0.1 MCP SSE bind address (localhost by default)
HTTP_RATE_LIMIT_PER_MINUTE No 60 Max requests per client IP per minute (write endpoints; 0 disables)
MCP_SSE_PORT No 5001 MCP SSE mode port

Development Quality Gates

Install dev tooling with pip install -e ".[dev]", then:

Tool Command Purpose
pytest + pytest-cov pytest Full test suite + coverage report (currently --cov-fail-under=65 regression floor; ECC target 80% is a follow-up once web_ui callbacks / main.py HTTP edges are covered)
ruff ruff check src tests Lint + import ordering
bandit bandit -r src -ll Static security scan (medium+ severity only)

These three steps run automatically on every push / PR via GitHub Actions (.github/workflows/ci.yml).


Project Structure

geo-content-optimizer/
├── config/
│   └── agent_llm_config.json      # Agent System Prompt + model config
├── scripts/                        # Run scripts (Linux/macOS)
├── src/
│   ├── __main__.py                 # python -m src entry
│   ├── main.py                     # FastAPI HTTP service
│   ├── cli.py                      # CLI interactive mode
│   ├── mcp_server.py               # MCP Server (connect to Claude etc.)
│   ├── web_ui.py                   # Streamlit Web UI
│   ├── agents/
│   │   └── agent.py                # Agent build (LangGraph) + AgentState
│   ├── tools/
│   │   ├── geo_pipeline.py         # Core: 4-stage pipeline + smart chunking + Word export
│   │   └── web_search.py           # Web search (Tavily/Bing/DuckDuckGo)
│   ├── utils/
│   │   ├── file/
│   │   │   └── file.py             # File parsing (PDF/Word/Excel/PPT/TXT)
│   │   └── docx_export.py          # Markdown → Word document conversion
│   └── storage/
│       ├── memory/                 # In-memory persistence (default)
│       ├── database/               # PostgreSQL (optional)
│       └── s3/                     # S3 storage (optional)
├── run.bat                         # Windows one-click launch
├── setup.bat                       # Windows one-click install
├── dsh-plugin/                     # DSH plugin package (dsh plugin add; includes preset/ copy)
├── docs/                           # Docs: dsh-integration.md (integration) / dsh-validation.md (validation flow)
├── scripts/                        # incl. sync_dsh_instance.ps1 (DSH working-instance sync)
├── .env.example                    # Environment variable template
├── pyproject.toml                  # Dependency config
├── LICENSE                         # MIT License
└── README.md

Tech Stack

Layer Technology
Agent Framework LangChain + LangGraph (create_react_agent)
LLM Calls ChatOpenAI (compatible with all OpenAI APIs)
Web API FastAPI + Uvicorn
Web UI Streamlit (optional)
MCP Protocol FastMCP (connect to Claude etc.)
CLI argparse + asyncio
Retry Mechanism tenacity (exponential backoff + JSON self-repair)
Persistence PostgreSQL (optional) + S3 (optional)

Contributing

Contributions welcome!

  1. Fork this repo
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push the branch (git push origin feature/amazing-feature)
  5. Create a Pull Request

Dev environment setup:

python -m venv .venv
pip install -e ".[all]"
pip install pytest pytest-asyncio

Changelog

See CHANGELOG.md for the full release history.

License

MIT License — Free to use, modify, and distribute.