Commit a37d46f8 authored by test's avatar test

更新AI生成、分镜工作台、数据库字段

parent 0aa3bd46
FROM docker.m.daocloud.io/library/node:20-alpine AS builder
ARG NODE_IMAGE=node:20-bookworm-slim
ARG NGINX_IMAGE=nginx:alpine
FROM ${NODE_IMAGE} AS builder
WORKDIR /app
......@@ -12,7 +15,7 @@ ENV VITE_API_BASE_URL=${VITE_API_BASE_URL}
RUN npm run build
FROM docker.m.daocloud.io/library/nginx:1.27-alpine
FROM ${NGINX_IMAGE}
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html
......
......@@ -19,7 +19,18 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /index.html {
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" always;
try_files /index.html =404;
}
location /assets/ {
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" always;
try_files $uri =404;
}
location / {
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" always;
try_files $uri $uri/ /index.html;
}
}
This diff is collapsed.
......@@ -367,7 +367,8 @@ export function useReorderStoryboards(projectId: string, episodeId: string) {
export function useGenerateStoryboardPrompt(projectId: string) {
return useMutation({
mutationFn: (storyboardId: string) => aiApi.generateStoryboardPrompt(projectId, storyboardId),
mutationFn: ({ storyboardId, ratio }: { storyboardId: string; ratio?: string }) =>
aiApi.generateStoryboardPrompt(projectId, storyboardId, ratio),
});
}
......
......@@ -261,8 +261,10 @@ export const aiApi = {
reorderStoryboards: async (projectId: string, ids: string[]): Promise<void> => {
await apiClient.put(`/projects/${projectId}/storyboards/reorder`, { ids });
},
generateStoryboardPrompt: async (projectId: string, storyboardId: string): Promise<string> => {
const r = await apiClient.post(`/projects/${projectId}/storyboards/${storyboardId}/generate-prompt`);
generateStoryboardPrompt: async (projectId: string, storyboardId: string, ratio?: string): Promise<string> => {
const r = await apiClient.post(`/projects/${projectId}/storyboards/${storyboardId}/generate-prompt`, null, {
params: ratio ? { ratio } : undefined,
});
return r.data.data.prompt;
},
listShotAssets: async (projectId: string, storyboardId: string): Promise<ShotAsset[]> => {
......
......@@ -6,8 +6,35 @@ $frontendDir = Join-Path $root "doc\html"
$adminDir = Join-Path $root "yaoai-admin-web"
$mavenCmd = Join-Path $root ".tools\apache-maven-3.9.6\bin\mvn.cmd"
$jdk17Candidates = @(
"C:\Program Files\Eclipse Adoptium\jdk-17.0.19.10-hotspot",
"C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot",
"C:\Program Files\Eclipse Adoptium\jdk-17",
"C:\Program Files\Java\jdk-17",
"D:\Program Files\Java\jdk-17"
)
$jdk17Home = $jdk17Candidates | Where-Object { Test-Path (Join-Path $_ "bin\java.exe") } | Select-Object -First 1
if (-not $jdk17Home) {
$jdk17Home = Get-ChildItem "C:\Program Files\Eclipse Adoptium" -Directory -Filter "jdk-17*" -ErrorAction SilentlyContinue |
Sort-Object Name -Descending |
Select-Object -First 1 -ExpandProperty FullName
}
if (-not $jdk17Home -or -not (Test-Path (Join-Path $jdk17Home "bin\java.exe"))) {
throw "Java 17 JDK not found. Please install JDK 17 and set JAVA_HOME."
}
$env:JAVA_HOME = $jdk17Home
$env:PATH = "$env:JAVA_HOME\bin;$env:PATH"
if (-not (Test-Path $mavenCmd)) {
$chocoMaven = "C:\ProgramData\chocolatey\lib\maven\apache-maven-3.9.16\bin\mvn.cmd"
if (Test-Path $chocoMaven) {
$mavenCmd = $chocoMaven
}
}
Push-Location $root
try {
Write-Host "[dev] using JAVA_HOME=$env:JAVA_HOME"
Write-Host "[dev] starting infrastructure from yaoai-comic-studio/docker-compose.yml ..."
docker compose -f (Join-Path $backendDir "docker-compose.yml") up -d
......@@ -24,9 +51,11 @@ try {
Write-Host ""
Write-Host "[dev] next commands"
Write-Host " 1. build backend"
Write-Host " `$env:JAVA_HOME = `"$env:JAVA_HOME`""
Write-Host " `$env:PATH = `"`$env:JAVA_HOME\bin;`$env:PATH`""
Write-Host " & `"$mavenCmd`" -f `"$backendDir\pom.xml`" package -pl yaoai-bootstrap -am -DskipTests"
Write-Host " 2. run backend"
Write-Host " java -jar `"$backendDir\yaoai-bootstrap\target\yaoai-bootstrap-0.1.0-SNAPSHOT.jar`""
Write-Host " & `"$env:JAVA_HOME\bin\java.exe`" -jar `"$backendDir\yaoai-bootstrap\target\yaoai-bootstrap-0.1.0-SNAPSHOT.jar`""
Write-Host " 3. run frontend"
Write-Host " Set-Location `"$frontendDir`"; npm install; npm run dev"
Write-Host " 4. run admin-web"
......
# ===== Stage 1: Build =====
FROM docker.m.daocloud.io/library/maven:3.9.9-eclipse-temurin-17 AS builder
ARG MAVEN_IMAGE=maven:3.9-eclipse-temurin-17-alpine
ARG RUNTIME_IMAGE=eclipse-temurin:17-jre-alpine
FROM ${MAVEN_IMAGE} AS builder
WORKDIR /workspace
......@@ -47,7 +50,7 @@ COPY . .
RUN mvn -s /root/.m2/settings.xml package -pl yaoai-bootstrap -am -DskipTests -B -ntp
# ===== Stage 2: Runtime =====
FROM docker.m.daocloud.io/library/eclipse-temurin:17-jre-jammy
FROM ${RUNTIME_IMAGE}
LABEL maintainer="YaoAI Team <yaoke251@gmail.com>"
LABEL org.opencontainers.image.title="YaoAI Comic Studio"
......@@ -60,6 +63,7 @@ ENV LANG=C.UTF-8 \
ARG APT_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/ubuntu
RUN set -eux; \
if command -v apt-get >/dev/null 2>&1; then \
if [ -f /etc/apt/sources.list ]; then \
sed -i "s|http://archive.ubuntu.com/ubuntu|${APT_MIRROR}|g; s|http://security.ubuntu.com/ubuntu|${APT_MIRROR}|g" /etc/apt/sources.list; \
fi; \
......@@ -68,10 +72,17 @@ RUN set -eux; \
fi; \
apt-get -o Acquire::Retries=5 update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ffmpeg \
&& rm -rf /var/lib/apt/lists/*
&& rm -rf /var/lib/apt/lists/*; \
elif command -v apk >/dev/null 2>&1; then \
apk add --no-cache ffmpeg; \
fi
# Non-root user
RUN groupadd -r yaoai && useradd -r -g yaoai yaoai
RUN if command -v groupadd >/dev/null 2>&1; then \
groupadd -r yaoai && useradd -r -g yaoai yaoai; \
else \
addgroup -S yaoai && adduser -S -G yaoai yaoai; \
fi
WORKDIR /app
......
......@@ -5,9 +5,30 @@
@setlocal
@REM ==== START VALIDATION ====
@REM Prefer Java 17 even when PATH or JAVA_HOME points to an older JDK.
for /d %%J in ("C:\Program Files\Eclipse Adoptium\jdk-17*") do (
if exist "%%~fJ\bin\java.exe" (
set "JAVA_HOME=%%~fJ"
)
)
for /d %%J in ("C:\Program Files\Java\jdk-17*") do (
if exist "%%~fJ\bin\java.exe" (
set "JAVA_HOME=%%~fJ"
)
)
for /d %%J in ("D:\Program Files\Java\jdk-17*") do (
if exist "%%~fJ\bin\java.exe" (
set "JAVA_HOME=%%~fJ"
)
)
if not "%JAVA_HOME%"=="" goto OkJHome
@REM Try common Java 17 locations on this machine
if exist "C:\Program Files\Eclipse Adoptium\jdk-17.0.19.10-hotspot\bin\java.exe" (
set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.19.10-hotspot"
goto OkJHome
)
if exist "D:\Program Files\Java\jdk-17\bin\java.exe" (
set "JAVA_HOME=D:\Program Files\Java\jdk-17"
goto OkJHome
......@@ -40,6 +61,14 @@ set _JAVACMD=%JAVA_HOME%\bin\java.exe
set MAVEN_WRAPPER_JAR=%~dp0.mvn\wrapper\maven-wrapper.jar
set MAVEN_WRAPPER_PROPERTIES=%~dp0.mvn\wrapper\maven-wrapper.properties
@REM Use locally installed Maven when the wrapper jar is not checked in.
if not exist "%MAVEN_WRAPPER_JAR%" (
if exist "C:\ProgramData\chocolatey\lib\maven\apache-maven-3.9.16\bin\mvn.cmd" (
call "C:\ProgramData\chocolatey\lib\maven\apache-maven-3.9.16\bin\mvn.cmd" %*
exit /B %ERRORLEVEL%
)
)
@REM Download wrapper jar if missing
if not exist "%MAVEN_WRAPPER_JAR%" (
echo Downloading Maven Wrapper...
......
......@@ -150,9 +150,10 @@ public class StoryboardController {
@Operation(summary = "AI 生成分镜视频描述提示词")
@PostMapping("/storyboards/{storyboardId}/generate-prompt")
public ApiResponse<Map<String, String>> generatePrompt(@PathVariable Long projectId,
@PathVariable Long storyboardId) {
@PathVariable Long storyboardId,
@RequestParam(required = false) String ratio) {
Long tenantId = TenantContext.get();
Map<String, String> body = Map.of("prompt", storyboardService.generatePrompt(storyboardId, tenantId));
Map<String, String> body = Map.of("prompt", storyboardService.generatePrompt(storyboardId, tenantId, ratio));
return ApiResponse.success(body);
}
......
ALTER TABLE storyboards
MODIFY COLUMN camera_direction TEXT DEFAULT NULL,
MODIFY COLUMN composition_guide TEXT DEFAULT NULL;
......@@ -3,6 +3,7 @@ package com.yaoai.domain.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yaoai.domain.entity.AiTask;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
......@@ -11,10 +12,10 @@ import java.util.List;
public interface AiTaskMapper extends BaseMapper<AiTask> {
@Select("SELECT * FROM ai_tasks WHERE project_id=#{projectId} AND tenant_id=#{tenantId} ORDER BY created_at DESC")
List<AiTask> findByProject(Long projectId, Long tenantId);
List<AiTask> findByProject(@Param("projectId") Long projectId, @Param("tenantId") Long tenantId);
@Select("SELECT * FROM ai_tasks WHERE episode_id=#{episodeId} ORDER BY created_at DESC LIMIT 1")
AiTask findLatestByEpisode(Long episodeId);
AiTask findLatestByEpisode(@Param("episodeId") Long episodeId);
@Select("""
SELECT t.* FROM ai_tasks t
......@@ -25,7 +26,7 @@ public interface AiTaskMapper extends BaseMapper<AiTask> {
AND t.result_video_url IS NOT NULL
ORDER BY COALESCE(s.sequence_num, 9999), t.created_at
""")
List<AiTask> findSucceededByEpisodeOrdered(Long episodeId, Long tenantId);
List<AiTask> findSucceededByEpisodeOrdered(@Param("episodeId") Long episodeId, @Param("tenantId") Long tenantId);
/** 待轮询的视频任务:已提交 Ark 且未到终态。limit 控制单轮处理上限,避免单次扫描挤占线程。 */
@Select("""
......@@ -35,7 +36,7 @@ public interface AiTaskMapper extends BaseMapper<AiTask> {
ORDER BY created_at ASC
LIMIT #{limit}
""")
List<AiTask> findPollableVideoTasks(int limit);
List<AiTask> findPollableVideoTasks(@Param("limit") int limit);
@Select("""
SELECT * FROM ai_tasks
......@@ -47,5 +48,8 @@ public interface AiTaskMapper extends BaseMapper<AiTask> {
ORDER BY created_at DESC
LIMIT 1
""")
AiTask findLatestSucceededVideoByStoryboard(Long storyboardId, Long tenantId);
AiTask findLatestSucceededVideoByStoryboard(
@Param("storyboardId") Long storyboardId,
@Param("tenantId") Long tenantId
);
}
......@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yaoai.domain.entity.CharacterState;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
......@@ -18,7 +19,10 @@ public interface CharacterStateMapper extends BaseMapper<CharacterState> {
WHERE cs.project_id=#{projectId} AND cs.tenant_id=#{tenantId}
ORDER BY c.created_at ASC, cs.created_at ASC
""")
List<CharacterState> findByProject(Long projectId, Long tenantId);
List<CharacterState> findByProject(
@Param("projectId") Long projectId,
@Param("tenantId") Long tenantId
);
@Select("""
SELECT cs.*, c.name AS character_name
......@@ -29,8 +33,15 @@ public interface CharacterStateMapper extends BaseMapper<CharacterState> {
AND cs.tenant_id=#{tenantId}
ORDER BY cs.created_at ASC
""")
List<CharacterState> findByCharacter(Long projectId, Long characterId, Long tenantId);
List<CharacterState> findByCharacter(
@Param("projectId") Long projectId,
@Param("characterId") Long characterId,
@Param("tenantId") Long tenantId
);
@Delete("DELETE FROM character_states WHERE character_id=#{characterId} AND tenant_id=#{tenantId}")
int deleteByCharacter(Long characterId, Long tenantId);
int deleteByCharacter(
@Param("characterId") Long characterId,
@Param("tenantId") Long tenantId
);
}
......@@ -29,7 +29,11 @@ public interface StoryboardPipelineService {
/**
* AI 根据分镜剧本信息生成视频描述提示词(分时段影视风格)
*/
String generatePrompt(Long storyboardId, Long tenantId);
default String generatePrompt(Long storyboardId, Long tenantId) {
return generatePrompt(storyboardId, tenantId, null);
}
String generatePrompt(Long storyboardId, Long tenantId, String videoRatio);
List<Storyboard> populateMissingVideoPromptsByEpisode(Long episodeId, Long tenantId);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment