fix: add task log

This commit is contained in:
p
2026-01-28 21:08:37 +08:00
parent 710562deb8
commit cc8869aeea
4 changed files with 47 additions and 23 deletions
+1 -1
View File
@@ -42,7 +42,6 @@ class TaskBase(SQLModel):
status: str # 'pending', 'processing', 'completed', 'failed' status: str # 'pending', 'processing', 'completed', 'failed'
progress: int = 0 # 0-100 progress: int = 0 # 0-100
message: Optional[str] = None message: Optional[str] = None
logs: List[str] = Field(default=[], sa_column=Column(JSON))
name: Optional[str] = None name: Optional[str] = None
description: Optional[str] = None description: Optional[str] = None
result: Dict = Field(default={}, sa_column=Column(JSON)) result: Dict = Field(default={}, sa_column=Column(JSON))
@@ -88,6 +87,7 @@ class Task(TaskBase, table=True):
project_id: str = Field(foreign_key="project.id") project_id: str = Field(foreign_key="project.id")
created_at: datetime = Field(default_factory=datetime.utcnow) created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow)
logs: List[str] = Field(default=[], sa_column=Column(JSON))
project: Project = Relationship(back_populates="tasks") project: Project = Relationship(back_populates="tasks")
+14 -5
View File
@@ -13,6 +13,7 @@ import traceback
import logging import logging
import sys import sys
import time
# Configure logging # Configure logging
logging.basicConfig(level=logging.INFO, stream=sys.stdout) logging.basicConfig(level=logging.INFO, stream=sys.stdout)
@@ -635,11 +636,19 @@ Ensure the character's expression and pose reflect their personality: {personali
""" """
log_task_event(session, task_id, f"Calling AI service for character {char.name}...") log_task_event(session, task_id, f"Calling AI service for character {char.name}...")
image_bytes = ai.generate_image( start_time = time.time()
prompt, try:
aspect_ratio=char.project.aspect_ratio or "16:9", image_bytes = ai.generate_image(
resolution=char.project.resolution or "2K" prompt,
) aspect_ratio=char.project.aspect_ratio or "16:9",
resolution=char.project.resolution or "2K"
)
elapsed = time.time() - start_time
log_task_event(session, task_id, f"AI generation finished in {elapsed:.2f}s. Image size: {len(image_bytes)} bytes.")
except Exception as e:
elapsed = time.time() - start_time
log_task_event(session, task_id, f"AI generation failed after {elapsed:.2f}s: {str(e)}")
raise e
relative_url = save_generated_image(session, char.project_id, "character", char.id, image_bytes) relative_url = save_generated_image(session, char.project_id, "character", char.id, image_bytes)
+30 -15
View File
@@ -1,5 +1,6 @@
import os import os
import time import time
import logging
from typing import List, Optional from typing import List, Optional
from sqlmodel import Session from sqlmodel import Session
from app.models.models import ModelConfig from app.models.models import ModelConfig
@@ -8,6 +9,8 @@ from google.genai import types
from PIL import Image from PIL import Image
import io import io
logger = logging.getLogger(__name__)
class AIService: class AIService:
def __init__(self, session: Session): def __init__(self, session: Session):
self.session = session self.session = session
@@ -30,15 +33,20 @@ class AIService:
full_prompt = f"{system_prompt}\n\nUser Input: {user_input}\n\nPlease generate the full storyboard in JSON format as requested." full_prompt = f"{system_prompt}\n\nUser Input: {user_input}\n\nPlease generate the full storyboard in JSON format as requested."
try: max_retries = 3
response = client.models.generate_content( for attempt in range(max_retries):
model=model_name, try:
contents=full_prompt response = client.models.generate_content(
) model=model_name,
return response.text contents=full_prompt
except Exception as e: )
print(f"Error generating storyboard: {e}") return response.text
raise e except Exception as e:
logger.error(f"Error generating storyboard (Attempt {attempt + 1}/{max_retries}): {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
continue
raise e
def generate_image(self, prompt: str, context_images: List[str] = None, aspect_ratio: str = "16:9", resolution: str = "2K") -> bytes: def generate_image(self, prompt: str, context_images: List[str] = None, aspect_ratio: str = "16:9", resolution: str = "2K") -> bytes:
client, model_name = self._get_client("image") client, model_name = self._get_client("image")
@@ -51,15 +59,20 @@ class AIService:
prev_img = Image.open(img_path) prev_img = Image.open(img_path)
contents.append(prev_img) contents.append(prev_img)
except Exception as e: except Exception as e:
print(f"Failed to load context image {img_path}: {e}") logger.warning(f"Failed to load context image {img_path}: {e}")
else: else:
# Log missing context image but don't fail, just skip it # Log missing context image but don't fail, just skip it
print(f"Warning: Context image not found at {img_path}, skipping.") logger.warning(f"Warning: Context image not found at {img_path}, skipping.")
# Retry loop # Retry loop
max_retries = 3 max_retries = 3
for attempt in range(max_retries): for attempt in range(max_retries):
try: try:
logger.info(f"DEBUG: Starting image generation attempt {attempt + 1}/{max_retries} with model {model_name}...")
logger.info(f"DEBUG: Prompt length: {len(prompt)}")
if context_images:
logger.info(f"DEBUG: Context images count: {len(context_images)}")
response = client.models.generate_content( response = client.models.generate_content(
model=model_name, model=model_name,
contents=contents, contents=contents,
@@ -70,28 +83,30 @@ class AIService:
), ),
) )
) )
logger.info(f"DEBUG: Generation API call completed for attempt {attempt + 1}")
if response.parts: if response.parts:
for part in response.parts: for part in response.parts:
if part.inline_data is not None: if part.inline_data is not None:
image_data = part.inline_data.data image_data = part.inline_data.data
if len(image_data) > 0: if len(image_data) > 0:
logger.info(f"DEBUG: Successfully received image data ({len(image_data)} bytes)")
return image_data return image_data
else: else:
print(f"Warning: Received empty image data on attempt {attempt + 1}") logger.warning(f"Warning: Received empty image data on attempt {attempt + 1}")
# Check for text refusal/error # Check for text refusal/error
if response.text: if response.text:
print(f"Model response text (no image): {response.text}") logger.warning(f"Model response text (no image): {response.text}")
print(f"Attempt {attempt + 1} failed: No valid image data found in response.") logger.warning(f"Attempt {attempt + 1} failed: No valid image data found in response.")
if attempt == max_retries - 1: if attempt == max_retries - 1:
raise ValueError(f"No image found in response after {max_retries} retries. Last response: {response.text if response.text else 'Empty'}") raise ValueError(f"No image found in response after {max_retries} retries. Last response: {response.text if response.text else 'Empty'}")
time.sleep(2 ** attempt) time.sleep(2 ** attempt)
except Exception as e: except Exception as e:
print(f"Error generating image (Attempt {attempt + 1}/{max_retries}): {e}") logger.error(f"Error generating image (Attempt {attempt + 1}/{max_retries}): {e}")
if attempt < max_retries - 1: if attempt < max_retries - 1:
time.sleep(2 ** attempt) time.sleep(2 ** attempt)
continue continue
+2 -2
View File
@@ -59,10 +59,10 @@
</div> </div>
<!-- Prompt (Existing) --> <!-- Prompt (Existing) -->
<div class="detail-group mt-3" v-if="item.data.prompt"> <div class="detail-group mt-3">
<label>Full Prompt:</label> <label>Full Prompt:</label>
<div class="detail-content prompt-text"> <div class="detail-content prompt-text">
{{ item.data.prompt }} {{ item.data.prompt || 'No prompt set' }}
</div> </div>
</div> </div>