mirror of
https://github.com/TheSmallHanCat/sora2api.git
synced 2026-02-14 01:54:41 +08:00
feat: 普号增加25s普通视频、增加pro系列高清模型、统一模型名字、过载不再计入错误禁用计数
This commit is contained in:
@@ -19,52 +19,139 @@ from ..core.logger import debug_logger
|
||||
|
||||
# Model configuration
|
||||
MODEL_CONFIG = {
|
||||
"sora-image": {
|
||||
"gpt-image": {
|
||||
"type": "image",
|
||||
"width": 360,
|
||||
"height": 360
|
||||
},
|
||||
"sora-image-landscape": {
|
||||
"gpt-image-landscape": {
|
||||
"type": "image",
|
||||
"width": 540,
|
||||
"height": 360
|
||||
},
|
||||
"sora-image-portrait": {
|
||||
"gpt-image-portrait": {
|
||||
"type": "image",
|
||||
"width": 360,
|
||||
"height": 540
|
||||
},
|
||||
# Video models with 10s duration (300 frames)
|
||||
"sora-video-10s": {
|
||||
"sora2-landscape-10s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 300
|
||||
},
|
||||
"sora-video-landscape-10s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 300
|
||||
},
|
||||
"sora-video-portrait-10s": {
|
||||
"sora2-portrait-10s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 300
|
||||
},
|
||||
# Video models with 15s duration (450 frames)
|
||||
"sora-video-15s": {
|
||||
"sora2-landscape-15s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 450
|
||||
},
|
||||
"sora-video-landscape-15s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 450
|
||||
},
|
||||
"sora-video-portrait-15s": {
|
||||
"sora2-portrait-15s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 450
|
||||
},
|
||||
# Video models with 25s duration (750 frames)
|
||||
"sora2-landscape-25s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 750,
|
||||
"model": "sy_8",
|
||||
"size": "small"
|
||||
},
|
||||
"sora2-portrait-25s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 750,
|
||||
"model": "sy_8",
|
||||
"size": "small"
|
||||
},
|
||||
# Pro video models (require Pro subscription)
|
||||
"sora2pro-landscape-10s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 300,
|
||||
"model": "sy_ore",
|
||||
"size": "small",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-portrait-10s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 300,
|
||||
"model": "sy_ore",
|
||||
"size": "small",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-landscape-15s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 450,
|
||||
"model": "sy_ore",
|
||||
"size": "small",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-portrait-15s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 450,
|
||||
"model": "sy_ore",
|
||||
"size": "small",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-landscape-25s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 750,
|
||||
"model": "sy_ore",
|
||||
"size": "small",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-portrait-25s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 750,
|
||||
"model": "sy_ore",
|
||||
"size": "small",
|
||||
"require_pro": True
|
||||
},
|
||||
# Pro HD video models (require Pro subscription, high quality)
|
||||
"sora2pro-hd-landscape-10s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 300,
|
||||
"model": "sy_ore",
|
||||
"size": "large",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-hd-portrait-10s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 300,
|
||||
"model": "sy_ore",
|
||||
"size": "large",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-hd-landscape-15s": {
|
||||
"type": "video",
|
||||
"orientation": "landscape",
|
||||
"n_frames": 450,
|
||||
"model": "sy_ore",
|
||||
"size": "large",
|
||||
"require_pro": True
|
||||
},
|
||||
"sora2pro-hd-portrait-15s": {
|
||||
"type": "video",
|
||||
"orientation": "portrait",
|
||||
"n_frames": 450,
|
||||
"model": "sy_ore",
|
||||
"size": "large",
|
||||
"require_pro": True
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,10 +381,20 @@ class GenerationHandler:
|
||||
return
|
||||
|
||||
# Streaming mode: proceed with actual generation
|
||||
# Check if model requires Pro subscription
|
||||
require_pro = model_config.get("require_pro", False)
|
||||
|
||||
# Select token (with lock for image generation, Sora2 quota check for video generation)
|
||||
token_obj = await self.load_balancer.select_token(for_image_generation=is_image, for_video_generation=is_video)
|
||||
# If Pro is required, filter for Pro tokens only
|
||||
token_obj = await self.load_balancer.select_token(
|
||||
for_image_generation=is_image,
|
||||
for_video_generation=is_video,
|
||||
require_pro=require_pro
|
||||
)
|
||||
if not token_obj:
|
||||
if is_image:
|
||||
if require_pro:
|
||||
raise Exception("No available Pro tokens. Pro models require a ChatGPT Pro subscription.")
|
||||
elif is_image:
|
||||
raise Exception("No available tokens for image generation. All tokens are either disabled, cooling down, locked, or expired.")
|
||||
else:
|
||||
raise Exception("No available tokens for video generation. All tokens are either disabled, cooling down, Sora2 quota exhausted, don't support Sora2, or expired.")
|
||||
@@ -383,12 +480,18 @@ class GenerationHandler:
|
||||
)
|
||||
else:
|
||||
# Normal video generation
|
||||
# Get model and size from config (default to sy_8 and small for backward compatibility)
|
||||
sora_model = model_config.get("model", "sy_8")
|
||||
video_size = model_config.get("size", "small")
|
||||
|
||||
task_id = await self.sora_client.generate_video(
|
||||
clean_prompt, token_obj.token,
|
||||
orientation=model_config["orientation"],
|
||||
media_id=media_id,
|
||||
n_frames=n_frames,
|
||||
style_id=style_id
|
||||
style_id=style_id,
|
||||
model=sora_model,
|
||||
size=video_size
|
||||
)
|
||||
else:
|
||||
task_id = await self.sora_client.generate_image(
|
||||
@@ -1271,10 +1374,16 @@ class GenerationHandler:
|
||||
# Get n_frames from model configuration
|
||||
n_frames = model_config.get("n_frames", 300) # Default to 300 frames (10s)
|
||||
|
||||
# Get model and size from config (default to sy_8 and small for backward compatibility)
|
||||
sora_model = model_config.get("model", "sy_8")
|
||||
video_size = model_config.get("size", "small")
|
||||
|
||||
task_id = await self.sora_client.generate_video(
|
||||
full_prompt, token_obj.token,
|
||||
orientation=model_config["orientation"],
|
||||
n_frames=n_frames
|
||||
n_frames=n_frames,
|
||||
model=sora_model,
|
||||
size=video_size
|
||||
)
|
||||
debug_logger.log_info(f"Video generation started, task_id: {task_id}")
|
||||
|
||||
@@ -1282,7 +1391,7 @@ class GenerationHandler:
|
||||
task = Task(
|
||||
task_id=task_id,
|
||||
token_id=token_obj.id,
|
||||
model=f"sora-video-{model_config['orientation']}",
|
||||
model=f"sora2-video-{model_config['orientation']}",
|
||||
prompt=full_prompt,
|
||||
status="processing",
|
||||
progress=0.0
|
||||
@@ -1375,7 +1484,7 @@ class GenerationHandler:
|
||||
task = Task(
|
||||
task_id=task_id,
|
||||
token_id=token_obj.id,
|
||||
model=f"sora-video-{model_config['orientation']}",
|
||||
model=f"sora2-video-{model_config['orientation']}",
|
||||
prompt=f"remix:{remix_target_id} {clean_prompt}",
|
||||
status="processing",
|
||||
progress=0.0
|
||||
|
||||
@@ -17,13 +17,14 @@ class LoadBalancer:
|
||||
# Use image timeout from config as lock timeout
|
||||
self.token_lock = TokenLock(lock_timeout=config.image_timeout)
|
||||
|
||||
async def select_token(self, for_image_generation: bool = False, for_video_generation: bool = False) -> Optional[Token]:
|
||||
async def select_token(self, for_image_generation: bool = False, for_video_generation: bool = False, require_pro: bool = False) -> Optional[Token]:
|
||||
"""
|
||||
Select a token using random load balancing
|
||||
|
||||
Args:
|
||||
for_image_generation: If True, only select tokens that are not locked for image generation and have image_enabled=True
|
||||
for_video_generation: If True, filter out tokens with Sora2 quota exhausted (sora2_cooldown_until not expired), tokens that don't support Sora2, and tokens with video_enabled=False
|
||||
require_pro: If True, only select tokens with ChatGPT Pro subscription (plan_type="chatgpt_pro")
|
||||
|
||||
Returns:
|
||||
Selected token or None if no available tokens
|
||||
@@ -56,6 +57,13 @@ class LoadBalancer:
|
||||
if not active_tokens:
|
||||
return None
|
||||
|
||||
# Filter for Pro tokens if required
|
||||
if require_pro:
|
||||
pro_tokens = [token for token in active_tokens if token.plan_type == "chatgpt_pro"]
|
||||
if not pro_tokens:
|
||||
return None
|
||||
active_tokens = pro_tokens
|
||||
|
||||
# If for video generation, filter out tokens with Sora2 quota exhausted and tokens without Sora2 support
|
||||
if for_video_generation:
|
||||
from datetime import datetime
|
||||
|
||||
@@ -254,8 +254,20 @@ class SoraClient:
|
||||
return result["id"]
|
||||
|
||||
async def generate_video(self, prompt: str, token: str, orientation: str = "landscape",
|
||||
media_id: Optional[str] = None, n_frames: int = 450, style_id: Optional[str] = None) -> str:
|
||||
"""Generate video (text-to-video or image-to-video)"""
|
||||
media_id: Optional[str] = None, n_frames: int = 450, style_id: Optional[str] = None,
|
||||
model: str = "sy_8", size: str = "small") -> str:
|
||||
"""Generate video (text-to-video or image-to-video)
|
||||
|
||||
Args:
|
||||
prompt: Video generation prompt
|
||||
token: Access token
|
||||
orientation: Video orientation (landscape/portrait)
|
||||
media_id: Optional image media_id for image-to-video
|
||||
n_frames: Number of frames (300/450/750)
|
||||
style_id: Optional style ID
|
||||
model: Model to use (sy_8 for standard, sy_ore for pro)
|
||||
size: Video size (small for standard, large for HD)
|
||||
"""
|
||||
inpaint_items = []
|
||||
if media_id:
|
||||
inpaint_items = [{
|
||||
@@ -267,9 +279,9 @@ class SoraClient:
|
||||
"kind": "video",
|
||||
"prompt": prompt,
|
||||
"orientation": orientation,
|
||||
"size": "small",
|
||||
"size": size,
|
||||
"n_frames": n_frames,
|
||||
"model": "sy_8",
|
||||
"model": model,
|
||||
"inpaint_items": inpaint_items,
|
||||
"style_id": style_id
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user