diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000000000000000000000000000000000..950bf81ba075d49255d0ad5c4a814bcadab220e9 --- /dev/null +++ b/.env.example @@ -0,0 +1,36 @@ +# ============================================ +# Gemini Business2API 配置示例 +# ============================================ + +# 管理员密钥(必需,用于登录管理面板) +# 明文示例: +ADMIN_KEY=your-admin-secret-key + +# 服务端口(可选,默认 7860) +# PORT=7860 + +# ============================================ +# 数据库配置(可选,用于无持久化存储的环境如 HF Spaces) +# ============================================ +# 支持 PostgreSQL 数据库存储(账户/设置/统计) +# 未设置时使用本地文件存储(原有行为) +# +# 示例(Neon PostgreSQL): +# DATABASE_URL=postgresql://user:password@ep-xxx.aws.neon.tech/dbname?sslmode=require +# +# 注意:使用数据库存储需要安装 asyncpg:pip install asyncpg +# DATABASE_URL= + +# ============================================ +# 其他配置请在管理面板的"系统设置"中配置 +# 包括:API密钥、代理、图片生成、重试策略等 +# 配置保存在 data/settings.yaml +# ============================================ + +# ============================================ +# 账户配置 +# ============================================ +# 使用 accounts.json 文件 +# 账户配置保存在 accounts.json 文件中 +# 首次启动时会自动创建空配置 +# 请在管理面板中添加账户,或直接编辑 accounts.json \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..dfe0770424b2a19faf507a501ebfc23be8f54e7b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000000000000000000000000000000000000..fbe16f97d5b5c4c250fd8a0dc61336fd080d4598 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,55 @@ +name: Build Multi-Arch Docker Image + +on: + push: + branches: + - main + tags: + - "v*" + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ secrets.DOCKERHUB_USERNAME }}/gemini-business2api + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + # 优化构建参数 + build-args: | + BUILDKIT_INLINE_CACHE=1 + provenance: false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e8be8dd548ba4ac125c041f2af341061a794757c --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Python lib directory (but not frontend/src/lib) +/lib/ + +# Virtual Environment +venv/ +env/ +ENV/ +.venv +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Project specific +.env +*.log + +# Generated files +data/ +logs/ +static/ + +# OS +.DS_Store +Thumbs.db +old_version.py +docs/img/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..822aef26789af2630a593f49cd6e8d00679ae113 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,68 @@ +# Stage 1: 构建前端 +FROM node:20-slim AS frontend-builder +WORKDIR /app/frontend + +# 先复制 package 文件利用 Docker 缓存 +COPY frontend/package.json frontend/package-lock.json ./ +RUN npm install --silent + +# 复制前端源码并构建 +COPY frontend/ ./ +RUN npm run build + +# Stage 2: 最终运行时镜像 +FROM python:3.11-slim +WORKDIR /app + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + TZ=Asia/Shanghai + +# 安装 Python 依赖和浏览器依赖(合并为单一 RUN 指令以减少层数) +COPY requirements.txt . +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc \ + curl \ + tzdata \ + chromium chromium-driver \ + dbus dbus-x11 \ + xvfb xauth \ + libglib2.0-0 libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 \ + libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 \ + libxfixes3 libxrandr2 libgbm1 libasound2 libpango-1.0-0 \ + libcairo2 fonts-liberation fonts-noto-cjk && \ + ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ + pip install --no-cache-dir -r requirements.txt && \ + apt-get purge -y gcc && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# 复制后端代码 +COPY main.py . +COPY core ./core +COPY util ./util +COPY scripts ./scripts + +# 从 builder 阶段只复制构建好的静态文件 +COPY --from=frontend-builder /app/static ./static + +# 创建数据目录 +RUN mkdir -p ./data + +# 复制启动脚本 +COPY entrypoint.sh . +RUN chmod +x entrypoint.sh + +# 声明数据卷 +VOLUME ["/app/data"] + +# 声明端口 +EXPOSE 7860 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:7860/health || exit 1 + +# 启动服务 +CMD ["./entrypoint.sh"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..5fd72d27c1cc96d48a16e41c9dbc71df39749674 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 yu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e41c84f991272cb648e6665869cf22a96023128c --- /dev/null +++ b/README.md @@ -0,0 +1,388 @@ +--- +title: Gemini Business2api +emoji: ♊ +colorFrom: blue +colorTo: green +sdk: docker +pinned: false +--- + +
+
+
赋予硅基生物以灵魂
+当时明月在 · 曾照彩云归
++ 简体中文 | English +
+
将 Gemini Business 转换为 OpenAI 兼容接口,支持多账号负载均衡、图像生成、视频生成、多模态能力与内置管理面板。
+ +--- + +## 📜 开源协议与声明 + +**开源协议**: MIT License - 查看 [LICENSE](LICENSE) 文件了解详情 + +### ⚠️ 严禁滥用:禁止将本工具用于商业用途或任何形式的滥用(无论规模大小) + +**本工具严禁用于以下行为:** +- 商业用途或盈利性使用 +- 任何形式的批量操作或自动化滥用(无论规模大小) +- 破坏市场秩序或恶意竞争 +- 违反 Google 服务条款的任何行为 +- 违反 Microsoft 服务条款的任何行为 + +**违规后果**:滥用行为可能导致账号永久封禁、法律追责,一切后果由使用者自行承担。 + +**合法用途**:本项目仅限个人学习、技术研究与非商业性技术交流。 + +📖 **完整声明与免责条款**:[DISCLAIMER.md](docs/DISCLAIMER.md) + +--- + +## ✨ 功能特性 + +- ✅ OpenAI API 完全兼容 - 无缝对接现有工具 +- ✅ 多账号负载均衡 - 轮询与故障自动切换 +- ✅ 自动化账号管理 - 支持自动注册与登录,集成多种临时邮箱,支持无头浏览器模式 +- ✅ 流式输出 - 实时响应 +- ✅ 多模态输入 - 100+ 文件类型(图片、PDF、Office 文档、音频、视频、代码等) +- ✅ 图片生成 & 图生图 - 模型可配置,Base64 或 URL 返回 +- ✅ 视频生成 - 专用模型,支持 HTML/URL/Markdown 输出格式 +- ✅ 智能文件处理 - 自动识别文件类型,支持 URL 与 Base64 +- ✅ 日志与监控 - 实时状态与统计信息 +- ✅ 代理支持 - 通过设置面板配置 +- ✅ 内置管理面板 - 在线配置与账号管理 +- ✅ PostgreSQL / SQLite 存储 - 账户/设置/统计持久化 + +## 🤖 模型功能 + +| 模型ID | 识图 | 原生联网 | 文件多模态 | 图片生成 | 视频生成 | +| ------------------------ | ---- | -------- | ---------- | -------- | -------- | +| `gemini-auto` | ✅ | ✅ | ✅ | 可选 | - | +| `gemini-2.5-flash` | ✅ | ✅ | ✅ | 可选 | - | +| `gemini-2.5-pro` | ✅ | ✅ | ✅ | 可选 | - | +| `gemini-3-flash-preview` | ✅ | ✅ | ✅ | 可选 | - | +| `gemini-3-pro-preview` | ✅ | ✅ | ✅ | 可选 | - | +| `gemini-3.1-pro-preview` | ✅ | ✅ | ✅ | 可选 | - | +| `gemini-imagen` | ✅ | ✅ | ✅ | ✅ | - | +| `gemini-veo` | ✅ | ✅ | ✅ | - | ✅ | + +> `gemini-imagen`:专用图片生成模型 · `gemini-veo`:专用视频生成模型 + +--- + +## 🚀 快速开始 + +### 方式一:Docker Compose(推荐) + +**支持 ARM64 和 AMD64 架构** + +```bash +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api +cp .env.example .env +# 编辑 .env 设置 ADMIN_KEY + +docker-compose up -d + +# 查看日志 +docker-compose logs -f + +# 更新到最新版本 +docker-compose pull && docker-compose up -d +``` + +--- + +### 方式二:安装脚本 + +> **前置要求**:Git、Node.js & npm(构建前端用)。脚本会自动安装 Python 3.11 和 uv。 + +**Linux / macOS / WSL:** +```bash +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api +bash setup.sh +# 编辑 .env 设置 ADMIN_KEY +source .venv/bin/activate +python main.py +# pm2 后台运行 +pm2 start main.py --name gemini-api --interpreter ./.venv/bin/python3 +``` + +**Windows:** +```cmd +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api +setup.bat +# 编辑 .env 设置 ADMIN_KEY +.venv\Scripts\activate.bat +python main.py +# pm2 后台运行 +pm2 start main.py --name gemini-api --interpreter ./.venv/Scripts/python.exe +``` + +安装脚本会自动完成:uv 安装、Python 3.11 下载、依赖安装、前端构建、`.env` 创建。 +更新项目时重新运行同一脚本即可。 + +--- + +### 方式三:手动部署 + +```bash +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api + +curl -LsSf https://astral.sh/uv/install.sh | sh +uv python install 3.11 + +cd frontend && npm install && npm run build && cd .. + +uv venv --python 3.11 .venv +source .venv/bin/activate # Windows: .venv\Scripts\activate.bat +uv pip install -r requirements.txt + +cp .env.example .env +# 编辑 .env 设置 ADMIN_KEY +python main.py +``` + +--- + +### 访问方式 + +- **管理面板**:`http://localhost:7860/`(使用 `ADMIN_KEY` 登录) +- **API 接口**:`http://localhost:7860/v1/chat/completions` + +--- + +## 🗄️ 数据库持久化 + +设置 `DATABASE_URL` 可将账户、设置、统计写入数据库,避免容器重启丢数据。未设置时自动使用 SQLite(本地 `data.db`)。 + +**配置方式:** +- 本地部署 → 写入 `.env` +- 云平台 → 在平台环境变量中设置 + +``` +DATABASE_URL=postgresql://user:password@host/dbname?sslmode=require +``` + +**免费 PostgreSQL 推荐:** + +| 服务 | 免费额度 | 获取方式 | +|------|---------|---------| +| [Neon](https://neon.tech) | 512MB 存储 / 100 CPUH 月 | 注册 → Create Project → 复制 Connection string | +| [Aiven](https://aiven.io) | 额度更充裕 | 注册 → 创建 PostgreSQL 服务 → 复制连接串 | + +> `postgres://` 和 `postgresql://` 两种格式均可直接使用,无需手动转换。 + +![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
+
+
Empowering AI with seamless integration
++ 简体中文 | English +
+
Convert Gemini Business to OpenAI-compatible API with multi-account load balancing, image generation, video generation, multimodal capabilities, and built-in admin panel.
+ +--- + +## 📜 License & Disclaimer + +**License**: MIT License - See [LICENSE](../LICENSE) for details + +### ⚠️ Prohibited Use & Anti-Abuse Policy + +**This tool is strictly prohibited for:** +- Commercial use or profit-making activities +- Batch operations or automated abuse of any scale +- Market disruption or malicious competition +- Violations of Google's Terms of Service +- Violations of Microsoft's Terms of Service + +**Consequences**: Violations may result in permanent account suspension and legal liability. All consequences are the sole responsibility of the user. + +**Legitimate Use Only**: Personal learning, technical research, and non-commercial educational purposes only. + +📖 **Full Disclaimer**: [DISCLAIMER_EN.md](DISCLAIMER_EN.md) + +--- + +## ✨ Features + +- ✅ Full OpenAI API compatibility - Seamless integration with existing tools +- ✅ Multi-account load balancing - Round-robin with automatic failover +- ✅ Automated account management - Auto registration & login, multiple temp email providers, headless browser mode +- ✅ Streaming output - Real-time responses +- ✅ Multimodal input - 100+ file types (images, PDF, Office docs, audio, video, code, etc.) +- ✅ Image generation & image-to-image - Configurable models, Base64 or URL output +- ✅ Video generation - Dedicated model with HTML/URL/Markdown output formats +- ✅ Smart file handling - Auto file type detection, supports URL and Base64 +- ✅ Logging & monitoring - Real-time status and statistics +- ✅ Proxy support - Configure via admin settings panel +- ✅ Built-in admin panel - Online configuration and account management +- ✅ PostgreSQL / SQLite storage - Persistent accounts/settings/stats + +## 🤖 Model Capabilities + +| Model ID | Vision | Native Web | File Multimodal | Image Gen | Video Gen | +| ------------------------ | ------ | ---------- | --------------- | --------- | --------- | +| `gemini-auto` | ✅ | ✅ | ✅ | Optional | - | +| `gemini-2.5-flash` | ✅ | ✅ | ✅ | Optional | - | +| `gemini-2.5-pro` | ✅ | ✅ | ✅ | Optional | - | +| `gemini-3-flash-preview` | ✅ | ✅ | ✅ | Optional | - | +| `gemini-3-pro-preview` | ✅ | ✅ | ✅ | Optional | - | +| `gemini-3.1-pro-preview` | ✅ | ✅ | ✅ | Optional | - | +| `gemini-imagen` | ✅ | ✅ | ✅ | ✅ | - | +| `gemini-veo` | ✅ | ✅ | ✅ | - | ✅ | + +> `gemini-imagen`: Dedicated image generation model · `gemini-veo`: Dedicated video generation model + +--- + +## 🚀 Quick Start + +### Method 1: Docker Compose (Recommended) + +**Supports ARM64 and AMD64 architectures** + +```bash +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api +cp .env.example .env +# Edit .env to set ADMIN_KEY + +docker-compose up -d + +# View logs +docker-compose logs -f + +# Update to latest version +docker-compose pull && docker-compose up -d +``` + +--- + +### Method 2: Setup Script + +> **Prerequisites**: Git, Node.js & npm (for frontend build). Script auto-installs Python 3.11 and uv. + +**Linux / macOS / WSL:** +```bash +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api +bash setup.sh +# Edit .env to set ADMIN_KEY +source .venv/bin/activate +python main.py +# Background with pm2 +pm2 start main.py --name gemini-api --interpreter ./.venv/bin/python3 +``` + +**Windows:** +```cmd +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api +setup.bat +# Edit .env to set ADMIN_KEY +.venv\Scripts\activate.bat +python main.py +# Background with pm2 +pm2 start main.py --name gemini-api --interpreter ./.venv/Scripts/python.exe +``` + +The script handles: uv install, Python 3.11 download, dependency install, frontend build, `.env` creation. +To update, simply re-run the same script. + +--- + +### Method 3: Manual Deployment + +```bash +git clone https://github.com/Dreamy-rain/gemini-business2api.git +cd gemini-business2api + +curl -LsSf https://astral.sh/uv/install.sh | sh +uv python install 3.11 + +cd frontend && npm install && npm run build && cd .. + +uv venv --python 3.11 .venv +source .venv/bin/activate # Windows: .venv\Scripts\activate.bat +uv pip install -r requirements.txt + +cp .env.example .env +# Edit .env to set ADMIN_KEY +python main.py +``` + +--- + +### Access + +- **Admin Panel**: `http://localhost:7860/` (Login with `ADMIN_KEY`) +- **API Endpoint**: `http://localhost:7860/v1/chat/completions` + +--- + +## 🗄️ Database Persistence + +Set `DATABASE_URL` to persist accounts, settings, and stats. Without it, SQLite (`data.db`) is used automatically. + +**Configuration:** +- Local deployment → add to `.env` +- Cloud platforms → set in platform environment variables + +``` +DATABASE_URL=postgresql://user:password@host/dbname?sslmode=require +``` + +**Free PostgreSQL Providers:** + +| Service | Free Tier | How to Get | +|---------|-----------|-----------| +| [Neon](https://neon.tech) | 512MB / 100 CPUH/month | Sign up → Create Project → Copy Connection string | +| [Aiven](https://aiven.io) | More generous | Sign up → Create PostgreSQL service → Copy connection string | + +> Both `postgres://` and `postgresql://` formats are supported natively. + +![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
![]() |
+ ![]() |
+
u-d&&(s=u-d,a.length=s);for(var f=0;f =a)}}for(var h=this.__startIndex;h n?a:o,h=Math.abs(l.label.y-n);if(h>=u.maxY){var c=l.label.x-e-l.len2*r,p=i+l.len,f=Math.abs(c) t.unconstrainedWidth?null:d:null;i.setStyle("width",f)}var g=i.getBoundingRect();o.width=g.width;var y=(i.style.margin||0)+2.1;o.height=g.height+y,o.y-=(o.height-c)/2}}}function kM(t){return"center"===t.position}function LM(t){var e,n,i=t.getData(),r=[],o=!1,a=(t.get("minShowLabelAngle")||0)*CM,s=i.getLayout("viewRect"),l=i.getLayout("r"),u=s.width,h=s.x,c=s.y,p=s.height;function d(t){t.ignore=!0}i.each((function(t){var s=i.getItemGraphicEl(t),c=s.shape,p=s.getTextContent(),f=s.getTextGuideLine(),g=i.getItemModel(t),y=g.getModel("label"),v=y.get("position")||g.get(["emphasis","label","position"]),m=y.get("distanceToLabelLine"),x=y.get("alignTo"),_=$r(y.get("edgeDistance"),u),b=y.get("bleedMargin"),w=g.getModel("labelLine"),S=w.get("length");S=$r(S,u);var M=w.get("length2");if(M=$r(M,u),Math.abs(c.endAngle-c.startAngle)0?"right":"left":k>0?"left":"right"}var B=Math.PI,F=0,G=y.get("rotate");if(j(G))F=G*(B/180);else if("center"===v)F=0;else if("radial"===G||!0===G){F=k<0?-A+B:-A}else if("tangential"===G&&"outside"!==v&&"outer"!==v){var W=Math.atan2(k,L);W<0&&(W=2*B+W),L>0&&(W=B+W),F=W-B}if(o=!!F,p.x=I,p.y=T,p.rotation=F,p.setStyle({verticalAlign:"middle"}),P){p.setStyle({align:D});var H=p.states.select;H&&(H.x+=p.x,H.y+=p.y)}else{var Y=p.getBoundingRect().clone();Y.applyTransform(p.getComputedTransform());var X=(p.style.margin||0)+2.1;Y.y-=X/2,Y.height+=X,r.push({label:p,labelLine:f,position:v,len:S,len2:M,minTurnAngle:w.get("minTurnAngle"),maxSurfaceAngle:w.get("maxSurfaceAngle"),surfaceNormal:new De(k,L),linePoints:C,textAlign:D,labelDistance:m,labelAlignTo:x,edgeDistance:_,bleedMargin:b,rect:Y,unconstrainedWidth:Y.width,labelStyleWidth:p.style.width})}s.setTextConfig({inside:P})}})),!o&&t.get("avoidLabelOverlap")&&function(t,e,n,i,r,o,a,s){for(var l=[],u=[],h=Number.MAX_VALUE,c=-Number.MAX_VALUE,p=0;p i&&(i=e);var o=i%2?i+2:i+3;r=[];for(var a=0;ah[1]&&(h[1]=y),c[p++]=v}return r._count=p,r._indices=c,r._updateGetRawIdx(),r},t.prototype.each=function(t,e){if(this._count)for(var n=t.length,i=this._chunks,r=0,o=this.count();r1||n>0&&!t.noHeader;return E(t.blocks,(function(t){var n=lg(t);n>=e&&(e=n+ +(i&&(!n||ag(t)&&!t.noHeader)))})),e}return 0}function ug(t,e,n,i){var r,o=e.noHeader,a=(r=lg(e),{html:ig[r],richText:rg[r]}),s=[],l=e.blocks||[];lt(!l||Y(l)),l=l||[];var u=t.orderMode;if(e.sortBlocks&&u){l=l.slice();var h={valueAsc:"asc",valueDesc:"desc"};if(_t(h,u)){var c=new kf(h[u],null);l.sort((function(t,e){return c.evaluate(t.sortParam,e.sortParam)}))}else"seriesDesc"===u&&l.reverse()}E(l,(function(n,r){var o=e.valueFormatter,l=sg(n)(o?A(A({},t),{valueFormatter:o}):t,n,r>0?a.html:0,i);null!=l&&s.push(l)}));var p="richText"===t.renderMode?s.join(a.richText):pg(i,s.join(""),o?n:a.html);if(o)return p;var d=mp(e.header,"ordinal",t.useUTC),f=ng(i,t.renderMode).nameStyle,g=eg(i);return"richText"===t.renderMode?dg(t,d,f)+a.richText+p:pg(i,'5)return;var i=this._model.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]);"none"!==i.behavior&&this._dispatchExpand({axisExpandWindow:i.axisExpandWindow})}this._mouseDownPoint=null},mousemove:function(t){if(!this._mouseDownPoint&&Rk(this,"mousemove")){var e=this._model,n=e.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]),i=n.behavior;"jump"===i&&this._throttledDispatchExpand.debounceNextCall(e.get("axisExpandDebounce")),this._throttledDispatchExpand("none"===i?null:{axisExpandWindow:n.axisExpandWindow,animation:"jump"===i?null:{duration:0}})}}};function Rk(t,e){var n=t._model;return n.get("axisExpandable")&&n.get("axisExpandTriggerOn")===e}var Nk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(){t.prototype.init.apply(this,arguments),this.mergeOption({})},e.prototype.mergeOption=function(t){var e=this.option;t&&C(e,t,!0),this._initDimensions()},e.prototype.contains=function(t,e){var n=t.get("parallelIndex");return null!=n&&e.getComponent("parallel",n)===this},e.prototype.setAxisExpand=function(t){E(["axisExpandable","axisExpandCenter","axisExpandCount","axisExpandWidth","axisExpandWindow"],(function(e){t.hasOwnProperty(e)&&(this.option[e]=t[e])}),this)},e.prototype._initDimensions=function(){var t=this.dimensions=[],e=this.parallelAxisIndex=[];E(B(this.ecModel.queryComponents({mainType:"parallelAxis"}),(function(t){return(t.get("parallelIndex")||0)===this.componentIndex}),this),(function(n){t.push("dim"+n.get("dim")),e.push(n.componentIndex)}))},e.type="parallel",e.dependencies=["parallelAxis"],e.layoutMode="box",e.defaultOption={z:0,left:80,top:60,right:80,bottom:60,layout:"horizontal",axisExpandable:!1,axisExpandCenter:null,axisExpandCount:0,axisExpandWidth:50,axisExpandRate:17,axisExpandDebounce:50,axisExpandSlideTriggerArea:[-.15,.05,.4],axisExpandTriggerOn:"click",parallelAxisDefault:null},e}(zp),Ek=function(t){function e(e,n,i,r,o){var a=t.call(this,e,n,i)||this;return a.type=r||"value",a.axisIndex=o,a}return n(e,t),e.prototype.isHorizontal=function(){return"horizontal"!==this.coordinateSystem.getModel().get("layout")},e}(ab);function zk(t,e,n,i,r,o){t=t||0;var a=n[1]-n[0];if(null!=r&&(r=Bk(r,[0,a])),null!=o&&(o=Math.max(o,null!=r?r:0)),"all"===i){var s=Math.abs(e[1]-e[0]);s=Bk(s,[0,a]),r=o=Bk(s,[r,o]),i=0}e[0]=Bk(e[0],n),e[1]=Bk(e[1],n);var l=Vk(e,i);e[i]+=t;var u,h=r||0,c=n.slice();return l.sign<0?c[0]+=h:c[1]-=h,e[i]=Bk(e[i],c),u=Vk(e,i),null!=r&&(u.sign!==l.sign||u.span