diff --git a/api/movie_queue.ts b/api/movie_queue.ts index 6e95690..273da29 100644 --- a/api/movie_queue.ts +++ b/api/movie_queue.ts @@ -84,7 +84,7 @@ export async function withQueuePolling( const poll = async (): Promise => { try { if (isCancelled) { - throw new Error('操作已取消'); + throw new Error('Operation canceled'); } const response = await apiCall(params); @@ -110,7 +110,7 @@ export async function withQueuePolling( // 检查是否达到最大尝试次数 if (attempts >= maxAttempts) { notification.destroy(); // 关闭通知 - throw new Error('超过最大轮询次数限制'); + throw new Error('Exceeded the maximum polling limit'); } // 继续轮询 diff --git a/app/api/stream/route.ts b/app/api/stream/route.ts deleted file mode 100644 index 269c1e6..0000000 --- a/app/api/stream/route.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { parseMDXContent } from '@/lib/mdx'; -import { BASE_URL } from '@/api/constants'; - -export const dynamic = 'force-dynamic'; -export const runtime = 'edge'; - -export async function GET() { - try { - const content = `[分析场景核心]: 一位舞者对完美的执念,使她的美丽舞蹈转化为一种自我毁灭的仪式。 - -### 第一幕:开端 - -内景 · 舞蹈室 - 傍晚 - -夕阳透过窗户,阳光携带着飞舞的尘埃,划出一块金色矩形洒在斑驳的木地板上。墙面苍白、剥落。一整面落地镜映出这空旷房间的寂静。 - -ELARA(20岁出头),身姿优雅至极,立于光影正中。她赤脚,穿着一件简单的黑色紧身舞衣,随着一段大提琴独奏起舞——旋律哀伤而高昂。 - -她的身体如流水般线条优雅。一只手臂伸展,手指在空气中描绘出无形的轨迹。她缓缓旋转,像是违抗了重力的引力。在这一刻,她是完美的化身。 - -但她的双眼,始终盯着镜中的自己,突然微微眯起——一丝自我厌弃的情绪一闪而过那个旋转,不够纯净。不够完美。对她而言。 - -她打断了舞姿。现在,她的呼吸变得可闻,如利刃般切入大提琴的温柔旋律。 - -她毫不迟疑地重新起舞。这一次,更快、更狠。舞姿仍美,却变得尖锐,带着绝望的锋芒。 - -一滴汗水,从她的太阳穴滑落。 - -她再次旋转,又旋转。一个狂热、残酷的段落。她的脸不再沉静,而是绷紧的面具,咬牙切齿。音乐愈发高亢,但我们所听见的,只有她脚步在木地板上滑出的尖锐声响,以及她粗重、急促的喘息。 - -镜中的倒影已模糊成一道疯狂的涂抹。她强迫自己再做一个旋转——那种超越极限的最后一圈。 - -她的脚踝崩溃了。 - -不是咔嚓断裂的声响,而是一种沉默、恶心的扭曲。Elara 倒在地上,如阳光外的一团残骸,四肢交错,失去光环。 - -大提琴继续演奏,平静、冷漠。 - -她喉间发出一声哽咽般的呜咽,是房间中唯一的声音。镜头穿过她起伏的肩膀,聚焦她的脚——足弓紧绷,脚趾青紫,地板上划出一丝血痕。 - -### 导演与表演附录 - -【导演风格解码】 -• 核心视觉基调: 高反差明暗对比,采用单一自然光源(窗户)。随着角色状态的恶化,色调从温暖金色逐渐转为冷峻的蓝灰。 -• 关键镜头处理建议: 开始用宽阔流畅的镜头呼应舞者的优雅;当其内心破裂时,剪切到突兀的特写镜头:颤抖的大腿肌肉、颈侧汗珠、扭曲的表情与模糊的镜中倒影。最后一个镜头采用固定机位,锁定她瘫倒的身体,强化突然静止的冲击感。她的舞步原本是以光影为中心的循环,她的倒地打破了这一循环,使她落入阴影。 - -### 核心表演关键 - -• 角色肢体表现: 表演需呈现双重性——外在看似毫不费力的优雅与内在痛苦的微妙细节同在。崩溃时不应夸张,而应如过度拉紧的身体对重力的安静屈服。 -• 潜台词驱动: 这是与"无形评审"——镜中自己——之间的战争。每一个动作都是抗议,每一个旋转是一种恳求,每一次喘息都是诅咒。核心动机是:"我要强迫这个不完美的身体创造一个完美的瞬间,即使这将摧毁我。" - -### 当代表达的连接 - -这个故事呼应了当代数字时代"精心营造的完美主义"现象,在理想化的自我形象背后,隐藏着焦虑与倦怠的真实生活。 -`; - - console.log('开始解析 MDX 内容...'); - const chunks = await parseMDXContent(content); - console.log('解析完成,获得块数:', chunks?.length); - - if (!chunks || chunks.length === 0) { - console.error('没有生成有效的内容块'); - return new Response( - JSON.stringify({ error: '内容解析失败' }), - { - status: 500, - headers: { 'Content-Type': 'application/json' } - } - ); - } - - // 创建一个可写流来处理数据 - const stream = new TransformStream(); - const writer = stream.writable.getWriter(); - const encoder = new TextEncoder(); - - // 异步处理数据流 - (async () => { - try { - for (const chunk of chunks) { - const data = encoder.encode(JSON.stringify(chunk) + '\n'); - await writer.write(data); - } - } catch (error) { - console.error('写入流时出错:', error); - } finally { - await writer.close(); - } - })(); - - return new Response(stream.readable, { - headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache, no-transform', - 'Connection': 'keep-alive', - }, - }); - - } catch (error) { - console.error('API 路由处理出错:', error); - return new Response( - JSON.stringify({ - error: '服务器处理请求时出错', - details: error instanceof Error ? error.message : '未知错误' - }), - { - status: 500, - headers: { 'Content-Type': 'application/json' } - } - ); - } -} \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index 5464391..35607f6 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,8 +3,6 @@ import './globals.css'; import { createContext, useContext, useEffect, useState } from 'react'; import { Providers } from '@/components/providers'; import { ConfigProvider, theme } from 'antd'; -import { createScreenAdapter } from '@/utils/tools'; -import { ScreenAdapter } from './ScreenAdapter'; import CallbackModal from '@/components/common/CallbackModal'; // 创建上下文来传递弹窗控制方法 diff --git a/app/model/enums.ts b/app/model/enums.ts index 245737e..8981774 100644 --- a/app/model/enums.ts +++ b/app/model/enums.ts @@ -64,11 +64,11 @@ export const ProjectTypeMap = { export const ModeMap = { [ModeEnum.MANUAL]: { value: "manual", - label: "手动" + label: "Manual" }, [ModeEnum.AUTOMATIC]: { value: "automatic", - label: "自动" + label: "Automatic" } } as const; @@ -108,66 +108,6 @@ export const VideoDurationMap = { } } as const; -// 工作流阶段映射 -export const FlowStageMap = { - [FlowStageEnum.PREVIEW]: { - value: "preview", - label: "预览图列表分镜草图" - }, - [FlowStageEnum.CHARACTERS]: { - value: "characters", - label: "角色列表" - }, - [FlowStageEnum.SHOTS]: { - value: "shots", - label: "分镜视频列表" - }, - [FlowStageEnum.BGM]: { - value: "bgm", - label: "背景音乐列表" - }, - [FlowStageEnum.POST_PRODUCTION]: { - value: "post_production", - label: "后期操作中" - }, - [FlowStageEnum.MERGE_VIDEO]: { - value: "merge_video", - label: "合并视频完成" - }, - [FlowStageEnum.ERROR]: { - value: "error", - label: "出错" - } -} as const; - -// 任务状态映射 -export const TaskStatusMap = { - [TaskStatusEnum.PENDING]: { - value: "pending", - label: "待处理" - }, - [TaskStatusEnum.PROCESSING]: { - value: "processing", - label: "处理中" - }, - [TaskStatusEnum.COMPLETED]: { - value: "completed", - label: "已完成" - }, - [TaskStatusEnum.FAILED]: { - value: "failed", - label: "失败" - }, - [TaskStatusEnum.RETRYING]: { - value: "retrying", - label: "重试中" - }, - [TaskStatusEnum.CANCELLED]: { - value: "cancelled", - label: "已取消" - } -} as const; - // 分镜脚本编辑器类型定义 export interface StoryboardCard { id: string; @@ -221,39 +161,3 @@ export interface CharacterOption { age: string; description: string; } - -// Mock 数据 -export const mockSceneOptions: SceneOption[] = [ - { sceneId: '1', name: '暮色森林', image: 'https://c.huiying.video/images/7fd3f2d6-840a-46ac-a97d-d3d1b37ec4e0.jpg', location: '西境边陲', time: '傍晚' } -]; - -export const mockCharacterOptions: CharacterOption[] = [ - { characterId: '1', name: '艾琳', image: 'https://c.huiying.video/images/32f6b07c-bceb-4b63-8a13-4749703ab08d.jpg', gender: '女', age: '24', description: '银发女剑士' }, - { characterId: '2', name: '影子猎手', image: 'https://c.huiying.video/images/97c6c59a-50cc-4159-aacd-94ab9d208150.jpg', gender: '男', age: '35', description: '神秘追踪者' }, -]; - -export const mockStoryboards: StoryboardCard[] = [ - { - id: '1', - shotId: 'SC-01', - scene: mockSceneOptions[0], - characters: [mockCharacterOptions[0], mockCharacterOptions[1]], - description: '艾琳警惕地穿过森林,影子猎手的身影若隐若现艾琳警惕地穿过森林,影子猎手的身影若隐若现艾琳警惕地穿过森林,影子猎手的身影若隐若现艾琳警惕地穿过森林,影子猎手的身影若隐若现', - shotType: '中景', - cameraMove: '缓慢推进', - dialogues: [ - { id: 'd1', speaker: '艾琳', text: '我们必须在 #影子猎手# 到来前穿过 [暮色森林]。' }, - { id: 'd2', speaker: '影子猎手', text: '你以为能逃出这里?' }, - ], - notes: '镜头缓慢推进至人物背影', - }, -]; - -export const characterInfoMap: Record = { - '艾琳': { avatar: 'https://c.huiying.video/images/32f6b07c-bceb-4b63-8a13-4749703ab08d.jpg', gender: '女', age: '24', description: '银发女剑士' }, - '影子猎手': { avatar: 'https://c.huiying.video/images/97c6c59a-50cc-4159-aacd-94ab9d208150.jpg', gender: '男', age: '35', description: '神秘追踪者' }, -}; - -export const sceneInfoMap: Record = { - '暮色森林': { image: 'https://c.huiying.video/images/7fd3f2d6-840a-46ac-a97d-d3d1b37ec4e0.jpg', location: '西境边陲', time: '傍晚' }, -}; diff --git a/app/payment-success/page.tsx b/app/payment-success/page.tsx index 710ee99..59b9c12 100644 --- a/app/payment-success/page.tsx +++ b/app/payment-success/page.tsx @@ -80,16 +80,16 @@ export default function PaymentSuccessPage() {
- 处理中... + Processing... - 正在确认您的支付,请稍候 + Confirming your payment, please wait
- 尝试次数: {attempts}/30 + Attempts: {attempts}/30

- 请不要关闭此页面,我们正在处理您的订阅 + Please do not close this page, we are processing your subscription

@@ -102,32 +102,32 @@ export default function PaymentSuccessPage() {
- 支付成功! + Payment successful! - 您的订阅已激活 + Your subscription has been activated {paymentData?.subscription && (

- {paymentData.subscription.plan_display_name} 套餐 + {paymentData.subscription.plan_display_name} Plan

- 状态: {paymentData.subscription.status} + Status: {paymentData.subscription.status}

{paymentData.subscription.current_period_end && (

- 有效期至: {new Date(paymentData.subscription.current_period_end).toLocaleDateString()} + Valid until: {new Date(paymentData.subscription.current_period_end).toLocaleDateString()}

)}
)}
-

订单号: {paymentData?.biz_order_no}

+

Order number: {paymentData?.biz_order_no}

{paymentData?.pay_time && ( -

支付时间: {new Date(paymentData.pay_time).toLocaleString()}

+

Payment time: {new Date(paymentData.pay_time).toLocaleString()}

)}
@@ -136,14 +136,14 @@ export default function PaymentSuccessPage() { onClick={() => window.location.href = '/dashboard'} className="flex-1" > - 前往控制台 + Go to dashboard
@@ -157,14 +157,14 @@ export default function PaymentSuccessPage() {
- 支付失败 + Payment failed - 很抱歉,您的支付未能成功完成 + Sorry, your payment was not successful

- 请检查您的支付信息或稍后重试 + Please check your payment information or try again later

@@ -172,14 +172,14 @@ export default function PaymentSuccessPage() { onClick={() => window.location.href = '/pricing'} className="flex-1" > - 重新选择套餐 + Re-select plan
@@ -193,14 +193,14 @@ export default function PaymentSuccessPage() {
- 处理中 + Processing - 支付正在处理中,请稍后查看 + Payment is being processed, please check later

- 您的支付可能仍在处理中,请稍后检查您的订阅状态 + Your payment may still be processing, please check your subscription status later

@@ -208,14 +208,14 @@ export default function PaymentSuccessPage() { onClick={() => window.location.reload()} className="flex-1" > - 刷新页面 + Refresh page
diff --git a/app/pricing/page.tsx b/app/pricing/page.tsx index 660dd98..533b4e7 100644 --- a/app/pricing/page.tsx +++ b/app/pricing/page.tsx @@ -80,7 +80,7 @@ function HomeModule5() { const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); if (!User.id) { - throw new Error("无法获取用户ID,请重新登录"); + throw new Error("Unable to obtain user ID, please log in again"); } // 1. 创建Checkout Session diff --git a/app/service/adapter/oldErrAdapter.ts b/app/service/adapter/oldErrAdapter.ts index 52f09a4..5fa328b 100644 --- a/app/service/adapter/oldErrAdapter.ts +++ b/app/service/adapter/oldErrAdapter.ts @@ -135,7 +135,7 @@ export class VideoSegmentEntityAdapter { // 如果没有任何镜头但有narrative_goal,将其作为镜头1 if (lens.length === 0 && result.narrative_goal) { - const narrativeLens = new LensType("镜头1", result.narrative_goal, []); + const narrativeLens = new LensType("shot_1", result.narrative_goal, []); lens.push(narrativeLens); } @@ -159,7 +159,7 @@ export class VideoSegmentEntityAdapter { // 创建VideoSegmentEntity const entity: VideoSegmentEntity = { id: `video_mock_${index}`, // 生成临时ID,包含索引 - name: `视频片段_${index}`, // 生成临时名称,包含索引 + name: `video_${index}`, // 生成临时名称,包含索引 sketchUrl: "", // 后端数据中没有sketchUrl,设为空字符串 videoUrl: result.videos, status: status, diff --git a/components/QueueBox/QueueNotification.tsx b/components/QueueBox/QueueNotification.tsx deleted file mode 100644 index e296513..0000000 --- a/components/QueueBox/QueueNotification.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { notification } from 'antd'; - -const darkGlassStyle = { - background: 'rgba(30, 32, 40, 0.95)', - backdropFilter: 'blur(10px)', - WebkitBackdropFilter: 'blur(10px)', - border: '1px solid rgba(255, 255, 255, 0.08)', - borderRadius: '8px', - boxShadow: '0 4px 16px rgba(0, 0, 0, 0.4)', - padding: '12px 16px', -}; - -/** 胶片容器样式 */ -const filmStripContainerStyle = { - position: 'relative' as const, - width: '100%', - height: '80px', - marginBottom: '16px', - overflow: 'hidden', -}; - -/** 胶片样式 */ -const filmStripStyle = { - display: 'flex', - alignItems: 'center', - animation: 'filmScroll 20s linear infinite', -}; - -/** 文字样式 */ -const textStyle = { - fontSize: '13px', - color: 'rgba(255, 255, 255, 0.9)', - marginBottom: '12px', -}; - -/** 胶片帧组件 */ -const FilmFrame = () => ( -
- - {/* 胶片外框 */} - - {/* 齿孔 */} - - - - - {/* 胶片画面区域 */} - - -
-); - -/** 放映机音效组件 */ -const ProjectorSound = () => ( -