diff --git a/README.md b/README.md index c49fc59..dba275f 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,7 @@ These are only needed for **headless / CI extraction** (`graphify extract`). Whe | `ANTHROPIC_API_KEY` | Claude (Anthropic) backend | `--backend claude` | | `GEMINI_API_KEY` or `GOOGLE_API_KEY` | Google Gemini backend | `--backend gemini` | | `OPENAI_API_KEY` | OpenAI or OpenAI-compatible APIs | `--backend openai` | +| `DEEPSEEK_API_KEY` | DeepSeek backend | `--backend deepseek` | | `MOONSHOT_API_KEY` | Kimi Code backend | `--backend kimi` | | `OLLAMA_BASE_URL` | Ollama local inference URL | `--backend ollama` (default: `http://localhost:11434`) | | `OLLAMA_MODEL` | Ollama model name | `--backend ollama` (default: auto-detect) | @@ -450,7 +451,7 @@ graphify kiro install / uninstall graphify antigravity install / uninstall graphify extract ./docs # headless LLM extraction for CI (no IDE needed) -graphify extract ./docs --backend gemini # explicit backend: gemini, kimi, claude, openai, ollama, bedrock, or claude-cli +graphify extract ./docs --backend gemini # explicit backend: gemini, kimi, claude, openai, deepseek, ollama, bedrock, or claude-cli graphify extract ./docs --backend gemini --model gemini-3.1-pro-preview graphify extract ./docs --backend ollama # local Ollama (set OLLAMA_BASE_URL / OLLAMA_MODEL) - no API key needed for loopback GRAPHIFY_OLLAMA_NUM_CTX=32768 graphify extract ./docs --backend ollama # override KV-cache window (auto-sized by default) diff --git a/graphify/__main__.py b/graphify/__main__.py index 4fff852..51c4db9 100644 --- a/graphify/__main__.py +++ b/graphify/__main__.py @@ -1255,7 +1255,7 @@ def main() -> None: print(" --top-k-edges N per-symbol outbound edges in inspector (default 12)") print(" --label NAME project label in header") print(" extract headless full extraction (AST + semantic LLM) for CI/scripts") - print(" --backend B gemini|kimi|claude|openai|ollama (default: whichever API key is set)") + print(" --backend B gemini|kimi|claude|openai|deepseek|ollama (default: whichever API key is set)") print(" --model M override backend default model") print(" --max-workers N AST extraction subprocess count (default: cpu_count)") print(" --token-budget N per-chunk token cap for semantic extraction (default: 60000)") @@ -1880,6 +1880,7 @@ def main() -> None: os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY") or os.environ.get("MOONSHOT_API_KEY") + or os.environ.get("DEEPSEEK_API_KEY") or os.environ.get("GRAPHIFY_NO_TIPS") ): print("Tip: set GEMINI_API_KEY or GOOGLE_API_KEY to use Gemini for semantic extraction.") @@ -2388,7 +2389,7 @@ def main() -> None: # has an API key set. if len(sys.argv) < 3: print( - "Usage: graphify extract [--backend gemini|kimi|claude|openai|ollama] " + "Usage: graphify extract [--backend gemini|kimi|claude|openai|deepseek|ollama] " "[--model M] [--out DIR] [--google-workspace] [--no-cluster] " "[--max-workers N] [--token-budget N] [--max-concurrency N] " "[--api-timeout S]", @@ -2507,7 +2508,8 @@ def main() -> None: print( "error: no LLM API key found. Set GEMINI_API_KEY or GOOGLE_API_KEY " "(gemini), MOONSHOT_API_KEY (kimi), ANTHROPIC_API_KEY (claude), " - "or OPENAI_API_KEY (openai), or pass --backend.", + "OPENAI_API_KEY (openai), DEEPSEEK_API_KEY (deepseek), " + "or pass --backend.", file=sys.stderr, ) sys.exit(1) diff --git a/graphify/llm.py b/graphify/llm.py index b4392bc..fb65ee1 100644 --- a/graphify/llm.py +++ b/graphify/llm.py @@ -87,6 +87,17 @@ BACKENDS: dict[str, dict] = { "pricing": {"input": 0.40, "output": 1.60}, # USD per 1M tokens "temperature": 0, }, + "deepseek": { + "base_url": "https://api.deepseek.com", + "default_model": "deepseek-v4-flash", + "env_key": "DEEPSEEK_API_KEY", + "model_env_key": "GRAPHIFY_DEEPSEEK_MODEL", + "pricing": {"input": 0.14, "output": 0.28}, # USD per 1M tokens (v4-flash) + # deepseek-reasoner / thinking-mode models silently ignore temperature; + # deepseek-chat / v4-flash (non-thinking) accept 0-2. Safe to send 0. + "temperature": 0, + "max_tokens": 16384, + }, "bedrock": { "default_model": "anthropic.claude-3-5-sonnet-20241022-v2:0", "model_env_key": "GRAPHIFY_BEDROCK_MODEL", @@ -1084,7 +1095,7 @@ def detect_backend() -> str | None: key now keeps you on the paid backend; remove the paid key (or pass --backend ollama explicitly) to route to the local model. """ - for backend in ("gemini", "kimi", "claude", "openai"): + for backend in ("gemini", "kimi", "claude", "openai", "deepseek"): if _get_backend_api_key(backend): return backend if os.environ.get("AWS_PROFILE") or os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION"):