Spaces:
Running
Running
| # claude-pick — Interactive model picker for free-claude-code | |
| # Usage: claude-pick [extra claude args...] | |
| set -euo pipefail | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| MODELS_FILE="$SCRIPT_DIR/nvidia_nim_models.json" | |
| ENV_FILE="${CLAUDE_PICK_ENV_FILE:-$SCRIPT_DIR/.env}" | |
| PORT="${CLAUDE_PICK_PORT:-8082}" | |
| BASE_URL="http://localhost:$PORT" | |
| OPENROUTER_MODELS_URL="https://openrouter.ai/api/v1/models" | |
| DEFAULT_LM_STUDIO_BASE_URL="http://localhost:1234/v1" | |
| DEFAULT_LLAMACPP_BASE_URL="http://localhost:8080/v1" | |
| if ! command -v python3 >/dev/null 2>&1; then | |
| echo "Error: python3 is required." >&2 | |
| exit 1 | |
| fi | |
| read_env_value() { | |
| local key="$1" | |
| [[ -f "$ENV_FILE" ]] || return 0 | |
| local raw | |
| raw="$(grep -E "^[[:space:]]*${key}[[:space:]]*=" "$ENV_FILE" | tail -n 1 || true)" | |
| raw="${raw#*=}" | |
| raw="${raw%%#*}" | |
| raw="$(echo "$raw" | xargs || true)" | |
| raw="${raw%\"}" | |
| raw="${raw#\"}" | |
| raw="${raw%\'}" | |
| raw="${raw#\'}" | |
| echo "$raw" | |
| } | |
| if ! command -v fzf >/dev/null 2>&1; then | |
| echo "Error: fzf is required for the model picker." >&2 | |
| echo "Install it from: https://github.com/junegunn/fzf" >&2 | |
| exit 1 | |
| fi | |
| parse_models_from_json() { | |
| python3 -c ' | |
| import json, sys | |
| try: | |
| payload = json.load(sys.stdin) | |
| except Exception: | |
| sys.exit(0) | |
| for item in payload.get("data", []): | |
| model_id = item.get("id") | |
| if model_id: | |
| print(model_id) | |
| ' | |
| } | |
| get_nvidia_models() { | |
| if [[ ! -f "$MODELS_FILE" ]]; then | |
| echo "Error: $MODELS_FILE not found." >&2 | |
| echo "Run: curl \"https://integrate.api.nvidia.com/v1/models\" > nvidia_nim_models.json" >&2 | |
| exit 1 | |
| fi | |
| python3 -c ' | |
| import json, sys | |
| with open(sys.argv[1], "r", encoding="utf-8") as f: | |
| payload = json.load(f) | |
| for item in payload.get("data", []): | |
| model_id = item.get("id") | |
| if model_id: | |
| print(model_id) | |
| ' "$MODELS_FILE" | |
| } | |
| get_openrouter_models() { | |
| if ! command -v curl >/dev/null 2>&1; then | |
| echo "Error: curl is required for OpenRouter model discovery." >&2 | |
| exit 1 | |
| fi | |
| local openrouter_key | |
| openrouter_key="${OPENROUTER_API_KEY:-$(read_env_value OPENROUTER_API_KEY)}" | |
| local response | |
| if [[ -n "$openrouter_key" ]]; then | |
| if ! response="$(curl -fsSL -H "Authorization: Bearer $openrouter_key" "$OPENROUTER_MODELS_URL")"; then | |
| echo "Error: Failed to fetch OpenRouter models." >&2 | |
| exit 1 | |
| fi | |
| else | |
| if ! response="$(curl -fsSL "$OPENROUTER_MODELS_URL")"; then | |
| echo "Error: Failed to fetch OpenRouter models." >&2 | |
| exit 1 | |
| fi | |
| fi | |
| parse_models_from_json <<< "$response" | |
| } | |
| get_lmstudio_models() { | |
| if ! command -v curl >/dev/null 2>&1; then | |
| echo "Error: curl is required for LM Studio model discovery." >&2 | |
| exit 1 | |
| fi | |
| local lm_base | |
| lm_base="${LM_STUDIO_BASE_URL:-$(read_env_value LM_STUDIO_BASE_URL)}" | |
| lm_base="${lm_base:-$DEFAULT_LM_STUDIO_BASE_URL}" | |
| local models_url | |
| if [[ "$lm_base" == */v1 ]]; then | |
| models_url="${lm_base}/models" | |
| else | |
| models_url="${lm_base}/v1/models" | |
| fi | |
| local response | |
| if ! response="$(curl -fsSL "$models_url")"; then | |
| echo "Error: Failed to query LM Studio models at $models_url" >&2 | |
| echo "Start LM Studio server first (Developer tab or: lms server start)." >&2 | |
| exit 1 | |
| fi | |
| parse_models_from_json <<< "$response" | |
| } | |
| provider="${CLAUDE_PICK_PROVIDER:-$(read_env_value PROVIDER_TYPE)}" | |
| provider="${provider:-nvidia_nim}" | |
| prompt="Select a model> " | |
| case "$provider" in | |
| nvidia_nim) | |
| models="$(get_nvidia_models)" | |
| prompt="Select a NVIDIA NIM model> " | |
| ;; | |
| open_router|openrouter) | |
| models="$(get_openrouter_models)" | |
| prompt="Select an OpenRouter model> " | |
| ;; | |
| lmstudio|lm_studio|lm-studio) | |
| models="$(get_lmstudio_models)" | |
| prompt="Select an LM Studio model> " | |
| ;; | |
| llamacpp|llama.cpp) | |
| # llama.cpp doesn't have a standardized /models endpoint that returns all loaded models reliably | |
| # in the same way, but it does support Anthropic routing. We can use a stub model or query if available. | |
| # For simple picker, we'll just allow passing a default or typing it in, but to match fzf we offer a stub. | |
| models="local-model\nllama-server" | |
| prompt="Select a llama.cpp model> " | |
| ;; | |
| *) | |
| echo "Error: Unsupported PROVIDER_TYPE='$provider'." >&2 | |
| echo "Expected one of: nvidia_nim, open_router, lmstudio, llamacpp" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| models="$(printf "%s\n" "$models" | sed '/^[[:space:]]*$/d' | sort -u)" | |
| if [[ -z "$models" ]]; then | |
| echo "Error: No models found for provider '$provider'." >&2 | |
| exit 1 | |
| fi | |
| model="$(printf "%s\n" "$models" | fzf --prompt="$prompt" --height=40% --reverse)" | |
| if [[ -z "${model:-}" ]]; then | |
| echo "No model selected." >&2 | |
| exit 1 | |
| fi | |
| # Read auth token from .env or environment | |
| auth_token="${ANTHROPIC_AUTH_TOKEN:-$(read_env_value ANTHROPIC_AUTH_TOKEN)}" | |
| if [[ -z "$auth_token" ]]; then | |
| auth_token="freecc" | |
| fi | |
| # If auth_token doesn't contain a colon, append ":$model" | |
| if [[ "$auth_token" != *:* ]]; then | |
| auth_token="$auth_token:$model" | |
| fi | |
| echo "Launching Claude with provider: $provider, model: $model" >&2 | |
| ANTHROPIC_AUTH_TOKEN="$auth_token" ANTHROPIC_BASE_URL="$BASE_URL" exec claude "$@" | |