2026-06-21 23:42:37 +08:00
2026-06-21 23:43:03 +08:00

GEO Agent Article Optimizer

Local MVP for optimizing pasted GEO-related articles while preserving confirmed brand facts. The app extracts a fact card, requires user confirmation, rewrites under those constraints, runs QA gates, and exports Markdown, Word, and JSON.

Setup

npm install
cp .env.example .env.local
npm run dev

Open http://localhost:3000.

Environment

Required for live model calls:

LLM_PROVIDER=deepseek
DEEPSEEK_API_KEY=
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-v4-pro
DEEPSEEK_THINKING=disabled
APP_DATA_DIR=./data
API_ACCESS_KEY=local-dev-key
API_AUTH_DISABLED=false

OpenAI-compatible fallback keys are also accepted:

OPENAI_API_KEY=
OPENAI_MODEL=gpt-4.1-mini

When a DeepSeek or OpenAI-compatible key is configured, the workflow uses the provider for fact extraction, article optimization, QA enrichment, and targeted rewrite. Every LLM response is validated with Zod before use. When no API key is configured, or when the provider response is invalid, deterministic local fallbacks keep the workflow usable for tests and local review.

All API requests require the configured access key:

x-api-key: <API_ACCESS_KEY>

LLM Runtime Logs

LLM calls emit regular server-side logs from src/lib/llm/client.ts. These logs are intended for local development, customer demos, and production troubleshooting.

Example:

[llm:start] provider=deepseek model=deepseek-v4-pro task=article_optimizer
[llm:response] task=article_optimizer duration_ms=18342 raw={"title":"..."}
[llm:validated] task=article_optimizer ok=true

The raw= field is truncated to 4000 characters to avoid log explosions. Set LLM_LOG_RAW_LIMIT=0 to suppress raw response snippets, or set a larger number when diagnosing model output. API keys, prompts, system messages, and environment secrets are not logged.

Workflow task names are:

  • fact_extractor
  • article_optimizer
  • quality_inspector
  • targeted_rewriter

Commands

npm test
npm run build
npx playwright test

Cloudflare Workers Deployment

Cloudflare deployment is manual. Pushing to Git does not deploy or hot-update the production Worker.

Local development:

npm run dev

Cloudflare preview:

cp .dev.vars.example .dev.vars
npm run d1:migrate:local
npm run preview:worker

Create private staging resources:

npx wrangler d1 create geo-agent-article-optimizer-staging
npx wrangler r2 bucket create geo-agent-article-optimizer-staging

Create private production resources:

npx wrangler d1 create geo-agent-article-optimizer-production
npx wrangler r2 bucket create geo-agent-article-optimizer-production

After D1 creation, copy the returned database IDs into the matching wrangler.jsonc environment entries. Keep R2 buckets private; do not add public bucket domains.

Set secrets:

npx wrangler secret put API_ACCESS_KEY --env staging
npx wrangler secret put DEEPSEEK_API_KEY --env staging
npx wrangler secret put API_ACCESS_KEY --env production
npx wrangler secret put DEEPSEEK_API_KEY --env production

D1 schema changes only through migrations. Runtime code must not rebuild or clear production tables. Apply migrations in this order:

npm run d1:migrate:local
npm run d1:migrate:staging
npm run deploy:worker:staging
npm run d1:migrate:production
npm run deploy:worker:production

FRP Mainland Access Tunnel

The Cloudflare staging URL can be unreachable from mainland networks. To expose the local project through an FRP server, copy the example configs and fill in the local server address, auth token, and shared secret:

cp deploy/frpc.geo-agent-article-optimizer.example.toml deploy/frpc.geo-agent-article-optimizer.toml
cp deploy/frpc.geo-agent-article-optimizer-visitor.example.toml deploy/frpc.geo-agent-article-optimizer-visitor.toml

The real deploy/*.toml files are ignored by Git so local credentials stay out of the public repository.

Run the app locally and start frpc with the project config:

npm run dev
frpc -c deploy/frpc.geo-agent-article-optimizer.toml

The project-side frpc config publishes local 127.0.0.1:3000 as the stcp service geo_agent_article_optimizer.

On the mainland access machine, start the visitor config that binds the remote service to a local port:

frpc -c deploy/frpc.geo-agent-article-optimizer-visitor.toml

Then open http://127.0.0.1:6009 on that machine.

Exports

Local generated files are written under:

data/exports/<job_id>/

Cloudflare exports are written to the private R2 bucket bound as EXPORT_BUCKET and served only through authenticated API routes.

Each passing or warning-only QA run can produce:

  • optimized.md
  • optimized.docx
  • qa_report.json

Hard QA failures block export.

MVP Limits

  • Pasted text only; no direct .docx parsing.
  • Local SQLite by default; Cloudflare deployments use D1.
  • No account permissions or collaboration.
  • No publishing platform APIs.
  • No batch queue.
  • Basic Word export layout only.
  • Unconfirmed facts are never used as truth.
S
Description
No description provided
Readme
1.6 MiB
Languages
TypeScript 95.9%
CSS 2.6%
JavaScript 1.5%