mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 08:06:19 +00:00
feat(openai): add Codex live voice call proxying (#308)
Add scoped call bootstrap, pinned-account sideband relay and hangup. Preserve model metadata, use standard WebSocket handshakes, and release session claims safely on cancellation. Validated with regression tests, CI and a real OAuth/WebRTC call. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
committed by
GitHub
co-authored by
Codex
parent
78ba7e412e
commit
22acbd1d10
+39
@@ -456,6 +456,45 @@ OpenAI 选号阶段确认本次可选账号全部额度耗尽时,HTTP 返回 `
|
||||
缺失、非法、已禁用或已删除的 Key 返回 OpenAI 风格 `401` 错误;未知查询参数返回 `400 invalid_usage_query`,
|
||||
读取账本失败返回 `503 usage_unavailable`,不会用零余额掩盖故障
|
||||
|
||||
### Codex Live 语音通话
|
||||
|
||||
语音通话复用数据面 Client Key 鉴权,并按该 Key 的账号分组选路。通话引导是一次性请求,走与其他
|
||||
`/v1/*` 数据面请求相同的调度、准入与请求记录;通话建立后的 sideband 与 hangup 使用引导时选中的
|
||||
账号(call id 与账号、创建 Key 绑定),音频流不经过网关。
|
||||
|
||||
| 路由 | 说明 |
|
||||
| --- | --- |
|
||||
| `POST /v1/live` | WebRTC SDP 引导;`POST /v1/realtime` 与 `POST /v1/realtime/calls` 为同一处理的别名,成功响应的 `Location` 会改写为 `/v1/realtime/calls/{call_id}` |
|
||||
| `GET /v1/live/{call_id}` | 通话 sideband WebSocket,双向透传事件帧 |
|
||||
| `GET /v1/realtime/calls/{call_id}` | 同上的 realtime 路径形态 |
|
||||
| `GET /v1/realtime?call_id=…` | 同上的查询参数形态 |
|
||||
| `POST /v1/realtime/calls/{call_id}/hangup` | 用钉住账号转发挂断,成功后解除绑定 |
|
||||
|
||||
引导请求接受三种入口形态并统一为上游要求的 `{"sdp": …, "session"?: …}` JSON:JSON 保留原有字段、
|
||||
`application/sdp` / `text/plain` 包装为 `sdp` 字段、`multipart/form-data` 取 `sdp` 与 `session` 两个部分。
|
||||
`session.model` 或顶层 `model` 中的 `gpt-realtime` 系模型名归一为 `gpt-live-1-codex`,其余模型原样透传;
|
||||
模型字段缺失时按默认语音模型参与检查。归一后的模型参与账号模型权限检查:账号范围整体禁止该模型时
|
||||
引导请求按路由错误拒绝,被禁账号不会服务语音通话。语音语义请求头按允许清单转发:`OpenAI-Alpha`、
|
||||
`X-Session-Id`、`Session-Id`、`Thread-Id`、`Originator`、`OpenAI-Safety-Identifier`、`OpenAI-Organization`、
|
||||
`OpenAI-Project`、`X-Oai-Attestation`;认证、账号身份等其余请求头一律不透传,上游账号身份由选中的账号提供。
|
||||
|
||||
引导响应透传上游状态码,并只回传 `Content-Type`、`Location`、`Retry-After`、`X-Request-Id`、
|
||||
`OpenAI-Request-Id` 五个响应头;正文按字节透传。sideband 中继不做协议解释:Text/Binary 帧双向透传,
|
||||
Ping 由网关本地应答,关闭帧保留原关闭码,异常中断投影为正常关闭。同一 call id 只允许一条 sideband,重复加入返回 `409`;
|
||||
非创建该通话的 Client Key 访问 sideband 或 hangup 返回 `403`;call id 未知或已过期返回 `404`。
|
||||
hangup 不受 sideband 占用限制,通话中可随时挂断;挂断与 sideband 都走钉住账号的出口代理。
|
||||
call 与账号的绑定保存在网关进程内,未连接时一小时过期;sideband 占用期间暂停过期,断开后重新计时,
|
||||
客户端可重连加入同一通话。挂断成功或上游报告通话不存在时立即解除绑定。
|
||||
进程重启后未完成通话失去 sideband 与 hangup 能力
|
||||
|
||||
限制:
|
||||
|
||||
- 引导与 sideband 只使用 OAuth 凭据账号;API Key 类账号不在语音调度范围。
|
||||
- 引导按当前账号范围、模型政策、额度与冷却状态选取账号;sideband 固定使用创建通话的账号,每次连接重新检查当前授权范围、模型政策与账号启用状态,失权时返回 `403`,不会切换账号
|
||||
- 已连接的 sideband 不随权限变更自动断开;仍有效的创建方 Client Key 可调用 hangup 结束通话
|
||||
- 标准实时 WebSocket(`GET /v1/realtime?model=…`)、realtime client secrets、legacy sessions、
|
||||
transcription/translation 会话与 SIP 控制返回 `501 realtime_capability_not_supported`。
|
||||
|
||||
## 4. 浏览器认证
|
||||
|
||||
### 统一登录与会话
|
||||
|
||||
Reference in New Issue
Block a user