mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
refactor: 重构异步任务系统和计费服务架构
- 重构任务系统:新增 lifecycle (TaskStatus/BillingStatus)、context、application 模块 - 将 video tasks 泛化为 async tasks,支持更通用的异步任务管理 - 新增 Gemini Files 管理模块和管理界面 - 重构 billing 服务:拆分 schema.py 和 service.py - 新增 candidate 服务模块用于请求候选管理 - 数据库迁移:添加 billing_status、request_id、gemini_file_mappings 表和索引 - 移除废弃的 video_telemetry、task orchestrator 等模块
This commit is contained in:
198
tests/core/api_format/conversion/test_video_format_conversion.py
Normal file
198
tests/core/api_format/conversion/test_video_format_conversion.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""
|
||||
视频格式转换单元测试
|
||||
|
||||
覆盖重点:
|
||||
- OpenAI <-> Gemini 视频请求格式转换
|
||||
- 视频任务响应格式转换
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from src.core.api_format.conversion.normalizers.gemini import GeminiNormalizer
|
||||
from src.core.api_format.conversion.normalizers.openai import OpenAINormalizer
|
||||
from src.core.api_format.conversion.registry import FormatConversionRegistry
|
||||
|
||||
|
||||
def _make_registry() -> FormatConversionRegistry:
|
||||
reg = FormatConversionRegistry()
|
||||
reg.register(OpenAINormalizer())
|
||||
reg.register(GeminiNormalizer())
|
||||
return reg
|
||||
|
||||
|
||||
class TestVideoRequestConversion:
|
||||
"""视频请求格式转换测试"""
|
||||
|
||||
def test_openai_to_gemini_video_request(self) -> None:
|
||||
"""OpenAI Sora -> Gemini Veo 请求格式转换"""
|
||||
reg = _make_registry()
|
||||
|
||||
openai_request = {
|
||||
"model": "sora-2",
|
||||
"prompt": "A cat playing piano",
|
||||
"size": "1280x720",
|
||||
"seconds": 8,
|
||||
}
|
||||
|
||||
gemini_request = reg.convert_video_request(openai_request, "openai:video", "gemini:video")
|
||||
|
||||
# 验证 Gemini 格式
|
||||
assert "instances" in gemini_request
|
||||
assert "parameters" in gemini_request
|
||||
assert isinstance(gemini_request["instances"], list)
|
||||
assert len(gemini_request["instances"]) > 0
|
||||
|
||||
instance = gemini_request["instances"][0]
|
||||
assert instance["prompt"] == "A cat playing piano"
|
||||
|
||||
params = gemini_request["parameters"]
|
||||
assert params["aspectRatio"] == "16:9"
|
||||
assert params["resolution"] == "720p"
|
||||
assert params["durationSeconds"] == 8
|
||||
|
||||
def test_gemini_to_openai_video_request(self) -> None:
|
||||
"""Gemini Veo -> OpenAI Sora 请求格式转换"""
|
||||
reg = _make_registry()
|
||||
|
||||
gemini_request = {
|
||||
"model": "veo-3.1-generate-preview",
|
||||
"instances": [{"prompt": "A beautiful sunset over mountains"}],
|
||||
"parameters": {
|
||||
"aspectRatio": "16:9",
|
||||
"resolution": "1080p",
|
||||
"durationSeconds": 5,
|
||||
},
|
||||
}
|
||||
|
||||
openai_request = reg.convert_video_request(gemini_request, "gemini:video", "openai:video")
|
||||
|
||||
# 验证 OpenAI 格式
|
||||
assert openai_request["prompt"] == "A beautiful sunset over mountains"
|
||||
assert openai_request["model"] == "veo-3.1-generate-preview"
|
||||
assert openai_request["seconds"] == 5
|
||||
assert openai_request["size"] == "1920x1080"
|
||||
|
||||
def test_same_format_no_conversion(self) -> None:
|
||||
"""相同格式不进行转换"""
|
||||
reg = _make_registry()
|
||||
|
||||
openai_request = {
|
||||
"model": "sora-2",
|
||||
"prompt": "Test",
|
||||
"size": "720x1280",
|
||||
"seconds": 4,
|
||||
}
|
||||
|
||||
result = reg.convert_video_request(openai_request, "openai:video", "openai:video")
|
||||
assert result == openai_request
|
||||
|
||||
def test_conversion_with_reference_image(self) -> None:
|
||||
"""带参考图片的请求转换"""
|
||||
reg = _make_registry()
|
||||
|
||||
openai_request = {
|
||||
"model": "sora-2",
|
||||
"prompt": "Animate this image",
|
||||
"size": "1280x720",
|
||||
"seconds": 4,
|
||||
"input_reference": "base64_encoded_image_data",
|
||||
}
|
||||
|
||||
gemini_request = reg.convert_video_request(openai_request, "openai:video", "gemini:video")
|
||||
|
||||
instance = gemini_request["instances"][0]
|
||||
assert "image" in instance
|
||||
assert instance["image"]["bytesBase64Encoded"] == "base64_encoded_image_data"
|
||||
|
||||
|
||||
class TestVideoTaskConversion:
|
||||
"""视频任务响应格式转换测试"""
|
||||
|
||||
def test_gemini_to_openai_processing_task(self) -> None:
|
||||
"""Gemini 处理中任务 -> OpenAI 格式"""
|
||||
reg = _make_registry()
|
||||
|
||||
gemini_response = {
|
||||
"name": "operations/12345",
|
||||
"done": False,
|
||||
"metadata": {"progress": 50},
|
||||
}
|
||||
|
||||
openai_response = reg.convert_video_task(gemini_response, "gemini:video", "openai:video")
|
||||
|
||||
# OpenAI 格式使用 status 字段
|
||||
assert openai_response["status"] in ("queued", "processing")
|
||||
assert "id" in openai_response
|
||||
|
||||
def test_gemini_to_openai_completed_task(self) -> None:
|
||||
"""Gemini 完成任务 -> OpenAI 格式"""
|
||||
reg = _make_registry()
|
||||
|
||||
gemini_response = {
|
||||
"name": "operations/12345",
|
||||
"done": True,
|
||||
"response": {
|
||||
"generateVideoResponse": {
|
||||
"generatedSamples": [{"video": {"uri": "https://example.com/video.mp4"}}]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
openai_response = reg.convert_video_task(gemini_response, "gemini:video", "openai:video")
|
||||
|
||||
assert openai_response["status"] == "completed"
|
||||
assert openai_response["progress"] == 100
|
||||
|
||||
def test_openai_to_gemini_processing_task(self) -> None:
|
||||
"""OpenAI 处理中任务 -> Gemini 格式"""
|
||||
reg = _make_registry()
|
||||
|
||||
openai_response = {
|
||||
"id": "task_12345",
|
||||
"object": "video",
|
||||
"status": "processing",
|
||||
"progress": 30,
|
||||
"created_at": 1700000000,
|
||||
}
|
||||
|
||||
gemini_response = reg.convert_video_task(openai_response, "openai:video", "gemini:video")
|
||||
|
||||
# Gemini 格式使用 done 字段
|
||||
assert gemini_response["done"] is False
|
||||
assert "name" in gemini_response
|
||||
|
||||
def test_openai_to_gemini_completed_task(self) -> None:
|
||||
"""OpenAI 完成任务 -> Gemini 格式"""
|
||||
reg = _make_registry()
|
||||
|
||||
openai_response = {
|
||||
"id": "task_12345",
|
||||
"object": "video",
|
||||
"status": "completed",
|
||||
"progress": 100,
|
||||
"created_at": 1700000000,
|
||||
"completed_at": 1700000100,
|
||||
}
|
||||
|
||||
gemini_response = reg.convert_video_task(openai_response, "openai:video", "gemini:video")
|
||||
|
||||
assert gemini_response["done"] is True
|
||||
|
||||
|
||||
class TestVideoConversionCapabilities:
|
||||
"""视频格式转换能力检查测试"""
|
||||
|
||||
def test_can_convert_video(self) -> None:
|
||||
"""检查视频格式转换能力"""
|
||||
reg = _make_registry()
|
||||
|
||||
assert reg.can_convert_video("openai:video", "gemini:video") is True
|
||||
assert reg.can_convert_video("gemini:video", "openai:video") is True
|
||||
assert reg.can_convert_video("openai:video", "openai:video") is True
|
||||
|
||||
def test_cannot_convert_unsupported_format(self) -> None:
|
||||
"""不支持的格式无法转换"""
|
||||
reg = _make_registry()
|
||||
|
||||
# 没有注册 Claude normalizer 用于视频
|
||||
assert reg.can_convert_video("openai:video", "claude:video") is False
|
||||
Reference in New Issue
Block a user