LM Arena Bridge

repository·main·Indexed 18 days ago

https://github.com/cloudwaddie/lmarenabridge

An OpenAI-compatible API proxy that allows users to interact with models hosted on LM Arena. It features a management dashboard for API keys and authentication tokens, supports integration with OpenWebUI, and includes optional AI-powered reCAPTCHA v2 solving using YOLO models. The bridge handles image uploads to LMArena's R2 storage and provides mechanisms to bypass Cloudflare Turnstile challenges.

Tokens
13.6K
Snippets
38
Records
62
Agent score
63%

What's inside lmarenabridge

  1. Handle Cloudflare Turnstile challenges in `main.py`

    main

    When using lmarenabridge, you may need to implement a Cloudflare/Turnstile pass-through logic within the get_recaptcha_v3_token function in main.py to bypass security challenges on https://arena.ai/.

    To implement this:

    1. Ensure AsyncCamoufox is initialized with headless=False and main_world_eval=True.
    2. Navigate to https://arena.ai/ using domcontentloaded wait state.
    3. Implement a loop to check for the "Just a moment" page title or the presence of the Turnstile widget.
    4. Use the click_turnstile(page) function to interact with the challenge if detected.
    5. Remove any existing logic that specifically waits for the arena-auth-prod-v1 cookie, as the priority is passing the challenge to allow the grecaptcha library to load.
    # Step 1: Ensure browser initialization is set to non-headless
    async with AsyncCamoufox(headless=False, main_world_eval=True) as browser:
    
    # Step 2: Implement Challenge Logic inside get_recaptcha_v3_token
    debug_print("  🌐 Navigating to arena.ai...")
    await page.goto("https://arena.ai/", wait_until="domcontentloaded")
    
    # --- NEW: Cloudflare/Turnstile Pass-Through ---
    debug_print("  🛡️  Checking for Cloudflare Turnstile...")
    
    try:
        for _ in range(5):
            title = await page.title()
            if "Just a moment" in title:
                debug_print("  🔒 Cloudflare challenge active. Attempting to click...")
                clicked = await click_turnstile(page)
                if clicked:
                    debug_print("  ✅ Clicked Turnstile.")
                    await asyncio.sleep(3)
            else:
                await click_turnstile(page)
                break
            await asyncio.sleep(1)
        
        await page.wait_for_load_state("domcontentloaded")
    except Exception as e:
        debug_print(f"  ⚠️ Error handling Turnstile: {e}")
    # ----------------------------------------------
  2. Configure and Run LM Arena Bridge

    main

    After obtaining your arena-auth-prod-v1 token, follow these steps to configure and start the server.

    1. Run the bridge initially: python -m src.main
    2. Access the Admin Portal: Open http://localhost:8000/dashboard in your browser.
    3. Login: Use the default password admin.
    4. Add Token: Add your arena-auth-prod-v1 token to the list.
    5. Optional: Change the admin password in the dashboard or via config.json.
    6. Start the application: Run python -m src.main to start the server on localhost:8000.
    python -m src.main
  3. Integrate LM Arena Bridge with OpenWebUI

    main

    You can use LM Arena Bridge as an OpenAI-compatible backend for OpenWebUI.

    1. Ensure the bridge is running: python -m src.main.
    2. In OpenWebUI, navigate to Profile > Admin Panel > Settings > Connections.
    3. Modify the OpenAI connection.
    4. Set the API Base URL to http://localhost:8000/api/v1.
    5. Leave the API Key field empty or enter any value (it is not used for authentication by the bridge).
    6. You can now select and chat with LM Arena models within OpenWebUI.
    http://localhost:8000/api/v1
  4. Get your LM Arena Authentication Token

    main

    The bridge requires an authentication token from the LM Arena website to function.

    1. Open the LM Arena website in a browser.
    2. Send a message to any model.
    3. Open browser Developer Tools (F12).
    4. Navigate to the Application or Storage tab.
    5. Under the Cookies section for the LM Arena site, locate the cookie named arena-auth-prod-v1.
    6. Copy the value (it should start with base64-). This is your authentication token.
  5. Deploy LM Arena Bridge with systemd

    main

    To run the bridge as a background service on Linux, create a systemd service file at /etc/systemd/system/lmarenabridge.service:

    [Unit]
    Description=LMArena Bridge API
    After=network.target
    
    [Service]
    Type=simple
    User=youruser
    WorkingDirectory=/path/to/lmarenabridge
    Environment="PATH=/path/to/venv/bin"
    ExecStart=/path/to/venv/bin/python -m src.main
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target

    Then, enable and start the service:

    sudo systemctl enable lmarenabridge
    sudo systemctl start lmarenabridge
    sudo systemctl status lmarenabridge
  6. Install and Configure AI Vision reCAPTCHA Solver

    main

    The bridge can optionally use an AI-powered solver to handle reCAPTCHA v2 image challenges using YOLO models. This is useful when standard reCAPTCHA v3 scoring fails.

    Installation Install the bridge with the [vision] extra or install the solver directly:

    pip install -e ".[vision]"
    # or
    pip install vision-ai-recaptcha-solver

    Configuration To enable the solver, add the following to your config.json:

    {
      "vision_recaptcha_solver": {
        "enabled": true,
        "headless": true,
        "timeout": 180,
        "max_attempts": 3,
        "browser_path": "C:\\path\\to\\chrome.exe",
        "proxy": "http://user:pass@ip:port"
      }
    }

    Requirements

    • Python 3.10+
    • A Chromium-based browser (Chrome for Testing, Edge)
    • The vision-ai-recaptcha-solver package (installs heavy dependencies like torch, ultralytics, and onnxruntime)

    Note: If the dependency is not installed, the bridge will continue to work normally but will silently skip the vision fallback.

  7. Install LM Arena Bridge

    main

    To install the LM Arena Bridge, clone the repository and install the required Python dependencies using pip.

    Prerequisites

    • Python 3.x

    Installation Steps

    # 1. Clone the repository
    git clone https://github.com/CloudWaddie/LMArenaBridge.git
    
    # 2. Navigate to the project directory
    cd LMArenaBridge
    
    # 3. Install the required packages
    pip install -r requirements.txt
    git clone https://github.com/CloudWaddie/LMArenaBridge.git
    cd LMArenaBridge
    pip install -r requirements.txt
  8. How the Userscript Proxy handles reCAPTCHA and fetching

    main

    The Userscript Proxy operates by injecting a fetch_script into the browser page. This script intercepts requests and manages complex authentication flows, specifically reCAPTCHA, to ensure requests are valid.

    Key behaviors include:

    • Automatic reCAPTCHA Minting: If a request payload contains a recaptchaV3Token that is missing or invalid, the script automatically mints a new v3 token using grecaptcha.execute.
    • Retry Logic: If an upstream fetch returns a 403 status code containing 'recaptcha', the script attempts to retry once with a fresh v3 token. If that fails, it falls back to minting a reCAPTCHA v2 token.
    • Streaming Support: The script uses a ReadableStream reader to process responses. It decodes chunks using TextDecoder and emits newline-delimited lines back to the host via console.log using the prefix LM_BRIDGE_PROXY|{jid}|.
    • Debugging: When LM_BRIDGE_PROXY_DEBUG is set, the script emits detailed debug events (e.g., before_fetch, after_fetch, v3_minted) through the same console logging mechanism.
    /* The proxy communicates via console.log with a specific format: */
    console.log('LM_BRIDGE_PROXY|' + jid + '|' + JSON.stringify(obj));
  9. Handle HTTP 403 (Forbidden) and reCAPTCHA Failures

    main

    The bridge manages 403 Forbidden errors differently depending on the transport used:

    Userscript Proxy

    If the transport is userscript, a 403 is often treated as a transient reCAPTCHA validation issue. The bridge waits for a grace period (configured via userscript_proxy_recaptcha_grace_seconds) to allow the in-page script to retry. If recaptcha validation failed is detected in the response body, it tracks consecutive failures. After 5 failures, it fails with a recaptcha_error.

    Browser Transports (Chrome/Camoufox)

    If using chrome or camoufox, a 403 triggers a side-channel reCAPTCHA token refresh via refresh_recaptcha_token(force_new=True).

    Transport Switching

    If consecutive reCAPTCHA failures occur (threshold of 2), the bridge automatically switches transport preference:

    • From chrome $\rightarrow$ camoufox (sets use_browser_transports = True and prefer_chrome_transport = False).
    • From other browser transports $\rightarrow$ chrome (sets use_browser_transports = True and prefer_chrome_transport = True).
  10. Handle HTTP 3xx Redirects

    main

    Redirects (status codes 300-399) break SSE streaming and often indicate an origin change (e.g., arena.ai to lmarena.ai) or bot mitigation.

    • If the transport was httpx, the bridge enables browser transports (use_browser_transports = True) and retries.
    • Otherwise, it simply retries the request.
  11. Handle HTTP 429 (Too Many Requests) and Rate Limiting

    main

    When the upstream server returns an HTTP 429 status code, the bridge implements the following retry logic:

    1. Backoff: It calculates a sleep duration using get_rate_limit_sleep_seconds, respecting the Retry-After header if present.
    2. Token Rotation: To avoid being blocked on the same account, the bridge rotates the current_token using get_next_auth_token (excluding the failed token).
    3. reCAPTCHA Reset: The recaptchaV3Token in the payload is cleared to ensure the next attempt mints a fresh token.
    4. Exhaustion: If retries exceed 3 attempts, it yields a JSON error chunk with type rate_limit_error and returns.
  12. Configure Userscript Proxy (Optional)

    main

    For models requiring strict browser-based fetching (to bypass advanced bot detection), the bridge supports a Userscript Proxy mechanism (e.g., via Tampermonkey). This allows the server to offload the actual network request to a user's browser.

    Proxy Workflow

    1. Polling: The userscript polls /api/v1/userscript/poll for new jobs. This is a long-poll endpoint that returns a 204 No Content if no jobs are available.
    2. Pushing Results: The userscript sends streamed lines or full responses back to the server via /api/v1/userscript/push using a job_id.