diff --git a/README.md b/README.md index f4ad2fa6b0..39ce7da0eb 100644 --- a/README.md +++ b/README.md @@ -550,12 +550,6 @@ default: rate_multiplier: 1.0 ``` -### Sora Status (Temporarily Unavailable) - -> ⚠️ Sora-related features are temporarily unavailable due to technical issues in upstream integration and media delivery. -> Please do not rely on Sora in production at this time. -> Existing `gateway.sora_*` configuration keys are reserved and may not take effect until these issues are resolved. - Additional security-related options are available in `config.yaml`: - `cors.allowed_origins` for CORS allowlist diff --git a/README_CN.md b/README_CN.md index 2d2a57a9ff..3fa4fa2e34 100644 --- a/README_CN.md +++ b/README_CN.md @@ -563,33 +563,6 @@ default: rate_multiplier: 1.0 ``` -### Sora 功能状态(暂不可用) - -> ⚠️ 当前 Sora 相关功能因上游接入与媒体链路存在技术问题,暂时不可用。 -> 现阶段请勿在生产环境依赖 Sora 能力。 -> 文档中的 `gateway.sora_*` 配置仅作预留,待技术问题修复后再恢复可用。 - -### Sora 媒体签名 URL(功能恢复后可选) - -当配置 `gateway.sora_media_signing_key` 且 `gateway.sora_media_signed_url_ttl_seconds > 0` 时,网关会将 Sora 输出的媒体地址改写为临时签名 URL(`/sora/media-signed/...`)。这样无需 API Key 即可在浏览器中直接访问,且具备过期控制与防篡改能力(签名包含 path + query)。 - -```yaml -gateway: - # /sora/media 是否强制要求 API Key(默认 false) - sora_media_require_api_key: false - # 媒体临时签名密钥(为空则禁用签名) - sora_media_signing_key: "your-signing-key" - # 临时签名 URL 有效期(秒) - sora_media_signed_url_ttl_seconds: 900 -``` - -> 若未配置签名密钥,`/sora/media-signed` 将返回 503。 -> 如需更严格的访问控制,可将 `sora_media_require_api_key` 设为 true,仅允许携带 API Key 的 `/sora/media` 访问。 - -访问策略说明: -- `/sora/media`:内部调用或客户端携带 API Key 才能下载 -- `/sora/media-signed`:外部可访问,但有签名 + 过期控制 - `config.yaml` 还支持以下安全相关配置: - `cors.allowed_origins` 配置 CORS 白名单 diff --git a/README_JA.md b/README_JA.md index 09aa77ee48..c8ed0adc64 100644 --- a/README_JA.md +++ b/README_JA.md @@ -550,12 +550,6 @@ default: rate_multiplier: 1.0 ``` -### Sora ステータス(一時的に利用不可) - -> ⚠️ Sora 関連の機能は、上流統合およびメディア配信の技術的問題により一時的に利用できません。 -> 現時点では本番環境で Sora に依存しないでください。 -> 既存の `gateway.sora_*` 設定キーは予約されていますが、これらの問題が解決されるまで有効にならない場合があります。 - `config.yaml` では追加のセキュリティ関連オプションも利用できます: - `cors.allowed_origins` - CORS 許可リスト diff --git a/backend/internal/handler/dto/public_settings_injection_schema_test.go b/backend/internal/handler/dto/public_settings_injection_schema_test.go index 428fed3d8a..6a35c8867e 100644 --- a/backend/internal/handler/dto/public_settings_injection_schema_test.go +++ b/backend/internal/handler/dto/public_settings_injection_schema_test.go @@ -29,8 +29,6 @@ func TestPublicSettingsInjectionPayload_SchemaDoesNotDrift(t *testing.T) { // Fields that legitimately live only on the DTO. Keep tiny; document each. dtoOnlyFields := map[string]string{ - // sora_client_enabled is an upstream-only field the fork does not surface. - "sora_client_enabled": "upstream-only field, not used on this fork", // force_email_on_third_party_signup lives on the DTO but is not injected via SSR. "force_email_on_third_party_signup": "auth-source default, not a feature flag", } diff --git a/backend/internal/handler/dto/settings.go b/backend/internal/handler/dto/settings.go index 5ab5eaa68b..a2fc178454 100644 --- a/backend/internal/handler/dto/settings.go +++ b/backend/internal/handler/dto/settings.go @@ -397,7 +397,6 @@ type PublicSettings struct { OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"` GitHubOAuthEnabled bool `json:"github_oauth_enabled"` GoogleOAuthEnabled bool `json:"google_oauth_enabled"` - SoraClientEnabled bool `json:"sora_client_enabled"` BackendModeEnabled bool `json:"backend_mode_enabled"` PaymentEnabled bool `json:"payment_enabled"` Version string `json:"version"` diff --git a/deploy/config.example.yaml b/deploy/config.example.yaml index 095c550993..e8c1c84b78 100644 --- a/deploy/config.example.yaml +++ b/deploy/config.example.yaml @@ -228,33 +228,6 @@ gateway: # Enable Gemini upstream response header debug logs (default: false) # 是否开启 Gemini 上游响应头调试日志(默认 false) gemini_debug_response_headers: false - # Sora max request body size in bytes (0=use max_body_size) - # Sora 请求体最大字节数(0=使用 max_body_size) - sora_max_body_size: 268435456 - # Sora stream timeout (seconds, 0=disable) - # Sora 流式请求总超时(秒,0=禁用) - sora_stream_timeout_seconds: 900 - # Sora non-stream timeout (seconds, 0=disable) - # Sora 非流式请求超时(秒,0=禁用) - sora_request_timeout_seconds: 180 - # Sora stream enforcement mode: force/error - # Sora stream 强制策略:force/error - sora_stream_mode: "force" - # Sora model filters - # Sora 模型过滤配置 - sora_model_filters: - # Hide prompt-enhance models by default - # 默认隐藏 prompt-enhance 模型 - hide_prompt_enhance: true - # Require API key for /sora/media proxy (default: false) - # /sora/media 是否强制要求 API Key(默认 true) - sora_media_require_api_key: true - # Sora media temporary signing key (empty disables signed URL) - # Sora 媒体临时签名密钥(为空则禁用签名) - sora_media_signing_key: "" - # Signed URL TTL seconds (<=0 disables) - # 临时签名 URL 有效期(秒,<=0 表示禁用) - sora_media_signed_url_ttl_seconds: 900 # Connection pool isolation strategy: # 连接池隔离策略: # - proxy: Isolate by proxy, same proxy shares connection pool (suitable for few proxies, many accounts) @@ -649,112 +622,9 @@ log: # 之后每 N 条保留 1 条 thereafter: 100 -# ============================================================================= -# Sora Direct Client Configuration -# Sora 直连配置 -# ============================================================================= -sora: - client: - # Sora backend base URL - # Sora 上游 Base URL - base_url: "https://sora.chatgpt.com/backend" - # Request timeout (seconds) - # 请求超时(秒) - timeout_seconds: 120 - # Max retries for upstream requests - # 上游请求最大重试次数 - max_retries: 3 - # Account+proxy cooldown window after Cloudflare challenge (seconds, 0 to disable) - # Cloudflare challenge 后按账号+代理冷却窗口(秒,0 表示关闭) - cloudflare_challenge_cooldown_seconds: 900 - # Poll interval (seconds) - # 轮询间隔(秒) - poll_interval_seconds: 2 - # Max poll attempts - # 最大轮询次数 - max_poll_attempts: 600 - # Recent task query limit (image) - # 最近任务查询数量(图片轮询) - recent_task_limit: 50 - # Recent task query max limit (fallback) - # 最近任务查询最大数量(回退) - recent_task_limit_max: 200 - # Enable debug logs for Sora upstream requests - # 启用 Sora 直连调试日志 - # 调试日志会输出上游请求尝试、重试、响应摘要;Authorization/openai-sentinel-token 等敏感头会自动脱敏 - debug: false - # Allow Sora client to fetch token via OpenAI token provider - # 是否允许 Sora 客户端通过 OpenAI token provider 取 token(默认 false,避免误走 OpenAI 刷新链路) - use_openai_token_provider: false - # Optional custom headers (key-value) - # 额外请求头(键值对) - headers: {} - # Default User-Agent for Sora requests - # Sora 默认 User-Agent - user_agent: "Sora/1.2026.007 (Android 15; 24122RKC7C; build 2600700)" - # Disable TLS fingerprint for Sora upstream - # 关闭 Sora 上游 TLS 指纹伪装 - disable_tls_fingerprint: false - # curl_cffi sidecar for Sora only (required) - # 仅 Sora 链路使用的 curl_cffi sidecar(必需) - curl_cffi_sidecar: - # Sora 强制通过 sidecar 请求,必须启用 - # Sora is forced to use sidecar only; keep enabled=true - enabled: true - # Sidecar base URL (default endpoint: /request) - # sidecar 基础地址(默认请求端点:/request) - base_url: "http://sora-curl-cffi-sidecar:8080" - # curl_cffi impersonate profile, e.g. chrome131/chrome124/safari18_0 - # curl_cffi 指纹伪装 profile,例如 chrome131/chrome124/safari18_0 - impersonate: "chrome131" - # Sidecar request timeout (seconds) - # sidecar 请求超时(秒) - timeout_seconds: 60 - # Reuse session key per account+proxy to let sidecar persist cookies/session - # 按账号+代理复用 session key,让 sidecar 持久化 cookies/session - session_reuse_enabled: true - # Session TTL in sidecar (seconds) - # sidecar 会话 TTL(秒) - session_ttl_seconds: 3600 - storage: - # Storage type (local only for now) - # 存储类型(首发仅支持 local) - type: "local" - # Local base path; empty uses /app/data/sora - # 本地存储基础路径;为空使用 /app/data/sora - local_path: "" - # Fallback to upstream URL when download fails - # 下载失败时回退到上游 URL - fallback_to_upstream: true - # Max concurrent downloads - # 并发下载上限 - max_concurrent_downloads: 4 - # Download timeout (seconds) - # 下载超时(秒) - download_timeout_seconds: 120 - # Max download bytes - # 最大下载字节数 - max_download_bytes: 209715200 - # Enable debug logs for media storage - # 启用媒体存储调试日志 - debug: false - cleanup: - # Enable cleanup task - # 启用清理任务 - enabled: true - # Retention days - # 保留天数 - retention_days: 7 - # Cron schedule - # Cron 调度表达式 - schedule: "0 3 * * *" - # Token refresh behavior # token 刷新行为控制 token_refresh: - # Whether OpenAI refresh flow is allowed to sync linked Sora accounts - # 是否允许 OpenAI 刷新流程同步覆盖 linked_openai_account_id 关联的 Sora 账号 token - sync_linked_sora_accounts: false # Candidate accounts loaded per cursor page (maximum 1000) # 每个游标分页加载的候选账号数量(最大 1000) candidate_page_size: 200 diff --git a/frontend/src/i18n/locales/en/admin/overview.ts b/frontend/src/i18n/locales/en/admin/overview.ts index b10dc0d7d1..d8ea00c62d 100644 --- a/frontend/src/i18n/locales/en/admin/overview.ts +++ b/frontend/src/i18n/locales/en/admin/overview.ts @@ -578,8 +578,6 @@ export default { failedToLoadApiKeys: 'Failed to load user API keys', emailRequired: 'Please enter email', concurrencyMin: 'Concurrency must be at least 1', - soraStorageQuota: 'Sora Storage Quota', - soraStorageQuotaHint: 'In GB, 0 means use group or system default quota', amountRequired: 'Please enter a valid amount', insufficientBalance: 'Insufficient balance', adjustBalance: 'Adjust Balance', diff --git a/frontend/src/i18n/locales/en/admin/settings.ts b/frontend/src/i18n/locales/en/admin/settings.ts index 9aff76d251..84ede270d6 100644 --- a/frontend/src/i18n/locales/en/admin/settings.ts +++ b/frontend/src/i18n/locales/en/admin/settings.ts @@ -653,12 +653,6 @@ export default { integrationDoc: 'Payment Integration Docs', integrationDocHint: 'Covers endpoint specs, idempotency semantics, and code samples' }, - soraClient: { - title: 'Sora Client', - description: 'Control whether to show the Sora client entry in the sidebar', - enabled: 'Enable Sora Client', - enabledHint: 'When enabled, the Sora entry will be shown in the sidebar for users to access Sora features' - }, customMenu: { title: 'Custom Menu Pages', description: 'Add custom iframe pages to the sidebar navigation. Each page can be visible to regular users or administrators.', @@ -981,98 +975,6 @@ export default { securityWarning: 'Warning: This key provides full admin access. Keep it secure.', usage: 'Usage: Add to request header - x-api-key: ' }, - soraS3: { - title: 'Sora Storage', - description: 'Manage Sora media storage profiles with S3 and Google Drive support', - newProfile: 'New Profile', - reloadProfiles: 'Reload Profiles', - empty: 'No storage profiles yet, create one first', - createTitle: 'Create Storage Profile', - editTitle: 'Edit Storage Profile', - selectProvider: 'Select Storage Type', - providerS3Desc: 'S3-compatible object storage', - providerGDriveDesc: 'Google Drive cloud storage', - profileID: 'Profile ID', - profileName: 'Profile Name', - setActive: 'Set as active after creation', - saveProfile: 'Save Profile', - activateProfile: 'Activate', - profileCreated: 'Storage profile created', - profileSaved: 'Storage profile saved', - profileDeleted: 'Storage profile deleted', - profileActivated: 'Active storage profile switched', - profileIDRequired: 'Profile ID is required', - profileNameRequired: 'Profile name is required', - profileSelectRequired: 'Please select a profile first', - endpointRequired: 'S3 endpoint is required when enabled', - bucketRequired: 'Bucket is required when enabled', - accessKeyRequired: 'Access Key ID is required when enabled', - deleteConfirm: 'Delete storage profile {profileID}?', - columns: { - profile: 'Profile', - profileId: 'Profile ID', - name: 'Name', - provider: 'Type', - active: 'Active', - endpoint: 'Endpoint', - bucket: 'Bucket', - storagePath: 'Storage Path', - capacityUsage: 'Capacity / Used', - capacityUnlimited: 'Unlimited', - videoCount: 'Videos', - videoCompleted: 'completed', - videoInProgress: 'in progress', - quota: 'Default Quota', - updatedAt: 'Updated At', - actions: 'Actions', - rootFolder: 'Root folder', - testInTable: 'Test', - testingInTable: 'Testing...', - testTimeout: 'Test timed out (15s)' - }, - enabled: 'Enable Storage', - enabledHint: 'When enabled, Sora generated media files will be automatically uploaded', - endpoint: 'S3 Endpoint', - region: 'Region', - bucket: 'Bucket', - prefix: 'Object Prefix', - accessKeyId: 'Access Key ID', - secretAccessKey: 'Secret Access Key', - secretConfigured: '(Configured, leave blank to keep)', - cdnUrl: 'CDN URL', - cdnUrlHint: 'Optional. When configured, files are accessed via CDN URL', - forcePathStyle: 'Force Path Style', - defaultQuota: 'Default Storage Quota', - defaultQuotaHint: 'Default quota when not specified at user or group level. 0 means unlimited', - testConnection: 'Test Connection', - testing: 'Testing...', - testSuccess: 'Connection test successful', - testFailed: 'Connection test failed', - saved: 'Storage settings saved successfully', - saveFailed: 'Failed to save storage settings', - gdrive: { - authType: 'Authentication Method', - serviceAccount: 'Service Account', - clientId: 'Client ID', - clientSecret: 'Client Secret', - clientSecretConfigured: '(Configured, leave blank to keep)', - refreshToken: 'Refresh Token', - refreshTokenConfigured: '(Configured, leave blank to keep)', - serviceAccountJson: 'Service Account JSON', - serviceAccountConfigured: '(Configured, leave blank to keep)', - folderId: 'Folder ID (optional)', - authorize: 'Authorize Google Drive', - authorizeHint: 'Get Refresh Token via OAuth2', - oauthFieldsRequired: 'Please fill in Client ID and Client Secret first', - oauthSuccess: 'Google Drive authorization successful', - oauthFailed: 'Google Drive authorization failed', - closeWindow: 'This window will close automatically', - processing: 'Processing authorization...', - testStorage: 'Test Storage', - testSuccess: 'Google Drive storage test passed (upload, access, delete all OK)', - testFailed: 'Google Drive storage test failed' - } - }, overloadCooldown: { title: '529 Overload Cooldown', description: 'Configure account scheduling pause strategy when upstream returns 529 (overloaded)', diff --git a/frontend/src/i18n/locales/zh/admin/overview.ts b/frontend/src/i18n/locales/zh/admin/overview.ts index e32cadc641..fdfbc8fdac 100644 --- a/frontend/src/i18n/locales/zh/admin/overview.ts +++ b/frontend/src/i18n/locales/zh/admin/overview.ts @@ -599,8 +599,6 @@ export default { failedToAdjust: '调整失败', emailRequired: '请输入邮箱', concurrencyMin: '并发数不能小于1', - soraStorageQuota: 'Sora 存储配额', - soraStorageQuotaHint: '单位 GB,0 表示使用分组或系统默认配额', amountRequired: '请输入有效金额', insufficientBalance: '余额不足', setAllowedGroups: '设置允许分组', diff --git a/frontend/src/i18n/locales/zh/admin/settings.ts b/frontend/src/i18n/locales/zh/admin/settings.ts index 82a932e564..f2f0435df1 100644 --- a/frontend/src/i18n/locales/zh/admin/settings.ts +++ b/frontend/src/i18n/locales/zh/admin/settings.ts @@ -648,12 +648,6 @@ export default { integrationDoc: '支付集成文档', integrationDocHint: '包含接口说明、幂等语义及示例代码' }, - soraClient: { - title: 'Sora 客户端', - description: '控制是否在侧边栏展示 Sora 客户端入口', - enabled: '启用 Sora 客户端', - enabledHint: '开启后,侧边栏将显示 Sora 入口,用户可访问 Sora 功能' - }, customMenu: { title: '自定义菜单页面', description: '添加自定义 iframe 页面到侧边栏导航。每个页面可以设置为普通用户或管理员可见。', @@ -975,98 +969,6 @@ export default { securityWarning: '警告:此密钥拥有完整的管理员权限,请妥善保管。', usage: '使用方法:在请求头中添加 x-api-key: ' }, - soraS3: { - title: 'Sora 存储配置', - description: '以多配置列表管理 Sora 媒体存储,支持 S3 和 Google Drive', - newProfile: '新建配置', - reloadProfiles: '刷新列表', - empty: '暂无存储配置,请先创建', - createTitle: '新建存储配置', - editTitle: '编辑存储配置', - selectProvider: '选择存储类型', - providerS3Desc: 'S3 兼容对象存储', - providerGDriveDesc: 'Google Drive 云盘', - profileID: '配置 ID', - profileName: '配置名称', - setActive: '创建后设为生效', - saveProfile: '保存配置', - activateProfile: '设为生效', - profileCreated: '存储配置创建成功', - profileSaved: '存储配置保存成功', - profileDeleted: '存储配置删除成功', - profileActivated: '生效配置已切换', - profileIDRequired: '请填写配置 ID', - profileNameRequired: '请填写配置名称', - profileSelectRequired: '请先选择配置', - endpointRequired: '启用时必须填写 S3 端点', - bucketRequired: '启用时必须填写存储桶', - accessKeyRequired: '启用时必须填写 Access Key ID', - deleteConfirm: '确定删除存储配置 {profileID} 吗?', - columns: { - profile: '配置', - profileId: 'Profile ID', - name: '名称', - provider: '存储类型', - active: '生效状态', - endpoint: '端点', - bucket: '存储桶', - storagePath: '存储路径', - capacityUsage: '容量 / 已用', - capacityUnlimited: '无限制', - videoCount: '视频数', - videoCompleted: '完成', - videoInProgress: '进行中', - quota: '默认配额', - updatedAt: '更新时间', - actions: '操作', - rootFolder: '根目录', - testInTable: '测试', - testingInTable: '测试中...', - testTimeout: '测试超时(15秒)' - }, - enabled: '启用存储', - enabledHint: '启用后,Sora 生成的媒体文件将自动上传到存储', - endpoint: 'S3 端点', - region: '区域', - bucket: '存储桶', - prefix: '对象前缀', - accessKeyId: 'Access Key ID', - secretAccessKey: 'Secret Access Key', - secretConfigured: '(已配置,留空保持不变)', - cdnUrl: 'CDN URL', - cdnUrlHint: '可选,配置后使用 CDN URL 访问文件', - forcePathStyle: '强制路径风格(Path Style)', - defaultQuota: '默认存储配额', - defaultQuotaHint: '未在用户或分组级别指定配额时的默认值,0 表示无限制', - testConnection: '测试连接', - testing: '测试中...', - testSuccess: '连接测试成功', - testFailed: '连接测试失败', - saved: '存储设置保存成功', - saveFailed: '保存存储设置失败', - gdrive: { - authType: '认证方式', - serviceAccount: '服务账号', - clientId: 'Client ID', - clientSecret: 'Client Secret', - clientSecretConfigured: '(已配置,留空保持不变)', - refreshToken: 'Refresh Token', - refreshTokenConfigured: '(已配置,留空保持不变)', - serviceAccountJson: '服务账号 JSON', - serviceAccountConfigured: '(已配置,留空保持不变)', - folderId: 'Folder ID(可选)', - authorize: '授权 Google Drive', - authorizeHint: '通过 OAuth2 获取 Refresh Token', - oauthFieldsRequired: '请先填写 Client ID 和 Client Secret', - oauthSuccess: 'Google Drive 授权成功', - oauthFailed: 'Google Drive 授权失败', - closeWindow: '此窗口将自动关闭', - processing: '正在处理授权...', - testStorage: '测试存储', - testSuccess: 'Google Drive 存储测试成功(上传、访问、删除均正常)', - testFailed: 'Google Drive 存储测试失败' - } - }, overloadCooldown: { title: '529 过载冷却', description: '配置上游返回 529(过载)时的账号调度暂停策略',