Commit 1dad0aea by 程裕兵

Initial commit

parents

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

# Luna TTS 排行榜冲榜 — 代码级业务逻辑梳理
> 基于 `tts-ranking/` 代码实际实现,2026-07-09
## 一、系统架构
```
Chrome 扩展 (MV3)
├── content.js → 页面注入、音频捕获、投票模拟、状态管理
├── background.js → WebSocket 客户端、消息转发、Debugger API 原生输入
├── inject.js → fetch 拦截器(注入页面主世界)
└── popup/ → 状态面板(启动/停止/统计)
Python 服务
├── server.py → WebSocket 服务、音频下载、日志
├── strategy.py → 投票决策引擎
├── matcher.py → 声纹匹配引擎 (Resemblyzer)
└── config.py → 可配置参数
```
## 二、对照音频库
三个库,通过 subdirectory symlinks 组织:
| 库 | 目录 | 厂商数 | 用途 |
|---|------|--------|------|
| 我方 | `standard/` | 1 (VUI Labs) | 识别自己的音频,投自己 |
| 大厂 | `big_vendors/` | 4 (SpeechifyAI/Google/Cartesia/Alibaba) | 优先投票目标 |
| 竞品 | `competitors/` | 16 | 仅监控+兜底决策 |
每个 subdirectory 命名格式:`Vendor__Model`,内部包含该模型的多个 mp3 文件。
## 三、声纹匹配流程
1. **启动时加载**:遍历三个目录,对每个 mp3 文件:
- `preprocess_wav()` → 音频预处理(静音裁剪)
- `VoiceEncoder.embed_utterance()` → 256 维声纹向量
- 文件名提取 speaker 名(兼容新旧两种格式)
- 文件名/pitch 判断性别
- 同 speaker 多片段取最高分
2. **运行时匹配**(收到音频 URL):
- 服务端下载音频 → 提取声纹
- pitch 检测未知音频性别 → 只与同性别对照音频匹配
- 每个库返回:best speaker + best score + 全量分数 + vendor/model
- 三个库各自的最佳结果汇总为 SideResult
3. **设备自动检测**:CUDA → MPS → CPU
## 四、投票决策引擎 (`strategy.py`)
### 核心逻辑
对左右两侧音频,分别从三个库的全量匹配中取**跨库最高分**,确定该侧的 `top_library` 和 `top_speaker`。然后按优先级决策:
| 优先级 | 条件 | 决策 |
|--------|------|------|
| 1 | 某侧 top_library == "our" AND top_score >= 0.80 | 投该侧 |
| 1a | 两侧都是 ours | 投高分侧(平局投左) |
| 2 | 某侧 top_library == "big_vendor" AND top_score >= 0.80 | 投该侧 |
| 2a | 两侧都是 big_vendor | 随机投一侧 |
| 3a | 两侧 top_library == "competitor" AND >= 0.80 | **刷新页面**(弃权) |
| 3b | 一侧 competitor,另一侧不是 | **投非竞品那一侧** |
| 3c | 都不是 competitor | **随机投一侧** |
### 可配置参数 (`config.py`)
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `OUR_THRESHOLD` / 匹配阈值 | 0.80 | 所有库共用一个阈值 |
| `DAILY_VOTE_LIMIT` | 800 | 达到后停止 |
| `WS_PORT` | 8765 | WebSocket 端口 |
(注:`COMPETITOR_THRESHOLD` 和 `BIG_VENDOR_VOTE_PROBABILITY` 仍存在于 config.py 但 server.py 已不再引用)
## 五、扩展端工作流 (`content.js`)
### 5.1 初始化
- `document_start` 注入 `inject.js` 劫持 `window.fetch`,捕获 mp3/wav 请求 URL
- 自动恢复:`chrome.storage.local` 存 enabled 状态,页面刷新后 3 秒自动续投
### 5.2 单轮投票循环 (`doVote`)
```
1. 检测 CAPTCHA(最多 20s)
- 自动点击 Turnstile(Debugger API 原生点击)
- 超时 → 刷新页面
2. 捕获 2 个音频 URL(最多 60s)
- 优先读 fetch 拦截队列
- 兜底读 <audio> DOM
- 使用消费指针 _consumedUrls 区分新旧音频
3. 等投票卡片渲染(最多 30s)
4. grant_autoplay(Debugger API 原生点击获取用户激活)
5. 点击播放按钮 + audio.play()
6. 等音频播放(最少 3s,最多 8s)
7. 发送 match_request → 等待匹配结果
8. 根据决策执行投票:
- vote_left/right → simulateVote → 验证 → 标记完成
- skip → skipAndRefresh(等 20s 后刷新)
9. scheduleNextVote(2-8s 随机延迟)
```
### 5.3 投票模拟 (`simulateVote`)
- 主方式:Debugger API 发送原生 keydown/keyup(ArrowLeft/ArrowRight)
- 失败兜底:synthetic keyboard + card click(实际无效)
- 验证:等 5s,检查是否有新 URL 入队;无则重试一次等 5s;再失败标为 FAILED → doVote 刷新页面
### 5.4 Reveal 验证 (`_captureRevealAndVerify`)
- 投票前启动 200ms 轮询
- 页面揭示后抓到 `.animate-arena-upvote`(投票的模型名)和 `.animate-arena-downvote`(另一个模型名)
- 直接输出到浏览器控制台(带颜色标注 + 对比结果 ✓/✗)
### 5.5 工作/休息周期
- 工作 10 分钟 → 休息 60-180 秒(随机)→ 继续工作
### 5.6 反检测
- 聆听后投票(min 3s)
- 投票间隔 2-8s 随机
- 弃权刷新:前 9 次随机 1-3s,第 10 次冷却 10-20s(通过 storage 跨页面持久化计数)
- Debugger API 原生输入事件(isTrusted: true)
## 六、通信协议
WebSocket JSON(localhost:8765)
### match_request(扩展 → 服务端)
```json
{
"type": "match_request",
"request_id": "uuid",
"audio_left": "https://cdn.../audio_a.mp3",
"audio_right": "https://cdn.../audio_b.mp3"
}
```
### match_result(服务端 → 扩展)
```json
{
"type": "match_result",
"decision": "vote_left|vote_right|skip",
"reason": "决策原因",
"details": {
"left": { "our_match": ..., "competitor_match": ..., "big_vendor_match": ..., "top_match": {...} },
"right": { ... }
},
"stats": { "today_votes": 23, "today_skips": 7, "daily_limit": 800 }
}
```
### 控制消息
- `status` — 查询当日统计
- `grant_autoplay` — 请求原生点击
- `dispatch_key` — 请求原生键盘事件
- `click_at` — 请求原生鼠标点击
- `captcha_detected` — 通知 CAPTCHA
## 七、日志格式
每次匹配输出到终端 + `server/logs/match-YYYYMMDD.log`:
```
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Ella(0.7863)
Ella: 0.7863
Grace: 0.6211
竞品最佳: Lively Girl_us_female(0.8549)
Lively Girl_us_female: 0.8549 ← [ElevenLabs / Eleven_v3]
...
大厂最佳: Caroline_us_female(0.8592)
Caroline_us_female: 0.8592 ← [Cartesia / Sonic_3.5]
>>> left 最高: Caroline_us_female(0.8592) [big_vendor]
RIGHT 音频
...
决策: vote_left
原因: left 最高分为大厂 Caroline_us_female(0.8592) → vote
统计: 23 票 / 7 弃
───────────────────────────────────────────────────────
```
标注说明:`←` 表示达到阈值 0.80;`[厂商 / 模型]` 表示所属厂商和模型。
## 八、竞品模型清单(当前加载的)
**大厂 (4)**:SpeechifyAI/Simba_3.2、Google/Gemini_3.1_Flash_TTS、Cartesia/Sonic_3.5、Alibaba/Fun-Realtime-TTS
**竞品 (19)**:Inworld(3个模型)、SpaceXAI、MiniMax(4个模型)、async(2个模型)、StepFun(3个模型)、ElevenLabs、Smallest.ai、Fish Audio(2个模型)、Microsoft、SpeechifyAI/Simba_3.0(竞品版本)
# Luna TTS 排行榜冲榜工具
Native Messaging 方案,扩展直连本地 Python 进程,不走网络层。兼容代理环境(AdsPower / Quark / SunBrowser 等指纹浏览器)。
## Mac 安装
### 0. 前置条件
```bash
# 1. 确认 Python 3.8+
python3 --version
# 2. 安装 Xcode Command Line Tools(提供 gcc 编译器)
xcode-select --install
# 3. 安装 Python 依赖
cd 项目路径/tts-ranking
python3 -m pip install -r requirements.txt
```
### 1. 加载扩展
打开 Chrome(或指纹浏览器),地址栏输入 `chrome://extensions/` → 开「开发者模式」→ 「加载已解压的扩展程序」→ 选择 `extension/` 目录。
记住卡片上显示的 **扩展 ID**(一长串字母)。
### 2. 安装 Native Host
```bash
cd 项目路径/tts-ranking/server
./install_host.sh 刚才的扩展ID
```
脚本会自动编译 wrapper、安装到 Chrome/Chromium/Quark/Edge/AdsPower 所有浏览器目录。
> 如果报 `gcc: command not found`,先跑 `xcode-select --install`。
> 每次移除扩展再重新加载,ID 会变,需要重新跑这步。
### 3. 刷新扩展
`chrome://extensions/` → 点 Luna TTS Bot 的刷新 ⟳。
### 4. 验证
打开 `https://artificialanalysis.ai/text-to-speech/arena`,点扩展图标,应显示绿色 `Connected`。
---
## Windows 安装
### 1. 安装 Python 依赖
```powershell
cd C:\path\to\tts-ranking
python -m pip install -r requirements.txt
```
### 2. 编译 Native Host
需要 gcc(可用 MinGW)或 Visual Studio。
```powershell
cd server
gcc -o run_host.exe runner_win.c
```
### 3. 加载扩展
`chrome://extensions/` → 开发者模式 → 加载已解压 → 选 `extension/` 目录。
### 4. 注册 Native Host
创建 `install_host.reg`(用记事本,注意把路径改成实际项目路径):
```reg
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.luna.tts]
@="C:\\path\\to\\tts-ranking\\server\\run_host.exe"
```
双击导入注册表。
指纹浏览器(AdsPower/Quark)需要同时导入到对应注册表路径。
### 5. 刷新扩展并验证
刷新扩展 → 打开打榜页面 → 检查弹窗是否绿了。
---
## 使用
1. 打开 `https://artificialanalysis.ai/text-to-speech/arena`
2. 有人机校验就手动点一下
3. 点扩展图标 → **Start Voting**
4. 页面右下角绿色提示条显示当前状态
## 人工介入
两侧都匹配到我方,同时有竞品也匹配到时,系统暂停等待。按快捷键:
| 快捷键 | 操作 |
|--------|------|
| `Ctrl+Shift+L` | 强制投左 |
| `Ctrl+Shift+R` | 强制投右 |
| `Ctrl+Shift+S` | 跳过本轮 |
5 分钟无操作自动刷新页面。
## 日志
- 匹配日志:`server/logs/native-YYYYMMDD.log`
- 崩溃日志:`server/logs/crash.log`
- 扩展状态:`chrome://extensions/` → Luna TTS Bot → 点 service worker 链接 → Console
## 故障排查
### 扩展显示 Disconnected
1. 检查 `server/logs/crash.log`,看是否有 `ModuleNotFoundError`(依赖没装全)
2. 确认 `install_host.sh` 成功跑过,`com.luna.tts.json` 在各浏览器目录下都存在:
```bash
find ~/Library -name "com.luna.tts.json" 2>/dev/null
```
3. 确认 manifest 里的扩展 ID 和 `chrome://extensions/` 上的一致:
```bash
cat ~/Library/Application\ Support/Google/Chrome/NativeMessagingHosts/com.luna.tts.json
```
4. 完全退出浏览器再重新打开,刷新扩展
### 稳定连接但报 `debugger blocked`
指纹浏览器可能限制了 Debugger API。CAPTCHA 自动点击和键盘投票会降级为备用方式,如果不是经常出现可以忽略。
### 连上又断开、反复循环
看 `server/logs/crash.log`——大概率是依赖问题或 Python 版本问题。确认:
```bash
python3 -c "import torch; import torchaudio; import resemblyzer; print('OK')"
```
### 跨芯片兼容(Apple Silicon ↔ Intel)
编译产物 `run_host` 绑定当前机器的芯片架构。发给别人用前,确认对方机器架构:
```bash
# 对方机器跑这个看芯片
uname -m
# arm64 = Apple Silicon (M1/M2/M3/M4)
# x86_64 = Intel Mac
```
如果不匹配(比如你在 M 芯片编译、发给 Intel 机器),对方会报 `bad CPU type in executable`。解决:让对方面重新编译:
```bash
cd 项目路径/tts-ranking/server
gcc -o run_host runner.c
```
### 提示需要手动点击人机验证
Cloudflare Turnstile PAT 挑战无法自动绕过,页面右下角会提示"人机验证,需要手动点击",点一下即可。
#!/usr/bin/env python3
"""Download remaining TTS models from Artificial Analysis (batch 2)."""
import subprocess
import json
import os
import time
import re
import sys
sys.stdout.reconfigure(line_buffering=True) if hasattr(sys.stdout, 'reconfigure') else None
BASE_URL = "https://artificialanalysis.ai/api/text-to-speech/speech-explorer"
OUTPUT_DIR = "/Users/chengyubing/Documents/projects/hzjj/tts-ranking/server/reference/raw_audios"
MODELS = [
("Speech-02-Turbo", "953aeced-7f15-4a02-a2f5-3c9cfccbbb39", "MiniMax"),
("Magpie Multilingual", "04719149-11ed-42b1-bc2c-166860c03c23", "Magpie"),
("Magpie-Multilingual 357M (Feb 2026)", "49198771-e5ea-4c4e-bad9-e57671a92291", "Magpie"),
("Coda", "cddf7ab5-43d6-488f-be03-1dcfbb8955d3", "Coda"),
("SSFM-v30", "b86c54d8-b51d-4186-b412-a705f2b9b76d", "SSFM"),
("Qwen3 TTS", "8eb42b0b-213a-4911-b096-a7455e944090", "Alibaba"),
("Seed-TTS 2.0", "31ef1e00-542b-4d06-8b0f-0bb52ef4e518", "ByteDance"),
("GPT-Realtime-2", "99365f44-415e-4ff2-94c9-59b8b2ec5847", "OpenAI"),
("Polly Standard", "d3f9b298-8e1a-4328-a2bd-ce3ceea6db1f", "Amazon"),
("SSFM-v21", "c8aa7fcf-69c0-4c7f-9ead-f640801a8069", "SSFM"),
("Voxtral TTS", "b424cd2e-abb9-4131-8f47-7731bdbff455", "Voxtral"),
("MiMo-V2.5-TTS", "abdcf494-6c73-4574-ade9-6672cdb21936", "MiMo"),
("Octave 2", "b4a9f921-ae13-4c12-b907-6e9c6bedaf58", "Octave"),
("Gemini 2.5 Flash TTS (Dec 2025)", "7b6ea07a-99e1-4635-9ea1-beee1b6520d5", "Google"),
("Arcana v3", "20c6b2a3-4881-4f5d-b82f-f135fab82711", "Arcana"),
("Higgs Audio V3 TTS", "49dc49c3-828e-4af5-8527-49606b4f6e14", "Higgs Audio"),
("Zonos-v0.1", "f5a3ab85-032b-41b1-8c78-c4b0eef2a9e8", "Zyphra"),
("Fun-Realtime-TTS-Preview", "48100868-7939-4cb3-a5be-8fb1202061ec", "Alibaba"),
("Standard", "7efc9790-17f6-44a5-8b4f-897deaeb0088", "MiniMax"),
("MetaVoice v1", "fb51ab93-d79a-49c5-a2f5-19f03e311afd", "Meta"),
("Gradium TTS", "2f3dbd41-a9c4-4f0c-a16b-427dea9feb6e", "Gradium"),
("MiMo-V2-TTS", "4489b587-5602-434a-9c24-772df19e879b", "MiMo"),
("MAI-Voice-1", "c8b0b07c-26a7-444c-a8ff-c412a3d433b7", "MAI"),
("XTTS v2", "f2f2989e-69d1-4b1c-a419-ee316e6c1c3d", "Coqui"),
("Speech 2.6", "6d2c7daa-7585-4b85-b1db-239c1c29b9a3", "MiniMax"),
("WaveNet", "16ad3e89-cc78-4478-a5a0-a048b5c72cfb", "Google"),
("Speech-02-HD", "65166a7b-b42c-4a68-b051-9662facd2f91", "MiniMax"),
("Qwen3 TTS Flash", "f05bc243-0723-4f05-aa19-31341d8f2677", "Alibaba"),
("Polly Neural", "eb3b0d75-134b-4e6a-82c5-4db2398d5c07", "Amazon"),
("Falcon (Beta)", "5ab04a8d-c698-4726-bebd-af5fc553b752", "Falcon"),
("Octave TTS", "009f6201-1862-454e-87b5-e2a367bc027f", "Octave"),
("Neural2", "666ff702-a2c8-413a-a8df-61902a6e7cb9", "Google"),
("Neuphonic TTS", "55912533-f2de-48e4-8318-990c435f1401", "Neuphonic"),
("VibeVoice 7B", "7395ed9e-1d19-4ab8-a989-eca165beefa4", "VibeVoice"),
("Orion", "90c81fc8-01ce-4e1d-bcd4-a57dff1c25cf", "Orion"),
("Chatterbox", "6cb43d71-bd49-4b44-9635-9ea5f28fd376", "Chatterbox"),
("VibeVoice 1.5B", "bd053b0f-5f69-4313-a7e5-5acd71422d4a", "VibeVoice"),
("SIMBA 1.6", "e0ca6a5b-6888-4e0f-8f4e-2c4cb59dd2aa", "SpeechifyAI"),
("Gemini 2.5 Flash Lite TTS", "a3824338-576c-4deb-8446-264eb9895db2", "Google"),
("Multilingual v2", "9cd43eb4-f436-4ea2-b3d9-5c912bdea912", "ElevenLabs"),
("T2A-01-HD", "0707d10e-e111-484c-8fd5-5dbb0a78029e", "MiniMax"),
("OpenAudio S1", "46730007-0d7b-4395-8077-2b5104ea79b0", "OpenAudio"),
("Turbo v2.5", "2d3f6b08-353d-40e9-a5e7-a3c1952b2dd8", "ElevenLabs"),
("Sonic 3", "a71d7774-e73e-4b6c-8dfe-7963273b2975", "Cartesia"),
("Maya1", "081709c5-d010-462f-b6ad-ef128df78cbd", "Maya"),
("T2A-01-Turbo", "c8c8fcf1-03cb-4b63-a6c9-d72cab227b3f", "MiniMax"),
("Fish Speech 1.5", "8bdfce7b-e8c5-4a29-984a-bd360d913c31", "Fish Audio"),
("Chatterbox HD", "06b8f3e3-e4fe-4cf7-9774-30816972bb59", "Chatterbox"),
("Polly Long-Form", "8b4be309-2f31-4ff2-be79-a6652c29ab12", "Amazon"),
("Murf Speech Gen 2", "86d3b629-8222-4ab6-ba77-6d2841fbf212", "Murf"),
("Mist V2", "5d922a1e-af77-4dae-adb4-7428dd634d5a", "Mist"),
("StyleTTS 2", "3b322e37-a016-4b2e-aacb-1aef8df00829", "StyleTTS"),
("Kokoro 82M v1.0", "6de03a42-66ce-484a-9c01-95fe9b4d7422", "Kokoro"),
("Flash v2.5", "cccb3742-da05-4447-910c-43a5d3eda5b7", "ElevenLabs"),
("Studio", "02265a20-67bc-4892-89d0-f54545b6b4a1", "ElevenLabs"),
("Async Flash v1.0", "765fd2b5-acb4-490f-a402-eaad710f23e1", "async"),
("TTS-1", "78588185-b188-46fb-8d06-c06f52009715", "OpenAI"),
("SIMBA 1.0", "588357bb-fe98-4286-b13e-3cae200e6085", "SpeechifyAI"),
("TTS-1 HD", "4a2776b8-a0c6-42f2-8ebe-db364f1ddf13", "OpenAI"),
("Polly Generative", "4ef13968-15ee-4311-a6d1-685f015b0717", "Amazon"),
("Journey", "2b5bb443-e32e-4cb4-a9f2-918c00210211", "Journey"),
("Chirp 3: HD", "f524429e-7e12-47eb-88df-6a9730f88989", "Google"),
("Gemini 2.5 Pro (Dec 2025)", "2e9ecf4e-7aca-41ac-9436-a5c0c5664fe0", "Google"),
("LMNT", "a8b4b1db-2a38-4649-9b57-a12fb0a85253", "LMNT"),
("OpenVoice v2", "80791fbe-7454-4719-9063-bedfcde606c7", "OpenVoice"),
("Fish Audio S1", "cfb0a07b-94b8-4b05-8d2c-3529f66cd1d2", "Fish Audio"),
("Sonic English (Oct 2024)", "798934ab-0f43-49d2-8343-15c1ade78458", "Cartesia"),
]
def safe_filename(name):
return re.sub(r'[<>:"/\\|?*()]', '', name).replace(' ', '_').strip()
def fetch_page(model_id, offset):
url = f"{BASE_URL}?model={model_id}&offset={offset}"
result = subprocess.run(
['curl', '-s', '--max-time', '30', url],
capture_output=True, text=True, timeout=35
)
if result.returncode != 0 or not result.stdout:
raise RuntimeError(f"API call failed")
return json.loads(result.stdout)
def download_file(url, dest):
if os.path.exists(dest) and os.path.getsize(dest) > 100:
return True
result = subprocess.run(
['curl', '-s', '-L', '--max-time', '60', '-o', dest, url],
capture_output=True, text=True, timeout=65
)
if result.returncode != 0:
return False
if os.path.getsize(dest) < 100:
os.remove(dest)
return False
return True
def download_model(model_name, model_id, creator):
folder_name = safe_filename(model_name)
folder_path = os.path.join(OUTPUT_DIR, creator, folder_name)
os.makedirs(folder_path, exist_ok=True)
existing = len([f for f in os.listdir(folder_path) if f.endswith('.mp3')])
try:
data = fetch_page(model_id, 0)
except Exception as e:
print(f" [{creator}] {model_name}: ERROR {e}", flush=True)
return 0, 0
total = data['total']
if total == 0:
print(f" [{creator}] {model_name}: 0 files, skip", flush=True)
return 0, 0
if existing >= total:
print(f" [{creator}] {model_name}: {existing}/{total} (done)", flush=True)
return existing, 0
print(f" [{creator}] {model_name}: {existing}/{total}, downloading...", flush=True)
downloaded = existing
failed = 0
offset = 0
while True:
try:
if offset > 0:
data = fetch_page(model_id, offset)
time.sleep(0.3)
for audio in data['audios']:
file_url = audio['fileName']
voice_name = audio['voice']['name']
accent = audio['voice']['accent']['slug']
gender = audio['voice']['gender']
file_id = file_url.split('/')[-1]
dest = os.path.join(folder_path, f"{voice_name}_{accent}_{gender}_{file_id}")
if download_file(file_url, dest):
downloaded += 1
else:
failed += 1
has_more = data['has_more']
offset = data['offset']
if not has_more:
break
except Exception as e:
print(f" ERROR at offset {offset}: {e}", flush=True)
offset += 20
if offset >= total:
break
time.sleep(2)
print(f" Done: {downloaded} ok, {failed} fail (total {total})", flush=True)
return downloaded, failed
def main():
os.makedirs(OUTPUT_DIR, exist_ok=True)
print(f"Downloading {len(MODELS)} remaining models to {OUTPUT_DIR}", flush=True)
total_ok = 0
total_fail = 0
for i, (model_name, model_id, creator) in enumerate(MODELS, 1):
ok, fail = download_model(model_name, model_id, creator)
total_ok += ok
total_fail += fail
time.sleep(0.5)
print(f"\nALL DONE: {total_ok} ok, {total_fail} failed", flush=True)
if __name__ == '__main__':
main()
// Luna TTS Ranking Bot — Background Service Worker
// Bridges content script ↔ Python native host via Chrome Native Messaging
const NATIVE_HOST = 'com.luna.tts';
let port = null;
let requestCallbacks = new Map();
let latestStats = { today_votes: 0, today_skips: 0, daily_limit: 800 };
let isConnected = false;
// ---- Native Messaging lifecycle ----
function connect() {
if (port) { try { port.disconnect(); } catch (e) {} }
port = chrome.runtime.connectNative(NATIVE_HOST);
port.onMessage.addListener((msg) => {
if (msg.type === 'match_result' && msg.request_id) {
const callback = requestCallbacks.get(msg.request_id);
if (callback) { callback(msg); requestCallbacks.delete(msg.request_id); }
}
if (msg.stats) latestStats = msg.stats;
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]) chrome.tabs.sendMessage(tabs[0].id, { type: 'from_server', payload: msg }).catch(() => {});
});
chrome.runtime.sendMessage({ type: 'from_server', payload: msg }).catch(() => {});
});
port.onDisconnect.addListener(() => {
console.log('[bg] Native host disconnected');
isConnected = false;
broadcastState('disconnected');
port = null;
setTimeout(connect, 5000);
});
isConnected = true;
console.log('[bg] Connected to native host');
broadcastState('connected');
}
connect();
// ---- Message routing ----
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'match_request') {
if (port && isConnected) {
requestCallbacks.set(message.request_id, sendResponse);
port.postMessage({ type: 'match_request', request_id: message.request_id, audio_left: message.audio_left, audio_right: message.audio_right });
} else {
sendResponse({ type: 'match_result', decision: 'skip', reason: 'Python host not connected', details: {} });
}
return true;
}
if (message.type === 'get_state') {
sendResponse({ ws_connected: isConnected, ...latestStats });
return true;
}
if (message.type === 'verify_result' && port && isConnected) {
port.postMessage(message);
return false;
}
});
function broadcastState(status) {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]) chrome.tabs.sendMessage(tabs[0].id, { type: 'ws_state', status }).catch(() => {});
});
}
// ---- Native input dispatch via Chrome Debugger API ----
async function _attachDebugger(tabId) {
return new Promise(resolve => {
chrome.debugger.attach({ tabId }, '1.3', () => {
if (chrome.runtime.lastError) { console.log('[bg] Debugger attach failed:', chrome.runtime.lastError.message); resolve(false); }
else resolve(true);
});
});
}
async function _debuggerSend(tabId, method, params) {
return new Promise(resolve => {
chrome.debugger.sendCommand({ tabId }, method, params, (result) => {
resolve(chrome.runtime.lastError ? null : result);
});
});
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const tabId = sender.tab?.id;
if (message.type === 'grant_autoplay') {
(async () => {
if (!tabId) { sendResponse({ ok: false }); return; }
if (!await _attachDebugger(tabId)) { sendResponse({ ok: false, error: 'debugger blocked' }); return; }
await _debuggerSend(tabId, 'Input.dispatchMouseEvent', { type: 'mousePressed', x: message.x || 500, y: message.y || 400, button: 'left', clickCount: 1 });
await _debuggerSend(tabId, 'Input.dispatchMouseEvent', { type: 'mouseReleased', x: message.x || 500, y: message.y || 400, button: 'left', clickCount: 1 });
chrome.debugger.detach({ tabId }, () => {});
sendResponse({ ok: true });
})();
return true;
}
if (message.type === 'click_at') {
(async () => {
if (!tabId) { sendResponse({ ok: false }); return; }
if (!await _attachDebugger(tabId)) { sendResponse({ ok: false }); return; }
await _debuggerSend(tabId, 'Input.dispatchMouseEvent', { type: 'mouseMoved', x: message.x, y: message.y });
await new Promise(r => setTimeout(r, 100 + Math.random() * 200));
await _debuggerSend(tabId, 'Input.dispatchMouseEvent', { type: 'mousePressed', x: message.x, y: message.y, button: 'left', clickCount: 1 });
await new Promise(r => setTimeout(r, 50 + Math.random() * 100));
await _debuggerSend(tabId, 'Input.dispatchMouseEvent', { type: 'mouseReleased', x: message.x, y: message.y, button: 'left', clickCount: 1 });
chrome.debugger.detach({ tabId }, () => {});
sendResponse({ ok: true });
})();
return true;
}
if (message.type === 'dispatch_key') {
(async () => {
if (!tabId) { sendResponse({ ok: false }); return; }
if (!await _attachDebugger(tabId)) { sendResponse({ ok: false }); return; }
const key = message.key === 'left' ? 'ArrowLeft' : 'ArrowRight';
const vk = message.key === 'left' ? 37 : 39;
await _debuggerSend(tabId, 'Input.dispatchKeyEvent', { type: 'rawKeyDown', key, code: key, windowsVirtualKeyCode: vk });
await _debuggerSend(tabId, 'Input.dispatchKeyEvent', { type: 'keyUp', key, code: key, windowsVirtualKeyCode: vk });
chrome.debugger.detach({ tabId }, () => {});
sendResponse({ ok: true });
})();
return true;
}
});
chrome.alarms.create('keepalive', { periodInMinutes: 1 });
chrome.alarms.onAlarm.addListener(() => {});
// Luna TTS Ranking Bot — Content Script
// Injected into artificialanalysis.ai/text-to-speech/arena
// Handles: audio capture, CAPTCHA detection, voting simulation, timing
(() => {
'use strict';
// ---- Shared audio URL capture (cross-world) ----
const _capturedAudioUrls = [];
let _consumedUrls = 0; // pointer: how many URLs we've already used for matching
window.addEventListener('message', (event) => {
if (event.source === window && event.data?.type === '__luna_audio') {
const url = event.data.url;
if (!_capturedAudioUrls.includes(url)) {
_capturedAudioUrls.push(url);
console.log(`[content] Captured audio #${_capturedAudioUrls.length}: ${url.substring(0, 60)}...`);
}
}
});
// Inject fetch interceptor into the page's main world via external script
function _injectInterceptor() {
const script = document.createElement('script');
script.src = chrome.runtime.getURL('inject.js');
(document.head || document.documentElement).appendChild(script);
script.remove();
}
if (document.head) {
_injectInterceptor();
} else {
const obs = new MutationObserver(() => {
if (document.head) { obs.disconnect(); _injectInterceptor(); }
});
obs.observe(document, { childList: true, subtree: true });
}
// ---- State ----
const DAILY_LIMIT = 800;
let enabled = false;
let voteCount = 0;
let skipCount = 0;
let consecutiveSkips = 0;
let voteTimerId = null;
let restTimerId = null;
// ---- Timing utilities ----
function randInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// ---- CAPTCHA detection ----
function _isVisible(el) {
if (!el) return false;
const style = window.getComputedStyle(el);
return style.display !== 'none' && style.visibility !== 'hidden' && el.offsetParent !== null;
}
function isCaptchaVisible() {
const frames = document.querySelectorAll('iframe[src*="challenges.cloudflare.com"], iframe[src*="recaptcha"], iframe[src*="hcaptcha"]');
for (const f of frames) {
if (_isVisible(f)) return true;
}
const turnstileDiv = document.getElementById('cf-turnstile');
if (turnstileDiv && _isVisible(turnstileDiv) && turnstileDiv.children.length > 0) return true;
const alerts = document.querySelectorAll('[role="alert"][aria-label*="challenge" i], [role="alert"][aria-label*="verif" i]');
for (const a of alerts) {
if (_isVisible(a)) return true;
}
return false;
}
function _clickTurnstile() {
// Get position of the Turnstile widget for native debugger click
const turnstileDiv = document.getElementById('cf-turnstile');
const iframe = document.querySelector('iframe[src*="challenges.cloudflare.com"]');
const target = (iframe && _isVisible(iframe)) ? iframe : (turnstileDiv && _isVisible(turnstileDiv) ? turnstileDiv : null);
if (!target) return false;
const rect = target.getBoundingClientRect();
const x = Math.round(rect.left + rect.width / 2);
const y = Math.round(rect.top + rect.height / 2);
// Send native mouse move + click via debugger (bypasses isTrusted check)
chrome.runtime.sendMessage({ type: 'click_at', x, y });
return true;
}
function waitForCaptchaClear(timeoutMs = 20000) {
return new Promise((resolve) => {
if (!isCaptchaVisible()) { resolve(); return; }
console.log('[content] CAPTCHA detected, attempting auto-click...');
_updateBanner('🔐 人机验证,需要手动点击...');
chrome.runtime.sendMessage({ type: 'captcha_detected' });
_clickTurnstile();
let attempts = 0;
const start = Date.now();
const check = setInterval(() => {
if (!isCaptchaVisible()) { clearInterval(check); console.log('[content] CAPTCHA cleared'); resolve(); }
else if (Date.now() - start > timeoutMs) { clearInterval(check); console.log('[content] CAPTCHA timeout — refreshing page'); location.reload(); }
else { attempts++; if (attempts % 3 === 0) _clickTurnstile(); }
}, 1000);
});
}
// ---- Audio capture ----
async function waitForAudios(timeoutMs = 60000) {
const need = _consumedUrls + 2;
console.log(`[content] Audio URLs: ${_capturedAudioUrls.length} total, need ${need} (consumed ${_consumedUrls})`);
// Already have enough unconsumed URLs
if (_capturedAudioUrls.length >= need) {
const urls = [_capturedAudioUrls[_consumedUrls], _capturedAudioUrls[_consumedUrls + 1]];
_consumedUrls += 2;
return urls;
}
// Also try DOM <audio> elements (first cycle only, when consumed==0)
if (_consumedUrls === 0) {
const audios = document.querySelectorAll('audio');
if (audios.length >= 2) {
const u0 = audios[0].currentSrc || audios[0].src;
const u1 = audios[1].currentSrc || audios[1].src;
if (u0 && u1) {
_consumedUrls += 2;
return [u0, u1];
}
}
}
console.log('[content] Waiting for new audio URLs...');
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('Audio URLs not captured within timeout')), timeoutMs);
const check = () => {
if (_capturedAudioUrls.length >= _consumedUrls + 2) {
clearTimeout(timer);
const urls = [_capturedAudioUrls[_consumedUrls], _capturedAudioUrls[_consumedUrls + 1]];
_consumedUrls += 2;
resolve(urls);
return;
}
setTimeout(check, 500);
};
check();
});
}
// ---- Voting simulation ----
async function simulateVote(side) {
await delay(randInt(100, 500));
const voted = { success: false, method: '', detail: '' };
// Send native keyboard event via Chrome Debugger API (trusted event)
const resp = await new Promise(resolve => {
chrome.runtime.sendMessage({ type: 'dispatch_key', key: side }, resolve);
});
if (resp?.ok) {
voted.method = `Native key (${side})`;
} else {
// Fallback 1: synthetic keyboard + card click
const key = side === 'left' ? 'ArrowLeft' : 'ArrowRight';
document.dispatchEvent(new KeyboardEvent('keydown', { key, code: key, bubbles: true, composed: true }));
// Fallback 2: card click
const cards = document.querySelectorAll('[class*="cursor-pointer"][class*="rounded-xl"]');
if (cards.length >= 2) {
const card = side === 'left' ? cards[0] : cards[1];
card.click();
}
voted.method = `Synthetic fallback (${resp?.error || 'no response'})`;
}
// Verify: wait for page to load next audio pair. Results page auto-advances after ~5s.
let verifyWait = 5000;
await delay(verifyWait);
// If no new URLs yet, retry native key + wait longer
if (_capturedAudioUrls.length <= _consumedUrls) {
await new Promise(resolve => {
chrome.runtime.sendMessage({ type: 'dispatch_key', key: side }, resolve);
});
await delay(5000);
}
voted.success = _capturedAudioUrls.length > _consumedUrls;
voted.detail = `urls: ${_capturedAudioUrls.length} (need >${_consumedUrls}, waited ${voted.success ? verifyWait : verifyWait + 5000}ms)`;
console.log(`[content] Vote ${side}: ${voted.method} → ${voted.success ? 'OK' : 'FAILED'} (${voted.detail})`);
return voted;
}
function _captureRevealAndVerify(matchResult, votedSide) {
// Poll every 200ms for reveal elements. Called BEFORE voting so it's already
// watching when the vote happens and the page shows model names.
const start = Date.now();
const predLeft = matchResult.details?.left?.top_match || {};
const predRight = matchResult.details?.right?.top_match || {};
const poll = setInterval(() => {
const upvote = document.querySelector('.animate-arena-upvote');
const downvote = document.querySelector('.animate-arena-downvote');
if (!upvote || !downvote) {
if (Date.now() - start > 20000) { clearInterval(poll); console.log('[content] Reveal timeout'); }
return;
}
clearInterval(poll);
const votedModel = (upvote.textContent || '').trim();
const otherModel = (downvote.textContent || '').trim();
console.log(`%c[REVEAL] VOTED: ${votedModel} | OTHER: ${otherModel}`,
'color: #22c55e; font-size: 14px; font-weight: bold');
console.log(`%c[PREDICT] LEFT: ${predLeft.speaker || '---'}(${predLeft.score || 0}) [${predLeft.library || '?'}] | RIGHT: ${predRight.speaker || '---'}(${predRight.score || 0}) [${predRight.library || '?'}]`,
'color: #3b82f6; font-size: 13px');
console.log(`%c[MATCH] LEFT→voted: ${predLeft.speaker && votedModel.includes(predLeft.speaker) ? '✓' : '✗'} | RIGHT→voted: ${predRight.speaker && votedModel.includes(predRight.speaker) ? '✓' : '✗'}`,
'color: #f59e0b; font-size: 13px');
}, 200);
}
function _waitForManualOverride(autoDecision) {
// Both sides match ours but competitor also close → wait 5 min for human
_updateBanner(`⚠️ 需人工确认 Ctrl+Shift+L=左 R=右 S=跳过 (5min 超时刷新)`);
return new Promise(resolve => {
let resolved = false;
const handler = (e) => {
if (!e.ctrlKey || !e.shiftKey) return;
if (e.code === 'KeyL') { resolved = true; resolve('vote_left'); }
else if (e.code === 'KeyR') { resolved = true; resolve('vote_right'); }
else if (e.code === 'KeyS') { resolved = true; resolve('skip'); }
if (resolved) {
window.removeEventListener('keydown', handler);
_updateBanner(`🔧 人工选择: ${e.code === 'KeyL' ? '左' : e.code === 'KeyR' ? '右' : '跳过'}`);
}
};
window.addEventListener('keydown', handler);
setTimeout(() => {
if (!resolved) {
window.removeEventListener('keydown', handler);
resolve('timeout'); // will trigger page refresh
}
}, 5 * 60 * 1000);
});
}
async function skipAndRefresh() {
skipCount++;
// Persist refresh counter across page loads to avoid triggering Cloudflare rate limits
const { refreshCount } = await chrome.storage.local.get(['refreshCount']);
const count = (refreshCount || 0) + 1;
const isTenth = count >= 10;
if (isTenth) {
await chrome.storage.local.set({ refreshCount: 0 });
const wait = randInt(10_000, 20_000);
_updateBanner(`⏭️ 弃权,第${count}次刷新,冷却${Math.round(wait/1000)}s...`);
await delay(wait);
} else {
await chrome.storage.local.set({ refreshCount: count });
const wait = randInt(1000, 3000);
_updateBanner(`⏭️ 弃权,${wait/1000}s 后刷新 (${count}/10)`);
await delay(wait);
}
location.reload();
}
// ---- Main voting loop ----
async function doVote() {
try {
_updateBanner('⏳ 检测人机验证...');
await waitForCaptchaClear();
await delay(1000);
_updateBanner('🎧 捕获音频 URL...');
const [audioLeftUrl, audioRightUrl] = await waitForAudios();
// Wait for voting cards to render (they appear after audio loads)
_updateBanner('🎧 等待投票卡片渲染...');
for (let i = 0; i < 30; i++) {
const c = document.querySelectorAll('[class*="cursor-pointer"][class*="rounded-xl"]');
if (c.length >= 2) break;
await delay(1000);
}
// Get user activation via native click, then play audio
await new Promise(resolve => {
chrome.runtime.sendMessage({ type: 'grant_autoplay', x: 700, y: 500 }, resolve);
});
// Click page's play buttons + call audio.play()
document.querySelectorAll('.lucide-play').forEach(svg => { svg.closest('button')?.click(); });
const audios = document.querySelectorAll('audio');
audios.forEach(a => { a.muted = false; a.play().catch(() => {}); });
// Wait for BOTH audios: min 3s + until ended (or 8s timeout)
_updateBanner('🎧 聆听中...');
if (audios.length >= 2) {
await Promise.all(Array.from(audios).map(a => new Promise(resolve => {
const minWait = delay(3000);
const ended = new Promise(r => {
a.addEventListener('ended', r, { once: true });
setTimeout(r, 8000); // 8s max
});
Promise.all([minWait, ended]).then(resolve);
})));
} else {
await delay(6000);
}
_updateBanner('🔍 声纹匹配中...');
const requestId = crypto.randomUUID();
const result = await new Promise((resolve) => {
chrome.runtime.sendMessage({
type: 'match_request',
request_id: requestId,
audio_left: audioLeftUrl,
audio_right: audioRightUrl,
}, (response) => resolve(response));
});
// Manual review: both sides match ours, but competitor(s) also close
let finalDecision = result.decision;
if (result.needs_review) {
finalDecision = await _waitForManualOverride(result.decision);
if (finalDecision === 'timeout') {
_updateBanner('⏰ 人工超时,刷新页面...');
await delay(1000);
location.reload();
return;
}
}
if (finalDecision === 'vote_left') {
_updateBanner('🗳️ 投票: 左侧...');
_captureRevealAndVerify(result, 'left');
const v = await simulateVote('left');
if (!v.success) { _updateBanner('❌ 投票未确认,刷新重试...'); await delay(3000); location.reload(); return; }
_updateBanner(`🗳️ 投左侧 ✓${finalDecision !== result.decision ? ' [手动]' : ''}`);
voteCount++;
consecutiveSkips = 0;
} else if (finalDecision === 'vote_right') {
_updateBanner('🗳️ 投票: 右侧...');
_captureRevealAndVerify(result, 'right');
const v = await simulateVote('right');
if (!v.success) { _updateBanner('❌ 投票未确认,刷新重试...'); await delay(3000); location.reload(); return; }
_updateBanner(`🗳️ 投右侧 ✓${finalDecision !== result.decision ? ' [手动]' : ''}`);
voteCount++;
consecutiveSkips = 0;
} else {
_updateBanner('⏭️ 弃权,刷新页面...');
await skipAndRefresh();
return;
}
await delay(2000);
_updateBanner(`✅ 已投票 (${voteCount}/${DAILY_LIMIT})`);
const unconsumed = _capturedAudioUrls.length - _consumedUrls;
if (unconsumed < 2) {
const nextBtn = document.querySelector('[aria-label*="Next" i], [aria-label*="Skip" i], button:has([aria-label*="next" i])');
if (nextBtn) nextBtn.click();
}
if (result.stats && result.stats.today_votes >= result.stats.daily_limit) {
console.log('[content] Daily limit reached, stopping');
stopVoting();
return;
}
} catch (err) {
_updateBanner(`❌ ${err.message} (5s 后刷新...)`);
console.error('[content] Vote cycle error:', err.message);
await delay(5000);
location.reload();
return;
}
scheduleNextVote();
}
function scheduleNextVote() {
voteTimerId = setTimeout(doVote, 1000); // minimal delay, page naturally loads next audio
}
// ---- Work/rest cycle ----
function startWorkCycle() {
_updateBanner('▶️ 工作周期开始');
doVote();
restTimerId = setTimeout(() => {
clearTimeout(voteTimerId);
const restDuration = randInt(60_000, 180_000);
_updateBanner(`⏸️ 休息中 (${Math.round(restDuration / 1000)}s)...`);
chrome.runtime.sendMessage({ type: 'rest_started', duration_seconds: restDuration / 1000 });
setTimeout(startWorkCycle, restDuration);
}, 10 * 60 * 1000);
}
// ---- Start/stop ----
function startVoting() {
if (enabled) return;
enabled = true;
chrome.storage.local.set({ enabled: true });
console.log('[content] Voting started');
_updateBanner('▶️ Voting started');
consecutiveSkips = 0;
startWorkCycle();
}
function stopVoting() {
enabled = false;
chrome.storage.local.set({ enabled: false });
clearTimeout(voteTimerId);
clearTimeout(restTimerId);
_removeBanner();
console.log('[content] Voting stopped');
}
// ---- Visual indicator ----
function _updateBanner(msg) {
_removeBanner();
const el = document.createElement('div');
el.id = '__luna_banner';
el.textContent = msg;
Object.assign(el.style, {
position: 'fixed', bottom: '16px', right: '16px',
background: '#22c55e', color: '#fff', padding: '8px 16px',
borderRadius: '6px', fontSize: '13px', zIndex: '99999',
fontFamily: '-apple-system, BlinkMacSystemFont, sans-serif',
boxShadow: '0 2px 8px rgba(0,0,0,0.2)',
});
document.body.appendChild(el);
}
function _removeBanner() {
const el = document.getElementById('__luna_banner');
if (el) el.remove();
}
// ---- Message handling ----
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'start') {
startVoting();
sendResponse({ status: 'started' });
} else if (message.type === 'stop') {
stopVoting();
sendResponse({ status: 'stopped' });
} else if (message.type === 'get_status') {
sendResponse({ enabled, voteCount, skipCount, consecutiveSkips });
}
return true;
});
// ---- Auto-resume after page refresh ----
chrome.storage.local.get(['enabled'], (result) => {
if (result.enabled) {
console.log('[content] Auto-resuming voting after page load (3s delay)...');
setTimeout(() => startVoting(), 3000);
}
});
console.log('[content] Luna TTS Ranking Bot loaded');
})();
// Injected into page main world — intercepts fetch for audio URLs
(() => {
const _fetch = window.fetch;
window.fetch = function (...args) {
const url = typeof args[0] === 'string' ? args[0] : (args[0] && args[0].url) || '';
if (/\.(mp3|wav|ogg|m4a|flac)(\?|#|$)/i.test(url)) {
window.postMessage({ type: '__luna_audio', url }, '*');
}
return _fetch.apply(this, args);
};
})();
{
"manifest_version": 3,
"name": "Luna TTS Ranking Bot",
"version": "0.1.0",
"description": "Semi-automated voting on Luna TTS Arena with voiceprint matching",
"permissions": [
"storage",
"alarms",
"activeTab",
"scripting",
"debugger",
"nativeMessaging"
],
"host_permissions": [
"https://artificialanalysis.ai/*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["https://artificialanalysis.ai/text-to-speech/arena*"],
"js": ["content.js"],
"run_at": "document_start"
}
],
"action": {
"default_popup": "popup/popup.html",
"default_title": "Luna TTS Bot"
},
"icons": {},
"web_accessible_resources": [
{
"resources": ["inject.js"],
"matches": ["https://artificialanalysis.ai/*"]
}
]
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { width: 280px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 16px; font-size: 13px; }
h2 { font-size: 15px; margin-bottom: 12px; }
.status { display: flex; align-items: center; gap: 6px; margin-bottom: 12px; }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot.on { background: #22c55e; }
.dot.off { background: #ef4444; }
.row { display: flex; justify-content: space-between; margin-bottom: 6px; }
.label { color: #6b7280; }
.value { font-weight: 600; }
button { width: 100%; padding: 8px; border: none; border-radius: 6px; font-size: 13px; cursor: pointer; margin-top: 12px; }
button.start { background: #22c55e; color: white; }
button.stop { background: #ef4444; color: white; }
button:disabled { opacity: 0.5; cursor: default; }
hr { border: none; border-top: 1px solid #e5e7eb; margin: 12px 0; }
.log { font-size: 11px; color: #6b7280; max-height: 100px; overflow-y: auto; }
</style>
</head>
<body>
<h2>Luna TTS Bot</h2>
<div class="status">
<span class="dot" id="dot"></span>
<span id="statusText">Disconnected</span>
</div>
<div class="row"><span class="label">Server</span><span class="value" id="serverStatus">—</span></div>
<div class="row"><span class="label">Today votes</span><span class="value" id="todayVotes">0 / 800</span></div>
<div class="row"><span class="label">Today skips</span><span class="value" id="todaySkips">0</span></div>
<button id="btnStart" class="start">Start Voting</button>
<button id="btnStop" class="stop" disabled>Stop</button>
<hr>
<div class="log" id="log"></div>
<script src="popup.js"></script>
</body>
</html>
// Luna TTS Ranking Bot — Popup controller
const btnStart = document.getElementById('btnStart');
const btnStop = document.getElementById('btnStop');
const statusText = document.getElementById('statusText');
const dot = document.getElementById('dot');
const serverStatus = document.getElementById('serverStatus');
const todayVotes = document.getElementById('todayVotes');
const todaySkips = document.getElementById('todaySkips');
const log = document.getElementById('log');
let tabId = null;
async function getArenaTab() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (tab && tab.url && tab.url.startsWith('https://artificialanalysis.ai/text-to-speech/arena')) {
return tab;
}
return null;
}
function updateUI(state) {
if (state.ws_connected) {
statusText.textContent = 'Connected';
dot.className = 'dot on';
} else {
statusText.textContent = 'Disconnected';
dot.className = 'dot off';
}
serverStatus.textContent = state.ws_connected ? 'Online' : 'Offline';
}
function addLog(msg) {
const time = new Date().toLocaleTimeString();
log.textContent = `[${time}] ${msg}\n` + log.textContent;
}
async function refreshState() {
const tab = await getArenaTab();
chrome.runtime.sendMessage({ type: 'get_state' }, (state) => {
updateUI(state);
if (state.today_votes !== undefined) {
todayVotes.textContent = `${state.today_votes} / ${state.daily_limit || 800}`;
todaySkips.textContent = state.today_skips || 0;
}
});
if (!tab) return;
tabId = tab.id;
chrome.tabs.sendMessage(tabId, { type: 'get_status' }).then((contentState) => {
if (contentState) {
btnStart.disabled = contentState.enabled;
btnStop.disabled = !contentState.enabled;
}
}).catch(() => {});
}
btnStart.addEventListener('click', async () => {
const tab = await getArenaTab();
if (!tab) {
addLog('Arena page not found. Open it first.');
return;
}
chrome.tabs.sendMessage(tab.id, { type: 'start' }).then((res) => {
if (res) {
btnStart.disabled = true;
btnStop.disabled = false;
addLog('Voting started');
}
}).catch(() => {
addLog('Failed to start. Reload the arena page.');
});
});
btnStop.addEventListener('click', async () => {
const tab = await getArenaTab();
if (!tab) return;
chrome.tabs.sendMessage(tab.id, { type: 'stop' }).then((res) => {
if (res) {
btnStart.disabled = false;
btnStop.disabled = true;
addLog('Voting stopped');
}
}).catch(() => {});
});
// Listen for updates from background
chrome.runtime.onMessage.addListener((message) => {
if (message.type === 'from_server') {
const payload = message.payload;
if (payload.stats) {
todayVotes.textContent = `${payload.stats.today_votes} / ${payload.stats.daily_limit}`;
todaySkips.textContent = payload.stats.today_skips;
}
}
if (message.type === 'ws_state') {
updateUI({ ws_connected: message.status === 'connected' });
}
});
refreshState();
setInterval(refreshState, 5000);
"""All tunable parameters for the Luna TTS ranking bot."""
# ---- Matching ----
OUR_THRESHOLD = 0.80 # Rule 1-3: min cosine similarity to claim "our speaker"
COMPETITOR_THRESHOLD = 0.80 # Rule 4: competitor match threshold
# ---- Voting strategy ----
BIG_VENDOR_VOTE_PROBABILITY = 75 # Rule 5: percentage (0-100), roll <= this → vote
DAILY_VOTE_LIMIT = 800 # Rule 6: stop after this many votes today
# ---- Anti-detection timing ----
VOTE_PERIOD_SECONDS = 600 # Vote for 10 min
REST_MIN_SECONDS = 60 # Then rest 1-3 min (random)
REST_MAX_SECONDS = 180
VOTE_INTERVAL_MIN_SECONDS = 2 # Gap between votes
VOTE_INTERVAL_MAX_SECONDS = 8
CLICK_DELAY_MIN_MS = 100 # Extra delay before simulating keypress
CLICK_DELAY_MAX_MS = 500
# ---- Server ----
WS_HOST = "localhost"
WS_PORT = 8765
# ---- Paths (relative to server.py location) ----
REFERENCE_DIRS = {
"our": "reference/standard",
"competitor": "reference/competitors",
"big_vendor": "reference/big_vendors",
}
#!/bin/bash
# Install Chrome Native Messaging host manifest (Mac)
EXT_ID="$1"
if [ -z "$EXT_ID" ]; then
echo "Usage: ./install_host.sh <extension-id>"
echo "Find your extension ID at chrome://extensions/"
echo "Example: ./install_host.sh abcdefghijklmnop"
exit 1
fi
HOST_DIR="$(cd "$(dirname "$0")" && pwd)"
# Compile wrapper binary
if [ ! -x "$HOST_DIR/run_host" ]; then
echo "Compiling native host wrapper..."
if ! command -v gcc &>/dev/null; then
echo ""
echo "========================================"
echo "ERROR: gcc 未安装"
echo "请先安装 Xcode Command Line Tools:"
echo " xcode-select --install"
echo "========================================"
echo ""
exit 1
fi
gcc -o "$HOST_DIR/run_host" "$HOST_DIR/runner.c" || {
echo "编译失败,请确认 gcc 可用"
exit 1
}
echo " 编译完成: $HOST_DIR/run_host"
fi
# Install manifest to all known Chromium browser directories
INSTALLED=0
install_to() {
local base="$1"
[ ! -d "$base" ] && return
local nm_dir="$base/NativeMessagingHosts"
mkdir -p "$nm_dir"
cat > "$nm_dir/com.luna.tts.json" << JSONEOF
{
"name": "com.luna.tts",
"description": "Luna TTS Ranking Bot - Native Messaging Host",
"path": "$HOST_DIR/run_host",
"type": "stdio",
"allowed_origins": ["chrome-extension://$EXT_ID/"]
}
JSONEOF
echo " $nm_dir/com.luna.tts.json"
INSTALLED=$((INSTALLED + 1))
}
for b in "Google/Chrome" "Chromium" "Quark" "Microsoft Edge"; do
install_to "$HOME/Library/Application Support/$b"
done
# AdsPower cache dirs
ADSPOWER_BASE="$HOME/Library/Application Support/adspower_global/cwd_global/source/cache"
if [ -d "$ADSPOWER_BASE" ]; then
for d in "$ADSPOWER_BASE"/*; do
[ -d "$d" ] && install_to "$d"
done
fi
if [ $INSTALLED -eq 0 ]; then
echo "WARNING: 没有找到浏览器目录,只装了以下基础路径:"
NM_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
mkdir -p "$NM_DIR"
cat > "$NM_DIR/com.luna.tts.json" << JSONEOF
{
"name": "com.luna.tts",
"description": "Luna TTS Ranking Bot - Native Messaging Host",
"path": "$HOST_DIR/run_host",
"type": "stdio",
"allowed_origins": ["chrome-extension://$EXT_ID/"]
}
JSONEOF
echo " $NM_DIR/com.luna.tts.json"
fi
echo ""
echo "完成!Host: $HOST_DIR/run_host"
echo "扩展 ID: $EXT_ID"
echo ""
echo "现在去 chrome://extensions/ 刷新扩展,然后打开打榜页面即可"
========================================
Traceback (most recent call last):
File "/Users/chengyubing/Documents/projects/hzjj/tts-ranking/server/run_host.py", line 12, in <module>
main()
File "/Users/chengyubing/Documents/projects/hzjj/tts-ranking/server/native_host.py", line 81, in main
print("[host] Ready, waiting for messages...", file=sys.stderr)
BrokenPipeError: [Errno 32] Broken pipe
[18:34:41]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.7815)
Daniel: 0.7815 [—]
竞品最佳: Douglas_us_male(0.9158)
Douglas_us_male: 0.9158 ← [SpeechifyAI / Simba_3.0]
Noble Cast_us_male: 0.8597 ← [StepFun / StepAudio_2.5_TTS]
Duncan_uk_male: 0.8444 ← [Inworld / Realtime_TTS_1.5_Max]
Jason_us_male: 0.8317 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Daniel_us_male: 0.8299 ← [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Reed_us_male: 0.8205 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Jarnathan_us_male: 0.8154 ← [ElevenLabs / Eleven_v3]
Insightful Speaker_us_male: 0.8127 ← [MiniMax / Speech_2.6_HD]
Vibrant Youth_us_male: 0.8096 ← [StepFun / Step_TTS_2_Mar_2026]
Expressive Narrator_uk_male: 0.8025 ← [MiniMax / Speech_2.6_HD]
Altair_us_male: 0.7983 [SpaceXAI / SpaceXAI_TTS]
Leo_uk_male: 0.7894 [SpaceXAI / SpaceXAI_TTS]
Felix_uk_male: 0.7831 [Inworld / Realtime_TTS-2_-_Research_Preview]
Dan_uk_male: 0.7740 [ElevenLabs / Eleven_v3]
HT-M319_us_male: 0.7699 [StepFun / Step_Audio_EditX_Mar_2026]
Sawyer_us_male: 0.7683 [Fish Audio / Fish_Audio_S2.1_Pro]
Archie_uk_male: 0.7644 [SpeechifyAI / Simba_3.0]
Rhys_uk_male: 0.7607 [Fish Audio / Fish_Audio_S2.1_Pro]
Liam_us_male: 0.7591 [ElevenLabs / Eleven_v3]
Jordan_us_male: 0.7575 [Fish Audio / Fish_Audio_S2_Pro]
Magnus_us_male: 0.7512 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Corin_us_male: 0.7413 [async / Async_Flash_v1.5]
Helix_us_male: 0.7389 [SpaceXAI / SpaceXAI_TTS]
Clive_uk_male: 0.7381 [Inworld / Realtime_TTS-2_-_Research_Preview]
Stellan_us_male: 0.7366 [Fish Audio / Fish_Audio_S2.1_Pro]
Alistair_uk_male: 0.7278 [Fish Audio / Fish_Audio_S2.1_Pro]
Edward_uk_male: 0.7239 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Dorian_us_male: 0.7217 [SpeechifyAI / Simba_3.0]
Patient Man_uk_male: 0.7114 [MiniMax / Speech_2.6_HD]
Nathaniel_uk_male: 0.7045 [ElevenLabs / Eleven_v3]
Liam_uk_male: 0.6931 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Alec_uk_male: 0.6819 [SpeechifyAI / Simba_3.0]
Adrian_us_male: 0.6813 [Fish Audio / Fish_Audio_S2_Pro]
Captivating Storyteller_us_male: 0.6778 [MiniMax / Speech_2.6_HD]
Fisher_us_male: 0.6591 [async / Async_Flash_v1.5]
Hayes_uk_male: 0.6312 [async / Async_Flash_v1.5]
Max_uk_male: 0.6034 [async / Async_Flash_v1.5]
大厂最佳: Daniel_us_male(0.8023)
Daniel_us_male: 0.8023 ← [Cartesia / Sonic_3.5]
Corey_us_male: 0.8016 ← [Cartesia / Sonic_3.5]
arthur_uk_male: 0.7888 [Alibaba / Fun-Realtime-TTS]
Charon_us_male: 0.7857 [Google / Gemini_3.1_Flash_TTS]
Edmund_uk_male: 0.7751 [SpeechifyAI / Simba_3.2]
George_uk_male: 0.7685 [Cartesia / Sonic_3.5]
davis_us_male: 0.7683 [Alibaba / Fun-Realtime-TTS]
Charon_uk_male: 0.7531 [Google / Gemini_3.1_Flash_TTS]
michael_us_male: 0.7492 [Alibaba / Fun-Realtime-TTS]
Fenrir_uk_male: 0.7477 [Google / Gemini_3.1_Flash_TTS]
Dominic_us_male: 0.7453 [SpeechifyAI / Simba_3.2]
barry_uk_male: 0.7433 [Alibaba / Fun-Realtime-TTS]
Hugh_uk_male: 0.7309 [SpeechifyAI / Simba_3.2]
Wyatt_us_male: 0.7010 [SpeechifyAI / Simba_3.2]
Archie_uk_male: 0.6872 [Cartesia / Sonic_3.5]
>>> left 最高: Douglas_us_male(0.9158) [competitor]
RIGHT 音频
我方最佳: Ella(0.6472)
Ella: 0.6472 [—]
Grace: 0.5455 [—]
竞品最佳: Laura_us_female(0.7428)
Laura_us_female: 0.7428 [ElevenLabs / Eleven_v3]
Jessica_us_female: 0.7194 [ElevenLabs / Eleven_v3]
Candid Girl_us_female: 0.7130 [StepFun / StepAudio_2.5_TTS]
Sabrina_us_female: 0.7106 [SpeechifyAI / Simba_3.0]
Ashley_us_female: 0.7032 [Inworld / Realtime_TTS-2_-_Research_Preview]
Geffen-v1_us_female: 0.6962 [SpeechifyAI / Simba_3.0]
Marley_us_female: 0.6950 [Fish Audio / Fish_Audio_S2.1_Pro]
Upbeat Woman_us_female: 0.6932 [MiniMax / Speech_2.6_HD]
Sarah_us_female: 0.6910 [Fish Audio / Fish_Audio_S2_Pro]
Jennie_uk_female: 0.6867 [async / Async_Flash_v1.5]
Captivating Female_us_female: 0.6839 [MiniMax / Speech_2.6_HD]
Marnie_uk_female: 0.6816 [SpeechifyAI / Simba_3.0]
Stella_us_female: 0.6786 [async / Async_Flash_v1.5]
Lively Girl_us_female: 0.6768 [StepFun / StepAudio_2.5_TTS]
HT-F404_us_female: 0.6684 [StepFun / Step_Audio_EditX_Mar_2026]
Cleo_uk_female: 0.6598 [async / Async_Flash_v1.5]
Olivia_us_female: 0.6586 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Elara_us_female: 0.6543 [async / Async_Flash_v1.5]
Marlowe_us_female: 0.6515 [Fish Audio / Fish_Audio_S2.1_Pro]
Compelling Lady_uk_female: 0.6513 [MiniMax / Speech_2.6_HD]
Sophie_uk_female: 0.6495 [Inworld / Realtime_TTS-2_-_Research_Preview]
Carina_us_female: 0.6455 [SpaceXAI / SpaceXAI_TTS]
Shelley_uk_female: 0.6403 [ElevenLabs / Eleven_v3]
Elizabeth_uk_female: 0.6382 [ElevenLabs / Eleven_v3]
Eleanor_uk_female: 0.6380 [Inworld / Realtime_TTS-2_-_Research_Preview]
Briony_uk_female: 0.6297 [Fish Audio / Fish_Audio_S2.1_Pro]
Maeve_uk_female: 0.6275 [Fish Audio / Fish_Audio_S2.1_Pro]
Alice_uk_female: 0.6259 [SpeechifyAI / Simba_3.0]
Noah_uk_female: 0.6253 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Luna_us_female: 0.6251 [SpaceXAI / SpaceXAI_TTS]
Quinn_us_female: 0.6145 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Eve_uk_female: 0.6112 [SpaceXAI / SpaceXAI_TTS]
Graceful Lady_uk_female: 0.5586 [MiniMax / Speech_2.6_HD]
大厂最佳: Zephyr_us_female(0.7261)
Zephyr_us_female: 0.7261 [Google / Gemini_3.1_Flash_TTS]
Aoede_us_female: 0.7260 [Google / Gemini_3.1_Flash_TTS]
Zephyr_uk_female: 0.7188 [Google / Gemini_3.1_Flash_TTS]
Aoede_uk_female: 0.7059 [Google / Gemini_3.1_Flash_TTS]
mary_uk_female: 0.6929 [Alibaba / Fun-Realtime-TTS]
Skylar_us_female: 0.6919 [Cartesia / Sonic_3.5]
seline_us_female: 0.6903 [Alibaba / Fun-Realtime-TTS]
Gemma_uk_female: 0.6756 [Cartesia / Sonic_3.5]
Geffen_us_female: 0.6729 [SpeechifyAI / Simba_3.2]
sarah_us_female: 0.6728 [Alibaba / Fun-Realtime-TTS]
Imogen_uk_female: 0.6586 [SpeechifyAI / Simba_3.2]
Caroline_us_female: 0.6580 [Cartesia / Sonic_3.5]
Beatrice_uk_female: 0.6500 [SpeechifyAI / Simba_3.2]
charlotte_uk_female: 0.6461 [Alibaba / Fun-Realtime-TTS]
Harper_us_female: 0.6398 [SpeechifyAI / Simba_3.2]
Victoria_uk_female: 0.5936 [Cartesia / Sonic_3.5]
>>> right 最高: Laura_us_female(0.7428) [competitor]
决策: vote_right
原因: left 最高分为竞品 Douglas_us_male(0.9158) → 投 right
统计: 1 票 / 0 弃
───────────────────────────────────────────────────────
[18:35:09]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.7055)
Daniel: 0.7055 [—]
竞品最佳: Rhys_uk_male(0.7993)
Rhys_uk_male: 0.7993 [Fish Audio / Fish_Audio_S2.1_Pro]
Noble Cast_us_male: 0.7986 [StepFun / StepAudio_2.5_TTS]
Alistair_uk_male: 0.7894 [Fish Audio / Fish_Audio_S2.1_Pro]
Jason_us_male: 0.7805 [Inworld / Realtime_TTS-2_-_Research_Preview]
Edward_uk_male: 0.7780 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Patient Man_uk_male: 0.7702 [MiniMax / Speech_2.6_HD]
Nathaniel_uk_male: 0.7698 [ElevenLabs / Eleven_v3]
Archie_uk_male: 0.7649 [SpeechifyAI / Simba_3.0]
Felix_uk_male: 0.7637 [Inworld / Realtime_TTS-2_-_Research_Preview]
Reed_us_male: 0.7636 [Inworld / Realtime_TTS-2_-_Research_Preview]
Liam_uk_male: 0.7630 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Leo_uk_male: 0.7561 [SpaceXAI / SpaceXAI_TTS]
Clive_uk_male: 0.7531 [Inworld / Realtime_TTS-2_-_Research_Preview]
Duncan_uk_male: 0.7509 [Inworld / Realtime_TTS_1.5_Max]
Dan_uk_male: 0.7502 [ElevenLabs / Eleven_v3]
Expressive Narrator_uk_male: 0.7447 [MiniMax / Speech_2.6_HD]
Liam_us_male: 0.7428 [ElevenLabs / Eleven_v3]
Insightful Speaker_us_male: 0.7397 [MiniMax / Speech_2.6_HD]
Corin_us_male: 0.7392 [async / Async_Flash_v1.5]
Daniel_us_male: 0.7328 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Magnus_us_male: 0.7328 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Jarnathan_us_male: 0.7318 [ElevenLabs / Eleven_v3]
Stellan_us_male: 0.7309 [Fish Audio / Fish_Audio_S2.1_Pro]
Jordan_us_male: 0.7297 [Fish Audio / Fish_Audio_S2_Pro]
Douglas_us_male: 0.7293 [SpeechifyAI / Simba_3.0]
Hayes_uk_male: 0.7225 [async / Async_Flash_v1.5]
Captivating Storyteller_us_male: 0.7214 [MiniMax / Speech_2.6_HD]
Max_uk_male: 0.7198 [async / Async_Flash_v1.5]
Alec_uk_male: 0.7099 [SpeechifyAI / Simba_3.0]
Fisher_us_male: 0.7097 [async / Async_Flash_v1.5]
Sawyer_us_male: 0.6922 [Fish Audio / Fish_Audio_S2.1_Pro]
Vibrant Youth_us_male: 0.6883 [StepFun / Step_TTS_2_Mar_2026]
Dorian_us_male: 0.6821 [SpeechifyAI / Simba_3.0]
Adrian_us_male: 0.6788 [Fish Audio / Fish_Audio_S2_Pro]
Altair_us_male: 0.6772 [SpaceXAI / SpaceXAI_TTS]
HT-M319_us_male: 0.6771 [StepFun / Step_Audio_EditX_Mar_2026]
Helix_us_male: 0.6137 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: michael_us_male(0.8029)
michael_us_male: 0.8029 ← [Alibaba / Fun-Realtime-TTS]
Edmund_uk_male: 0.7783 [SpeechifyAI / Simba_3.2]
barry_uk_male: 0.7763 [Alibaba / Fun-Realtime-TTS]
Corey_us_male: 0.7717 [Cartesia / Sonic_3.5]
Hugh_uk_male: 0.7694 [SpeechifyAI / Simba_3.2]
Charon_uk_male: 0.7570 [Google / Gemini_3.1_Flash_TTS]
arthur_uk_male: 0.7407 [Alibaba / Fun-Realtime-TTS]
Daniel_us_male: 0.7402 [Cartesia / Sonic_3.5]
Archie_uk_male: 0.7307 [Cartesia / Sonic_3.5]
Charon_us_male: 0.7294 [Google / Gemini_3.1_Flash_TTS]
Fenrir_uk_male: 0.7108 [Google / Gemini_3.1_Flash_TTS]
davis_us_male: 0.6955 [Alibaba / Fun-Realtime-TTS]
Dominic_us_male: 0.6942 [SpeechifyAI / Simba_3.2]
George_uk_male: 0.6844 [Cartesia / Sonic_3.5]
Wyatt_us_male: 0.5946 [SpeechifyAI / Simba_3.2]
>>> left 最高: michael_us_male(0.8029) [big_vendor]
RIGHT 音频
我方最佳: Ella(0.6583)
Ella: 0.6583 [—]
Grace: 0.5389 [—]
竞品最佳: Sarah_us_female(0.6907)
Sarah_us_female: 0.6907 [Fish Audio / Fish_Audio_S2_Pro]
Sophie_uk_female: 0.6898 [Inworld / Realtime_TTS-2_-_Research_Preview]
Lively Girl_us_female: 0.6891 [StepFun / StepAudio_2.5_TTS]
HT-F404_us_female: 0.6852 [StepFun / Step_Audio_EditX_Mar_2026]
Upbeat Woman_us_female: 0.6762 [MiniMax / Speech_2.6_HD]
Captivating Female_us_female: 0.6710 [MiniMax / Speech_2.6_HD]
Jennie_uk_female: 0.6620 [async / Async_Flash_v1.5]
Ashley_us_female: 0.6613 [Inworld / Realtime_TTS-2_-_Research_Preview]
Compelling Lady_uk_female: 0.6495 [MiniMax / Speech_2.6_HD]
Laura_us_female: 0.6494 [ElevenLabs / Eleven_v3]
Luna_us_female: 0.6473 [SpaceXAI / SpaceXAI_TTS]
Briony_uk_female: 0.6432 [Fish Audio / Fish_Audio_S2.1_Pro]
Candid Girl_us_female: 0.6419 [StepFun / StepAudio_2.5_TTS]
Cleo_uk_female: 0.6330 [async / Async_Flash_v1.5]
Eleanor_uk_female: 0.6318 [Inworld / Realtime_TTS-2_-_Research_Preview]
Marnie_uk_female: 0.6315 [SpeechifyAI / Simba_3.0]
Noah_uk_female: 0.6295 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Alice_uk_female: 0.6294 [SpeechifyAI / Simba_3.0]
Olivia_us_female: 0.6267 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Marley_us_female: 0.6245 [Fish Audio / Fish_Audio_S2.1_Pro]
Elara_us_female: 0.6220 [async / Async_Flash_v1.5]
Jessica_us_female: 0.6208 [ElevenLabs / Eleven_v3]
Shelley_uk_female: 0.6192 [ElevenLabs / Eleven_v3]
Sabrina_us_female: 0.6106 [SpeechifyAI / Simba_3.0]
Elizabeth_uk_female: 0.6089 [ElevenLabs / Eleven_v3]
Graceful Lady_uk_female: 0.5991 [MiniMax / Speech_2.6_HD]
Quinn_us_female: 0.5941 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Geffen-v1_us_female: 0.5820 [SpeechifyAI / Simba_3.0]
Eve_uk_female: 0.5737 [SpaceXAI / SpaceXAI_TTS]
Stella_us_female: 0.5710 [async / Async_Flash_v1.5]
Maeve_uk_female: 0.5652 [Fish Audio / Fish_Audio_S2.1_Pro]
Marlowe_us_female: 0.5611 [Fish Audio / Fish_Audio_S2.1_Pro]
Carina_us_female: 0.5530 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: Zephyr_uk_female(0.7015)
Zephyr_uk_female: 0.7015 [Google / Gemini_3.1_Flash_TTS]
Gemma_uk_female: 0.6881 [Cartesia / Sonic_3.5]
Aoede_us_female: 0.6854 [Google / Gemini_3.1_Flash_TTS]
Zephyr_us_female: 0.6852 [Google / Gemini_3.1_Flash_TTS]
charlotte_uk_female: 0.6736 [Alibaba / Fun-Realtime-TTS]
Aoede_uk_female: 0.6690 [Google / Gemini_3.1_Flash_TTS]
Skylar_us_female: 0.6358 [Cartesia / Sonic_3.5]
mary_uk_female: 0.6251 [Alibaba / Fun-Realtime-TTS]
sarah_us_female: 0.6234 [Alibaba / Fun-Realtime-TTS]
seline_us_female: 0.6233 [Alibaba / Fun-Realtime-TTS]
Victoria_uk_female: 0.6125 [Cartesia / Sonic_3.5]
Caroline_us_female: 0.6103 [Cartesia / Sonic_3.5]
Imogen_uk_female: 0.6014 [SpeechifyAI / Simba_3.2]
Beatrice_uk_female: 0.5850 [SpeechifyAI / Simba_3.2]
Geffen_us_female: 0.5819 [SpeechifyAI / Simba_3.2]
Harper_us_female: 0.5802 [SpeechifyAI / Simba_3.2]
>>> right 最高: Zephyr_uk_female(0.7015) [big_vendor]
决策: vote_left
原因: left 最高分为大厂 michael_us_male(0.8029) → vote
统计: 2 票 / 0 弃
───────────────────────────────────────────────────────
[18:35:32]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.7516)
Daniel: 0.7516 [—]
竞品最佳: Reed_us_male(0.8714)
Reed_us_male: 0.8714 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Corin_us_male: 0.8459 ← [async / Async_Flash_v1.5]
Edward_uk_male: 0.8211 ← [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Rhys_uk_male: 0.8162 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Jarnathan_us_male: 0.7974 [ElevenLabs / Eleven_v3]
Leo_uk_male: 0.7864 [SpaceXAI / SpaceXAI_TTS]
Magnus_us_male: 0.7847 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Sawyer_us_male: 0.7650 [Fish Audio / Fish_Audio_S2.1_Pro]
Dan_uk_male: 0.7628 [ElevenLabs / Eleven_v3]
Felix_uk_male: 0.7573 [Inworld / Realtime_TTS-2_-_Research_Preview]
Jason_us_male: 0.7560 [Inworld / Realtime_TTS-2_-_Research_Preview]
Clive_uk_male: 0.7484 [Inworld / Realtime_TTS-2_-_Research_Preview]
Nathaniel_uk_male: 0.7469 [ElevenLabs / Eleven_v3]
Daniel_us_male: 0.7418 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Alistair_uk_male: 0.7289 [Fish Audio / Fish_Audio_S2.1_Pro]
Duncan_uk_male: 0.7236 [Inworld / Realtime_TTS_1.5_Max]
Noble Cast_us_male: 0.7109 [StepFun / StepAudio_2.5_TTS]
Hayes_uk_male: 0.7008 [async / Async_Flash_v1.5]
Insightful Speaker_us_male: 0.7001 [MiniMax / Speech_2.6_HD]
Patient Man_uk_male: 0.6908 [MiniMax / Speech_2.6_HD]
Douglas_us_male: 0.6901 [SpeechifyAI / Simba_3.0]
Liam_uk_male: 0.6883 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
HT-M319_us_male: 0.6882 [StepFun / Step_Audio_EditX_Mar_2026]
Altair_us_male: 0.6867 [SpaceXAI / SpaceXAI_TTS]
Dorian_us_male: 0.6757 [SpeechifyAI / Simba_3.0]
Jordan_us_male: 0.6734 [Fish Audio / Fish_Audio_S2_Pro]
Vibrant Youth_us_male: 0.6734 [StepFun / Step_TTS_2_Mar_2026]
Archie_uk_male: 0.6705 [SpeechifyAI / Simba_3.0]
Stellan_us_male: 0.6679 [Fish Audio / Fish_Audio_S2.1_Pro]
Captivating Storyteller_us_male: 0.6629 [MiniMax / Speech_2.6_HD]
Liam_us_male: 0.6626 [ElevenLabs / Eleven_v3]
Alec_uk_male: 0.6507 [SpeechifyAI / Simba_3.0]
Adrian_us_male: 0.6464 [Fish Audio / Fish_Audio_S2_Pro]
Fisher_us_male: 0.6308 [async / Async_Flash_v1.5]
Max_uk_male: 0.6280 [async / Async_Flash_v1.5]
Expressive Narrator_uk_male: 0.6126 [MiniMax / Speech_2.6_HD]
Helix_us_male: 0.6039 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: Corey_us_male(0.8954)
Corey_us_male: 0.8954 ← [Cartesia / Sonic_3.5]
michael_us_male: 0.7705 [Alibaba / Fun-Realtime-TTS]
Edmund_uk_male: 0.7699 [SpeechifyAI / Simba_3.2]
Daniel_us_male: 0.7681 [Cartesia / Sonic_3.5]
Fenrir_uk_male: 0.7638 [Google / Gemini_3.1_Flash_TTS]
Archie_uk_male: 0.7628 [Cartesia / Sonic_3.5]
George_uk_male: 0.7613 [Cartesia / Sonic_3.5]
Charon_us_male: 0.7287 [Google / Gemini_3.1_Flash_TTS]
arthur_uk_male: 0.7047 [Alibaba / Fun-Realtime-TTS]
Hugh_uk_male: 0.7032 [SpeechifyAI / Simba_3.2]
Dominic_us_male: 0.6885 [SpeechifyAI / Simba_3.2]
barry_uk_male: 0.6869 [Alibaba / Fun-Realtime-TTS]
Charon_uk_male: 0.6865 [Google / Gemini_3.1_Flash_TTS]
Wyatt_us_male: 0.6595 [SpeechifyAI / Simba_3.2]
davis_us_male: 0.6575 [Alibaba / Fun-Realtime-TTS]
>>> left 最高: Corey_us_male(0.8954) [big_vendor]
RIGHT 音频
我方最佳: Daniel(0.6258)
Daniel: 0.6258 [—]
竞品最佳: Fisher_us_male(0.8257)
Fisher_us_male: 0.8257 ← [async / Async_Flash_v1.5]
HT-M319_us_male: 0.8103 ← [StepFun / Step_Audio_EditX_Mar_2026]
Vibrant Youth_us_male: 0.7820 [StepFun / Step_TTS_2_Mar_2026]
Captivating Storyteller_us_male: 0.7551 [MiniMax / Speech_2.6_HD]
Helix_us_male: 0.7170 [SpaceXAI / SpaceXAI_TTS]
Adrian_us_male: 0.7071 [Fish Audio / Fish_Audio_S2_Pro]
Jarnathan_us_male: 0.7027 [ElevenLabs / Eleven_v3]
Altair_us_male: 0.7018 [SpaceXAI / SpaceXAI_TTS]
Noble Cast_us_male: 0.6935 [StepFun / StepAudio_2.5_TTS]
Magnus_us_male: 0.6884 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Reed_us_male: 0.6875 [Inworld / Realtime_TTS-2_-_Research_Preview]
Archie_uk_male: 0.6819 [SpeechifyAI / Simba_3.0]
Max_uk_male: 0.6726 [async / Async_Flash_v1.5]
Expressive Narrator_uk_male: 0.6667 [MiniMax / Speech_2.6_HD]
Sawyer_us_male: 0.6620 [Fish Audio / Fish_Audio_S2.1_Pro]
Liam_us_male: 0.6612 [ElevenLabs / Eleven_v3]
Jason_us_male: 0.6581 [Inworld / Realtime_TTS-2_-_Research_Preview]
Corin_us_male: 0.6452 [async / Async_Flash_v1.5]
Clive_uk_male: 0.6399 [Inworld / Realtime_TTS-2_-_Research_Preview]
Leo_uk_male: 0.6328 [SpaceXAI / SpaceXAI_TTS]
Daniel_us_male: 0.6315 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Felix_uk_male: 0.6178 [Inworld / Realtime_TTS-2_-_Research_Preview]
Duncan_uk_male: 0.6137 [Inworld / Realtime_TTS_1.5_Max]
Dorian_us_male: 0.6112 [SpeechifyAI / Simba_3.0]
Insightful Speaker_us_male: 0.6086 [MiniMax / Speech_2.6_HD]
Jordan_us_male: 0.6075 [Fish Audio / Fish_Audio_S2_Pro]
Dan_uk_male: 0.6057 [ElevenLabs / Eleven_v3]
Douglas_us_male: 0.6056 [SpeechifyAI / Simba_3.0]
Edward_uk_male: 0.6005 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Nathaniel_uk_male: 0.5977 [ElevenLabs / Eleven_v3]
Patient Man_uk_male: 0.5748 [MiniMax / Speech_2.6_HD]
Stellan_us_male: 0.5646 [Fish Audio / Fish_Audio_S2.1_Pro]
Hayes_uk_male: 0.5595 [async / Async_Flash_v1.5]
Rhys_uk_male: 0.5541 [Fish Audio / Fish_Audio_S2.1_Pro]
Alec_uk_male: 0.5268 [SpeechifyAI / Simba_3.0]
Alistair_uk_male: 0.5191 [Fish Audio / Fish_Audio_S2.1_Pro]
Liam_uk_male: 0.5049 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
大厂最佳: davis_us_male(0.8026)
davis_us_male: 0.8026 ← [Alibaba / Fun-Realtime-TTS]
Wyatt_us_male: 0.7786 [SpeechifyAI / Simba_3.2]
michael_us_male: 0.7764 [Alibaba / Fun-Realtime-TTS]
Charon_uk_male: 0.7738 [Google / Gemini_3.1_Flash_TTS]
Dominic_us_male: 0.7685 [SpeechifyAI / Simba_3.2]
Charon_us_male: 0.7573 [Google / Gemini_3.1_Flash_TTS]
Daniel_us_male: 0.7230 [Cartesia / Sonic_3.5]
Hugh_uk_male: 0.7039 [SpeechifyAI / Simba_3.2]
arthur_uk_male: 0.7034 [Alibaba / Fun-Realtime-TTS]
Edmund_uk_male: 0.7008 [SpeechifyAI / Simba_3.2]
Fenrir_uk_male: 0.6712 [Google / Gemini_3.1_Flash_TTS]
Archie_uk_male: 0.6551 [Cartesia / Sonic_3.5]
barry_uk_male: 0.6372 [Alibaba / Fun-Realtime-TTS]
Corey_us_male: 0.6166 [Cartesia / Sonic_3.5]
George_uk_male: 0.5700 [Cartesia / Sonic_3.5]
>>> right 最高: Fisher_us_male(0.8257) [competitor]
决策: vote_left
原因: left 最高分为大厂 Corey_us_male(0.8954) → vote
统计: 3 票 / 0 弃
───────────────────────────────────────────────────────
[18:35:55]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Ella(0.8780)
Ella: 0.8780 ← [—]
Grace: 0.7319 [—]
竞品最佳: Candid Girl_us_female(0.9072)
Candid Girl_us_female: 0.9072 ← [StepFun / StepAudio_2.5_TTS]
Upbeat Woman_us_female: 0.8679 ← [MiniMax / Speech_2.6_HD]
Sarah_us_female: 0.8678 ← [Fish Audio / Fish_Audio_S2_Pro]
Laura_us_female: 0.8635 ← [ElevenLabs / Eleven_v3]
Ashley_us_female: 0.8627 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Captivating Female_us_female: 0.8627 ← [MiniMax / Speech_2.6_HD]
Elara_us_female: 0.8489 ← [async / Async_Flash_v1.5]
Marley_us_female: 0.8476 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Sabrina_us_female: 0.8423 ← [SpeechifyAI / Simba_3.0]
Lively Girl_us_female: 0.8394 ← [StepFun / StepAudio_2.5_TTS]
HT-F404_us_female: 0.8296 ← [StepFun / Step_Audio_EditX_Mar_2026]
Marlowe_us_female: 0.8277 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Carina_us_female: 0.8096 ← [SpaceXAI / SpaceXAI_TTS]
Jessica_us_female: 0.8087 ← [ElevenLabs / Eleven_v3]
Alice_uk_female: 0.8040 ← [SpeechifyAI / Simba_3.0]
Olivia_us_female: 0.7960 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Geffen-v1_us_female: 0.7784 [SpeechifyAI / Simba_3.0]
Stella_us_female: 0.7729 [async / Async_Flash_v1.5]
Briony_uk_female: 0.7568 [Fish Audio / Fish_Audio_S2.1_Pro]
Quinn_us_female: 0.7547 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Shelley_uk_female: 0.7356 [ElevenLabs / Eleven_v3]
Elizabeth_uk_female: 0.7351 [ElevenLabs / Eleven_v3]
Compelling Lady_uk_female: 0.7331 [MiniMax / Speech_2.6_HD]
Jennie_uk_female: 0.7303 [async / Async_Flash_v1.5]
Eve_uk_female: 0.7192 [SpaceXAI / SpaceXAI_TTS]
Luna_us_female: 0.7180 [SpaceXAI / SpaceXAI_TTS]
Eleanor_uk_female: 0.7078 [Inworld / Realtime_TTS-2_-_Research_Preview]
Sophie_uk_female: 0.6985 [Inworld / Realtime_TTS-2_-_Research_Preview]
Cleo_uk_female: 0.6971 [async / Async_Flash_v1.5]
Graceful Lady_uk_female: 0.6466 [MiniMax / Speech_2.6_HD]
Maeve_uk_female: 0.6375 [Fish Audio / Fish_Audio_S2.1_Pro]
Marnie_uk_female: 0.6122 [SpeechifyAI / Simba_3.0]
Noah_uk_female: 0.5515 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
大厂最佳: Aoede_us_female(0.8647)
Aoede_us_female: 0.8647 ← [Google / Gemini_3.1_Flash_TTS]
Skylar_us_female: 0.8591 ← [Cartesia / Sonic_3.5]
Zephyr_us_female: 0.8341 ← [Google / Gemini_3.1_Flash_TTS]
Harper_us_female: 0.8120 ← [SpeechifyAI / Simba_3.2]
sarah_us_female: 0.8100 ← [Alibaba / Fun-Realtime-TTS]
mary_uk_female: 0.8049 ← [Alibaba / Fun-Realtime-TTS]
Caroline_us_female: 0.8030 ← [Cartesia / Sonic_3.5]
Aoede_uk_female: 0.7794 [Google / Gemini_3.1_Flash_TTS]
seline_us_female: 0.7755 [Alibaba / Fun-Realtime-TTS]
Zephyr_uk_female: 0.7631 [Google / Gemini_3.1_Flash_TTS]
charlotte_uk_female: 0.7476 [Alibaba / Fun-Realtime-TTS]
Geffen_us_female: 0.7443 [SpeechifyAI / Simba_3.2]
Victoria_uk_female: 0.6916 [Cartesia / Sonic_3.5]
Beatrice_uk_female: 0.6877 [SpeechifyAI / Simba_3.2]
Gemma_uk_female: 0.6547 [Cartesia / Sonic_3.5]
Imogen_uk_female: 0.6090 [SpeechifyAI / Simba_3.2]
>>> left 最高: Candid Girl_us_female(0.9072) [competitor]
RIGHT 音频
我方最佳: Ella(0.9405)
Ella: 0.9405 ← [—]
Grace: 0.6755 [—]
竞品最佳: Sarah_us_female(0.8925)
Sarah_us_female: 0.8925 ← [Fish Audio / Fish_Audio_S2_Pro]
Ashley_us_female: 0.8809 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
HT-F404_us_female: 0.8732 ← [StepFun / Step_Audio_EditX_Mar_2026]
Lively Girl_us_female: 0.8685 ← [StepFun / StepAudio_2.5_TTS]
Candid Girl_us_female: 0.8678 ← [StepFun / StepAudio_2.5_TTS]
Captivating Female_us_female: 0.8460 ← [MiniMax / Speech_2.6_HD]
Upbeat Woman_us_female: 0.8432 ← [MiniMax / Speech_2.6_HD]
Marley_us_female: 0.8324 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Olivia_us_female: 0.8256 ← [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Stella_us_female: 0.8168 ← [async / Async_Flash_v1.5]
Marlowe_us_female: 0.8162 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Jessica_us_female: 0.8156 ← [ElevenLabs / Eleven_v3]
Alice_uk_female: 0.8155 ← [SpeechifyAI / Simba_3.0]
Eleanor_uk_female: 0.8113 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Sophie_uk_female: 0.8104 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Laura_us_female: 0.8089 ← [ElevenLabs / Eleven_v3]
Compelling Lady_uk_female: 0.8066 ← [MiniMax / Speech_2.6_HD]
Jennie_uk_female: 0.8053 ← [async / Async_Flash_v1.5]
Sabrina_us_female: 0.8016 ← [SpeechifyAI / Simba_3.0]
Geffen-v1_us_female: 0.8003 ← [SpeechifyAI / Simba_3.0]
Elara_us_female: 0.7973 [async / Async_Flash_v1.5]
Briony_uk_female: 0.7959 [Fish Audio / Fish_Audio_S2.1_Pro]
Shelley_uk_female: 0.7864 [ElevenLabs / Eleven_v3]
Luna_us_female: 0.7743 [SpaceXAI / SpaceXAI_TTS]
Quinn_us_female: 0.7706 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Cleo_uk_female: 0.7699 [async / Async_Flash_v1.5]
Eve_uk_female: 0.7605 [SpaceXAI / SpaceXAI_TTS]
Carina_us_female: 0.7331 [SpaceXAI / SpaceXAI_TTS]
Elizabeth_uk_female: 0.7304 [ElevenLabs / Eleven_v3]
Graceful Lady_uk_female: 0.7196 [MiniMax / Speech_2.6_HD]
Marnie_uk_female: 0.6857 [SpeechifyAI / Simba_3.0]
Maeve_uk_female: 0.6834 [Fish Audio / Fish_Audio_S2.1_Pro]
Noah_uk_female: 0.6784 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
大厂最佳: mary_uk_female(0.8791)
mary_uk_female: 0.8791 ← [Alibaba / Fun-Realtime-TTS]
Caroline_us_female: 0.8641 ← [Cartesia / Sonic_3.5]
sarah_us_female: 0.8615 ← [Alibaba / Fun-Realtime-TTS]
Aoede_us_female: 0.8581 ← [Google / Gemini_3.1_Flash_TTS]
Zephyr_us_female: 0.8563 ← [Google / Gemini_3.1_Flash_TTS]
Harper_us_female: 0.8402 ← [SpeechifyAI / Simba_3.2]
Skylar_us_female: 0.8378 ← [Cartesia / Sonic_3.5]
seline_us_female: 0.8321 ← [Alibaba / Fun-Realtime-TTS]
Aoede_uk_female: 0.8182 ← [Google / Gemini_3.1_Flash_TTS]
charlotte_uk_female: 0.8114 ← [Alibaba / Fun-Realtime-TTS]
Victoria_uk_female: 0.8108 ← [Cartesia / Sonic_3.5]
Zephyr_uk_female: 0.8017 ← [Google / Gemini_3.1_Flash_TTS]
Geffen_us_female: 0.8013 ← [SpeechifyAI / Simba_3.2]
Beatrice_uk_female: 0.7818 [SpeechifyAI / Simba_3.2]
Gemma_uk_female: 0.7334 [Cartesia / Sonic_3.5]
Imogen_uk_female: 0.7061 [SpeechifyAI / Simba_3.2]
>>> right 最高: Ella(0.9405) [our]
决策: vote_right
原因: right 最高分为我方 Ella(0.9405) → vote
统计: 4 票 / 0 弃
───────────────────────────────────────────────────────
[18:36:13]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.7656)
Daniel: 0.7656 [—]
竞品最佳: Corin_us_male(0.8839)
Corin_us_male: 0.8839 ← [async / Async_Flash_v1.5]
Reed_us_male: 0.8597 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Magnus_us_male: 0.8465 ← [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Jason_us_male: 0.8044 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Jarnathan_us_male: 0.8030 ← [ElevenLabs / Eleven_v3]
Daniel_us_male: 0.7974 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Edward_uk_male: 0.7891 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Duncan_uk_male: 0.7809 [Inworld / Realtime_TTS_1.5_Max]
Rhys_uk_male: 0.7742 [Fish Audio / Fish_Audio_S2.1_Pro]
Clive_uk_male: 0.7698 [Inworld / Realtime_TTS-2_-_Research_Preview]
Leo_uk_male: 0.7569 [SpaceXAI / SpaceXAI_TTS]
Noble Cast_us_male: 0.7513 [StepFun / StepAudio_2.5_TTS]
Nathaniel_uk_male: 0.7510 [ElevenLabs / Eleven_v3]
Stellan_us_male: 0.7493 [Fish Audio / Fish_Audio_S2.1_Pro]
Felix_uk_male: 0.7478 [Inworld / Realtime_TTS-2_-_Research_Preview]
Alistair_uk_male: 0.7449 [Fish Audio / Fish_Audio_S2.1_Pro]
Dan_uk_male: 0.7414 [ElevenLabs / Eleven_v3]
Patient Man_uk_male: 0.7389 [MiniMax / Speech_2.6_HD]
Sawyer_us_male: 0.7338 [Fish Audio / Fish_Audio_S2.1_Pro]
Fisher_us_male: 0.7198 [async / Async_Flash_v1.5]
Archie_uk_male: 0.7177 [SpeechifyAI / Simba_3.0]
Vibrant Youth_us_male: 0.7173 [StepFun / Step_TTS_2_Mar_2026]
Expressive Narrator_uk_male: 0.7124 [MiniMax / Speech_2.6_HD]
Liam_uk_male: 0.7076 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Insightful Speaker_us_male: 0.7048 [MiniMax / Speech_2.6_HD]
Douglas_us_male: 0.7025 [SpeechifyAI / Simba_3.0]
Altair_us_male: 0.6968 [SpaceXAI / SpaceXAI_TTS]
Liam_us_male: 0.6892 [ElevenLabs / Eleven_v3]
Dorian_us_male: 0.6855 [SpeechifyAI / Simba_3.0]
HT-M319_us_male: 0.6845 [StepFun / Step_Audio_EditX_Mar_2026]
Jordan_us_male: 0.6830 [Fish Audio / Fish_Audio_S2_Pro]
Captivating Storyteller_us_male: 0.6532 [MiniMax / Speech_2.6_HD]
Adrian_us_male: 0.6479 [Fish Audio / Fish_Audio_S2_Pro]
Hayes_uk_male: 0.6421 [async / Async_Flash_v1.5]
Alec_uk_male: 0.6336 [SpeechifyAI / Simba_3.0]
Max_uk_male: 0.6307 [async / Async_Flash_v1.5]
Helix_us_male: 0.5757 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: Corey_us_male(0.8420)
Corey_us_male: 0.8420 ← [Cartesia / Sonic_3.5]
Charon_us_male: 0.7508 [Google / Gemini_3.1_Flash_TTS]
michael_us_male: 0.7492 [Alibaba / Fun-Realtime-TTS]
Fenrir_uk_male: 0.7482 [Google / Gemini_3.1_Flash_TTS]
Edmund_uk_male: 0.7437 [SpeechifyAI / Simba_3.2]
arthur_uk_male: 0.7398 [Alibaba / Fun-Realtime-TTS]
davis_us_male: 0.7234 [Alibaba / Fun-Realtime-TTS]
Archie_uk_male: 0.7184 [Cartesia / Sonic_3.5]
Charon_uk_male: 0.7169 [Google / Gemini_3.1_Flash_TTS]
Hugh_uk_male: 0.7099 [SpeechifyAI / Simba_3.2]
Dominic_us_male: 0.7049 [SpeechifyAI / Simba_3.2]
Daniel_us_male: 0.7016 [Cartesia / Sonic_3.5]
George_uk_male: 0.6955 [Cartesia / Sonic_3.5]
Wyatt_us_male: 0.6741 [SpeechifyAI / Simba_3.2]
barry_uk_male: 0.6575 [Alibaba / Fun-Realtime-TTS]
>>> left 最高: Corin_us_male(0.8839) [competitor]
RIGHT 音频
我方最佳: Daniel(0.7075)
Daniel: 0.7075 [—]
竞品最佳: Reed_us_male(0.8238)
Reed_us_male: 0.8238 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Sawyer_us_male: 0.7937 [Fish Audio / Fish_Audio_S2.1_Pro]
Jarnathan_us_male: 0.7918 [ElevenLabs / Eleven_v3]
Magnus_us_male: 0.7777 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Captivating Storyteller_us_male: 0.7473 [MiniMax / Speech_2.6_HD]
Liam_uk_male: 0.7387 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Jason_us_male: 0.7369 [Inworld / Realtime_TTS-2_-_Research_Preview]
Corin_us_male: 0.7323 [async / Async_Flash_v1.5]
Dan_uk_male: 0.7151 [ElevenLabs / Eleven_v3]
Leo_uk_male: 0.7126 [SpaceXAI / SpaceXAI_TTS]
Noble Cast_us_male: 0.7115 [StepFun / StepAudio_2.5_TTS]
Stellan_us_male: 0.7078 [Fish Audio / Fish_Audio_S2.1_Pro]
Nathaniel_uk_male: 0.7013 [ElevenLabs / Eleven_v3]
Felix_uk_male: 0.7008 [Inworld / Realtime_TTS-2_-_Research_Preview]
HT-M319_us_male: 0.6951 [StepFun / Step_Audio_EditX_Mar_2026]
Edward_uk_male: 0.6934 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Daniel_us_male: 0.6861 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Insightful Speaker_us_male: 0.6768 [MiniMax / Speech_2.6_HD]
Vibrant Youth_us_male: 0.6768 [StepFun / Step_TTS_2_Mar_2026]
Dorian_us_male: 0.6752 [SpeechifyAI / Simba_3.0]
Archie_uk_male: 0.6714 [SpeechifyAI / Simba_3.0]
Max_uk_male: 0.6712 [async / Async_Flash_v1.5]
Rhys_uk_male: 0.6695 [Fish Audio / Fish_Audio_S2.1_Pro]
Hayes_uk_male: 0.6635 [async / Async_Flash_v1.5]
Alistair_uk_male: 0.6614 [Fish Audio / Fish_Audio_S2.1_Pro]
Adrian_us_male: 0.6614 [Fish Audio / Fish_Audio_S2_Pro]
Alec_uk_male: 0.6597 [SpeechifyAI / Simba_3.0]
Clive_uk_male: 0.6569 [Inworld / Realtime_TTS-2_-_Research_Preview]
Duncan_uk_male: 0.6474 [Inworld / Realtime_TTS_1.5_Max]
Helix_us_male: 0.6368 [SpaceXAI / SpaceXAI_TTS]
Fisher_us_male: 0.6363 [async / Async_Flash_v1.5]
Douglas_us_male: 0.6347 [SpeechifyAI / Simba_3.0]
Altair_us_male: 0.6294 [SpaceXAI / SpaceXAI_TTS]
Patient Man_uk_male: 0.6250 [MiniMax / Speech_2.6_HD]
Liam_us_male: 0.6120 [ElevenLabs / Eleven_v3]
Jordan_us_male: 0.6033 [Fish Audio / Fish_Audio_S2_Pro]
Expressive Narrator_uk_male: 0.5123 [MiniMax / Speech_2.6_HD]
大厂最佳: Corey_us_male(0.7811)
Corey_us_male: 0.7811 [Cartesia / Sonic_3.5]
michael_us_male: 0.7759 [Alibaba / Fun-Realtime-TTS]
Dominic_us_male: 0.7564 [SpeechifyAI / Simba_3.2]
Wyatt_us_male: 0.7536 [SpeechifyAI / Simba_3.2]
Archie_uk_male: 0.7443 [Cartesia / Sonic_3.5]
arthur_uk_male: 0.7418 [Alibaba / Fun-Realtime-TTS]
Hugh_uk_male: 0.7257 [SpeechifyAI / Simba_3.2]
barry_uk_male: 0.7002 [Alibaba / Fun-Realtime-TTS]
George_uk_male: 0.7000 [Cartesia / Sonic_3.5]
Charon_us_male: 0.6943 [Google / Gemini_3.1_Flash_TTS]
Daniel_us_male: 0.6914 [Cartesia / Sonic_3.5]
Edmund_uk_male: 0.6776 [SpeechifyAI / Simba_3.2]
davis_us_male: 0.6690 [Alibaba / Fun-Realtime-TTS]
Fenrir_uk_male: 0.6580 [Google / Gemini_3.1_Flash_TTS]
Charon_uk_male: 0.6546 [Google / Gemini_3.1_Flash_TTS]
>>> right 最高: Reed_us_male(0.8238) [competitor]
决策: skip
原因: 两侧都是竞品 (Corin_us_male(0.8839) vs Reed_us_male(0.8238)) → 刷新
统计: 4 票 / 1 弃
───────────────────────────────────────────────────────
[18:36:29]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.7007)
Daniel: 0.7007 [—]
竞品最佳: Jason_us_male(0.7768)
Jason_us_male: 0.7768 [Inworld / Realtime_TTS-2_-_Research_Preview]
Liam_us_male: 0.7754 [ElevenLabs / Eleven_v3]
Noble Cast_us_male: 0.7732 [StepFun / StepAudio_2.5_TTS]
Alistair_uk_male: 0.7671 [Fish Audio / Fish_Audio_S2.1_Pro]
Expressive Narrator_uk_male: 0.7619 [MiniMax / Speech_2.6_HD]
Nathaniel_uk_male: 0.7603 [ElevenLabs / Eleven_v3]
Rhys_uk_male: 0.7601 [Fish Audio / Fish_Audio_S2.1_Pro]
Patient Man_uk_male: 0.7547 [MiniMax / Speech_2.6_HD]
Felix_uk_male: 0.7538 [Inworld / Realtime_TTS-2_-_Research_Preview]
Leo_uk_male: 0.7504 [SpaceXAI / SpaceXAI_TTS]
Duncan_uk_male: 0.7463 [Inworld / Realtime_TTS_1.5_Max]
Insightful Speaker_us_male: 0.7455 [MiniMax / Speech_2.6_HD]
Edward_uk_male: 0.7436 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Liam_uk_male: 0.7425 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Magnus_us_male: 0.7423 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Clive_uk_male: 0.7410 [Inworld / Realtime_TTS-2_-_Research_Preview]
Daniel_us_male: 0.7381 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Douglas_us_male: 0.7351 [SpeechifyAI / Simba_3.0]
Dan_uk_male: 0.7308 [ElevenLabs / Eleven_v3]
Reed_us_male: 0.7277 [Inworld / Realtime_TTS-2_-_Research_Preview]
Altair_us_male: 0.7182 [SpaceXAI / SpaceXAI_TTS]
Archie_uk_male: 0.7174 [SpeechifyAI / Simba_3.0]
Jarnathan_us_male: 0.7140 [ElevenLabs / Eleven_v3]
Jordan_us_male: 0.7043 [Fish Audio / Fish_Audio_S2_Pro]
Vibrant Youth_us_male: 0.7036 [StepFun / Step_TTS_2_Mar_2026]
Stellan_us_male: 0.6993 [Fish Audio / Fish_Audio_S2.1_Pro]
Corin_us_male: 0.6927 [async / Async_Flash_v1.5]
Alec_uk_male: 0.6754 [SpeechifyAI / Simba_3.0]
Max_uk_male: 0.6749 [async / Async_Flash_v1.5]
Fisher_us_male: 0.6746 [async / Async_Flash_v1.5]
Captivating Storyteller_us_male: 0.6744 [MiniMax / Speech_2.6_HD]
HT-M319_us_male: 0.6730 [StepFun / Step_Audio_EditX_Mar_2026]
Adrian_us_male: 0.6722 [Fish Audio / Fish_Audio_S2_Pro]
Hayes_uk_male: 0.6709 [async / Async_Flash_v1.5]
Dorian_us_male: 0.6460 [SpeechifyAI / Simba_3.0]
Helix_us_male: 0.6130 [SpaceXAI / SpaceXAI_TTS]
Sawyer_us_male: 0.6071 [Fish Audio / Fish_Audio_S2.1_Pro]
大厂最佳: michael_us_male(0.7758)
michael_us_male: 0.7758 [Alibaba / Fun-Realtime-TTS]
barry_uk_male: 0.7689 [Alibaba / Fun-Realtime-TTS]
Edmund_uk_male: 0.7619 [SpeechifyAI / Simba_3.2]
arthur_uk_male: 0.7577 [Alibaba / Fun-Realtime-TTS]
Charon_uk_male: 0.7543 [Google / Gemini_3.1_Flash_TTS]
Daniel_us_male: 0.7473 [Cartesia / Sonic_3.5]
Hugh_uk_male: 0.7403 [SpeechifyAI / Simba_3.2]
Charon_us_male: 0.7329 [Google / Gemini_3.1_Flash_TTS]
George_uk_male: 0.7246 [Cartesia / Sonic_3.5]
Corey_us_male: 0.7175 [Cartesia / Sonic_3.5]
Fenrir_uk_male: 0.7088 [Google / Gemini_3.1_Flash_TTS]
Archie_uk_male: 0.6889 [Cartesia / Sonic_3.5]
davis_us_male: 0.6776 [Alibaba / Fun-Realtime-TTS]
Dominic_us_male: 0.6673 [SpeechifyAI / Simba_3.2]
Wyatt_us_male: 0.5807 [SpeechifyAI / Simba_3.2]
>>> left 最高: Jason_us_male(0.7768) [competitor]
RIGHT 音频
我方最佳: Daniel(0.6732)
Daniel: 0.6732 [—]
竞品最佳: Max_uk_male(0.9790)
Max_uk_male: 0.9790 ← [async / Async_Flash_v1.5]
Archie_uk_male: 0.7525 [SpeechifyAI / Simba_3.0]
Adrian_us_male: 0.7509 [Fish Audio / Fish_Audio_S2_Pro]
Captivating Storyteller_us_male: 0.7475 [MiniMax / Speech_2.6_HD]
Jarnathan_us_male: 0.7468 [ElevenLabs / Eleven_v3]
Fisher_us_male: 0.7404 [async / Async_Flash_v1.5]
Felix_uk_male: 0.7402 [Inworld / Realtime_TTS-2_-_Research_Preview]
Reed_us_male: 0.7344 [Inworld / Realtime_TTS-2_-_Research_Preview]
Liam_us_male: 0.7317 [ElevenLabs / Eleven_v3]
Nathaniel_uk_male: 0.7188 [ElevenLabs / Eleven_v3]
Leo_uk_male: 0.7187 [SpaceXAI / SpaceXAI_TTS]
Duncan_uk_male: 0.7047 [Inworld / Realtime_TTS_1.5_Max]
Vibrant Youth_us_male: 0.6977 [StepFun / Step_TTS_2_Mar_2026]
Liam_uk_male: 0.6850 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
HT-M319_us_male: 0.6766 [StepFun / Step_Audio_EditX_Mar_2026]
Jason_us_male: 0.6714 [Inworld / Realtime_TTS-2_-_Research_Preview]
Alistair_uk_male: 0.6695 [Fish Audio / Fish_Audio_S2.1_Pro]
Dan_uk_male: 0.6663 [ElevenLabs / Eleven_v3]
Rhys_uk_male: 0.6639 [Fish Audio / Fish_Audio_S2.1_Pro]
Patient Man_uk_male: 0.6604 [MiniMax / Speech_2.6_HD]
Dorian_us_male: 0.6571 [SpeechifyAI / Simba_3.0]
Sawyer_us_male: 0.6530 [Fish Audio / Fish_Audio_S2.1_Pro]
Daniel_us_male: 0.6519 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Clive_uk_male: 0.6448 [Inworld / Realtime_TTS-2_-_Research_Preview]
Magnus_us_male: 0.6343 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Altair_us_male: 0.6336 [SpaceXAI / SpaceXAI_TTS]
Edward_uk_male: 0.6315 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Insightful Speaker_us_male: 0.6203 [MiniMax / Speech_2.6_HD]
Hayes_uk_male: 0.6203 [async / Async_Flash_v1.5]
Expressive Narrator_uk_male: 0.6171 [MiniMax / Speech_2.6_HD]
Noble Cast_us_male: 0.6153 [StepFun / StepAudio_2.5_TTS]
Jordan_us_male: 0.6084 [Fish Audio / Fish_Audio_S2_Pro]
Corin_us_male: 0.6028 [async / Async_Flash_v1.5]
Helix_us_male: 0.6017 [SpaceXAI / SpaceXAI_TTS]
Alec_uk_male: 0.5927 [SpeechifyAI / Simba_3.0]
Douglas_us_male: 0.5383 [SpeechifyAI / Simba_3.0]
Stellan_us_male: 0.5311 [Fish Audio / Fish_Audio_S2.1_Pro]
大厂最佳: Edmund_uk_male(0.7883)
Edmund_uk_male: 0.7883 [SpeechifyAI / Simba_3.2]
michael_us_male: 0.7756 [Alibaba / Fun-Realtime-TTS]
arthur_uk_male: 0.7736 [Alibaba / Fun-Realtime-TTS]
Hugh_uk_male: 0.7724 [SpeechifyAI / Simba_3.2]
Charon_uk_male: 0.7602 [Google / Gemini_3.1_Flash_TTS]
Daniel_us_male: 0.7516 [Cartesia / Sonic_3.5]
Charon_us_male: 0.7288 [Google / Gemini_3.1_Flash_TTS]
Wyatt_us_male: 0.7191 [SpeechifyAI / Simba_3.2]
davis_us_male: 0.7094 [Alibaba / Fun-Realtime-TTS]
Archie_uk_male: 0.7032 [Cartesia / Sonic_3.5]
Dominic_us_male: 0.6978 [SpeechifyAI / Simba_3.2]
Corey_us_male: 0.6800 [Cartesia / Sonic_3.5]
barry_uk_male: 0.6717 [Alibaba / Fun-Realtime-TTS]
George_uk_male: 0.6639 [Cartesia / Sonic_3.5]
Fenrir_uk_male: 0.6203 [Google / Gemini_3.1_Flash_TTS]
>>> right 最高: Max_uk_male(0.9790) [competitor]
决策: vote_left
原因: right 最高分为竞品 Max_uk_male(0.9790) → 投 left
统计: 5 票 / 1 弃
───────────────────────────────────────────────────────
[18:36:57]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.6346)
Daniel: 0.6346 [—]
竞品最佳: Fisher_us_male(0.8423)
Fisher_us_male: 0.8423 ← [async / Async_Flash_v1.5]
Vibrant Youth_us_male: 0.7988 [StepFun / Step_TTS_2_Mar_2026]
Duncan_uk_male: 0.7810 [Inworld / Realtime_TTS_1.5_Max]
Clive_uk_male: 0.7773 [Inworld / Realtime_TTS-2_-_Research_Preview]
Captivating Storyteller_us_male: 0.7766 [MiniMax / Speech_2.6_HD]
Liam_us_male: 0.7743 [ElevenLabs / Eleven_v3]
Jason_us_male: 0.7709 [Inworld / Realtime_TTS-2_-_Research_Preview]
HT-M319_us_male: 0.7689 [StepFun / Step_Audio_EditX_Mar_2026]
Archie_uk_male: 0.7573 [SpeechifyAI / Simba_3.0]
Reed_us_male: 0.7456 [Inworld / Realtime_TTS-2_-_Research_Preview]
Leo_uk_male: 0.7405 [SpaceXAI / SpaceXAI_TTS]
Expressive Narrator_uk_male: 0.7316 [MiniMax / Speech_2.6_HD]
Jarnathan_us_male: 0.7239 [ElevenLabs / Eleven_v3]
Daniel_us_male: 0.7142 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Altair_us_male: 0.7066 [SpaceXAI / SpaceXAI_TTS]
Max_uk_male: 0.6985 [async / Async_Flash_v1.5]
Dan_uk_male: 0.6976 [ElevenLabs / Eleven_v3]
Adrian_us_male: 0.6868 [Fish Audio / Fish_Audio_S2_Pro]
Felix_uk_male: 0.6850 [Inworld / Realtime_TTS-2_-_Research_Preview]
Edward_uk_male: 0.6841 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Douglas_us_male: 0.6823 [SpeechifyAI / Simba_3.0]
Noble Cast_us_male: 0.6789 [StepFun / StepAudio_2.5_TTS]
Sawyer_us_male: 0.6719 [Fish Audio / Fish_Audio_S2.1_Pro]
Alistair_uk_male: 0.6713 [Fish Audio / Fish_Audio_S2.1_Pro]
Jordan_us_male: 0.6566 [Fish Audio / Fish_Audio_S2_Pro]
Magnus_us_male: 0.6558 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Patient Man_uk_male: 0.6514 [MiniMax / Speech_2.6_HD]
Rhys_uk_male: 0.6485 [Fish Audio / Fish_Audio_S2.1_Pro]
Liam_uk_male: 0.6342 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Nathaniel_uk_male: 0.6313 [ElevenLabs / Eleven_v3]
Alec_uk_male: 0.6261 [SpeechifyAI / Simba_3.0]
Helix_us_male: 0.6237 [SpaceXAI / SpaceXAI_TTS]
Dorian_us_male: 0.6007 [SpeechifyAI / Simba_3.0]
Corin_us_male: 0.5986 [async / Async_Flash_v1.5]
Insightful Speaker_us_male: 0.5880 [MiniMax / Speech_2.6_HD]
Stellan_us_male: 0.5810 [Fish Audio / Fish_Audio_S2.1_Pro]
Hayes_uk_male: 0.5652 [async / Async_Flash_v1.5]
大厂最佳: Edmund_uk_male(0.8270)
Edmund_uk_male: 0.8270 ← [SpeechifyAI / Simba_3.2]
michael_us_male: 0.7815 [Alibaba / Fun-Realtime-TTS]
davis_us_male: 0.7790 [Alibaba / Fun-Realtime-TTS]
Charon_uk_male: 0.7786 [Google / Gemini_3.1_Flash_TTS]
Charon_us_male: 0.7637 [Google / Gemini_3.1_Flash_TTS]
arthur_uk_male: 0.7603 [Alibaba / Fun-Realtime-TTS]
Hugh_uk_male: 0.7534 [SpeechifyAI / Simba_3.2]
barry_uk_male: 0.7205 [Alibaba / Fun-Realtime-TTS]
Dominic_us_male: 0.7052 [SpeechifyAI / Simba_3.2]
George_uk_male: 0.6888 [Cartesia / Sonic_3.5]
Daniel_us_male: 0.6828 [Cartesia / Sonic_3.5]
Wyatt_us_male: 0.6532 [SpeechifyAI / Simba_3.2]
Fenrir_uk_male: 0.6189 [Google / Gemini_3.1_Flash_TTS]
Archie_uk_male: 0.6114 [Cartesia / Sonic_3.5]
Corey_us_male: 0.5813 [Cartesia / Sonic_3.5]
>>> left 最高: Fisher_us_male(0.8423) [competitor]
RIGHT 音频
我方最佳: Grace(0.4975)
Grace: 0.4975 [—]
Ella: 0.4947 [—]
竞品最佳: Eleanor_uk_female(0.6898)
Eleanor_uk_female: 0.6898 [Inworld / Realtime_TTS-2_-_Research_Preview]
Graceful Lady_uk_female: 0.6679 [MiniMax / Speech_2.6_HD]
Luna_us_female: 0.6520 [SpaceXAI / SpaceXAI_TTS]
Elizabeth_uk_female: 0.6495 [ElevenLabs / Eleven_v3]
Shelley_uk_female: 0.6443 [ElevenLabs / Eleven_v3]
Maeve_uk_female: 0.6400 [Fish Audio / Fish_Audio_S2.1_Pro]
Sophie_uk_female: 0.6380 [Inworld / Realtime_TTS-2_-_Research_Preview]
Briony_uk_female: 0.6112 [Fish Audio / Fish_Audio_S2.1_Pro]
Compelling Lady_uk_female: 0.6082 [MiniMax / Speech_2.6_HD]
Cleo_uk_female: 0.6069 [async / Async_Flash_v1.5]
Marnie_uk_female: 0.6005 [SpeechifyAI / Simba_3.0]
Jessica_us_female: 0.5838 [ElevenLabs / Eleven_v3]
Marley_us_female: 0.5779 [Fish Audio / Fish_Audio_S2.1_Pro]
Noah_uk_female: 0.5756 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Ashley_us_female: 0.5745 [Inworld / Realtime_TTS-2_-_Research_Preview]
Candid Girl_us_female: 0.5709 [StepFun / StepAudio_2.5_TTS]
Alice_uk_female: 0.5616 [SpeechifyAI / Simba_3.0]
Eve_uk_female: 0.5609 [SpaceXAI / SpaceXAI_TTS]
Geffen-v1_us_female: 0.5609 [SpeechifyAI / Simba_3.0]
Marlowe_us_female: 0.5536 [Fish Audio / Fish_Audio_S2.1_Pro]
Jennie_uk_female: 0.5527 [async / Async_Flash_v1.5]
Stella_us_female: 0.5501 [async / Async_Flash_v1.5]
Sabrina_us_female: 0.5396 [SpeechifyAI / Simba_3.0]
Laura_us_female: 0.5193 [ElevenLabs / Eleven_v3]
Captivating Female_us_female: 0.5156 [MiniMax / Speech_2.6_HD]
Lively Girl_us_female: 0.5107 [StepFun / StepAudio_2.5_TTS]
Quinn_us_female: 0.5096 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Elara_us_female: 0.5077 [async / Async_Flash_v1.5]
Sarah_us_female: 0.5029 [Fish Audio / Fish_Audio_S2_Pro]
Olivia_us_female: 0.4989 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
HT-F404_us_female: 0.4988 [StepFun / Step_Audio_EditX_Mar_2026]
Upbeat Woman_us_female: 0.4987 [MiniMax / Speech_2.6_HD]
Carina_us_female: 0.4661 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: Imogen_uk_female(0.6390)
Imogen_uk_female: 0.6390 [SpeechifyAI / Simba_3.2]
Zephyr_uk_female: 0.6383 [Google / Gemini_3.1_Flash_TTS]
charlotte_uk_female: 0.6380 [Alibaba / Fun-Realtime-TTS]
Aoede_uk_female: 0.5967 [Google / Gemini_3.1_Flash_TTS]
Zephyr_us_female: 0.5877 [Google / Gemini_3.1_Flash_TTS]
Gemma_uk_female: 0.5875 [Cartesia / Sonic_3.5]
Victoria_uk_female: 0.5867 [Cartesia / Sonic_3.5]
Beatrice_uk_female: 0.5826 [SpeechifyAI / Simba_3.2]
mary_uk_female: 0.5793 [Alibaba / Fun-Realtime-TTS]
Aoede_us_female: 0.5695 [Google / Gemini_3.1_Flash_TTS]
sarah_us_female: 0.5682 [Alibaba / Fun-Realtime-TTS]
Harper_us_female: 0.5604 [SpeechifyAI / Simba_3.2]
Caroline_us_female: 0.5590 [Cartesia / Sonic_3.5]
seline_us_female: 0.5546 [Alibaba / Fun-Realtime-TTS]
Geffen_us_female: 0.5373 [SpeechifyAI / Simba_3.2]
Skylar_us_female: 0.5244 [Cartesia / Sonic_3.5]
>>> right 最高: Eleanor_uk_female(0.6898) [competitor]
决策: vote_right
原因: left 最高分为竞品 Fisher_us_male(0.8423) → 投 right
统计: 6 票 / 1 弃
───────────────────────────────────────────────────────
[18:37:25]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Ella(0.6923)
Ella: 0.6923 [—]
Grace: 0.5981 [—]
竞品最佳: Alice_uk_female(0.8549)
Alice_uk_female: 0.8549 ← [SpeechifyAI / Simba_3.0]
Shelley_uk_female: 0.8504 ← [ElevenLabs / Eleven_v3]
Marlowe_us_female: 0.8006 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Sarah_us_female: 0.8001 ← [Fish Audio / Fish_Audio_S2_Pro]
Geffen-v1_us_female: 0.7924 [SpeechifyAI / Simba_3.0]
Laura_us_female: 0.7838 [ElevenLabs / Eleven_v3]
Eve_uk_female: 0.7793 [SpaceXAI / SpaceXAI_TTS]
Briony_uk_female: 0.7772 [Fish Audio / Fish_Audio_S2.1_Pro]
Stella_us_female: 0.7728 [async / Async_Flash_v1.5]
Jessica_us_female: 0.7580 [ElevenLabs / Eleven_v3]
Upbeat Woman_us_female: 0.7577 [MiniMax / Speech_2.6_HD]
Candid Girl_us_female: 0.7570 [StepFun / StepAudio_2.5_TTS]
Marley_us_female: 0.7536 [Fish Audio / Fish_Audio_S2.1_Pro]
Captivating Female_us_female: 0.7497 [MiniMax / Speech_2.6_HD]
Maeve_uk_female: 0.7374 [Fish Audio / Fish_Audio_S2.1_Pro]
Sabrina_us_female: 0.7294 [SpeechifyAI / Simba_3.0]
Cleo_uk_female: 0.7268 [async / Async_Flash_v1.5]
Compelling Lady_uk_female: 0.7254 [MiniMax / Speech_2.6_HD]
Elara_us_female: 0.7214 [async / Async_Flash_v1.5]
Lively Girl_us_female: 0.7173 [StepFun / StepAudio_2.5_TTS]
Graceful Lady_uk_female: 0.7161 [MiniMax / Speech_2.6_HD]
Olivia_us_female: 0.7056 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Carina_us_female: 0.7028 [SpaceXAI / SpaceXAI_TTS]
Elizabeth_uk_female: 0.7016 [ElevenLabs / Eleven_v3]
Quinn_us_female: 0.7014 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Sophie_uk_female: 0.7004 [Inworld / Realtime_TTS-2_-_Research_Preview]
Ashley_us_female: 0.6988 [Inworld / Realtime_TTS-2_-_Research_Preview]
Marnie_uk_female: 0.6986 [SpeechifyAI / Simba_3.0]
HT-F404_us_female: 0.6942 [StepFun / Step_Audio_EditX_Mar_2026]
Jennie_uk_female: 0.6749 [async / Async_Flash_v1.5]
Luna_us_female: 0.6740 [SpaceXAI / SpaceXAI_TTS]
Noah_uk_female: 0.6685 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Eleanor_uk_female: 0.6598 [Inworld / Realtime_TTS-2_-_Research_Preview]
大厂最佳: Victoria_uk_female(0.8211)
Victoria_uk_female: 0.8211 ← [Cartesia / Sonic_3.5]
Beatrice_uk_female: 0.8185 ← [SpeechifyAI / Simba_3.2]
Aoede_us_female: 0.8006 ← [Google / Gemini_3.1_Flash_TTS]
Geffen_us_female: 0.8004 ← [SpeechifyAI / Simba_3.2]
Zephyr_us_female: 0.7961 [Google / Gemini_3.1_Flash_TTS]
Aoede_uk_female: 0.7956 [Google / Gemini_3.1_Flash_TTS]
Harper_us_female: 0.7891 [SpeechifyAI / Simba_3.2]
Skylar_us_female: 0.7786 [Cartesia / Sonic_3.5]
Gemma_uk_female: 0.7591 [Cartesia / Sonic_3.5]
Zephyr_uk_female: 0.7478 [Google / Gemini_3.1_Flash_TTS]
mary_uk_female: 0.7332 [Alibaba / Fun-Realtime-TTS]
Caroline_us_female: 0.7293 [Cartesia / Sonic_3.5]
charlotte_uk_female: 0.7220 [Alibaba / Fun-Realtime-TTS]
seline_us_female: 0.7150 [Alibaba / Fun-Realtime-TTS]
sarah_us_female: 0.7091 [Alibaba / Fun-Realtime-TTS]
Imogen_uk_female: 0.6951 [SpeechifyAI / Simba_3.2]
>>> left 最高: Alice_uk_female(0.8549) [competitor]
RIGHT 音频
我方最佳: Ella(0.7451)
Ella: 0.7451 [—]
Grace: 0.7372 [—]
竞品最佳: Marlowe_us_female(0.8435)
Marlowe_us_female: 0.8435 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Sarah_us_female: 0.8398 ← [Fish Audio / Fish_Audio_S2_Pro]
Alice_uk_female: 0.8382 ← [SpeechifyAI / Simba_3.0]
Laura_us_female: 0.8037 ← [ElevenLabs / Eleven_v3]
Eve_uk_female: 0.7988 [SpaceXAI / SpaceXAI_TTS]
Shelley_uk_female: 0.7933 [ElevenLabs / Eleven_v3]
Marley_us_female: 0.7931 [Fish Audio / Fish_Audio_S2.1_Pro]
Upbeat Woman_us_female: 0.7684 [MiniMax / Speech_2.6_HD]
Candid Girl_us_female: 0.7641 [StepFun / StepAudio_2.5_TTS]
Ashley_us_female: 0.7606 [Inworld / Realtime_TTS-2_-_Research_Preview]
Geffen-v1_us_female: 0.7598 [SpeechifyAI / Simba_3.0]
Captivating Female_us_female: 0.7515 [MiniMax / Speech_2.6_HD]
Luna_us_female: 0.7445 [SpaceXAI / SpaceXAI_TTS]
Carina_us_female: 0.7376 [SpaceXAI / SpaceXAI_TTS]
Elara_us_female: 0.7362 [async / Async_Flash_v1.5]
Jessica_us_female: 0.7352 [ElevenLabs / Eleven_v3]
Maeve_uk_female: 0.7330 [Fish Audio / Fish_Audio_S2.1_Pro]
Stella_us_female: 0.7315 [async / Async_Flash_v1.5]
Sabrina_us_female: 0.7287 [SpeechifyAI / Simba_3.0]
Graceful Lady_uk_female: 0.7258 [MiniMax / Speech_2.6_HD]
Briony_uk_female: 0.7198 [Fish Audio / Fish_Audio_S2.1_Pro]
Jennie_uk_female: 0.7167 [async / Async_Flash_v1.5]
Compelling Lady_uk_female: 0.7118 [MiniMax / Speech_2.6_HD]
Cleo_uk_female: 0.7113 [async / Async_Flash_v1.5]
Lively Girl_us_female: 0.7054 [StepFun / StepAudio_2.5_TTS]
Elizabeth_uk_female: 0.7046 [ElevenLabs / Eleven_v3]
Olivia_us_female: 0.6954 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
HT-F404_us_female: 0.6838 [StepFun / Step_Audio_EditX_Mar_2026]
Quinn_us_female: 0.6825 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Sophie_uk_female: 0.6773 [Inworld / Realtime_TTS-2_-_Research_Preview]
Eleanor_uk_female: 0.6763 [Inworld / Realtime_TTS-2_-_Research_Preview]
Marnie_uk_female: 0.6308 [SpeechifyAI / Simba_3.0]
Noah_uk_female: 0.5860 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
大厂最佳: Victoria_uk_female(0.8179)
Victoria_uk_female: 0.8179 ← [Cartesia / Sonic_3.5]
Skylar_us_female: 0.8165 ← [Cartesia / Sonic_3.5]
Zephyr_us_female: 0.7968 [Google / Gemini_3.1_Flash_TTS]
Aoede_us_female: 0.7787 [Google / Gemini_3.1_Flash_TTS]
Harper_us_female: 0.7785 [SpeechifyAI / Simba_3.2]
charlotte_uk_female: 0.7699 [Alibaba / Fun-Realtime-TTS]
Aoede_uk_female: 0.7661 [Google / Gemini_3.1_Flash_TTS]
mary_uk_female: 0.7507 [Alibaba / Fun-Realtime-TTS]
Zephyr_uk_female: 0.7484 [Google / Gemini_3.1_Flash_TTS]
Geffen_us_female: 0.7434 [SpeechifyAI / Simba_3.2]
Beatrice_uk_female: 0.7381 [SpeechifyAI / Simba_3.2]
sarah_us_female: 0.7165 [Alibaba / Fun-Realtime-TTS]
Caroline_us_female: 0.7063 [Cartesia / Sonic_3.5]
Gemma_uk_female: 0.7005 [Cartesia / Sonic_3.5]
seline_us_female: 0.6988 [Alibaba / Fun-Realtime-TTS]
Imogen_uk_female: 0.6258 [SpeechifyAI / Simba_3.2]
>>> right 最高: Marlowe_us_female(0.8435) [competitor]
决策: skip
原因: 两侧都是竞品 (Alice_uk_female(0.8549) vs Marlowe_us_female(0.8435)) → 刷新
统计: 6 票 / 2 弃
───────────────────────────────────────────────────────
[18:37:40]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.4466)
Daniel: 0.4466 [—]
竞品最佳: Dan_uk_male(0.5955)
Dan_uk_male: 0.5955 [ElevenLabs / Eleven_v3]
Edward_uk_male: 0.5850 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Expressive Narrator_uk_male: 0.5777 [MiniMax / Speech_2.6_HD]
Hayes_uk_male: 0.5695 [async / Async_Flash_v1.5]
Altair_us_male: 0.5689 [SpaceXAI / SpaceXAI_TTS]
Insightful Speaker_us_male: 0.5686 [MiniMax / Speech_2.6_HD]
Stellan_us_male: 0.5629 [Fish Audio / Fish_Audio_S2.1_Pro]
Leo_uk_male: 0.5616 [SpaceXAI / SpaceXAI_TTS]
Vibrant Youth_us_male: 0.5611 [StepFun / Step_TTS_2_Mar_2026]
Jason_us_male: 0.5589 [Inworld / Realtime_TTS-2_-_Research_Preview]
HT-M319_us_male: 0.5514 [StepFun / Step_Audio_EditX_Mar_2026]
Corin_us_male: 0.5459 [async / Async_Flash_v1.5]
Noble Cast_us_male: 0.5425 [StepFun / StepAudio_2.5_TTS]
Patient Man_uk_male: 0.5417 [MiniMax / Speech_2.6_HD]
Magnus_us_male: 0.5391 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Adrian_us_male: 0.5345 [Fish Audio / Fish_Audio_S2_Pro]
Jordan_us_male: 0.5117 [Fish Audio / Fish_Audio_S2_Pro]
Felix_uk_male: 0.5100 [Inworld / Realtime_TTS-2_-_Research_Preview]
Nathaniel_uk_male: 0.5089 [ElevenLabs / Eleven_v3]
Daniel_us_male: 0.5073 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Duncan_uk_male: 0.5070 [Inworld / Realtime_TTS_1.5_Max]
Clive_uk_male: 0.5045 [Inworld / Realtime_TTS-2_-_Research_Preview]
Captivating Storyteller_us_male: 0.5019 [MiniMax / Speech_2.6_HD]
Reed_us_male: 0.5001 [Inworld / Realtime_TTS-2_-_Research_Preview]
Jarnathan_us_male: 0.4963 [ElevenLabs / Eleven_v3]
Douglas_us_male: 0.4955 [SpeechifyAI / Simba_3.0]
Alec_uk_male: 0.4935 [SpeechifyAI / Simba_3.0]
Max_uk_male: 0.4915 [async / Async_Flash_v1.5]
Liam_us_male: 0.4881 [ElevenLabs / Eleven_v3]
Helix_us_male: 0.4841 [SpaceXAI / SpaceXAI_TTS]
Rhys_uk_male: 0.4800 [Fish Audio / Fish_Audio_S2.1_Pro]
Fisher_us_male: 0.4743 [async / Async_Flash_v1.5]
Liam_uk_male: 0.4701 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Dorian_us_male: 0.4445 [SpeechifyAI / Simba_3.0]
Alistair_uk_male: 0.4399 [Fish Audio / Fish_Audio_S2.1_Pro]
Archie_uk_male: 0.4374 [SpeechifyAI / Simba_3.0]
Sawyer_us_male: 0.4369 [Fish Audio / Fish_Audio_S2.1_Pro]
大厂最佳: Fenrir_uk_male(0.7756)
Fenrir_uk_male: 0.7756 [Google / Gemini_3.1_Flash_TTS]
Charon_uk_male: 0.6267 [Google / Gemini_3.1_Flash_TTS]
George_uk_male: 0.6097 [Cartesia / Sonic_3.5]
Archie_uk_male: 0.5728 [Cartesia / Sonic_3.5]
Dominic_us_male: 0.5622 [SpeechifyAI / Simba_3.2]
Daniel_us_male: 0.5595 [Cartesia / Sonic_3.5]
michael_us_male: 0.5561 [Alibaba / Fun-Realtime-TTS]
Charon_us_male: 0.5526 [Google / Gemini_3.1_Flash_TTS]
arthur_uk_male: 0.5523 [Alibaba / Fun-Realtime-TTS]
Corey_us_male: 0.5497 [Cartesia / Sonic_3.5]
barry_uk_male: 0.5359 [Alibaba / Fun-Realtime-TTS]
Wyatt_us_male: 0.5330 [SpeechifyAI / Simba_3.2]
davis_us_male: 0.5274 [Alibaba / Fun-Realtime-TTS]
Hugh_uk_male: 0.5019 [SpeechifyAI / Simba_3.2]
Edmund_uk_male: 0.4948 [SpeechifyAI / Simba_3.2]
>>> left 最高: Fenrir_uk_male(0.7756) [big_vendor]
RIGHT 音频
我方最佳: Ella(0.7419)
Ella: 0.7419 [—]
Grace: 0.6542 [—]
竞品最佳: Alice_uk_female(0.8704)
Alice_uk_female: 0.8704 ← [SpeechifyAI / Simba_3.0]
Marlowe_us_female: 0.8536 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Sarah_us_female: 0.8433 ← [Fish Audio / Fish_Audio_S2_Pro]
Laura_us_female: 0.8297 ← [ElevenLabs / Eleven_v3]
Shelley_uk_female: 0.8263 ← [ElevenLabs / Eleven_v3]
Marley_us_female: 0.8135 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Geffen-v1_us_female: 0.8086 ← [SpeechifyAI / Simba_3.0]
Jessica_us_female: 0.8078 ← [ElevenLabs / Eleven_v3]
Upbeat Woman_us_female: 0.8068 ← [MiniMax / Speech_2.6_HD]
Candid Girl_us_female: 0.8027 ← [StepFun / StepAudio_2.5_TTS]
Eve_uk_female: 0.8002 ← [SpaceXAI / SpaceXAI_TTS]
Captivating Female_us_female: 0.7979 [MiniMax / Speech_2.6_HD]
Stella_us_female: 0.7948 [async / Async_Flash_v1.5]
Elara_us_female: 0.7859 [async / Async_Flash_v1.5]
Compelling Lady_uk_female: 0.7767 [MiniMax / Speech_2.6_HD]
Briony_uk_female: 0.7759 [Fish Audio / Fish_Audio_S2.1_Pro]
Carina_us_female: 0.7713 [SpaceXAI / SpaceXAI_TTS]
Lively Girl_us_female: 0.7640 [StepFun / StepAudio_2.5_TTS]
Quinn_us_female: 0.7602 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Ashley_us_female: 0.7526 [Inworld / Realtime_TTS-2_-_Research_Preview]
Sabrina_us_female: 0.7514 [SpeechifyAI / Simba_3.0]
HT-F404_us_female: 0.7507 [StepFun / Step_Audio_EditX_Mar_2026]
Maeve_uk_female: 0.7505 [Fish Audio / Fish_Audio_S2.1_Pro]
Luna_us_female: 0.7423 [SpaceXAI / SpaceXAI_TTS]
Olivia_us_female: 0.7407 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Elizabeth_uk_female: 0.7313 [ElevenLabs / Eleven_v3]
Sophie_uk_female: 0.7273 [Inworld / Realtime_TTS-2_-_Research_Preview]
Graceful Lady_uk_female: 0.7271 [MiniMax / Speech_2.6_HD]
Cleo_uk_female: 0.7246 [async / Async_Flash_v1.5]
Marnie_uk_female: 0.7165 [SpeechifyAI / Simba_3.0]
Eleanor_uk_female: 0.7153 [Inworld / Realtime_TTS-2_-_Research_Preview]
Jennie_uk_female: 0.7018 [async / Async_Flash_v1.5]
Noah_uk_female: 0.6626 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
大厂最佳: Beatrice_uk_female(0.8292)
Beatrice_uk_female: 0.8292 ← [SpeechifyAI / Simba_3.2]
Skylar_us_female: 0.8184 ← [Cartesia / Sonic_3.5]
Geffen_us_female: 0.8181 ← [SpeechifyAI / Simba_3.2]
Aoede_us_female: 0.8112 ← [Google / Gemini_3.1_Flash_TTS]
Zephyr_us_female: 0.8075 ← [Google / Gemini_3.1_Flash_TTS]
Gemma_uk_female: 0.8032 ← [Cartesia / Sonic_3.5]
Victoria_uk_female: 0.8015 ← [Cartesia / Sonic_3.5]
Harper_us_female: 0.7972 [SpeechifyAI / Simba_3.2]
Aoede_uk_female: 0.7921 [Google / Gemini_3.1_Flash_TTS]
Caroline_us_female: 0.7705 [Cartesia / Sonic_3.5]
mary_uk_female: 0.7615 [Alibaba / Fun-Realtime-TTS]
Zephyr_uk_female: 0.7570 [Google / Gemini_3.1_Flash_TTS]
sarah_us_female: 0.7488 [Alibaba / Fun-Realtime-TTS]
charlotte_uk_female: 0.7242 [Alibaba / Fun-Realtime-TTS]
seline_us_female: 0.7038 [Alibaba / Fun-Realtime-TTS]
Imogen_uk_female: 0.6993 [SpeechifyAI / Simba_3.2]
>>> right 最高: Alice_uk_female(0.8704) [competitor]
决策: vote_left
原因: right 最高分为竞品 Alice_uk_female(0.8704) → 投 left
统计: 7 票 / 2 弃
───────────────────────────────────────────────────────
[18:38:09]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Ella(0.7249)
Ella: 0.7249 [—]
Grace: 0.6810 [—]
竞品最佳: Briony_uk_female(0.9625)
Briony_uk_female: 0.9625 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Shelley_uk_female: 0.8783 ← [ElevenLabs / Eleven_v3]
Alice_uk_female: 0.8400 ← [SpeechifyAI / Simba_3.0]
Marley_us_female: 0.8360 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Eleanor_uk_female: 0.8335 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Elizabeth_uk_female: 0.8330 ← [ElevenLabs / Eleven_v3]
Sarah_us_female: 0.8242 ← [Fish Audio / Fish_Audio_S2_Pro]
Graceful Lady_uk_female: 0.8122 ← [MiniMax / Speech_2.6_HD]
Eve_uk_female: 0.8111 ← [SpaceXAI / SpaceXAI_TTS]
Stella_us_female: 0.8078 ← [async / Async_Flash_v1.5]
Candid Girl_us_female: 0.8066 ← [StepFun / StepAudio_2.5_TTS]
Jessica_us_female: 0.7993 [ElevenLabs / Eleven_v3]
Geffen-v1_us_female: 0.7989 [SpeechifyAI / Simba_3.0]
Cleo_uk_female: 0.7957 [async / Async_Flash_v1.5]
Luna_us_female: 0.7885 [SpaceXAI / SpaceXAI_TTS]
Captivating Female_us_female: 0.7855 [MiniMax / Speech_2.6_HD]
Maeve_uk_female: 0.7854 [Fish Audio / Fish_Audio_S2.1_Pro]
Upbeat Woman_us_female: 0.7851 [MiniMax / Speech_2.6_HD]
Ashley_us_female: 0.7769 [Inworld / Realtime_TTS-2_-_Research_Preview]
Marlowe_us_female: 0.7707 [Fish Audio / Fish_Audio_S2.1_Pro]
Sophie_uk_female: 0.7624 [Inworld / Realtime_TTS-2_-_Research_Preview]
Compelling Lady_uk_female: 0.7571 [MiniMax / Speech_2.6_HD]
Noah_uk_female: 0.7525 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Sabrina_us_female: 0.7510 [SpeechifyAI / Simba_3.0]
Marnie_uk_female: 0.7463 [SpeechifyAI / Simba_3.0]
Jennie_uk_female: 0.7347 [async / Async_Flash_v1.5]
Laura_us_female: 0.7266 [ElevenLabs / Eleven_v3]
Olivia_us_female: 0.7217 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Quinn_us_female: 0.7094 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Lively Girl_us_female: 0.6931 [StepFun / StepAudio_2.5_TTS]
Elara_us_female: 0.6887 [async / Async_Flash_v1.5]
HT-F404_us_female: 0.6831 [StepFun / Step_Audio_EditX_Mar_2026]
Carina_us_female: 0.6220 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: Victoria_uk_female(0.8643)
Victoria_uk_female: 0.8643 ← [Cartesia / Sonic_3.5]
Zephyr_uk_female: 0.8416 ← [Google / Gemini_3.1_Flash_TTS]
Beatrice_uk_female: 0.8382 ← [SpeechifyAI / Simba_3.2]
Aoede_uk_female: 0.8213 ← [Google / Gemini_3.1_Flash_TTS]
Harper_us_female: 0.8161 ← [SpeechifyAI / Simba_3.2]
Geffen_us_female: 0.8091 ← [SpeechifyAI / Simba_3.2]
Aoede_us_female: 0.8039 ← [Google / Gemini_3.1_Flash_TTS]
charlotte_uk_female: 0.8027 ← [Alibaba / Fun-Realtime-TTS]
Imogen_uk_female: 0.7963 [SpeechifyAI / Simba_3.2]
Zephyr_us_female: 0.7880 [Google / Gemini_3.1_Flash_TTS]
Skylar_us_female: 0.7799 [Cartesia / Sonic_3.5]
sarah_us_female: 0.7697 [Alibaba / Fun-Realtime-TTS]
mary_uk_female: 0.7652 [Alibaba / Fun-Realtime-TTS]
seline_us_female: 0.7647 [Alibaba / Fun-Realtime-TTS]
Gemma_uk_female: 0.7296 [Cartesia / Sonic_3.5]
Caroline_us_female: 0.7010 [Cartesia / Sonic_3.5]
>>> left 最高: Briony_uk_female(0.9625) [competitor]
RIGHT 音频
我方最佳: Ella(0.7543)
Ella: 0.7543 [—]
Grace: 0.6269 [—]
竞品最佳: Sophie_uk_female(0.8774)
Sophie_uk_female: 0.8774 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Jennie_uk_female: 0.8462 ← [async / Async_Flash_v1.5]
Eleanor_uk_female: 0.8191 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Cleo_uk_female: 0.8115 ← [async / Async_Flash_v1.5]
Ashley_us_female: 0.8076 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Briony_uk_female: 0.8020 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Marnie_uk_female: 0.7997 [SpeechifyAI / Simba_3.0]
Compelling Lady_uk_female: 0.7955 [MiniMax / Speech_2.6_HD]
Jessica_us_female: 0.7725 [ElevenLabs / Eleven_v3]
Shelley_uk_female: 0.7718 [ElevenLabs / Eleven_v3]
Marley_us_female: 0.7639 [Fish Audio / Fish_Audio_S2.1_Pro]
Maeve_uk_female: 0.7628 [Fish Audio / Fish_Audio_S2.1_Pro]
Noah_uk_female: 0.7525 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Eve_uk_female: 0.7502 [SpaceXAI / SpaceXAI_TTS]
Lively Girl_us_female: 0.7421 [StepFun / StepAudio_2.5_TTS]
HT-F404_us_female: 0.7415 [StepFun / Step_Audio_EditX_Mar_2026]
Graceful Lady_uk_female: 0.7374 [MiniMax / Speech_2.6_HD]
Elizabeth_uk_female: 0.7373 [ElevenLabs / Eleven_v3]
Geffen-v1_us_female: 0.7320 [SpeechifyAI / Simba_3.0]
Luna_us_female: 0.7319 [SpaceXAI / SpaceXAI_TTS]
Stella_us_female: 0.7273 [async / Async_Flash_v1.5]
Olivia_us_female: 0.7271 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Sabrina_us_female: 0.7268 [SpeechifyAI / Simba_3.0]
Candid Girl_us_female: 0.7129 [StepFun / StepAudio_2.5_TTS]
Sarah_us_female: 0.7090 [Fish Audio / Fish_Audio_S2_Pro]
Quinn_us_female: 0.7013 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Marlowe_us_female: 0.6992 [Fish Audio / Fish_Audio_S2.1_Pro]
Upbeat Woman_us_female: 0.6861 [MiniMax / Speech_2.6_HD]
Alice_uk_female: 0.6832 [SpeechifyAI / Simba_3.0]
Captivating Female_us_female: 0.6820 [MiniMax / Speech_2.6_HD]
Laura_us_female: 0.6626 [ElevenLabs / Eleven_v3]
Elara_us_female: 0.6391 [async / Async_Flash_v1.5]
Carina_us_female: 0.5767 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: mary_uk_female(0.8518)
mary_uk_female: 0.8518 ← [Alibaba / Fun-Realtime-TTS]
Zephyr_uk_female: 0.8361 ← [Google / Gemini_3.1_Flash_TTS]
Victoria_uk_female: 0.8356 ← [Cartesia / Sonic_3.5]
sarah_us_female: 0.8200 ← [Alibaba / Fun-Realtime-TTS]
Imogen_uk_female: 0.8086 ← [SpeechifyAI / Simba_3.2]
charlotte_uk_female: 0.7898 [Alibaba / Fun-Realtime-TTS]
Aoede_uk_female: 0.7859 [Google / Gemini_3.1_Flash_TTS]
Beatrice_uk_female: 0.7831 [SpeechifyAI / Simba_3.2]
Zephyr_us_female: 0.7827 [Google / Gemini_3.1_Flash_TTS]
Gemma_uk_female: 0.7757 [Cartesia / Sonic_3.5]
seline_us_female: 0.7600 [Alibaba / Fun-Realtime-TTS]
Aoede_us_female: 0.7270 [Google / Gemini_3.1_Flash_TTS]
Geffen_us_female: 0.7141 [SpeechifyAI / Simba_3.2]
Harper_us_female: 0.7119 [SpeechifyAI / Simba_3.2]
Skylar_us_female: 0.6887 [Cartesia / Sonic_3.5]
Caroline_us_female: 0.6829 [Cartesia / Sonic_3.5]
>>> right 最高: Sophie_uk_female(0.8774) [competitor]
决策: skip
原因: 两侧都是竞品 (Briony_uk_female(0.9625) vs Sophie_uk_female(0.8774)) → 刷新
统计: 7 票 / 3 弃
───────────────────────────────────────────────────────
[18:38:26]
───────────────────────────────────────────────────────
LEFT 音频
我方最佳: Daniel(0.7210)
Daniel: 0.7210 [—]
竞品最佳: Edward_uk_male(0.8774)
Edward_uk_male: 0.8774 ← [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Leo_uk_male: 0.8498 ← [SpaceXAI / SpaceXAI_TTS]
Dan_uk_male: 0.8422 ← [ElevenLabs / Eleven_v3]
Rhys_uk_male: 0.8380 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Patient Man_uk_male: 0.8313 ← [MiniMax / Speech_2.6_HD]
Duncan_uk_male: 0.8276 ← [Inworld / Realtime_TTS_1.5_Max]
Liam_uk_male: 0.8262 ← [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Alistair_uk_male: 0.8071 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Clive_uk_male: 0.8050 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Felix_uk_male: 0.8010 ← [Inworld / Realtime_TTS-2_-_Research_Preview]
Nathaniel_uk_male: 0.7902 [ElevenLabs / Eleven_v3]
Alec_uk_male: 0.7846 [SpeechifyAI / Simba_3.0]
Archie_uk_male: 0.7782 [SpeechifyAI / Simba_3.0]
Daniel_us_male: 0.7740 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Jarnathan_us_male: 0.7693 [ElevenLabs / Eleven_v3]
Hayes_uk_male: 0.7638 [async / Async_Flash_v1.5]
Reed_us_male: 0.7619 [Inworld / Realtime_TTS-2_-_Research_Preview]
Noble Cast_us_male: 0.7570 [StepFun / StepAudio_2.5_TTS]
Sawyer_us_male: 0.7371 [Fish Audio / Fish_Audio_S2.1_Pro]
Jason_us_male: 0.7358 [Inworld / Realtime_TTS-2_-_Research_Preview]
Jordan_us_male: 0.7290 [Fish Audio / Fish_Audio_S2_Pro]
Magnus_us_male: 0.7237 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Expressive Narrator_uk_male: 0.7214 [MiniMax / Speech_2.6_HD]
Corin_us_male: 0.7192 [async / Async_Flash_v1.5]
Max_uk_male: 0.7089 [async / Async_Flash_v1.5]
Stellan_us_male: 0.7081 [Fish Audio / Fish_Audio_S2.1_Pro]
Captivating Storyteller_us_male: 0.7043 [MiniMax / Speech_2.6_HD]
Douglas_us_male: 0.7005 [SpeechifyAI / Simba_3.0]
Vibrant Youth_us_male: 0.6807 [StepFun / Step_TTS_2_Mar_2026]
Dorian_us_male: 0.6671 [SpeechifyAI / Simba_3.0]
Altair_us_male: 0.6614 [SpaceXAI / SpaceXAI_TTS]
Liam_us_male: 0.6610 [ElevenLabs / Eleven_v3]
Insightful Speaker_us_male: 0.6603 [MiniMax / Speech_2.6_HD]
HT-M319_us_male: 0.6532 [StepFun / Step_Audio_EditX_Mar_2026]
Adrian_us_male: 0.6482 [Fish Audio / Fish_Audio_S2_Pro]
Fisher_us_male: 0.5909 [async / Async_Flash_v1.5]
Helix_us_male: 0.5842 [SpaceXAI / SpaceXAI_TTS]
大厂最佳: Edmund_uk_male(0.8986)
Edmund_uk_male: 0.8986 ← [SpeechifyAI / Simba_3.2]
arthur_uk_male: 0.8406 ← [Alibaba / Fun-Realtime-TTS]
Corey_us_male: 0.8088 ← [Cartesia / Sonic_3.5]
barry_uk_male: 0.7986 [Alibaba / Fun-Realtime-TTS]
Hugh_uk_male: 0.7965 [SpeechifyAI / Simba_3.2]
George_uk_male: 0.7815 [Cartesia / Sonic_3.5]
Archie_uk_male: 0.7802 [Cartesia / Sonic_3.5]
Charon_uk_male: 0.7723 [Google / Gemini_3.1_Flash_TTS]
Charon_us_male: 0.7604 [Google / Gemini_3.1_Flash_TTS]
michael_us_male: 0.7368 [Alibaba / Fun-Realtime-TTS]
Fenrir_uk_male: 0.7259 [Google / Gemini_3.1_Flash_TTS]
Daniel_us_male: 0.7132 [Cartesia / Sonic_3.5]
davis_us_male: 0.6997 [Alibaba / Fun-Realtime-TTS]
Dominic_us_male: 0.6620 [SpeechifyAI / Simba_3.2]
Wyatt_us_male: 0.6188 [SpeechifyAI / Simba_3.2]
>>> left 最高: Edmund_uk_male(0.8986) [big_vendor]
RIGHT 音频
我方最佳: Daniel(0.6586)
Daniel: 0.6586 [—]
竞品最佳: Edward_uk_male(0.8315)
Edward_uk_male: 0.8315 ← [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Rhys_uk_male: 0.8116 ← [Fish Audio / Fish_Audio_S2.1_Pro]
Leo_uk_male: 0.7984 [SpaceXAI / SpaceXAI_TTS]
Liam_uk_male: 0.7811 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Dan_uk_male: 0.7711 [ElevenLabs / Eleven_v3]
Patient Man_uk_male: 0.7653 [MiniMax / Speech_2.6_HD]
Jarnathan_us_male: 0.7603 [ElevenLabs / Eleven_v3]
Sawyer_us_male: 0.7558 [Fish Audio / Fish_Audio_S2.1_Pro]
Duncan_uk_male: 0.7425 [Inworld / Realtime_TTS_1.5_Max]
Archie_uk_male: 0.7387 [SpeechifyAI / Simba_3.0]
Alistair_uk_male: 0.7385 [Fish Audio / Fish_Audio_S2.1_Pro]
Clive_uk_male: 0.7380 [Inworld / Realtime_TTS-2_-_Research_Preview]
Alec_uk_male: 0.7285 [SpeechifyAI / Simba_3.0]
Felix_uk_male: 0.7212 [Inworld / Realtime_TTS-2_-_Research_Preview]
Nathaniel_uk_male: 0.7192 [ElevenLabs / Eleven_v3]
Max_uk_male: 0.7047 [async / Async_Flash_v1.5]
Reed_us_male: 0.7009 [Inworld / Realtime_TTS-2_-_Research_Preview]
Hayes_uk_male: 0.7004 [async / Async_Flash_v1.5]
Magnus_us_male: 0.6792 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Captivating Storyteller_us_male: 0.6710 [MiniMax / Speech_2.6_HD]
Daniel_us_male: 0.6706 [Smallest.ai / Lightning_V3.1_Pro_TTS_Jun_2026]
Jason_us_male: 0.6670 [Inworld / Realtime_TTS-2_-_Research_Preview]
Adrian_us_male: 0.6517 [Fish Audio / Fish_Audio_S2_Pro]
Jordan_us_male: 0.6462 [Fish Audio / Fish_Audio_S2_Pro]
Expressive Narrator_uk_male: 0.6436 [MiniMax / Speech_2.6_HD]
Vibrant Youth_us_male: 0.6413 [StepFun / Step_TTS_2_Mar_2026]
Insightful Speaker_us_male: 0.6381 [MiniMax / Speech_2.6_HD]
Stellan_us_male: 0.6321 [Fish Audio / Fish_Audio_S2.1_Pro]
Corin_us_male: 0.6320 [async / Async_Flash_v1.5]
HT-M319_us_male: 0.6316 [StepFun / Step_Audio_EditX_Mar_2026]
Noble Cast_us_male: 0.6288 [StepFun / StepAudio_2.5_TTS]
Douglas_us_male: 0.6287 [SpeechifyAI / Simba_3.0]
Altair_us_male: 0.6171 [SpaceXAI / SpaceXAI_TTS]
Dorian_us_male: 0.6126 [SpeechifyAI / Simba_3.0]
Helix_us_male: 0.6058 [SpaceXAI / SpaceXAI_TTS]
Liam_us_male: 0.5938 [ElevenLabs / Eleven_v3]
Fisher_us_male: 0.5806 [async / Async_Flash_v1.5]
大厂最佳: Edmund_uk_male(0.8695)
Edmund_uk_male: 0.8695 ← [SpeechifyAI / Simba_3.2]
arthur_uk_male: 0.8227 ← [Alibaba / Fun-Realtime-TTS]
George_uk_male: 0.7975 [Cartesia / Sonic_3.5]
barry_uk_male: 0.7813 [Alibaba / Fun-Realtime-TTS]
Archie_uk_male: 0.7762 [Cartesia / Sonic_3.5]
Charon_uk_male: 0.7474 [Google / Gemini_3.1_Flash_TTS]
michael_us_male: 0.7312 [Alibaba / Fun-Realtime-TTS]
Charon_us_male: 0.7280 [Google / Gemini_3.1_Flash_TTS]
Hugh_uk_male: 0.7278 [SpeechifyAI / Simba_3.2]
Corey_us_male: 0.7237 [Cartesia / Sonic_3.5]
Fenrir_uk_male: 0.7051 [Google / Gemini_3.1_Flash_TTS]
davis_us_male: 0.6822 [Alibaba / Fun-Realtime-TTS]
Daniel_us_male: 0.6609 [Cartesia / Sonic_3.5]
Wyatt_us_male: 0.6398 [SpeechifyAI / Simba_3.2]
Dominic_us_male: 0.6150 [SpeechifyAI / Simba_3.2]
>>> right 最高: Edmund_uk_male(0.8695) [big_vendor]
决策: vote_right
原因: 两侧都是大厂 (Edmund_uk_male(0.8986) vs Edmund_uk_male(0.8695)) → 随机投right
统计: 8 票 / 3 弃
───────────────────────────────────────────────────────
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
"""Voiceprint matching engine using Resemblyzer VoiceEncoder.
Pre-loads reference audio embeddings at startup, then matches incoming
unknown audio against all three reference libraries (ours, competitors,
big vendors) on demand.
Each speaker can have multiple reference audio files — all embeddings
are stored and the best match across all clips is used.
Matching is gender-filtered: unknown audio is only compared against
same-gender reference speakers. Cross-gender matching is skipped.
"""
import os
import re
import warnings
from pathlib import Path
from typing import Optional, Tuple, Dict, List
import numpy as np
import torch
import torchaudio
from resemblyzer import VoiceEncoder, preprocess_wav
# Suppress verbose warnings from librosa/audioread for corrupted files
warnings.filterwarnings("ignore", category=UserWarning, module="resemblyzer")
warnings.filterwarnings("ignore", category=FutureWarning, module="librosa")
os.environ.setdefault("LIBROSA_VERBOSE", "0")
def _detect_device() -> str:
"""Auto-detect the best available torch device."""
if torch.cuda.is_available():
return "cuda"
if torch.backends.mps.is_available():
return "mps"
return "cpu"
_UUID_PATTERN = re.compile(
r"_[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
)
def _extract_speaker_name(stem: str) -> str:
"""Extract speaker identity from filename stem.
Handles two formats:
- Old: "Daniel (Male, US)" → "Daniel"
- New: "Archie_uk_male_b2740dd7-..." → "Archie_uk_male"
"""
no_uuid = _UUID_PATTERN.sub("", stem)
if no_uuid != stem:
return no_uuid
return stem.split("(")[0].strip()
def _extract_gender_from_filename(stem: str) -> Optional[str]:
"""Extract gender from filename stem. Returns 'male', 'female', or None."""
lower = stem.lower()
# New format: name_region_gender_uuid → check each underscore-delimited part
for part in lower.split("_"):
if part in ("male", "female"):
return part
# Old format: Name (Gender, Region) — check female before male ("female" contains "male")
if "(female" in lower or "female," in lower:
return "female"
if "(male" in lower or "male," in lower:
return "male"
return None
def _detect_gender_from_pitch(audio_path: Path) -> Optional[str]:
"""Detect gender by median pitch. f0 > 160Hz → female, else male.
Returns None if pitch detection fails (too few frames).
"""
try:
wav, sr = torchaudio.load(str(audio_path))
if sr != 16000:
wav = torchaudio.transforms.Resample(sr, 16000)(wav)
if wav.shape[0] > 1:
wav = wav.mean(dim=0, keepdim=True)
pitch = torchaudio.functional.detect_pitch_frequency(wav, 16000)
valid = pitch[(pitch > 50) & (pitch < 500)]
if valid.numel() < 10:
return None
f0 = valid.median().item()
return "female" if f0 > 160 else "male"
except Exception:
return None
def _detect_gender(audio_path: Path, filename_hint: Optional[str] = None) -> Optional[str]:
"""Detect gender: filename first, then pitch fallback.
Args:
audio_path: Path to audio file.
filename_hint: If known, use this stem for filename-based detection.
"""
if filename_hint:
g = _extract_gender_from_filename(filename_hint)
if g:
return g
g = _extract_gender_from_filename(audio_path.stem)
if g:
return g
return _detect_gender_from_pitch(audio_path)
class VoiceMatcher:
"""Pre-loads one reference library and matches audios against it.
Each speaker may have multiple reference clips. All embeddings are
stored; matching uses the average of top 5 clip scores (same-gender only).
Subdirectories named Vendor__Model provide vendor/model metadata.
"""
def __init__(self, reference_dir: Path, device: Optional[str] = None):
self.encoder = VoiceEncoder(device=device or _detect_device())
self.references: Dict[str, List[np.ndarray]] = {}
self.genders: Dict[str, str] = {}
self.speaker_vendor: Dict[str, str] = {} # speaker → "Vendor / Model"
self._load_references(reference_dir)
def _load_references(self, reference_dir: Path) -> None:
if not reference_dir.exists():
print(f" [matcher] Reference dir not found: {reference_dir}, skipping")
return
loaded = 0
skipped = 0
# Walk subdirectories — each subdir is "Vendor__Model"
for entry in sorted(reference_dir.iterdir()):
if entry.is_symlink() or entry.is_dir():
# Parse vendor/model from directory name: Vendor__Model
dir_name = entry.name
vendor_model = dir_name.replace("__", " / ") if "__" in dir_name else dir_name
files = list(entry.glob("*")) if entry.is_dir() else []
else:
# Flat file in root dir — no vendor info
vendor_model = "—"
files = [entry]
for f in sorted(files):
if f.suffix.lower() not in (".wav", ".mp3", ".flac", ".m4a"):
continue
if f.name.startswith("._"):
continue
try:
wav = preprocess_wav(f)
emb = self.encoder.embed_utterance(wav)
emb = emb / np.linalg.norm(emb)
name = _extract_speaker_name(f.stem)
self.references.setdefault(name, []).append(emb)
if name not in self.genders:
gender = _detect_gender(f, filename_hint=f.stem)
self.genders[name] = gender or "unknown"
if name not in self.speaker_vendor:
self.speaker_vendor[name] = vendor_model
loaded += 1
except Exception:
skipped += 1
speaker_count = len(self.references)
total_clips = sum(len(v) for v in self.references.values())
male_count = sum(1 for g in self.genders.values() if g == "male")
female_count = sum(1 for g in self.genders.values() if g == "female")
unknown_count = speaker_count - male_count - female_count
unique_vendors = len(set(self.speaker_vendor.values()))
print(f" [matcher] {speaker_count} speakers ({total_clips} clips, {skipped} skipped)"
f" — 👨 {male_count} / 👩 {female_count}" +
(f" / ❓ {unknown_count}" if unknown_count else "") +
f" — {unique_vendors} vendors from {reference_dir}")
def match(self, audio_path: Path) -> Tuple[Optional[str], float, Dict[str, float], Dict[str, str]]:
"""Match one audio against all loaded references.
Returns (best_speaker_name, best_score, all_scores, speaker_vendors).
speaker_vendors maps speaker_name → "Vendor / Model".
Returns (None, 0.0, {}, {}) if no references or audio can't be processed.
"""
if not self.references:
return None, 0.0, {}, {}
query_gender = _detect_gender_from_pitch(audio_path)
try:
wav = preprocess_wav(audio_path)
emb = self.encoder.embed_utterance(wav)
except Exception as e:
print(f" [matcher] Failed to process {audio_path.name}: {e}")
return None, 0.0, {}, {}
emb = emb / np.linalg.norm(emb)
all_scores: Dict[str, float] = {}
best_name, best_score = None, 0.0
for name, ref_embeddings in self.references.items():
ref_gender = self.genders.get(name, "unknown")
if query_gender and ref_gender not in (query_gender, "unknown"):
continue
scores = sorted([float(np.dot(emb, ref_emb)) for ref_emb in ref_embeddings], reverse=True)
top = sum(scores[:5]) / min(len(scores), 5) # average of top 5 clips
all_scores[name] = round(top, 4)
if top > best_score:
best_score = top
best_name = name
return best_name, round(best_score, 4), all_scores, dict(self.speaker_vendor)
class MatchResult:
"""Result of matching one audio against all three libraries."""
def __init__(self):
self.our: Tuple[Optional[str], float] = (None, 0.0)
self.our_scores: Dict[str, float] = {}
self.our_vendors: Dict[str, str] = {}
self.competitor: Tuple[Optional[str], float] = (None, 0.0)
self.competitor_scores: Dict[str, float] = {}
self.competitor_vendors: Dict[str, str] = {}
self.big_vendor: Tuple[Optional[str], float] = (None, 0.0)
self.big_vendor_scores: Dict[str, float] = {}
self.big_vendor_vendors: Dict[str, str] = {}
def to_dict(self) -> Dict:
def fmt(match):
name, score = match
return {"speaker": name, "score": score} if name else None
return {
"our_match": fmt(self.our),
"competitor_match": fmt(self.competitor),
"big_vendor_match": fmt(self.big_vendor),
}
class MultiMatcher:
"""Holds three VoiceMatcher instances and matches an audio against all."""
def __init__(self, our_dir: Path, competitor_dir: Path, big_vendor_dir: Path, device: Optional[str] = None):
device = device or _detect_device()
print(f"[matcher] Using device: {device}")
print("[matcher] Loading our references...")
self.our = VoiceMatcher(our_dir, device)
print("[matcher] Loading competitor references...")
self.competitor = VoiceMatcher(competitor_dir, device)
print("[matcher] Loading big vendor references...")
self.big_vendor = VoiceMatcher(big_vendor_dir, device)
def match_one(self, audio_path: Path) -> MatchResult:
result = MatchResult()
r = self.our.match(audio_path); result.our = r[:2]; result.our_scores = r[2]; result.our_vendors = r[3]
r = self.competitor.match(audio_path); result.competitor = r[:2]; result.competitor_scores = r[2]; result.competitor_vendors = r[3]
r = self.big_vendor.match(audio_path); result.big_vendor = r[:2]; result.big_vendor_scores = r[2]; result.big_vendor_vendors = r[3]
return result
#!/usr/bin/env python3
"""Native Messaging host for Luna TTS Ranking Bot.
Communicates with Chrome extension via stdin/stdout using the
Chrome Native Messaging protocol (4-byte length prefix + JSON).
No network — bypasses AdsPower proxy entirely.
"""
import json
import logging
import struct
import sys
import tempfile
import urllib.request
import ssl
from datetime import datetime
from pathlib import Path
from config import OUR_THRESHOLD, DAILY_VOTE_LIMIT, REFERENCE_DIRS
from matcher import MultiMatcher
from strategy import decide, SideResult
BASE_DIR = Path(__file__).resolve().parent
def _log_stderr(msg):
"""Print to stderr, ignoring broken pipe."""
try:
print(msg, file=sys.stderr, flush=True)
except (BrokenPipeError, OSError):
pass
# File logger for match results
LOG_DIR = BASE_DIR / "logs"
LOG_DIR.mkdir(exist_ok=True)
_match_logger = logging.getLogger("match")
_match_logger.setLevel(logging.INFO)
_fh = logging.FileHandler(LOG_DIR / f"native-{datetime.now().strftime('%Y%m%d')}.log", encoding="utf-8")
_fh._original_emit = _fh.emit
_fh.emit = lambda record: (_fh._original_emit(record), _fh.flush()) # force flush every write
_fh.setFormatter(logging.Formatter("%(message)s"))
_match_logger.addHandler(_fh)
_match_logger.propagate = False
def read_message():
"""Read a native messaging message from stdin."""
raw_len = sys.stdin.buffer.read(4)
if not raw_len or len(raw_len) < 4:
return None
msg_len = struct.unpack('=I', raw_len)[0]
raw_msg = sys.stdin.buffer.read(msg_len)
return json.loads(raw_msg.decode('utf-8'))
def send_message(msg):
"""Send a native messaging message to stdout."""
encoded = json.dumps(msg, ensure_ascii=False).encode('utf-8')
sys.stdout.buffer.write(struct.pack('=I', len(encoded)))
sys.stdout.buffer.write(encoded)
sys.stdout.buffer.flush()
def download_audio(url: str, dest: Path) -> bool:
try:
req = urllib.request.Request(url, headers={
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Referer": "https://artificialanalysis.ai/text-to-speech/arena",
"Origin": "https://artificialanalysis.ai",
})
ctx = ssl.create_default_context()
with urllib.request.urlopen(req, timeout=15, context=ctx) as resp:
dest.write_bytes(resp.read())
return True
except Exception as e:
_log_stderr(f"[host] Download failed: {e}")
return False
def _write_status(status, detail=""):
"""Write a status file for external monitoring."""
status_file = LOG_DIR / "host.status"
status_file.write_text(f"{status}|{detail}|{datetime.now().strftime('%H:%M:%S')}")
def main():
_log_stderr("[host] Starting Native Messaging host...")
_write_status("starting", "Loading voice encoder model...")
# Load matcher once at startup
our_dir = BASE_DIR / REFERENCE_DIRS["our"]
competitor_dir = BASE_DIR / REFERENCE_DIRS["competitor"]
big_vendor_dir = BASE_DIR / REFERENCE_DIRS["big_vendor"]
matcher = MultiMatcher(our_dir, competitor_dir, big_vendor_dir)
today_votes = 0
today_skips = 0
_write_status("ready", f"Models loaded, {today_votes} votes today")
_log_stderr("[host] Ready, waiting for messages...")
while True:
data = read_message()
if data is None:
break
msg_type = data.get("type")
if msg_type == "match_request":
request_id = data["request_id"]
audio_left_url = data["audio_left"]
audio_right_url = data["audio_right"]
# Daily limit
if today_votes >= DAILY_VOTE_LIMIT:
send_message({
"type": "match_result", "request_id": request_id,
"decision": "skip",
"reason": f"Daily limit reached ({DAILY_VOTE_LIMIT})",
"details": {},
})
continue
# Download both audios
with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as f_left, \
tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as f_right:
left_path = Path(f_left.name)
right_path = Path(f_right.name)
try:
if not download_audio(audio_left_url, left_path):
send_message({
"type": "match_result", "request_id": request_id,
"decision": "skip", "reason": "Failed to download left audio", "details": {},
})
continue
if not download_audio(audio_right_url, right_path):
send_message({
"type": "match_result", "request_id": request_id,
"decision": "skip", "reason": "Failed to download right audio", "details": {},
})
continue
left_result = matcher.match_one(left_path)
right_result = matcher.match_one(right_path)
def _build_side(label, r):
our_sp, our_sc = r.our
comp_sp, comp_sc = r.competitor
bv_sp, bv_sc = r.big_vendor
candidates = [("our", our_sp, our_sc), ("competitor", comp_sp, comp_sc), ("big_vendor", bv_sp, bv_sc)]
top_lib, top_sp, top_sc = max(candidates, key=lambda x: x[2])
if our_sp and our_sc >= OUR_THRESHOLD and top_lib != "our" and (top_sc - our_sc) <= 0.05:
top_lib, top_sp, top_sc = "our", our_sp, our_sc
return SideResult(
label=label, top_library=top_lib, top_speaker=top_sp or "---", top_score=top_sc,
our_speaker=our_sp, our_score=our_sc,
competitor_speaker=comp_sp, competitor_score=comp_sc,
big_vendor_speaker=bv_sp, big_vendor_score=bv_sc,
our_scores=r.our_scores, competitor_scores=r.competitor_scores, big_vendor_scores=r.big_vendor_scores,
), {"our": r.our_vendors, "competitor": r.competitor_vendors, "big_vendor": r.big_vendor_vendors}
left_side, left_vendors = _build_side("left", left_result)
right_side, right_vendors = _build_side("right", right_result)
decision_obj = decide(left_side, right_side, OUR_THRESHOLD)
if decision_obj.action == "skip":
today_skips += 1
else:
today_votes += 1
needs_review = (
left_side.our_score >= OUR_THRESHOLD and right_side.our_score >= OUR_THRESHOLD and
(left_side.competitor_score >= OUR_THRESHOLD or right_side.competitor_score >= OUR_THRESHOLD)
)
response = {
"type": "match_result", "request_id": request_id,
"decision": decision_obj.action, "reason": decision_obj.reason,
"needs_review": needs_review,
"details": {
"left": {**left_result.to_dict(), "top_match": {"speaker": left_side.top_speaker, "score": left_side.top_score, "library": left_side.top_library}},
"right": {**right_result.to_dict(), "top_match": {"speaker": right_side.top_speaker, "score": right_side.top_score, "library": right_side.top_library}},
},
"stats": {"today_votes": today_votes, "today_skips": today_skips, "daily_limit": DAILY_VOTE_LIMIT},
}
_write_status("ready", f"Votes: {today_votes}, Skips: {today_skips}")
send_message(response)
# Log to file + stderr
def _fmt_scores(scores, vendors, threshold=0.80):
if not scores: return " (无)"
items = sorted(scores.items(), key=lambda x: -x[1])
lines = []
for n, s in items:
mark = " ←" if s >= threshold else ""
v = (vendors or {}).get(n, "")
vinfo = f" [{v}]" if v else ""
lines.append(f" {n}: {s:.4f}{mark}{vinfo}")
return "\n".join(lines)
def _fmt_side(side, vendors):
our = f"{side.our_speaker}({side.our_score:.4f})" if side.our_speaker else "---"
comp = f"{side.competitor_speaker}({side.competitor_score:.4f})" if side.competitor_speaker else "---"
bv = f"{side.big_vendor_speaker}({side.big_vendor_score:.4f})" if side.big_vendor_speaker else "---"
max_other = max(side.competitor_score, side.big_vendor_score)
margin_note = ""
if side.top_library == "our" and max_other > side.our_score and (max_other - side.our_score) <= 0.05:
margin_note = " 🔒保护区间"
return (
f" 我方最佳: {our}\n{_fmt_scores(side.our_scores, vendors.get('our', {}))}\n\n"
f" 竞品最佳: {comp}\n{_fmt_scores(side.competitor_scores, vendors.get('competitor', {}))}\n\n"
f" 大厂最佳: {bv}\n{_fmt_scores(side.big_vendor_scores, vendors.get('big_vendor', {}))}\n\n"
f" >>> {side.label} 最高: {side.top_speaker}({side.top_score:.4f}) [{side.top_library}]{margin_note}"
)
report = f"""
{'─' * 55}
LEFT 音频
{_fmt_side(left_side, left_vendors)}
RIGHT 音频
{_fmt_side(right_side, right_vendors)}
决策: {decision_obj.action}
原因: {decision_obj.reason}
统计: {today_votes} 票 / {today_skips} 弃
{'─' * 55}"""
_log_stderr(report)
_match_logger.info(f"[{datetime.now().strftime('%H:%M:%S')}]{report}")
finally:
left_path.unlink(missing_ok=True)
right_path.unlink(missing_ok=True)
elif msg_type == "status":
send_message({
"type": "status", "today_votes": today_votes,
"today_skips": today_skips, "daily_limit": DAILY_VOTE_LIMIT,
})
if __name__ == "__main__":
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment