爆款开头复刻
This commit is contained in:
@@ -10,9 +10,15 @@ import RecordsPage from './pages/RecordsPage';
|
||||
import CreditsPage from './pages/CreditsPage';
|
||||
import GenerateConver from './pages/GenerateConver';
|
||||
import InitialReplication from './pages/InitialReplication';
|
||||
import InitialInfo from './pages/InitialInfo';
|
||||
import RemoveLens from './pages/RemoveLens';
|
||||
import GeneratedRecord from './pages/GeneratedRecord';
|
||||
import AuthorizationPage from './pages/AuthorizationPage';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import { useAuthStore } from './store/useAuthStore';
|
||||
|
||||
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
|
||||
@@ -88,10 +94,15 @@ const App = () => {
|
||||
<Route path="credits" element={<CreditsPage />} />
|
||||
<Route path="conversation" element={<GenerateConver />} />
|
||||
<Route path="initial" element={<InitialReplication />} />
|
||||
<Route path="initial/:creatID/initialinfo" element={<InitialInfo />} />
|
||||
<Route path="removelens" element={<RemoveLens />} />
|
||||
<Route path="generated" element={<GeneratedRecord />} />
|
||||
<Route path="authorization" element={<AuthorizationPage />} />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Route>
|
||||
<Route path="*" element={<Navigate to="/projects" replace />} />
|
||||
</Routes>
|
||||
|
||||
@@ -608,12 +608,16 @@ const AIChatPage: React.FC = () => {
|
||||
// 视频参数(仅视频模式时添加)
|
||||
...(mediaType === 'video' && {
|
||||
duration: videoDuration,
|
||||
ratio: videoAspectRatio,
|
||||
aspect_ratio: videoAspectRatio,
|
||||
resolution: videoResolution,
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 设置加载状态
|
||||
setLoading(true);
|
||||
|
||||
@@ -1132,6 +1136,7 @@ const AIChatPage: React.FC = () => {
|
||||
<DeleteOutlined style={{ fontSize: 12 }} />
|
||||
</button>
|
||||
</Popconfirm>
|
||||
|
||||
</div>
|
||||
|
||||
{/* 文本内容 */}
|
||||
@@ -1162,30 +1167,37 @@ const AIChatPage: React.FC = () => {
|
||||
{/* 根据 status 显示不同内容 */}
|
||||
{/* 生成中 - 显示加载动画 */}
|
||||
{msg.status === 'generating' && (
|
||||
<div style={{ height: 200, marginBottom: 10, marginTop: 12, borderRadius: 8, overflow: 'hidden', position: 'relative', backgroundColor: '#f1f5f9' }}>
|
||||
<div style={{
|
||||
height: 200,
|
||||
marginBottom: 10,
|
||||
marginTop: 12,
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
background: 'linear-gradient(135deg, #e0e7ff 0%, #f3e8ff 50%, #e0e7ff 100%)',
|
||||
}}>
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
top: 12,
|
||||
left: 12,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 16
|
||||
gap: 8,
|
||||
}}>
|
||||
<div style={{
|
||||
width: 48,
|
||||
height: 48,
|
||||
border: '3px solid #e2e8f0',
|
||||
width: 24,
|
||||
height: 24,
|
||||
border: '2px solid #c7d2fe',
|
||||
borderTopColor: '#6366f1',
|
||||
borderRadius: '50%',
|
||||
animation: 'spin 1s linear infinite'
|
||||
}} />
|
||||
<span style={{ fontSize: 14, color: '#64748b' }}>正在生成中...</span>
|
||||
<span style={{ fontSize: 13, color: '#6366f1' }}>生成中...</span>
|
||||
</div>
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent)',
|
||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.3) 50%, transparent 100%)',
|
||||
animation: 'shimmer 2s infinite'
|
||||
}} />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Typography, Collapse, Space, Modal, Input, Table } from 'antd';
|
||||
import { ArrowLeftOutlined, PlayCircleOutlined, CheckCircleOutlined, EditOutlined, DownloadOutlined } from '@ant-design/icons';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import './css/InitialInfo.css';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
const { TextArea } = Input;
|
||||
|
||||
function InitialInfo() {
|
||||
const navigate = useNavigate();
|
||||
const { creatID } = useParams<{ creatID: string }>();
|
||||
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [promptText, setPromptText] = useState('');
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
// 创作记录表格数据
|
||||
const [tableData, setTableData] = useState<any[]>([
|
||||
{
|
||||
id: 1,
|
||||
image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=product%20image%20red%20gift%20box%20with%20hearts&image_size=square',
|
||||
originalName: '进圈',
|
||||
productName: '他趣',
|
||||
status: '视频成功',
|
||||
createTime: '2026-05-14 17:49:20',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=luxury%20perfume%20bottle%20golden%20elegant&image_size=square',
|
||||
originalName: '香水',
|
||||
productName: '面霜',
|
||||
status: '视频提示词成功',
|
||||
createTime: '2026-05-08 08:57:46',
|
||||
},
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('路由参数 creatID:', creatID);
|
||||
}, [creatID]);
|
||||
|
||||
const handleOpenModal = () => {
|
||||
console.log('打开弹窗');
|
||||
setPromptText('室内居家卧室场景,严格复刻原背景:人物后方是带黑色铆钉包边的浅灰色拉扣软包床头,床头前摆放蓬松白色枕头,保留柔和暖调居家氛围,禁止篡改背景元素。画面中心为上半身入镜的女性,身穿浅灰色V领长袖上衣,脸部全程用白色涂鸦完全打码,禁止生成清晰人脸;颈部佩戴目标华丽项链,替代原有细项链,佩戴位置与原项链一致,贴合颈部肌肤,光影与场景柔和光源完全统一,无半透明合成痕迹。目标项链为玫瑰金基底,镶嵌圆润白色珍珠与碎钻,中心是水滴形主钻,下方垂挂同形态水滴钻吊坠,设计精致华丽,项链为画面视觉焦点,尺寸符合颈部佩戴的合理比例。主光源来自画面面前侧偏上方,光线柔和自然,阴影清淡真实,禁止出现AI合成假阴影;整体为低饱和暖调,写实柔和质感,拍摄为平视角度,视觉优先级:颈部项链>人物上半身>背景床头与枕头。禁止出现未打码人脸,禁止项链设计偏差、佩戴错位,禁止光影色调偏离柔和暖调居家感,画面无多余字幕。');
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
setModalVisible(false);
|
||||
console.log('修改后的提示词:', promptText);
|
||||
};
|
||||
|
||||
const steps = [
|
||||
{ id: 1, title: '原始素材', status: 'done', description: '上传原始视频素材' },
|
||||
{ id: 2, title: '生成提示词', status: 'done', description: '根据素材生成描述词' },
|
||||
{ id: 3, title: '生成产品融合图', status: 'done', description: '生成产品与场景融合图' },
|
||||
{ id: 4, title: '生成视频提示词', status: 'done', description: '生成视频生成提示词' },
|
||||
{ id: 5, title: '生成最终视频', status: 'active', description: '合成最终视频' },
|
||||
];
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div style={{ height: '94vh', background: '#f8fafc' }}>
|
||||
<div style={{ height: 'calc(94vh)', padding: 24, }}>
|
||||
<div style={{ height: '100%', display: 'flex', justifyContent: 'space-between', gap: '2%' }}>
|
||||
<div style={{ width: '70%', background: '#fff', borderRadius: 12, overflowY: 'auto' }}>
|
||||
<div style={{ borderBottom: '1px solid #e2e8f0', width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '14px', boxSizing: 'border-box' }}>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={() => navigate(-1)}
|
||||
style={{ color: '#64748b' }}
|
||||
>
|
||||
返回
|
||||
</Button>
|
||||
<h3 style={{ margin: 0 }}>
|
||||
爆款开头复刻 - 任务详情
|
||||
</h3>
|
||||
<Button type="primary" ghost style={{ borderRadius: 6, padding: '4px 12px', fontSize: 12, borderColor: '#6366f1', color: '#6366f1' }} onClick={() => setIsModalOpen(true)}>
|
||||
创作记录
|
||||
</Button>
|
||||
</div>
|
||||
<div className="material_box">
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div>
|
||||
<span>视频</span>
|
||||
<div className="medio_box">
|
||||
<video controls src={null} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="product_img">
|
||||
<span>产品图片</span>
|
||||
<div className="medio_box">
|
||||
<img src="https://imagecdn.gaopinimages.com/image-preview/133141727501.jpg_w.webp" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span>场景图片</span>
|
||||
<div className="medio_box">
|
||||
<img src="https://imagecdn.gaopinimages.com/image-preview/133141727501.jpg_w.webp" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span>生成视频</span>
|
||||
<div className="medio_box">
|
||||
<video controls src={null} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ width: '28%', minWidth: '400px', background: '#fff', borderRadius: 12, overflowY: 'auto' }}>
|
||||
<div style={{padding:'14px'}}> 生成步骤</div>
|
||||
<Collapse
|
||||
defaultActiveKey={['2']}
|
||||
ghost
|
||||
bordered={false}
|
||||
style={{ background: 'transparent' }}
|
||||
expandIconPosition="end"
|
||||
items={steps.map((step) => ({
|
||||
key: String(step.id),
|
||||
label: (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', justifyContent: 'space-between' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 16, height: 16 }}>
|
||||
{step.status === 'done' ? (
|
||||
<CheckCircleOutlined style={{ fontSize: 16, color: '#22c55e' }} />
|
||||
) : step.status === 'active' ? (
|
||||
<div style={{ width: 8, height: 8, borderRadius: '50%', background: '#6366f1', animation: 'spinSlow 1s linear infinite' }} />
|
||||
) : (
|
||||
<span style={{ fontSize: 12, color: '#94a3b8' }}>{step.id}</span>
|
||||
)}
|
||||
</div>
|
||||
<span style={{ fontSize: 14, color: step.status === 'active' ? '#6366f1' : '#1e293b', fontWeight: 500 }}>
|
||||
{step.title}
|
||||
</span>
|
||||
{step.status === 'active' && (
|
||||
<span style={{ fontSize: 12, color: '#6366f1', marginLeft: 8 }}>生成中</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<div style={{ padding: '16px', background: '#f8fafc', borderRadius: 8, marginTop: 8 }}>
|
||||
{step.id === 1 && <div>12312</div>}
|
||||
{step.id === 2 && (
|
||||
<>
|
||||
<Text style={{ color: '#475569', fontSize: 13, lineHeight: 1.8, whiteSpace: 'pre-wrap' }}>
|
||||
竖版社交 APP 宣传海报,平视正面拍摄,视觉焦点为画面正中间偏上位置的 APP 图标;背景为虚化的室内居家场景,背景中心是身着浅色服装的长发女性,人物整体虚化、面部模糊,占画面大部分区域,画面下半部分分布淡紫色细碎星光闪光特效;整体为柔和暖色调,主光源从正面打来,光线柔和自然,阴影浅淡,整体质感真实柔和,无生硬合成痕迹。将画面中心的原 APP 图标替换为他趣的圆角方形图标:黑底,顶部有淡黄色椭圆形装饰,中间黄色圆形承载两个带高光的亮面红色爱心,底部为粉紫渐变横条,横条上有白色"脱单交友"文字,图标位置与参考图完全一致。去除原图所有宣传类字幕文字,仅保留 APP 图标自带的文字;禁止篡改背景元素、星光特效、光影色调,禁止将背景人物清晰化,禁止改变图标位置与画面视觉优先级,禁止出现生硬合成痕迹。
|
||||
</Text>
|
||||
<Space style={{ marginTop: 16, gap: 12, width: '100%' }}>
|
||||
<Button
|
||||
type="default"
|
||||
icon={<EditOutlined />}
|
||||
onClick={handleOpenModal}
|
||||
style={{ flex: 1, borderRadius: 8, borderColor: '#6366f1', color: '#6366f1', height: 36 }}
|
||||
>
|
||||
修改提示词
|
||||
</Button>
|
||||
<Button type="primary" style={{ flex: 1, borderRadius: 8, background: '#6366f1', borderColor: '#6366f1', height: 36 }}>
|
||||
下一步:生成图片
|
||||
</Button>
|
||||
</Space>
|
||||
</>
|
||||
)}
|
||||
{step.id === 5 && (
|
||||
<>
|
||||
<div style={{ borderRadius: 8, overflow: 'hidden', marginBottom: 16, position: 'relative' }}>
|
||||
<img
|
||||
src="https://neeko-copilot.bytedance.net/api/text2image?prompt=cute%20orange%20cartoon%20character%20with%20text%20overlay%20on%20pink%20background&image_size=landscape_4_3"
|
||||
alt="最终视频"
|
||||
style={{ width: '100%', height: 180, objectFit: 'cover' }}
|
||||
/>
|
||||
<div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', display: 'flex', alignItems: 'center', justifyContent: 'center', width: 48, height: 48, background: 'rgba(255,255,255,0.9)', borderRadius: '50%' }}>
|
||||
<PlayCircleOutlined style={{ fontSize: 24, color: '#6366f1', marginLeft: 2 }} />
|
||||
</div>
|
||||
</div>
|
||||
<Space style={{ width: '100%', gap: 12 }}>
|
||||
<Button type="default" icon={<EditOutlined />} style={{ flex: 1, borderRadius: 8, borderColor: '#6366f1', color: '#6366f1', height: 36 }}>
|
||||
重新生成
|
||||
</Button>
|
||||
<Button type="primary" icon={<DownloadOutlined />} style={{ flex: 1, borderRadius: 8, background: '#6366f1', borderColor: '#6366f1', height: 36 }}>
|
||||
下载视频
|
||||
</Button>
|
||||
</Space>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Modal
|
||||
title="修改提示词"
|
||||
open={modalVisible}
|
||||
onCancel={() => setModalVisible(false)}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={() => setModalVisible(false)}>取消</Button>,
|
||||
<Button key="confirm" type="primary" onClick={handleConfirm}>确认</Button>,
|
||||
]}
|
||||
width={800}
|
||||
>
|
||||
<TextArea
|
||||
value={promptText}
|
||||
onChange={(e) => setPromptText(e.target.value)}
|
||||
rows={8}
|
||||
style={{ width: '100%', height: 300 }}
|
||||
placeholder="请输入提示词"
|
||||
/>
|
||||
</Modal>
|
||||
{/* 创作记录弹窗 */}
|
||||
<Modal
|
||||
title="创作记录"
|
||||
open={isModalOpen}
|
||||
onCancel={() => setIsModalOpen(false)}
|
||||
width={800}
|
||||
footer={null}
|
||||
style={{ borderRadius: 12 }}
|
||||
>
|
||||
{/* 搜索区域 */}
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 16 }}>
|
||||
<Input
|
||||
placeholder="搜索产品名称"
|
||||
style={{ width: 200, borderRadius: 6, marginRight: 8 }}
|
||||
/>
|
||||
<Button type="primary" style={{ borderRadius: 6 }}>
|
||||
搜索
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 表格 */}
|
||||
<Table
|
||||
columns={[
|
||||
{
|
||||
title: '产品图片',
|
||||
dataIndex: 'image',
|
||||
key: 'image',
|
||||
width: 90,
|
||||
render: (image: string) => (
|
||||
<img
|
||||
src={image}
|
||||
alt="产品图片"
|
||||
style={{ width: 50, height: 50, objectFit: 'cover', borderRadius: 6 }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '原产品名称',
|
||||
dataIndex: 'originalName',
|
||||
key: 'originalName',
|
||||
},
|
||||
{
|
||||
title: '产品名称',
|
||||
dataIndex: 'productName',
|
||||
key: 'productName',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (_, record) => (
|
||||
<button
|
||||
onClick={() => navigate(`/initial/${record.id}/initialinfo`)}
|
||||
style={{ color: '#6366f1', textDecoration: 'none', fontSize: 12, border: 'none', background: 'none', cursor: 'pointer' }}
|
||||
>
|
||||
查看详情
|
||||
</button>
|
||||
),
|
||||
},
|
||||
]}
|
||||
dataSource={tableData}
|
||||
rowKey="id"
|
||||
pagination={false}
|
||||
style={{ fontSize: 13 }}
|
||||
/>
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default InitialInfo;
|
||||
@@ -15,31 +15,33 @@ import {
|
||||
VideoCameraOutlined,
|
||||
PictureOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const { Header, Content } = Layout;
|
||||
const { TextArea } = Input;
|
||||
|
||||
const GenerateConver: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [tableData, setTableData] = useState<any[]>(
|
||||
// [
|
||||
// {
|
||||
// id: 1,
|
||||
// image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=product%20image%20red%20gift%20box%20with%20hearts&image_size=square',
|
||||
// originalName: '进圈',
|
||||
// productName: '他趣',
|
||||
// status: '视频成功',
|
||||
// createTime: '2026-05-14 17:49:20',
|
||||
// },
|
||||
// {
|
||||
// id: 2,
|
||||
// image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=luxury%20perfume%20bottle%20golden%20elegant&image_size=square',
|
||||
// originalName: '香水',
|
||||
// productName: '面霜',
|
||||
// status: '视频提示词成功',
|
||||
// createTime: '2026-05-08 08:57:46',
|
||||
// },
|
||||
// ]
|
||||
[
|
||||
{
|
||||
id: 1,
|
||||
image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=product%20image%20red%20gift%20box%20with%20hearts&image_size=square',
|
||||
originalName: '进圈',
|
||||
productName: '他趣',
|
||||
status: '视频成功',
|
||||
createTime: '2026-05-14 17:49:20',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: 'https://neeko-copilot.bytedance.net/api/text_to_image?prompt=luxury%20perfume%20bottle%20golden%20elegant&image_size=square',
|
||||
originalName: '香水',
|
||||
productName: '面霜',
|
||||
status: '视频提示词成功',
|
||||
createTime: '2026-05-08 08:57:46',
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -517,10 +519,13 @@ const GenerateConver: React.FC = () => {
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: () => (
|
||||
<a href="#" style={{ color: '#6366f1', textDecoration: 'none', fontSize: 12 }}>
|
||||
render: (_, record) => (
|
||||
<button
|
||||
onClick={() => navigate(`/initial/${record.id}/initialinfo`)}
|
||||
style={{ color: '#6366f1', textDecoration: 'none', fontSize: 12, border: 'none', background: 'none', cursor: 'pointer' }}
|
||||
>
|
||||
查看详情
|
||||
</a>
|
||||
</button>
|
||||
),
|
||||
},
|
||||
]}
|
||||
|
||||
@@ -154,6 +154,9 @@ const RecordsPage: React.FC = () => {
|
||||
const isGenerating = generating[record.id];
|
||||
const isExpanded = expandedId === record.id;
|
||||
const type: any = record.genType || 'image';
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div key={record.id} className="animate-slideInCard" style={{ animationDelay: `${i * 0.04}s` }}>
|
||||
{/* Record summary row */}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.material_box>div{
|
||||
margin: 20px 10px;
|
||||
}
|
||||
.medio_box {
|
||||
width: 280px;
|
||||
height: 150px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.medio_box img ,.medio_box video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.product_img{
|
||||
margin-left: 20px;
|
||||
}
|
||||
Reference in New Issue
Block a user