diff --git a/video-gen-api/app/schemas/hot_opening_replicate.py b/video-gen-api/app/schemas/hot_opening_replicate.py index f06d5e5d..b3be0fd7 100644 --- a/video-gen-api/app/schemas/hot_opening_replicate.py +++ b/video-gen-api/app/schemas/hot_opening_replicate.py @@ -193,8 +193,8 @@ class HotOpeningTaskCreate(BaseModel): material_video_url: str = Field(..., min_length=1, description="素材视频链接,参考素材,1份。由项目已有上传接口返回,本接口不负责上传,不做后端素材校验") material_image_url: str = Field(..., min_length=1, description="素材图片链接,新产品图片,1份。由项目已有上传接口返回,本接口不负责上传,不做后端素材校验") - source_project_name: str = Field(..., min_length=1, max_length=120, description="视频素材内容项目名称") - target_project_name: str = Field(..., min_length=1, max_length=120, description="生成项目名称") + source_project_name: str = Field(..., min_length=1, max_length=20, description="视频素材内容项目名称") + target_project_name: str = Field(..., min_length=1, max_length=20, description="生成项目名称") core_content_point: str = Field(..., min_length=1, max_length=50, description="生成的项目核心内容点,最多50字") idempotency_key: str | None = Field(None, max_length=64, description="创建总任务幂等键。只用于 module_generation_projects,不用于 ChatGenerationTask") @@ -224,8 +224,8 @@ class HotOpeningMaterialUpdateRequest(BaseModel): material_video_url: str | None = Field(None, min_length=1, description="素材视频链接,未传则沿用旧值") material_image_url: str | None = Field(None, min_length=1, description="素材图片链接,未传则沿用旧值") - source_project_name: str | None = Field(None, min_length=1, max_length=120, description="视频素材内容项目名称,未传则沿用旧值") - target_project_name: str | None = Field(None, min_length=1, max_length=120, description="生成项目名称,未传则沿用旧值") + source_project_name: str | None = Field(None, min_length=1, max_length=20, description="视频素材内容项目名称,未传则沿用旧值") + target_project_name: str | None = Field(None, min_length=1, max_length=20, description="生成项目名称,未传则沿用旧值") core_content_point: str | None = Field(None, min_length=1, max_length=50, description="生成项目核心内容点,最多50字,未传则沿用旧值") @field_validator("material_video_url", "material_image_url", "source_project_name", "target_project_name", "core_content_point", mode="before") @@ -250,8 +250,8 @@ class HotOpeningStepUpdate(BaseModel): material_video_url: str | None = Field(None, description="修改第1步素材视频链接") material_image_url: str | None = Field(None, description="修改第1步素材图片链接") - source_project_name: str | None = Field(None, max_length=120, description="修改第1步视频素材内容项目名称") - target_project_name: str | None = Field(None, max_length=120, description="修改第1步生成项目名称") + source_project_name: str | None = Field(None, max_length=20, description="修改第1步视频素材内容项目名称") + target_project_name: str | None = Field(None, max_length=20, description="修改第1步生成项目名称") core_content_point: str | None = Field(None, max_length=50, description="修改第1步生成项目核心内容点,最多50字") prompt: str | None = Field(None, description="修改第2步图片提词或第4步视频最终提词") prompt_schema: dict[str, Any] | None = Field(None, description="修改第4步视频提词 JSON schema。只对视频提词步骤有意义") diff --git a/video-gen-api/app/services/payment.py b/video-gen-api/app/services/payment.py index 74732dc9..1ff12e8b 100644 --- a/video-gen-api/app/services/payment.py +++ b/video-gen-api/app/services/payment.py @@ -1,5 +1,6 @@ import logging import os +import certifi from datetime import datetime, timedelta from sqlalchemy import select @@ -156,7 +157,13 @@ def _get_alipay_client(app_id: str, private_key: str, public_key: str, gateway: config.alipay_public_key = public_key config.sign_type = "RSA2" config.charset = "utf-8" - + config.cert_path = certifi.where() + logger.info( + f"Initializing Alipay client: app_id={app_id}, gateway={config.server_url}, " + f"public_key={config.alipay_public_key}, " + f"private_key={config.app_private_key}, " + f"cert_path={config.cert_path}" + ) try: _alipay_client = DefaultAlipayClient(config) _alipay_client_app_id = app_id diff --git a/video-gen-app/private-folder-alias.json b/video-gen-app/private-folder-alias.json index 9e26dfee..5a0fdfb6 100644 --- a/video-gen-app/private-folder-alias.json +++ b/video-gen-app/private-folder-alias.json @@ -1 +1,20 @@ -{} \ No newline at end of file +{ + "src/pages/GenerateConver.tsx": { + "description": "ai创建" + }, + "src/pages/GeneratedRecord.tsx": { + "description": "生成历史" + }, + "src/pages/GeneratePage.tsx": { + "description": "生成记录" + }, + "src/pages/ProjectsPage.tsx": { + "description": "我的项目" + }, + "src/pages/RemoveLens.tsx": { + "description": "拆镜复刻" + }, + "src/pages/InitialReplication.tsx": { + "description": "爆款开头复刻" + } +} \ No newline at end of file diff --git a/video-gen-app/src/App.tsx b/video-gen-app/src/App.tsx index 1f867562..751f3f72 100644 --- a/video-gen-app/src/App.tsx +++ b/video-gen-app/src/App.tsx @@ -14,6 +14,7 @@ import InitialInfo from './pages/InitialInfo'; import RemoveLens from './pages/RemoveLens'; import GeneratedRecord from './pages/GeneratedRecord'; import AuthorizationPage from './pages/AuthorizationPage'; +import RemoveInfo from './pages/RemoveInfo'; @@ -96,6 +97,7 @@ const App = () => { } /> } /> } /> + } /> } /> } /> diff --git a/video-gen-app/src/pages/GeneratedRecord.tsx b/video-gen-app/src/pages/GeneratedRecord.tsx index b54deefd..bd4446f6 100644 --- a/video-gen-app/src/pages/GeneratedRecord.tsx +++ b/video-gen-app/src/pages/GeneratedRecord.tsx @@ -1066,10 +1066,10 @@ const GeneratedRecord: React.FC = () => {
diff --git a/video-gen-app/src/pages/InitialInfo.tsx b/video-gen-app/src/pages/InitialInfo.tsx index 807093dd..577511de 100644 --- a/video-gen-app/src/pages/InitialInfo.tsx +++ b/video-gen-app/src/pages/InitialInfo.tsx @@ -61,7 +61,7 @@ function InitialInfo() { return (
-
+
diff --git a/video-gen-app/src/pages/RemoveInfo.tsx b/video-gen-app/src/pages/RemoveInfo.tsx new file mode 100644 index 00000000..ec24e62f --- /dev/null +++ b/video-gen-app/src/pages/RemoveInfo.tsx @@ -0,0 +1,419 @@ +import React, { useState } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { Button, Table, Tag, Drawer, Input, Upload, message } from 'antd'; +import { ArrowLeftOutlined, PlayCircleOutlined, XOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons'; +import type { UploadFile } from 'antd'; + +const { TextArea } = Input; + +function RemoveInfo() { + const { creatID } = useParams<{ creatID: string }>(); + const navigate = useNavigate(); + const [drawerVisible, setDrawerVisible] = useState(false); + const [currentSegment, setCurrentSegment] = useState(null); + const [productName, setProductName] = useState(''); + const [productSellingPoint, setProductSellingPoint] = useState(''); + const [productImage, setProductImage] = useState(''); + const [detailImage, setDetailImage] = useState(''); + + const handleGenerate = (segmentId: number) => { + setCurrentSegment(segmentId); + setDrawerVisible(true); + }; + + const handleCloseDrawer = () => { + setDrawerVisible(false); + setCurrentSegment(null); + setProductName(''); + setProductSellingPoint(''); + setProductImage(''); + setDetailImage(''); + }; + + const handleProductImageChange: any = (info: any) => { + if (info.fileList.length > 0) { + const file = info.fileList[0]; + if (file.originFileObj) { + const reader = new FileReader(); + reader.onload = (e) => { + setProductImage(e.target?.result as string); + }; + reader.readAsDataURL(file.originFileObj); + } + } else { + setProductImage(''); + } + }; + + const handleDetailImageChange: any = (info: any) => { + if (info.fileList.length > 0) { + const file = info.fileList[0]; + if (file.originFileObj) { + const reader = new FileReader(); + reader.onload = (e) => { + setDetailImage(e.target?.result as string); + }; + reader.readAsDataURL(file.originFileObj); + } + } else { + setDetailImage(''); + } + }; + + const handleManualGenerate = () => { + // 必填校验 + if (!productImage) { + message.warning('请上传产品图'); + return; + } + if (!productName.trim()) { + message.warning('请输入产品名称'); + return; + } + if (!productSellingPoint.trim()) { + message.warning('请输入产品卖点'); + return; + } + + // 输出内容 + console.log('手动生成 - 片段', currentSegment); + console.log('产品图:', productImage); + console.log('细节图:', detailImage); + console.log('产品名称:', productName); + console.log('产品卖点:', productSellingPoint); + + message.success(`手动生成成功!片段: ${currentSegment}`); + }; + + const mockData = { + productName: '返回', + uploadTime: '2026-06-09 09:01:16', + sellingPoints: ['一键匹配', '连麦聊天'], + audience: '123123', + audienceAnalysis: '123123', + videoUrl: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=320&h=180&fit=crop', + segments: [ + { + key: '1', + id: 1, + timeRange: '00:00 - 00:03', + thumbnail: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=120&h=80&fit=crop', + content: '11111', + lines: 'qqqqqqqqqqq', + contentStrategy: '展示礼盒' + }, + { + key: '2', + id: 2, + timeRange: '00:03 - 00:06', + thumbnail: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=120&h=80&fit=crop', + content: '1231231231', + lines: 'qqqqqqqqqqq', + contentStrategy: '开箱展示' + }, + { + key: '3', + id: 3, + timeRange: '00:06 - 00:09', + thumbnail: 'https://images.unsplash.com/photo-1522202176988-66273c2fd55f?w=120&h=80&fit=crop', + content: '123123', + lines: 'qqqqqqqqqqq', + contentStrategy: '取出产品' + }, + ] + }; + + const columns = [ + { + title: '片段', + width: 100, + render: (text: any, record: any) => ( +
+
片段{record.id}
+
{record.timeRange}
+
+ ) + }, + { + title: '片段视频', + width: 120, + render: (text: any, record: any) => ( +
+ {`片段${record.id}`} +
+ +
+
+ ) + }, + { + title: '画面内容', + width: 250, + + render: (text: any, record: any) => ( +
+ {record.content} +
+ ) + }, + { + title: '台词', + width: 250, + + render: (text: any, record: any) => ( +
+ {record.lines} +
+ ) + }, + { + title: '内容策略', + width: 120, + align: 'left' as const, + render: (text: any, record: any) => ( +
+ {record.contentStrategy || '-'} +
+ ) + }, + { + title: '素材', + width: 140, + align: 'center' as const, + render: (text: any, record: any) => ( +
+
+ 等待生成 +
+ +
+ ) + } + ]; + + return ( + +
+
+
+
+
+ +
+
+
+
+ 视频缩略图 +
+ +
+
+ +
+
+
+

视频总结

+
+ 上传时间: {mockData.uploadTime} +
+ +
+
+ 产品名称: + {mockData.productName} +
+
+ 卖点词: +
+ {mockData.sellingPoints.map((point, index) => ( + + {point} + + ))} +
+
+
+ 受众群体: + {mockData.audience} +
+
+ 受众分析: + {mockData.audienceAnalysis} +
+
+ + +
+
+
+ +
+ + + + + + + + 智能视频复刻 + -片段{currentSegment} + +