diff --git a/README.md b/README.md index e6c2e98..ae61adc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # QuickSilver Pro CLI -`qsp` — a command-line client for [QuickSilver Pro](https://quicksilverpro.io), one OpenAI-compatible API for top LLMs (DeepSeek, Qwen, Kimi, Gemini) **and** FLUX text-to-image — billed to a single balance. Open-source chat models run 20% below OpenRouter / Together / Fireworks. +`qsp` — a command-line client for [QuickSilver Pro](https://quicksilverpro.io), one OpenAI-compatible API for frontier and open-source LLMs (Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, Muse) **and** FLUX text-to-image — all billed to a single balance. Open-source chat models run up to 20% below OpenRouter. Designed to be **AI-agent friendly**: data commands accept `--json` for structured output, exit codes are reliable, and the API surface is intentionally small. @@ -26,6 +26,15 @@ End-user site: . pip install quicksilverpro ``` +Or run it with no install: + +```bash +uvx quicksilverpro chat "Write me a haiku" # via uv — fetches Python for you: https://docs.astral.sh/uv/ +pipx run quicksilverpro chat "Write me a haiku" # via pipx (needs Python 3.10+) +``` + +On Windows, `uvx` is the simplest path — uv downloads a suitable Python automatically. On macOS you can also `brew install machinefi/qspro/qspro`. + Python 3.9+. Also exports itself as `quicksilverpro` if you prefer the long name. --- diff --git a/pyproject.toml b/pyproject.toml index 0317d1b..06c9e3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,16 +4,17 @@ build-backend = "hatchling.build" [project] name = "quicksilverpro" -version = "0.2.0" -description = "CLI for QuickSilver Pro — one OpenAI-compatible API for DeepSeek, Qwen, Kimi, Gemini chat and FLUX image generation." +version = "0.3.0" +description = "CLI for QuickSilver Pro — one OpenAI-compatible API for Claude, GPT, Gemini, DeepSeek, Qwen, Kimi and Muse chat plus FLUX image generation, on a single balance." readme = "README.md" requires-python = ">=3.9" license = { text = "MIT" } authors = [{ name = "MachineFi Inc.", email = "hello@quicksilverpro.io" }] keywords = [ - "openai", "deepseek", "qwen", "kimi", "gemini", "flux", - "llm", "inference", "api", "chatgpt", "ai", "cli", - "image-generation", "text-to-image", "openrouter-alternative", "quicksilverpro", + "openai", "claude", "anthropic", "gpt", "gemini", "deepseek", "qwen", + "kimi", "muse", "flux", "llm", "inference", "api", "chatgpt", "ai", "cli", + "coding-agent", "image-generation", "text-to-image", + "openrouter-alternative", "quicksilverpro", ] classifiers = [ "Development Status :: 4 - Beta", diff --git a/src/quicksilverpro/__init__.py b/src/quicksilverpro/__init__.py index 83ffd8b..af9393b 100644 --- a/src/quicksilverpro/__init__.py +++ b/src/quicksilverpro/__init__.py @@ -3,4 +3,4 @@ See https://quicksilverpro.io for docs. `qsp --help` for quick reference. """ -__version__ = "0.2.0" +__version__ = "0.3.0" diff --git a/src/quicksilverpro/cli.py b/src/quicksilverpro/cli.py index f7528cf..4b9208c 100644 --- a/src/quicksilverpro/cli.py +++ b/src/quicksilverpro/cli.py @@ -275,53 +275,54 @@ def balance(as_json: bool) -> None: # not expose per-image pricing (its schema is per-token), so the CLI carries it # here so `qsp models` can show image costs whether or not the user is signed in. _IMAGE_PRICES: dict[str, float] = { - "flux.2-pro": 0.027, - "flux.1-schnell": 0.0025, + "flux.2-pro": 0.027, } -# Hardcoded so `qsp models` works before the user has signed in. A curated view -# of the lineup — once signed in, `qsp models` shows the full live catalog -# (incl. Qwen/Kimi/Gemini variants). Keep prices in sync with the backend; CI -# smoke-tests this path. Prices verified 2026-07-31. +# Hardcoded so `qsp models` works before the user has signed in. A curated, +# hot-first view of the lineup — once signed in, `qsp models` shows the full +# live catalog (30+ models incl. every Qwen/Kimi/Gemini/Claude variant). Keep +# prices in sync with the backend; CI smoke-tests this path. Prices verified +# 2026-08-08 against qsp.gateway_model_pricing. _MODELS_FALLBACK: list[dict] = [ - {"id": "deepseek-v4-flash", "object": "model", "owned_by": "quicksilverpro", - "context_length": 1048576, - "pricing": {"prompt": "0.0000001120", "completion": "0.0000002240"}, - "best_for": "official 0731 agent model · Codex · 1M context"}, - {"id": "deepseek-v4-pro", "object": "model", "owned_by": "quicksilverpro", + {"id": "claude-opus-5", "object": "model", "owned_by": "quicksilverpro", + "context_length": 1000000, + "pricing": {"prompt": "0.0000040000", "completion": "0.0000200000"}, + "best_for": "Anthropic flagship · deepest reasoning + agentic coding"}, + {"id": "claude-sonnet-5", "object": "model", "owned_by": "quicksilverpro", + "context_length": 1000000, + "pricing": {"prompt": "0.0000020000", "completion": "0.0000100000"}, + "best_for": "Claude Sonnet 5 · balanced coding + long-context agents"}, + {"id": "gpt-5.6-sol", "object": "model", "owned_by": "quicksilverpro", "context_length": 1048576, - "pricing": {"prompt": "0.0000003480", "completion": "0.0000006960"}, - "best_for": "frontier reasoning + coding · 1M context"}, + "pricing": {"prompt": "0.0000040000", "completion": "0.0000240000"}, + "best_for": "OpenAI GPT-5.6 Sol · frontier reasoning + tool use"}, {"id": "qwen3.8-max", "object": "model", "owned_by": "quicksilverpro", "context_length": 1048576, "pricing": {"prompt": "0.0000020000", "completion": "0.0000060000"}, "best_for": "flagship Qwen · autonomous coding, long-horizon agents"}, - {"id": "qwen3.7-max", "object": "model", "owned_by": "quicksilverpro", + {"id": "kimi-k3", "object": "model", "owned_by": "quicksilverpro", "context_length": 1048576, - "pricing": {"prompt": "0.0000012500", "completion": "0.0000037500"}, - "best_for": "flagship Qwen · agentic, long-context"}, - {"id": "qwen3.7-flash", "object": "model", "owned_by": "quicksilverpro", + "pricing": {"prompt": "0.0000024000", "completion": "0.0000120000"}, + "best_for": "Moonshot Kimi K3 · agentic coding + tool use · 1M context"}, + {"id": "muse-spark-1.2", "object": "model", "owned_by": "quicksilverpro", "context_length": 1048576, - "pricing": {"prompt": "0.0000000240", "completion": "0.0000001040"}, - "best_for": "fast multimodal agents · vision · 1M context"}, - {"id": "qwen3.6-plus", "object": "model", "owned_by": "quicksilverpro", + "pricing": {"prompt": "0.0000010000", "completion": "0.0000034000"}, + "best_for": "Meta Muse Spark · long-context coding agent"}, + {"id": "deepseek-v4-pro", "object": "model", "owned_by": "quicksilverpro", + "context_length": 1048576, + "pricing": {"prompt": "0.0000003480", "completion": "0.0000006960"}, + "best_for": "frontier reasoning + coding · 1M context"}, + {"id": "deepseek-v4-flash", "object": "model", "owned_by": "quicksilverpro", + "context_length": 1048576, + "pricing": {"prompt": "0.0000001120", "completion": "0.0000002240"}, + "best_for": "official 0731 agent model · lowest cost · 1M context"}, + {"id": "gemini-3.6-flash", "object": "model", "owned_by": "quicksilverpro", "context_length": 1048576, - "pricing": {"prompt": "0.0000002600", "completion": "0.0000015600"}, - "best_for": "strong general-purpose · 1M context"}, - {"id": "qwen3.6-35b", "object": "model", "owned_by": "quicksilverpro", - "context_length": 262144, - "pricing": {"prompt": "0.0000001120", "completion": "0.0000008000"}, - "best_for": "efficient long-context RAG (thinking model)"}, - {"id": "kimi-k2.6", "object": "model", "owned_by": "quicksilverpro", - "context_length": 256000, - "pricing": {"prompt": "0.0000005472", "completion": "0.0000027280"}, - "best_for": "agentic, tool use, long-context"}, + "pricing": {"prompt": "0.0000012750", "completion": "0.0000063750"}, + "best_for": "Google Gemini · fast multimodal · 1M context"}, {"id": "flux.2-pro", "object": "model", "owned_by": "quicksilverpro", "price_per_image": 0.027, "best_for": "high-fidelity text-to-image"}, - {"id": "flux.1-schnell", "object": "model", "owned_by": "quicksilverpro", - "price_per_image": 0.0025, - "best_for": "fast, cheap text-to-image"}, ] @@ -584,7 +585,7 @@ def _image_path(stem: Path, index: int, count: int, ext: str) -> Path: @main.command(help="Generate an image from a text prompt and save it to disk.") @click.argument("prompt") @click.option("-m", "--model", default=DEFAULT_IMAGE_MODEL, show_default=True, - help="Image model, e.g. flux.2-pro or flux.1-schnell.") + help="Image model, e.g. flux.2-pro.") @click.option("-o", "--output", default=None, help="Output file. Default: qsp-image-. in the current dir. " "With -n > 1 a 1-based index is inserted before the extension.")