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 WORKDIR /app
...@@ -12,7 +15,7 @@ ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} ...@@ -12,7 +15,7 @@ ENV VITE_API_BASE_URL=${VITE_API_BASE_URL}
RUN npm run build 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 nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html COPY --from=builder /app/dist /usr/share/nginx/html
......
...@@ -19,7 +19,18 @@ server { ...@@ -19,7 +19,18 @@ server {
proxy_set_header X-Forwarded-Proto $scheme; 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 / { location / {
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" always;
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;
} }
} }
This diff is collapsed.
...@@ -367,7 +367,8 @@ export function useReorderStoryboards(projectId: string, episodeId: string) { ...@@ -367,7 +367,8 @@ export function useReorderStoryboards(projectId: string, episodeId: string) {
export function useGenerateStoryboardPrompt(projectId: string) { export function useGenerateStoryboardPrompt(projectId: string) {
return useMutation({ 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 = { ...@@ -261,8 +261,10 @@ export const aiApi = {
reorderStoryboards: async (projectId: string, ids: string[]): Promise<void> => { reorderStoryboards: async (projectId: string, ids: string[]): Promise<void> => {
await apiClient.put(`/projects/${projectId}/storyboards/reorder`, { ids }); await apiClient.put(`/projects/${projectId}/storyboards/reorder`, { ids });
}, },
generateStoryboardPrompt: async (projectId: string, storyboardId: string): Promise<string> => { generateStoryboardPrompt: async (projectId: string, storyboardId: string, ratio?: string): Promise<string> => {
const r = await apiClient.post(`/projects/${projectId}/storyboards/${storyboardId}/generate-prompt`); const r = await apiClient.post(`/projects/${projectId}/storyboards/${storyboardId}/generate-prompt`, null, {
params: ratio ? { ratio } : undefined,
});
return r.data.data.prompt; return r.data.data.prompt;
}, },
listShotAssets: async (projectId: string, storyboardId: string): Promise<ShotAsset[]> => { listShotAssets: async (projectId: string, storyboardId: string): Promise<ShotAsset[]> => {
......
...@@ -6,8 +6,35 @@ $frontendDir = Join-Path $root "doc\html" ...@@ -6,8 +6,35 @@ $frontendDir = Join-Path $root "doc\html"
$adminDir = Join-Path $root "yaoai-admin-web" $adminDir = Join-Path $root "yaoai-admin-web"
$mavenCmd = Join-Path $root ".tools\apache-maven-3.9.6\bin\mvn.cmd" $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 Push-Location $root
try { try {
Write-Host "[dev] using JAVA_HOME=$env:JAVA_HOME"
Write-Host "[dev] starting infrastructure from yaoai-comic-studio/docker-compose.yml ..." Write-Host "[dev] starting infrastructure from yaoai-comic-studio/docker-compose.yml ..."
docker compose -f (Join-Path $backendDir "docker-compose.yml") up -d docker compose -f (Join-Path $backendDir "docker-compose.yml") up -d
...@@ -24,9 +51,11 @@ try { ...@@ -24,9 +51,11 @@ try {
Write-Host "" Write-Host ""
Write-Host "[dev] next commands" Write-Host "[dev] next commands"
Write-Host " 1. build backend" 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 " & `"$mavenCmd`" -f `"$backendDir\pom.xml`" package -pl yaoai-bootstrap -am -DskipTests"
Write-Host " 2. run backend" 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 " 3. run frontend"
Write-Host " Set-Location `"$frontendDir`"; npm install; npm run dev" Write-Host " Set-Location `"$frontendDir`"; npm install; npm run dev"
Write-Host " 4. run admin-web" Write-Host " 4. run admin-web"
......
# ===== Stage 1: Build ===== # ===== 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 WORKDIR /workspace
...@@ -47,7 +50,7 @@ COPY . . ...@@ -47,7 +50,7 @@ COPY . .
RUN mvn -s /root/.m2/settings.xml package -pl yaoai-bootstrap -am -DskipTests -B -ntp RUN mvn -s /root/.m2/settings.xml package -pl yaoai-bootstrap -am -DskipTests -B -ntp
# ===== Stage 2: Runtime ===== # ===== 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 maintainer="YaoAI Team <yaoke251@gmail.com>"
LABEL org.opencontainers.image.title="YaoAI Comic Studio" LABEL org.opencontainers.image.title="YaoAI Comic Studio"
...@@ -60,6 +63,7 @@ ENV LANG=C.UTF-8 \ ...@@ -60,6 +63,7 @@ ENV LANG=C.UTF-8 \
ARG APT_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/ubuntu ARG APT_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/ubuntu
RUN set -eux; \ RUN set -eux; \
if command -v apt-get >/dev/null 2>&1; then \
if [ -f /etc/apt/sources.list ]; 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; \ 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; \ fi; \
...@@ -68,10 +72,17 @@ RUN set -eux; \ ...@@ -68,10 +72,17 @@ RUN set -eux; \
fi; \ fi; \
apt-get -o Acquire::Retries=5 update \ apt-get -o Acquire::Retries=5 update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ffmpeg \ && 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 # 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 WORKDIR /app
......
...@@ -5,9 +5,30 @@ ...@@ -5,9 +5,30 @@
@setlocal @setlocal
@REM ==== START VALIDATION ==== @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 if not "%JAVA_HOME%"=="" goto OkJHome
@REM Try common Java 17 locations on this machine @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" ( if exist "D:\Program Files\Java\jdk-17\bin\java.exe" (
set "JAVA_HOME=D:\Program Files\Java\jdk-17" set "JAVA_HOME=D:\Program Files\Java\jdk-17"
goto OkJHome goto OkJHome
...@@ -40,6 +61,14 @@ set _JAVACMD=%JAVA_HOME%\bin\java.exe ...@@ -40,6 +61,14 @@ set _JAVACMD=%JAVA_HOME%\bin\java.exe
set MAVEN_WRAPPER_JAR=%~dp0.mvn\wrapper\maven-wrapper.jar set MAVEN_WRAPPER_JAR=%~dp0.mvn\wrapper\maven-wrapper.jar
set MAVEN_WRAPPER_PROPERTIES=%~dp0.mvn\wrapper\maven-wrapper.properties 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 @REM Download wrapper jar if missing
if not exist "%MAVEN_WRAPPER_JAR%" ( if not exist "%MAVEN_WRAPPER_JAR%" (
echo Downloading Maven Wrapper... echo Downloading Maven Wrapper...
......
...@@ -150,9 +150,10 @@ public class StoryboardController { ...@@ -150,9 +150,10 @@ public class StoryboardController {
@Operation(summary = "AI 生成分镜视频描述提示词") @Operation(summary = "AI 生成分镜视频描述提示词")
@PostMapping("/storyboards/{storyboardId}/generate-prompt") @PostMapping("/storyboards/{storyboardId}/generate-prompt")
public ApiResponse<Map<String, String>> generatePrompt(@PathVariable Long projectId, public ApiResponse<Map<String, String>> generatePrompt(@PathVariable Long projectId,
@PathVariable Long storyboardId) { @PathVariable Long storyboardId,
@RequestParam(required = false) String ratio) {
Long tenantId = TenantContext.get(); 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); 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; ...@@ -3,6 +3,7 @@ package com.yaoai.domain.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yaoai.domain.entity.AiTask; import com.yaoai.domain.entity.AiTask;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import java.util.List; import java.util.List;
...@@ -11,10 +12,10 @@ import java.util.List; ...@@ -11,10 +12,10 @@ import java.util.List;
public interface AiTaskMapper extends BaseMapper<AiTask> { public interface AiTaskMapper extends BaseMapper<AiTask> {
@Select("SELECT * FROM ai_tasks WHERE project_id=#{projectId} AND tenant_id=#{tenantId} ORDER BY created_at DESC") @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") @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("""
SELECT t.* FROM ai_tasks t SELECT t.* FROM ai_tasks t
...@@ -25,7 +26,7 @@ public interface AiTaskMapper extends BaseMapper<AiTask> { ...@@ -25,7 +26,7 @@ public interface AiTaskMapper extends BaseMapper<AiTask> {
AND t.result_video_url IS NOT NULL AND t.result_video_url IS NOT NULL
ORDER BY COALESCE(s.sequence_num, 9999), t.created_at 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 控制单轮处理上限,避免单次扫描挤占线程。 */ /** 待轮询的视频任务:已提交 Ark 且未到终态。limit 控制单轮处理上限,避免单次扫描挤占线程。 */
@Select(""" @Select("""
...@@ -35,7 +36,7 @@ public interface AiTaskMapper extends BaseMapper<AiTask> { ...@@ -35,7 +36,7 @@ public interface AiTaskMapper extends BaseMapper<AiTask> {
ORDER BY created_at ASC ORDER BY created_at ASC
LIMIT #{limit} LIMIT #{limit}
""") """)
List<AiTask> findPollableVideoTasks(int limit); List<AiTask> findPollableVideoTasks(@Param("limit") int limit);
@Select(""" @Select("""
SELECT * FROM ai_tasks SELECT * FROM ai_tasks
...@@ -47,5 +48,8 @@ public interface AiTaskMapper extends BaseMapper<AiTask> { ...@@ -47,5 +48,8 @@ public interface AiTaskMapper extends BaseMapper<AiTask> {
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 1 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; ...@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yaoai.domain.entity.CharacterState; import com.yaoai.domain.entity.CharacterState;
import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import java.util.List; import java.util.List;
...@@ -18,7 +19,10 @@ public interface CharacterStateMapper extends BaseMapper<CharacterState> { ...@@ -18,7 +19,10 @@ public interface CharacterStateMapper extends BaseMapper<CharacterState> {
WHERE cs.project_id=#{projectId} AND cs.tenant_id=#{tenantId} WHERE cs.project_id=#{projectId} AND cs.tenant_id=#{tenantId}
ORDER BY c.created_at ASC, cs.created_at ASC 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("""
SELECT cs.*, c.name AS character_name SELECT cs.*, c.name AS character_name
...@@ -29,8 +33,15 @@ public interface CharacterStateMapper extends BaseMapper<CharacterState> { ...@@ -29,8 +33,15 @@ public interface CharacterStateMapper extends BaseMapper<CharacterState> {
AND cs.tenant_id=#{tenantId} AND cs.tenant_id=#{tenantId}
ORDER BY cs.created_at ASC 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}") @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 { ...@@ -29,7 +29,11 @@ public interface StoryboardPipelineService {
/** /**
* AI 根据分镜剧本信息生成视频描述提示词(分时段影视风格) * 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); 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