revert: restore original image generation config
This commit is contained in:
326
api/main.py
326
api/main.py
@@ -132,169 +132,26 @@ IMAGE_SIZE_CHOICES = [
|
||||
"id": "auto",
|
||||
"label": "自动",
|
||||
"value": "auto",
|
||||
"ratio": "auto",
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"description": "由图片模型自行决定输出尺寸,生成后显示实际像素",
|
||||
"description": "由图片模型自行决定输出尺寸",
|
||||
},
|
||||
{
|
||||
"id": "1024x1536",
|
||||
"label": "竖图 2:3 · 1024×1536",
|
||||
"label": "竖图 2:3",
|
||||
"value": "1024x1536",
|
||||
"ratio": "2:3",
|
||||
"width": 1024,
|
||||
"height": 1536,
|
||||
"description": "适合信息流营销图、人物和产品竖版构图",
|
||||
},
|
||||
{
|
||||
"id": "1536x2304",
|
||||
"label": "竖图 2:3 · 1536×2304",
|
||||
"value": "1536x2304",
|
||||
"ratio": "2:3",
|
||||
"width": 1536,
|
||||
"height": 2304,
|
||||
"description": "适合高精细竖版海报和后期裁切",
|
||||
},
|
||||
{
|
||||
"id": "1088x1920",
|
||||
"label": "竖屏 9:16 · 1088×1920",
|
||||
"value": "1088x1920",
|
||||
"ratio": "9:16",
|
||||
"width": 1088,
|
||||
"height": 1920,
|
||||
"description": "接近 1080p 竖屏,宽度按 16 像素倍数提交",
|
||||
},
|
||||
{
|
||||
"id": "1440x2560",
|
||||
"label": "竖屏 9:16 · 1440×2560",
|
||||
"value": "1440x2560",
|
||||
"ratio": "9:16",
|
||||
"width": 1440,
|
||||
"height": 2560,
|
||||
"description": "适合短视频封面、竖屏高清素材和二次裁切",
|
||||
},
|
||||
{
|
||||
"id": "960x1280",
|
||||
"label": "竖图 3:4 · 960×1280",
|
||||
"value": "960x1280",
|
||||
"ratio": "3:4",
|
||||
"width": 960,
|
||||
"height": 1280,
|
||||
"description": "适合偏人物或产品竖图,文件体积较轻",
|
||||
},
|
||||
{
|
||||
"id": "1536x1920",
|
||||
"label": "竖图 4:5 · 1536×1920",
|
||||
"value": "1536x1920",
|
||||
"ratio": "4:5",
|
||||
"width": 1536,
|
||||
"height": 1920,
|
||||
"description": "适合小红书、社媒封面和产品展示图",
|
||||
},
|
||||
{
|
||||
"id": "1024x1024",
|
||||
"label": "方图 1:1 · 1024×1024",
|
||||
"label": "方图 1:1",
|
||||
"value": "1024x1024",
|
||||
"ratio": "1:1",
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"description": "适合头像、方形素材和电商图",
|
||||
},
|
||||
{
|
||||
"id": "2048x2048",
|
||||
"label": "方图 1:1 · 2048×2048",
|
||||
"value": "2048x2048",
|
||||
"ratio": "1:1",
|
||||
"width": 2048,
|
||||
"height": 2048,
|
||||
"description": "适合高清方形素材和后期抠图",
|
||||
},
|
||||
{
|
||||
"id": "1536x1024",
|
||||
"label": "横图 3:2 · 1536×1024",
|
||||
"label": "横图 3:2",
|
||||
"value": "1536x1024",
|
||||
"ratio": "3:2",
|
||||
"width": 1536,
|
||||
"height": 1024,
|
||||
"description": "适合横版封面和详情页配图",
|
||||
},
|
||||
{
|
||||
"id": "2304x1536",
|
||||
"label": "横图 3:2 · 2304×1536",
|
||||
"value": "2304x1536",
|
||||
"ratio": "3:2",
|
||||
"width": 2304,
|
||||
"height": 1536,
|
||||
"description": "适合高清横版主视觉和详情页大图",
|
||||
},
|
||||
{
|
||||
"id": "1280x720",
|
||||
"label": "横屏 16:9 · 1280×720",
|
||||
"value": "1280x720",
|
||||
"ratio": "16:9",
|
||||
"width": 1280,
|
||||
"height": 720,
|
||||
"description": "适合轻量横版封面、网页首屏和视频首帧",
|
||||
},
|
||||
{
|
||||
"id": "2048x1152",
|
||||
"label": "横屏 16:9 · 2048×1152",
|
||||
"value": "2048x1152",
|
||||
"ratio": "16:9",
|
||||
"width": 2048,
|
||||
"height": 1152,
|
||||
"description": "适合高清横版视频封面和大屏展示",
|
||||
},
|
||||
]
|
||||
GEMINI_IMAGE_SIZE_CHOICES = [
|
||||
{
|
||||
"id": "auto",
|
||||
"label": "自动",
|
||||
"value": "auto",
|
||||
"ratio": "auto",
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"description": "由 Gemini 自行决定输出尺寸,生成后显示实际像素",
|
||||
},
|
||||
{"id": "1024x1024", "label": "方图 1:1 · 1K · 1024×1024", "value": "1024x1024", "ratio": "1:1", "image_size": "1K", "width": 1024, "height": 1024},
|
||||
{"id": "848x1264", "label": "竖图 2:3 · 1K · 848×1264", "value": "848x1264", "ratio": "2:3", "image_size": "1K", "width": 848, "height": 1264},
|
||||
{"id": "1264x848", "label": "横图 3:2 · 1K · 1264×848", "value": "1264x848", "ratio": "3:2", "image_size": "1K", "width": 1264, "height": 848},
|
||||
{"id": "896x1200", "label": "竖图 3:4 · 1K · 896×1200", "value": "896x1200", "ratio": "3:4", "image_size": "1K", "width": 896, "height": 1200},
|
||||
{"id": "928x1152", "label": "竖图 4:5 · 1K · 928×1152", "value": "928x1152", "ratio": "4:5", "image_size": "1K", "width": 928, "height": 1152},
|
||||
{"id": "768x1376", "label": "竖屏 9:16 · 1K · 768×1376", "value": "768x1376", "ratio": "9:16", "image_size": "1K", "width": 768, "height": 1376},
|
||||
{"id": "1376x768", "label": "横屏 16:9 · 1K · 1376×768", "value": "1376x768", "ratio": "16:9", "image_size": "1K", "width": 1376, "height": 768},
|
||||
{"id": "2048x2048", "label": "方图 1:1 · 2K · 2048×2048", "value": "2048x2048", "ratio": "1:1", "image_size": "2K", "width": 2048, "height": 2048},
|
||||
{"id": "1696x2528", "label": "竖图 2:3 · 2K · 1696×2528", "value": "1696x2528", "ratio": "2:3", "image_size": "2K", "width": 1696, "height": 2528},
|
||||
{"id": "2528x1696", "label": "横图 3:2 · 2K · 2528×1696", "value": "2528x1696", "ratio": "3:2", "image_size": "2K", "width": 2528, "height": 1696},
|
||||
{"id": "1792x2400", "label": "竖图 3:4 · 2K · 1792×2400", "value": "1792x2400", "ratio": "3:4", "image_size": "2K", "width": 1792, "height": 2400},
|
||||
{"id": "1856x2304", "label": "竖图 4:5 · 2K · 1856×2304", "value": "1856x2304", "ratio": "4:5", "image_size": "2K", "width": 1856, "height": 2304},
|
||||
{"id": "1536x2752", "label": "竖屏 9:16 · 2K · 1536×2752", "value": "1536x2752", "ratio": "9:16", "image_size": "2K", "width": 1536, "height": 2752},
|
||||
{"id": "2752x1536", "label": "横屏 16:9 · 2K · 2752×1536", "value": "2752x1536", "ratio": "16:9", "image_size": "2K", "width": 2752, "height": 1536},
|
||||
{"id": "4096x4096", "label": "方图 1:1 · 4K · 4096×4096", "value": "4096x4096", "ratio": "1:1", "image_size": "4K", "width": 4096, "height": 4096},
|
||||
{"id": "3392x5056", "label": "竖图 2:3 · 4K · 3392×5056", "value": "3392x5056", "ratio": "2:3", "image_size": "4K", "width": 3392, "height": 5056},
|
||||
{"id": "5056x3392", "label": "横图 3:2 · 4K · 5056×3392", "value": "5056x3392", "ratio": "3:2", "image_size": "4K", "width": 5056, "height": 3392},
|
||||
{"id": "3072x5504", "label": "竖屏 9:16 · 4K · 3072×5504", "value": "3072x5504", "ratio": "9:16", "image_size": "4K", "width": 3072, "height": 5504},
|
||||
{"id": "5504x3072", "label": "横屏 16:9 · 4K · 5504×3072", "value": "5504x3072", "ratio": "16:9", "image_size": "4K", "width": 5504, "height": 3072},
|
||||
]
|
||||
IMAGE_QUALITY_CHOICES = [
|
||||
{
|
||||
"id": "low",
|
||||
"label": "低 · 快速草稿",
|
||||
"value": "low",
|
||||
"description": "更快生成,适合批量试方向",
|
||||
},
|
||||
{
|
||||
"id": "medium",
|
||||
"label": "中 · 常规出图",
|
||||
"value": "medium",
|
||||
"description": "速度和质量折中,适合日常迭代",
|
||||
},
|
||||
{
|
||||
"id": "high",
|
||||
"label": "高 · 最终稿",
|
||||
"value": "high",
|
||||
"description": "质量优先,适合定稿和高清素材",
|
||||
},
|
||||
]
|
||||
VIDEO_SIZE_CHOICES = [
|
||||
{
|
||||
@@ -597,10 +454,6 @@ class GeneratedImage(BaseModel):
|
||||
model: str
|
||||
mode: str = "edit" # "edit"(带参考图) | "text"(纯文字)
|
||||
url: str # /jobs/{job_id}/frames/{idx}/gen/{id}.jpg
|
||||
size: str = ""
|
||||
quality: str = ""
|
||||
width: int = 0
|
||||
height: int = 0
|
||||
selected: bool = False
|
||||
created_at: float = 0.0
|
||||
|
||||
@@ -4714,9 +4567,6 @@ def image_model_options() -> list[dict]:
|
||||
"model": GPT_IMAGE_MODEL,
|
||||
"description": "优先 GPT Image 2,必要时按后端熔断和兜底策略切到备用图片模型",
|
||||
"available": bool(IMAGE_API_KEY),
|
||||
"size_options": IMAGE_SIZE_CHOICES,
|
||||
"quality_options": IMAGE_QUALITY_CHOICES,
|
||||
"supports_custom_size": True,
|
||||
},
|
||||
{
|
||||
"id": GPT_IMAGE_MODEL,
|
||||
@@ -4724,9 +4574,6 @@ def image_model_options() -> list[dict]:
|
||||
"model": GPT_IMAGE_MODEL,
|
||||
"description": "主生图模型,适合营销图和参考图重绘",
|
||||
"available": bool(IMAGE_API_KEY),
|
||||
"size_options": IMAGE_SIZE_CHOICES,
|
||||
"quality_options": IMAGE_QUALITY_CHOICES,
|
||||
"supports_custom_size": True,
|
||||
},
|
||||
]
|
||||
if IMAGE_FALLBACK_ENABLED and IMAGE_FALLBACK_MODEL and IMAGE_FALLBACK_MODEL != GPT_IMAGE_MODEL:
|
||||
@@ -4734,11 +4581,8 @@ def image_model_options() -> list[dict]:
|
||||
"id": IMAGE_FALLBACK_MODEL,
|
||||
"label": "Gemini 图片",
|
||||
"model": IMAGE_FALLBACK_MODEL,
|
||||
"description": "备用图片模型,使用 Gemini 官方比例和 1K/2K/4K 固定规格",
|
||||
"description": "备用图片模型,适合主模型慢或失败时手动选择",
|
||||
"available": bool(IMAGE_API_KEY),
|
||||
"size_options": GEMINI_IMAGE_SIZE_CHOICES,
|
||||
"quality_options": [],
|
||||
"supports_custom_size": False,
|
||||
})
|
||||
return options
|
||||
|
||||
@@ -4747,145 +4591,28 @@ def image_size_options() -> list[dict]:
|
||||
return IMAGE_SIZE_CHOICES
|
||||
|
||||
|
||||
def gemini_image_size_options() -> list[dict]:
|
||||
return GEMINI_IMAGE_SIZE_CHOICES
|
||||
|
||||
|
||||
def image_quality_options() -> list[dict]:
|
||||
return IMAGE_QUALITY_CHOICES
|
||||
|
||||
|
||||
def _parse_image_dimensions(value: str) -> tuple[int, int] | None:
|
||||
normalized = value.strip().lower().replace("×", "x")
|
||||
m = re.fullmatch(r"(\d{3,4})\s*x\s*(\d{3,4})", normalized)
|
||||
if not m:
|
||||
return None
|
||||
return int(m.group(1)), int(m.group(2))
|
||||
|
||||
|
||||
def _validate_custom_image_size(width: int, height: int, raw: str) -> str:
|
||||
pixels = width * height
|
||||
long_edge = max(width, height)
|
||||
short_edge = min(width, height)
|
||||
if width % 16 != 0 or height % 16 != 0:
|
||||
raise HTTPException(400, f"unsupported image size: {raw} (宽高必须都是 16 的倍数,例如 1088x1920)")
|
||||
if long_edge > 3840:
|
||||
raise HTTPException(400, f"unsupported image size: {raw} (最长边不能超过 3840px)")
|
||||
if long_edge / short_edge > 3:
|
||||
raise HTTPException(400, f"unsupported image size: {raw} (画幅比例不能超过 3:1)")
|
||||
if pixels < 655_360 or pixels > 8_294_400:
|
||||
raise HTTPException(400, f"unsupported image size: {raw} (总像素需在 655360 到 8294400 之间)")
|
||||
return f"{width}x{height}"
|
||||
|
||||
|
||||
def _is_gemini_image_model(model: str | None) -> bool:
|
||||
normalized = (model or "").strip().lower()
|
||||
return bool(normalized and normalized.startswith("gemini")) or (
|
||||
bool(IMAGE_FALLBACK_MODEL) and normalized == IMAGE_FALLBACK_MODEL.lower()
|
||||
)
|
||||
|
||||
|
||||
def _normalize_image_size(raw: str | None, model: str | None = GPT_IMAGE_MODEL, fallback_to_auto: bool = False) -> str:
|
||||
def _normalize_image_size(raw: str | None) -> str:
|
||||
value = (raw or "auto").strip().lower()
|
||||
gpt_aliases = {
|
||||
"9:16": "1088x1920",
|
||||
"9x16": "1088x1920",
|
||||
"16:9": "1280x720",
|
||||
"16x9": "1280x720",
|
||||
"1:1": "1024x1024",
|
||||
"1x1": "1024x1024",
|
||||
"2:3": "1024x1536",
|
||||
"2x3": "1024x1536",
|
||||
"3:2": "1536x1024",
|
||||
"3x2": "1536x1024",
|
||||
"3:4": "960x1280",
|
||||
"3x4": "960x1280",
|
||||
"4:5": "1536x1920",
|
||||
"4x5": "1536x1920",
|
||||
aliases = {
|
||||
"vertical": "1024x1536",
|
||||
"portrait": "1024x1536",
|
||||
"竖图": "1024x1536",
|
||||
"竖屏": "1088x1920",
|
||||
"square": "1024x1024",
|
||||
"方图": "1024x1024",
|
||||
"horizontal": "1536x1024",
|
||||
"landscape": "1536x1024",
|
||||
"横图": "1536x1024",
|
||||
"横屏": "1280x720",
|
||||
}
|
||||
gemini_aliases = {
|
||||
"1:1": "1024x1024",
|
||||
"1x1": "1024x1024",
|
||||
"2:3": "848x1264",
|
||||
"2x3": "848x1264",
|
||||
"3:2": "1264x848",
|
||||
"3x2": "1264x848",
|
||||
"3:4": "896x1200",
|
||||
"3x4": "896x1200",
|
||||
"4:5": "928x1152",
|
||||
"4x5": "928x1152",
|
||||
"9:16": "768x1376",
|
||||
"9x16": "768x1376",
|
||||
"16:9": "1376x768",
|
||||
"16x9": "1376x768",
|
||||
"竖屏": "768x1376",
|
||||
"横屏": "1376x768",
|
||||
"方图": "1024x1024",
|
||||
}
|
||||
if _is_gemini_image_model(model):
|
||||
value = gemini_aliases.get(value, value)
|
||||
allowed = {str(item["value"]) for item in GEMINI_IMAGE_SIZE_CHOICES}
|
||||
if value in allowed:
|
||||
return value
|
||||
if fallback_to_auto:
|
||||
return "auto"
|
||||
raise HTTPException(400, f"unsupported Gemini image size: {raw}")
|
||||
value = gpt_aliases.get(value, value)
|
||||
allowed = {str(item["value"]) for item in IMAGE_SIZE_CHOICES}
|
||||
if value in allowed:
|
||||
return value
|
||||
dimensions = _parse_image_dimensions(value)
|
||||
if dimensions:
|
||||
return _validate_custom_image_size(dimensions[0], dimensions[1], raw or value)
|
||||
raise HTTPException(400, f"unsupported image size: {raw}")
|
||||
|
||||
|
||||
def _image_size_payload(raw: str | None, model: str | None = GPT_IMAGE_MODEL, fallback_to_auto: bool = False) -> dict:
|
||||
size = _normalize_image_size(raw, model, fallback_to_auto=fallback_to_auto)
|
||||
return {} if size == "auto" else {"size": size}
|
||||
|
||||
|
||||
def _normalize_image_quality(raw: str | None) -> str:
|
||||
value = (raw or "high").strip().lower()
|
||||
aliases = {
|
||||
"standard": "high",
|
||||
"hd": "high",
|
||||
"best": "high",
|
||||
"高": "high",
|
||||
"high-quality": "high",
|
||||
"normal": "medium",
|
||||
"regular": "medium",
|
||||
"中": "medium",
|
||||
"medium-quality": "medium",
|
||||
"draft": "low",
|
||||
"fast": "low",
|
||||
"低": "low",
|
||||
"low-quality": "low",
|
||||
}
|
||||
value = aliases.get(value, value)
|
||||
allowed = {str(item["value"]) for item in IMAGE_QUALITY_CHOICES}
|
||||
allowed = {str(item["value"]) for item in IMAGE_SIZE_CHOICES}
|
||||
if value not in allowed:
|
||||
raise HTTPException(400, f"unsupported image quality: {raw}")
|
||||
raise HTTPException(400, f"unsupported image size: {raw}")
|
||||
return value
|
||||
|
||||
|
||||
def _image_quality_payload(raw: str | None, model: str | None) -> dict:
|
||||
quality = _normalize_image_quality(raw)
|
||||
return {"quality": quality} if model == GPT_IMAGE_MODEL else {}
|
||||
|
||||
|
||||
def _image_options_payload(size: str | None, quality: str | None, model: str | None) -> dict:
|
||||
return {**_image_size_payload(size, model, fallback_to_auto=True), **_image_quality_payload(quality, model)}
|
||||
def _image_size_payload(raw: str | None) -> dict:
|
||||
size = _normalize_image_size(raw)
|
||||
return {} if size == "auto" else {"size": size}
|
||||
|
||||
|
||||
def video_duration_options() -> list[int]:
|
||||
@@ -5047,12 +4774,12 @@ def _image_endpoint(path: str) -> str:
|
||||
return f"{base}/{path.lstrip('/')}"
|
||||
|
||||
|
||||
def _image_generation_response(prompt: str, model: str, size: str | None = "auto", quality: str | None = "high") -> dict:
|
||||
def _image_generation_response(prompt: str, model: str, size: str | None = "auto") -> dict:
|
||||
with ai_http_client(timeout=IMAGE_REQUEST_TIMEOUT_SECONDS) as client:
|
||||
r = client.post(
|
||||
_image_endpoint("/images/generations"),
|
||||
headers={"Authorization": f"Bearer {IMAGE_API_KEY}"},
|
||||
json={"model": model, "prompt": prompt, "n": 1, **_image_options_payload(size, quality, model)},
|
||||
json={"model": model, "prompt": prompt, "n": 1, **_image_size_payload(size)},
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
@@ -6381,8 +6108,6 @@ def health() -> dict:
|
||||
"image_request_timeout_seconds": IMAGE_REQUEST_TIMEOUT_SECONDS,
|
||||
"image_options": image_model_options(),
|
||||
"image_size_options": image_size_options(),
|
||||
"gemini_image_size_options": gemini_image_size_options(),
|
||||
"image_quality_options": image_quality_options(),
|
||||
"ai_proxy_configured": bool(AI_HTTP_PROXY),
|
||||
"image_fallbacks": _image_fallback_models(),
|
||||
"image_circuit": _image_circuit_snapshot(),
|
||||
@@ -6871,8 +6596,7 @@ class GenerateReq(BaseModel):
|
||||
extra_prompt: str = "" # ✓ 需要的元素(正向)
|
||||
negative_prompt: str = "" # ✗ 不需要的元素(负向)
|
||||
model: str = "auto" # auto / gpt-image-2 / gemini-3-pro-image-preview
|
||||
size: str = "auto" # auto / 1024x1536 / 1088x1920 / custom WxH
|
||||
quality: str = "high" # low / medium / high
|
||||
size: str = "auto" # auto / 1024x1536 / 1024x1024 / 1536x1024
|
||||
mode: str = "edit" # "edit" 带参考图,"text" 纯文字
|
||||
from_selected: bool = False # True 时优先用 frame.selected 的生成图作 reference(迭代),否则原关键帧
|
||||
|
||||
@@ -6909,10 +6633,7 @@ def generate_image(job_id: str, idx: int, req: GenerateReq) -> Job:
|
||||
if not raw_prompt:
|
||||
raise HTTPException(400, "prompt required")
|
||||
full_prompt = _ensure_english(raw_prompt)
|
||||
requested_model = _normalize_image_model_preference(req.model)
|
||||
strict_size_model = IMAGE_FALLBACK_MODEL if requested_model == IMAGE_FALLBACK_MODEL else GPT_IMAGE_MODEL
|
||||
image_size = _normalize_image_size(req.size, strict_size_model)
|
||||
image_quality = _normalize_image_quality(req.quality)
|
||||
image_size = _normalize_image_size(req.size)
|
||||
if not IMAGE_API_KEY:
|
||||
raise HTTPException(503, "IMAGE_API_KEY 或 LLM_API_KEY 未配置")
|
||||
|
||||
@@ -6953,14 +6674,14 @@ def generate_image(job_id: str, idx: int, req: GenerateReq) -> Job:
|
||||
headers={
|
||||
"Authorization": f"Bearer {IMAGE_API_KEY}",
|
||||
},
|
||||
data={"model": current_model, "prompt": full_prompt, "n": "1", **_image_options_payload(image_size, image_quality, current_model)},
|
||||
data={"model": current_model, "prompt": full_prompt, "n": "1", **_image_size_payload(image_size)},
|
||||
files={"image": ("reference.jpg", img_bytes_in, "image/jpeg")},
|
||||
)
|
||||
r.raise_for_status()
|
||||
resp_data = r.json()
|
||||
else:
|
||||
# text-only
|
||||
resp_data = _image_generation_response(full_prompt, current_model, image_size, image_quality)
|
||||
resp_data = _image_generation_response(full_prompt, current_model, image_size)
|
||||
|
||||
if resp_data.get("data"):
|
||||
effective_mode = f"{current_mode}:{current_model}"
|
||||
@@ -7025,13 +6746,6 @@ def generate_image(job_id: str, idx: int, req: GenerateReq) -> Job:
|
||||
gen_dir.mkdir(parents=True, exist_ok=True)
|
||||
out_path = gen_dir / f"{idx:03d}_{gen_id}.jpg"
|
||||
out_path.write_bytes(out_bytes)
|
||||
actual_width = 0
|
||||
actual_height = 0
|
||||
try:
|
||||
with Image.open(io.BytesIO(out_bytes)) as im:
|
||||
actual_width, actual_height = im.size
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
new_gen = GeneratedImage(
|
||||
id=gen_id,
|
||||
@@ -7039,10 +6753,6 @@ def generate_image(job_id: str, idx: int, req: GenerateReq) -> Job:
|
||||
model=model,
|
||||
mode=effective_mode,
|
||||
url=f"/jobs/{job_id}/frames/{idx}/gen/{gen_id}.jpg",
|
||||
size=image_size,
|
||||
quality=image_quality,
|
||||
width=actual_width,
|
||||
height=actual_height,
|
||||
selected=False,
|
||||
created_at=_time.time(),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user