diff --git a/.gitignore b/.gitignore index ac8c8837d..243fe5ea5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Credential files - should never be committed *.json +!install-gcli2api.sh +!uninstall-gcli2api.sh !package.json !package-lock.json !tsconfig.json diff --git a/README.md b/README.md index e3b32042c..d7cda938f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,130 @@ # GeminiCLI to API +> 本仓库维护版:`qingan123/gcli2api` +> +> 支持 Gemini CLI / Antigravity,包含改进后的 Antigravity 流式抗截断续写逻辑。 + +## ⚡ 一键部署(推荐) + +Linux / macOS / WSL: + +```bash +curl -fsSL https://raw.githubusercontent.com/qingan123/gcli2api/master/install-gcli2api.sh | bash +``` + +默认配置: + +- 部署目录:`~/gcli2api` +- 端口:`7861` +- 默认密码:`584248` +- 容器启动后会自动检查 `/antigravity/v1/models` + +自定义密码、端口和目录: + +```bash +PASSWORD='你的密码' PORT=7861 GCLI2API_DIR=/opt/gcli2api \ + bash -c "$(curl -fsSL https://raw.githubusercontent.com/qingan123/gcli2api/master/install-gcli2api.sh)" +``` + +## 🧹 一键卸载 + +默认卸载容器和服务,但保留凭证数据: + +```bash +curl -fsSL https://raw.githubusercontent.com/qingan123/gcli2api/master/uninstall-gcli2api.sh | bash +``` + +卸载并删除部署目录、凭证和全部数据: + +```bash +REMOVE_DATA=1 bash -c "$(curl -fsSL https://raw.githubusercontent.com/qingan123/gcli2api/master/uninstall-gcli2api.sh)" +``` + +## 🔌 API 接口 + +公网部署后,将下面的 `HOST` 替换为服务器公网 IP 或域名: + +```text +HOST=http://你的公网IP:7861 +API_BASE=$HOST/antigravity/v1 +PASSWORD=584248 +``` + +### Antigravity OpenAI 兼容接口(推荐) + +模型列表: + +```http +GET $API_BASE/models +Authorization: Bearer 584248 +``` + +聊天接口: + +```http +POST $API_BASE/chat/completions +Authorization: Bearer 584248 +Content-Type: application/json +``` + +请求示例: + +```bash +curl "$API_BASE/chat/completions" \ + -H "Authorization: Bearer 584248" \ + -H 'Content-Type: application/json' \ + -d '{ + "model": "gemini-2.5-flash", + "messages": [{"role": "user", "content": "你好"}], + "stream": false + }' +``` + +### 抗截断请求 + +抗截断仅对流式请求启用,模型名前加 `抗截断/`: + +```bash +curl "$API_BASE/chat/completions" \ + -H "Authorization: Bearer 584248" \ + -H 'Content-Type: application/json' \ + -d '{ + "model": "抗截断/gemini-2.5-flash", + "messages": [{"role": "user", "content": "写一篇长文章"}], + "stream": true + }' +``` + +### Antigravity Gemini 原生接口 + +```http +POST $API_BASE/models/{model}:generateContent +Authorization: Bearer 584248 +Content-Type: application/json +``` + +### Antigravity Claude 兼容接口 + +```http +POST $API_BASE/messages +Authorization: Bearer 584248 +Content-Type: application/json +``` + +### Gemini CLI 接口 + +如果上传的是 Gemini CLI 凭证而不是 Antigravity 凭证,使用: + +```text +http://你的公网IP:7861/v1 +``` + +Antigravity 凭证必须使用: + +```text +http://你的公网IP:7861/antigravity/v1 +``` + **将 GeminiCLI 和 Antigravity 转换为 OpenAI 、GEMINI 和 Claude API 兼容接口** [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/) diff --git a/install-gcli2api.sh b/install-gcli2api.sh new file mode 100755 index 000000000..8ac153e59 --- /dev/null +++ b/install-gcli2api.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# One-click deployment for qingan123/gcli2api. +# Usage: curl -fsSL https://raw.githubusercontent.com/qingan123/gcli2api/master/install-gcli2api.sh | bash + +APP_DIR="${GCLI2API_DIR:-$HOME/gcli2api}" +PORT="${PORT:-7861}" +PASSWORD="${PASSWORD:-584248}" +REPO_URL="${GCLI2API_REPO:-https://github.com/qingan123/gcli2api.git}" +BRANCH="${GCLI2API_BRANCH:-master}" + +if ! command -v docker >/dev/null 2>&1; then + printf '%s\n' '错误:未检测到 Docker,请先安装 Docker Engine 和 Docker Compose。' >&2 + exit 1 +fi +if ! docker compose version >/dev/null 2>&1; then + printf '%s\n' '错误:未检测到 Docker Compose v2。' >&2 + exit 1 +fi + +mkdir -p "$APP_DIR/data/creds" +if [ -d "$APP_DIR/.git" ]; then + git -C "$APP_DIR" fetch origin "$BRANCH" + git -C "$APP_DIR" checkout "$BRANCH" + git -C "$APP_DIR" reset --hard "origin/$BRANCH" +else + tmp_dir="${APP_DIR}.tmp.$$" + rm -rf "$tmp_dir" + git clone --depth 1 --branch "$BRANCH" "$REPO_URL" "$tmp_dir" + if [ -d "$APP_DIR/data/creds" ]; then + cp -a "$APP_DIR/data/creds/." "$tmp_dir/data/creds/" 2>/dev/null || true + fi + rm -rf "$APP_DIR" + mv "$tmp_dir" "$APP_DIR" +fi + +mkdir -p "$APP_DIR/data/creds" +cat > "$APP_DIR/.env" </dev/null + +printf '\n部署完成\n' +printf '目录: %s\n' "$APP_DIR" +printf '面板: http://%s:%s\n' "$(hostname -I | awk '{print $1}')" "$PORT" +printf 'Antigravity API: http://%s:%s/antigravity/v1\n' "$(hostname -I | awk '{print $1}')" "$PORT" +printf '密码: %s\n' "$PASSWORD" +printf '验证: HTTP 200\n' diff --git a/src/router/antigravity/openai.py b/src/router/antigravity/openai.py index ea1b7fc8d..9cc68c723 100644 --- a/src/router/antigravity/openai.py +++ b/src/router/antigravity/openai.py @@ -259,7 +259,9 @@ async def stream_request_wrapper(payload): stream_request_wrapper, anti_truncation_payload, max_attempts, - enable_prefill_mode=("claude" not in str(api_request.get("model", "")).lower()), + # Antigravity may ignore model prefill and finish immediately. Use an + # explicit continuation user message so plain-text fallback can resume. + enable_prefill_mode=False, ) # 转换为 OpenAI 格式 diff --git a/uninstall-gcli2api.sh b/uninstall-gcli2api.sh new file mode 100755 index 000000000..878275f4b --- /dev/null +++ b/uninstall-gcli2api.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# One-click uninstall. Credentials are preserved by default. +# Set REMOVE_DATA=1 to remove credentials and local deployment data too. + +APP_DIR="${GCLI2API_DIR:-$HOME/gcli2api}" +REMOVE_DATA="${REMOVE_DATA:-0}" + +if [ ! -d "$APP_DIR" ]; then + printf '未找到部署目录: %s\n' "$APP_DIR" + exit 0 +fi + +if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1 && [ -f "$APP_DIR/docker-compose.yml" ]; then + docker compose -f "$APP_DIR/docker-compose.yml" down --remove-orphans || true +fi + +if [ "$REMOVE_DATA" = "1" ]; then + rm -rf "$APP_DIR" + printf '已卸载并删除部署目录及凭证数据: %s\n' "$APP_DIR" +else + rm -f "$APP_DIR/.env" + rm -rf "$APP_DIR/.git" "$APP_DIR"/source-inspect + printf '已卸载服务;凭证数据保留在: %s/data/creds\n' "$APP_DIR" + printf '如需删除凭证和全部数据,请执行: REMOVE_DATA=1 %s\n' "$0" +fi