Skip to content

LMArenaBridge 是一个强大的开源工具,它充当一座桥梁,让你能通过任何兼容 OpenAI API 的应用程序(例如各类AI聊天客户端、编程插件等)来使用 [LMArena.ai](https://lmarena.ai/) 网站上提供的海量先进测试大语言模型。

Notifications You must be signed in to change notification settings

XXXxx7258/LMArenaBridge

 
 

Repository files navigation

🚀 LMArena Bridge - AI模型竞技场API代理器 🌉

欢迎来到新一代的 LMArena Bridge!🎉 这是一个基于 FastAPI 和 WebSocket 的高性能工具集,它能让你通过任何兼容 OpenAI API 的客户端或应用程序,无缝使用 LMArena.ai 平台上提供的海量大语言模型。

这个重构版本旨在提供更稳定、更易于维护和扩展的体验。

✨ 主要功能

  • 🚀 高性能后端: 基于 FastAPIUvicorn,提供异步、高性能的 API 服务。
  • 🔌 稳定的 WebSocket 通信: 使用 WebSocket 替代 Server-Sent Events (SSE),实现更可靠、低延迟的双向通信。
  • 🤖 OpenAI 兼容接口: 完全兼容 OpenAI v1/chat/completionsv1/models 以及 v1/images/generations 端点。
  • 📋 手动模型列表更新: 新增 model_updater.py 脚本,可手动触发从 LMArena 页面提取最新的可用模型列表,并保存为 available_models.json,方便查阅和更新核心的 models.json
  • 📎 通用文件上传: 支持通过 Base64 上传任意类型的文件(图片、音频、PDF、代码等),并支持一次性上传多个文件。
  • 🎨 原生流式文生图: 文生图功能已与文本生成完全统一。只需在 /v1/chat/completions 接口中请求图像模型,即可像接收文本一样,流式接收到 Markdown 格式的图片。
  • 🗣️ 完整对话历史支持: 自动将会话历史注入到 LMArena,实现有上下文的连续对话。
  • 🌊 实时流式响应: 像原生 OpenAI API 一样,实时接收来自模型的文本回应。
  • 🔄 自动程序更新: 启动时自动检查 GitHub 仓库,发现新版本时可自动下载并更新程序。
  • 🆔 一键式会话ID更新: 提供 id_updater.py 脚本,只需在浏览器操作一次,即可自动捕获并更新 config.jsonc 中所需的会话 ID。
  • ⚙️ 浏览器自动化: 配套的油猴脚本 (LMArenaApiBridge.js) 负责与后端服务器通信,并在浏览器中执行所有必要操作。
  • 🍻 酒馆模式 (Tavern Mode): 专为 SillyTavern 等应用设计,智能合并 system 提示词,确保兼容性。
  • 🤫 Bypass 模式: 尝试通过在请求中额外注入一个空的用户消息,绕过平台的敏感词审查。
  • 🔐 API Key 保护: 可在配置文件中设置 API Key,为你的服务增加一层安全保障。
  • 🎯 模型-会话高级映射: 支持为不同模型配置独立的会话ID池,并能为每个会话指定特定的工作模式(如 battledirect_chat),实现更精细的请求控制。
  • 🖼️ 可选的外部文件床: 新增一个独立的 FastAPI 文件床服务器。启用后,所有附件会先上传到此服务器并转换为直接 URL,从而绕过 LMArena 对 Base64 大小和类型的限制,让你能上传更大的文件或视频等。

📂 新增:文件床服务器

为了解决 LMArena 对 Base64 附件大小(通常约5MB)的限制,并支持更多文件类型,本项目现在包含一个独立的文件床服务器。

工作原理

  1. 当你在 config.jsonc 中启用 file_bed_enabled 时。
  2. api_server.py 在处理你的请求时,会截获所有 data: URI 格式的附件。
  3. 它会调用文件床服务器的 /upload API,将文件上传。
  4. 文件床服务器将文件保存在本地 file_bed_server/uploads/ 目录中,并返回一个可公开访问的 URL (例如 http://127.0.0.1:5104/uploads/xxxx.png)。
  5. api_server.py 随后将这个 URL 作为纯文本插入到你的消息内容中,而不是作为附件发送。
  6. 这样,即使是 LMArena 不直接支持的视频、大型图片或压缩包,也能以链接的形式发送给模型。

如何使用

  1. 安装依赖 进入 file_bed_server 目录并安装其特定依赖:

    cd file_bed_server
    pip install -r requirements.txt
    cd ..
  2. 启动文件床服务器一个新的终端中,运行文件床服务器:

    python file_bed_server/main.py

    服务器默认运行在 http://127.0.0.1:5104

  3. 修改主配置 打开 config.jsonc 文件,进行如下设置:

    • "file_bed_enabled": true, // 启用文件床
    • "file_bed_upload_url": "http:\/\/127.0.0.1:5180/upload", // 确保地址和端口正确。注意:为了确保最大兼容性,建议将URL中的 // 转义为 \/\/
    • "file_bed_api_key": "your_secret_api_key" // (可选) 如果你在 file_bed_server/main.py 中修改了 API_KEY,请在此处同步。
  4. 正常运行主服务 像往常一样启动 api_server.py。现在,当你通过客户端发送带有多媒体附件的请求时,它们将自动通过文件床进行处理。

⚙️ 配置文件说明

项目的主要行为通过 config.jsonc, models.jsonmodel_endpoint_map.json 进行控制。

models.json - 核心模型映射

这个文件包含了 LMArena 平台上的模型名称到其内部ID的映射,并支持通过特定格式指定模型类型。

  • 重要: 这是程序运行所必需的核心文件。你需要手动维护这个列表。
  • 格式:
    • 标准文本模型: "model-name": "model-id"
    • 图像生成模型: "model-name": "model-id:image"
  • 说明:
    • 程序通过检查模型ID字符串中是否包含 :image 来识别图像模型。
    • 这种格式保持了对旧配置文件的最大兼容性,未指定类型的模型将默认为 "text"
  • 示例:
    {
      "gemini-1.5-pro-flash-20240514": "gemini-1.5-pro-flash-20240514",
      "dall-e-3": "null:image"
    }

available_models.json - 可用模型参考 (可选)

  • 这是一个参考文件,由新增的 model_updater.py 脚本生成。
  • 它包含了从 LMArena 页面上提取的所有模型的完整信息(ID, 名称, 组织等)。
  • 你可以运行 model_updater.py 来生成或更新此文件,然后从中复制你需要使用的模型信息到 models.json 中。

config.jsonc - 全局配置

这是主要的配置文件,包含了服务器的全局设置。

  • session_id / message_id: 全局默认的会话ID。当模型没有在 model_endpoint_map.json 中找到特定映射时,会使用这里的ID。
  • id_updater_last_mode / id_updater_battle_target: 全局默认的请求模式。同样,当特定会话没有指定模式时,会使用这里的设置。
  • use_default_ids_if_mapping_not_found: 一个非常重要的开关(默认为 true)。
    • true: 如果请求的模型在 model_endpoint_map.json 中找不到,就使用全局默认的ID和模式。
    • false: 如果找不到映射,则直接返回错误。这在你需要严格控制每个模型的会话时非常有用。
  • 其他配置项如 api_key, tavern_mode_enabled 等,请参考文件内的注释。

model_endpoint_map.json - 模型专属配置

这是一个强大的高级功能,允许你覆盖全局配置,为特定的模型设置一个或多个专属的会话。

核心优势:

  1. 会话隔离: 为不同的模型使用独立的会话,避免上下文串扰。
  2. 提高并发: 为热门模型配置一个ID池,程序会在每次请求时随机选择一个ID使用,模拟轮询,减少单个会话被频繁请求的风险。
  3. 模式绑定: 将一个会话ID与它被捕获时的模式(direct_chatbattle)绑定,确保请求格式永远正确。

配置示例:

{
  "claude-3-opus-20240229": [
    {
      "session_id": "session_for_direct_chat_1",
      "message_id": "message_for_direct_chat_1",
      "mode": "direct_chat"
    },
    {
      "session_id": "session_for_battle_A",
      "message_id": "message_for_battle_A",
      "mode": "battle",
      "battle_target": "A"
    }
  ],
  "gemini-1.5-pro-20241022": {
      "session_id": "single_session_id_no_mode",
      "message_id": "single_message_id_no_mode"
  }
}
  • Opus: 配置了一个ID池。请求时会随机选择其中一个,并严格按照其绑定的 modebattle_target 来发送请求。
  • Gemini: 使用了单个ID对象(旧格式,依然兼容)。由于它没有指定 mode,程序会自动使用 config.jsonc 中定义的全局模式。

🛠️ 安装与使用

你需要准备好 Python 环境和一款支持油猴脚本的浏览器 (如 Chrome, Firefox, Edge)。

1. 准备工作

  • 安装 Python 依赖 打开终端,进入项目根目录,运行以下命令:

    pip install -r requirements.txt
  • 安装油猴脚本管理器 为你的浏览器安装 Tampermonkey 扩展。

  • 安装本项目油猴脚本

    1. 打开 Tampermonkey 扩展的管理面板。
    2. 点击“添加新脚本”或“Create a new script”。
    3. TampermonkeyScript/LMArenaApiBridge.js 文件中的所有代码复制并粘贴到编辑器中。
    4. 保存脚本。

2. 运行主程序

  1. 启动本地服务器 在项目根目录下,运行主服务程序:

    python api_server.py

    当你看到服务器在 http://127.0.0.1:5102 启动的提示时,表示服务器已准备就绪。

  2. 保持 LMArena 页面开启 确保你至少有一个 LMArena 页面是打开的,并且油猴脚本已成功连接到本地服务器(页面标题会以 开头)。这里无需保持在对话页面,只要是域名下的页面都可以LeaderBoard都可以。

3. 更新可用模型列表 (可选,但推荐)

此步骤会生成 available_models.json 文件,让你知道当前 LMArena 上有哪些可用的模型,方便你更新 models.json

  1. 确保主服务器正在运行
  2. 打开一个新的终端,运行模型更新器:
    python model_updater.py
  3. 脚本会自动请求浏览器抓取模型列表,并在根目录生成 available_models.json 文件。
  4. 打开 available_models.json,找到你想要的模型,将其 "publicName""id" 键值对复制到 models.json 文件中(格式为 "publicName": "id")。

4. 配置会话 ID (需要时,一般只配置一次即可,除非切换模型或者原对话失效)

这是最重要的一步。你需要获取一个有效的会话 ID 和消息 ID,以便程序能够正确地与 LMArena API 通信。

  1. 确保主服务器正在运行 api_server.py 必须处于运行状态,因为 ID 更新器需要通过它来激活浏览器的捕获功能。

  2. 运行 ID 更新器 打开一个新的终端,在项目根目录下运行 id_updater.py 脚本:

    python id_updater.py
    • 脚本会提示你选择模式 (DirectChat / Battle)。
    • 选择后,它会通知正在运行的主服务器。
  3. 激活与捕获

    • 此时,你应该会看到浏览器中 LMArena 页面的标题栏最前面出现了一个准星图标 (🎯),这表示ID捕获模式已激活
    • 在浏览器中打开一个 LMArena 竞技场的 目标模型发送给消息的页面。请注意,如果是Battle页面,请不要查看模型名称,保持匿名状态,并保证当前消息界面的最后一条是目标模型的一个回答;如果是Direct Chat,请保证当前消息界面的最后一条是目标模型的一个回答。
    • 点击目标模型的回答卡片右上角的重试(Retry)按钮
    • 油猴脚本会捕获到 sessionIdmessageId,并将其发送给 id_updater.py
  4. 验证结果

    • 回到你运行 id_updater.py 的终端,你会看到它打印出成功捕获到的 ID,并提示已将其写入 config.jsonc 文件。
    • 脚本在成功后会自动关闭。现在你的配置已完成!

5. 配置你的 OpenAI 客户端

将你的客户端或应用的 OpenAI API 地址指向本地服务器:

  • API Base URL: http://127.0.0.1:5102/v1
  • API Key: 如果 config.jsonc 中的 api_key 为空,则可随便输入;如果已设置,则必须提供正确的 Key。
  • Model Name: 在你的客户端中指定你想使用的模型名称(必须与 models.json 中的名称完全匹配)。服务器会根据这个名称查找对应的模型ID。

6. 开始聊天! 💬

现在你可以正常使用你的客户端了,所有的请求都会通过本地服务器代理到 LMArena 上!

🤔 它是如何工作的?

这个项目由两部分组成:一个本地 Python FastAPI 服务器和一个在浏览器中运行的油猴脚本。它们通过 WebSocket 协同工作。

sequenceDiagram
    participant C as OpenAI 客户端 💻
    participant S as 本地 FastAPI 服务器 🐍
    participant MU as 模型更新脚本 (model_updater.py) 📋
    participant IU as ID 更新脚本 (id_updater.py) 🆔
    participant T as 油猴脚本 🐵 (在 LMArena 页面)
    participant L as LMArena.ai 🌐

    alt 初始化
        T->>+S: (页面加载) 建立 WebSocket 连接
        S-->>-T: 确认连接
    end

    alt 手动更新模型列表 (可选)
        MU->>+S: (用户运行) POST /internal/request_model_update
        S->>T: (WebSocket) 发送 'send_page_source' 指令
        T->>T: 抓取页面 HTML
        T->>S: (HTTP) POST /internal/update_available_models (含HTML)
        S->>S: 解析HTML并保存到 available_models.json
        S-->>-MU: 确认
    end

    alt 手动更新会话ID
        IU->>+S: (用户运行) POST /internal/start_id_capture
        S->>T: (WebSocket) 发送 'activate_id_capture' 指令
        T->>L: (用户点击Retry) 拦截到 fetch 请求
        T->>IU: (HTTP) 发送捕获到的ID
        IU->>IU: 更新 config.jsonc
        IU-->>-T: 确认
    end

    alt 正常聊天流程
        C->>+S: (用户聊天) /v1/chat/completions 请求
        S->>S: 转换请求为 LMArena 格式 (并从 models.json 获取模型ID)
        S->>T: (WebSocket) 发送包含 request_id 和载荷的消息
        T->>L: (fetch) 发送真实请求到 LMArena API
        L-->>T: (流式)返回模型响应
        T->>S: (WebSocket) 将响应数据块一块块发回
        S-->>-C: (流式) 返回 OpenAI 格式的响应
    end

    alt 正常聊天流程 (包含文生图)
        C->>+S: (用户聊天) /v1/chat/completions 请求
        S->>S: 检查模型名称
        alt 如果是文生图模型 (如 DALL-E)
            S->>S: (并行) 创建 n 个文生图任务
            S->>T: (WebSocket) 发送 n 个包含 request_id 的任务
            T->>L: (fetch) 发送 n 个真实请求
            L-->>T: (流式) 返回图片 URL
            T->>S: (WebSocket) 将 URL 发回
            S->>S: 将 URL 格式化为 Markdown 文本
            S-->>-C: (HTTP) 返回包含 Markdown 图片的聊天响应
        else 如果是普通文本模型
            S->>S: 转换请求为 LMArena 格式
            S->>T: (WebSocket) 发送包含 request_id 和载荷的消息
            T->>L: (fetch) 发送真实请求到 LMArena API
            L-->>T: (流式)返回模型响应
            T->>S: (WebSocket) 将响应数据块一块块发回
            S-->>-C: (流式) 返回 OpenAI 格式的响应
        end
    end
Loading
  1. 建立连接: 当你在浏览器中打开 LMArena 页面时,油猴脚本会立即与本地 FastAPI 服务器建立一个持久的 WebSocket 连接

    注意: 当前架构假定只有一个浏览器标签页在工作。如果打开多个页面,只有最后一个连接会生效。

  2. 接收请求: OpenAI 客户端向本地服务器发送标准的聊天请求,并在请求体中指定 model 名称。
  3. 任务分发: 服务器接收到请求后,会根据 model 名称从 models.json 查找对应的模型ID,然后将请求转换为 LMArena 需要的格式,并附上一个唯一的请求 ID (request_id),最后通过 WebSocket 将这个任务发送给已连接的油猴脚本。
  4. 执行与响应: 油猴脚本收到任务后,会直接向 LMArena 的 API 端点发起 fetch 请求。当 LMArena 返回流式响应时,油猴脚本会捕获这些数据块,并将它们一块块地通过 WebSocket 发回给本地服务器。
  5. 响应中继: 服务器根据每块数据附带的 request_id,将其放入正确的响应队列中,并实时地将这些数据流式传输回 OpenAI 客户端。

📖 API 端点

获取模型列表

  • 端点: GET /v1/models
  • 描述: 返回一个与 OpenAI 兼容的模型列表,该列表从 models.json 文件中读取。

聊天补全

  • 端点: POST /v1/chat/completions
  • 描述: 接收标准的 OpenAI 聊天请求,支持流式和非流式响应。

图像生成 (已集成)

  • 端点: POST /v1/chat/completions
  • 描述: 文生图功能现已完全集成到主聊天端点中。要生成图片,只需在请求体中指定一个图像模型(例如 "model": "dall-e-3"),然后像发送普通聊天消息一样发送请求即可。服务器会自动识别并处理。
  • 请求示例:
    curl http://127.0.0.1:5102/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "dall-e-3",
        "messages": [
          {
            "role": "user",
            "content": "A futuristic cityscape at sunset, neon lights, flying cars"
          }
        ],
        "n": 1
      }'
  • 响应示例 (与普通聊天一致):
    {
      "id": "img-as-chat-...",
      "object": "chat.completion",
      "created": 1677663338,
      "model": "dall-e-3",
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "![A futuristic cityscape at sunset, neon lights, flying cars](https://...)"
          },
          "finish_reason": "stop"
        }
      ],
      "usage": { ... }
    }

📂 文件结构

.
├── .gitignore                  # Git 忽略文件
├── api_server.py               # 核心后端服务 (FastAPI) 🐍
├── id_updater.py               # 一键式会话ID更新脚本 🆔
├── model_updater.py              # 手动模型列表更新脚本 📋
├── models.json                 # 核心模型映射表 (需手动维护) 🗺️
├── available_models.json       # 可用模型参考列表 (自动生成) 📄
├── model_endpoint_map.json     # [高级] 模型到专属会话ID的映射表 🎯
├── requirements.txt            # Python 依赖包列表 📦
├── README.md                   # 就是你现在正在看的这个文件 👋
├── config.jsonc                # 全局功能配置文件 ⚙️
├── modules/
│   ├── update_script.py        # 自动更新逻辑脚本 🔄
│   └── file_uploader.py        # 文件床上传客户端模块 🖼️
├── file_bed_server/              # [新增] 独立的文件床服务器 📂
│   ├── main.py                 # 文件床 FastAPI 应用
│   ├── requirements.txt        # 文件床服务的依赖
│   ├── .gitignore              # 忽略上传的文件
│   └── uploads/                # (自动创建) 存储上传文件的目录
└── TampermonkeyScript/
    └── LMArenaApiBridge.js     # 前端自动化油猴脚本 🐵

享受在 LMArena 的模型世界中自由探索的乐趣吧! 💖

About

LMArenaBridge 是一个强大的开源工具,它充当一座桥梁,让你能通过任何兼容 OpenAI API 的应用程序(例如各类AI聊天客户端、编程插件等)来使用 [LMArena.ai](https://lmarena.ai/) 网站上提供的海量先进测试大语言模型。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 85.4%
  • JavaScript 14.6%