Compare commits
2 Commits
659ee10efb
...
10d955c6f2
| Author | SHA1 | Date | |
|---|---|---|---|
| 10d955c6f2 | |||
| eeb7186d7a |
4501
.memory/worklog.json
4501
.memory/worklog.json
File diff suppressed because it is too large
Load Diff
2
RULES.md
2
RULES.md
@@ -11,7 +11,7 @@
|
||||
- 详见 `CLAUDE.md` 立项决策段 + `.memory/plan.md` 七步管线拆解
|
||||
- 风格:`04-Dark-Gallery-Ambient`(路径:`~/Projects/research/20260305-网页风格库/04-Dark-Gallery-Ambient.md`)
|
||||
- 第一冲刺:步骤 1-4(下载 / 拆轨 / 关键帧 / ASR+翻译)
|
||||
- 当前产品方向(2026-05-20 再确认):信息流广告快速复刻默认进入“三字段候选生成”工作流。主界面为“左侧素材输入列 + 右侧信息流复刻工作表”。用户粘贴 TK 链接或上传视频后点击“开始分析”,系统自动下载源视频;下载完成后并行启动两条路:音频文案路提取原音频文案/字幕,并分析讲话人、语速节奏、背景音乐/环境声/音效;视频视觉路自动抽取参考帧。源视频工作区右侧主体链路是“参考帧池 → 转换层 → 主体元素”:参考帧池竖向排列;转换层是轻量对话式生图确认区,参考图可通过左侧缩略图 `+`、参考帧拖拽、胶片拖拽或本地图片拖入进入转换层,用户选择 GPT/Gemini 套件后先分析参考图,再在下方消息输入区发送复刻/创新/卡通/数量和画面要求;后端返回英文出图 prompt 后必须弹窗确认,用户点确认才生成对应数量的统一多角度套图。右侧主体元素区的套图输出、文件夹分组、单张重生、删除和 hover 预览逻辑保持不变。旧下方“相似主体 / 主体模板库”不再作为主路径。波形下方的画面胶片只是临时预览,点击只跳转原视频时间点,双击或拖进参考帧池才正式加入关键帧,已加入的胶片直接显示“已添加”。产品图上传后独立形成产品资产包,自动识别视角/结构/比例并补缺角度。分镜工作台按逐句时间轴默认只露“文案 / 场景一句话 / 人物+产品+动作”,产品素材池、批量控制、三字段、视频候选和高级区都必须可折叠;视频候选无内容时默认不占大面积,有候选时默认只显示迷你缩略条,展开后才显示 4-grid。单条默认生成 4 个视频候选,顶部支持整片批量生成候选;首尾帧、视觉规划、产品出现方式和旧 6 字段保留在“高级”抽屉与后端 quick-plan 自动展开中,不能再作为客户默认闸门。
|
||||
- 当前产品方向(2026-05-20 再确认):信息流广告快速复刻默认进入“三字段候选生成”工作流。主界面为“左侧素材输入列 + 右侧信息流复刻工作表”。用户粘贴 TK 链接或上传视频后点击“开始分析”,系统自动下载源视频;下载完成后并行启动两条路:音频文案路提取原音频文案/字幕,并分析讲话人、语速节奏、背景音乐/环境声/音效;视频视觉路自动抽取参考帧。源视频工作区右侧主体链路是“参考帧池 → 转换层 → 主体元素”:参考帧池竖向排列;转换层是轻量对话式生图确认区,参考图可通过左侧缩略图 `+`、参考帧拖拽、胶片拖拽或本地图片拖入进入转换层,用户选择 GPT/Gemini 套件后先分析参考图,再在下方消息输入区发送复刻/创新/卡通和画面要求,生成数量通过发送区旁边的张数控件控制;后端返回英文出图 prompt 后必须弹窗确认,用户点确认才生成对应数量的统一多角度套图。右侧主体元素区的套图输出、文件夹分组、单张重生、删除和 hover 预览逻辑保持不变。旧下方“相似主体 / 主体模板库”不再作为主路径。波形下方的画面胶片只是临时预览,点击只跳转原视频时间点,双击或拖进参考帧池才正式加入关键帧,已加入的胶片直接显示“已添加”。产品图上传后独立形成产品资产包,自动识别视角/结构/比例并补缺角度。分镜工作台按逐句时间轴默认只露“文案 / 场景一句话 / 人物+产品+动作”,产品素材池、批量控制、三字段、视频候选和高级区都必须可折叠;视频候选无内容时默认不占大面积,有候选时默认只显示迷你缩略条,展开后才显示 4-grid。单条默认生成 4 个视频候选,顶部支持整片批量生成候选;首尾帧、视觉规划、产品出现方式和旧 6 字段保留在“高级”抽屉与后端 quick-plan 自动展开中,不能再作为客户默认闸门。
|
||||
|
||||
## 部署事实
|
||||
- 平台:VPS `76.13.31.179`(Ubuntu 24.04 / Docker Compose / Coolify Traefik)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
import { type DragEvent as ReactDragEvent, type MouseEvent as ReactMouseEvent, type ReactNode, type RefObject, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { createPortal } from "react-dom"
|
||||
import {
|
||||
AlertTriangle, BookOpen, Check, ChevronDown, Circle, Film, FileText, Image as ImageIcon, Info, Link2, Loader2,
|
||||
AlertTriangle, BookOpen, Check, ChevronDown, Circle, Film, FileText, Image as ImageIcon, Info, Link2, Loader2, Minus,
|
||||
MessageSquare, Mic, Moon, Package, PanelRight, Play, Plus, RefreshCw, Scissors, Send, Sparkles, Sun, Trash2, Upload, Wand2,
|
||||
} from "lucide-react"
|
||||
import { toast } from "sonner"
|
||||
@@ -3854,7 +3854,7 @@ function SourceSubjectPipeline({
|
||||
const agentTraits = agentAnalysis?.trait_chips ?? []
|
||||
const selectedAgentTraits = subjectAgent?.selected_traits ?? []
|
||||
const effectiveAgentMode = subjectAgent?.selected_mode ?? agentMode
|
||||
const effectiveAgentQuantity = subjectAgent?.quantity ?? agentQuantity
|
||||
const effectiveAgentQuantity = agentQuantity
|
||||
const effectiveAgentViews = subjectViewsForQuantity(effectiveAgentQuantity)
|
||||
const effectivePrompt = (agentPrompt || subjectAgent?.generation_prompt_en || "").trim()
|
||||
const effectiveRequirement = (subjectAgent?.requirements_zh || agentRequirement).trim()
|
||||
@@ -4021,7 +4021,7 @@ function SourceSubjectPipeline({
|
||||
<span className="text-[9px] text-white/34">{agentReferenceFrames.length}/{RECONSTRUCTION_FRAME_LIMIT}</span>
|
||||
</div>
|
||||
{agentReferenceFrames.length ? (
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
<div className="flex min-h-[78px] items-center justify-center gap-1.5 overflow-x-auto rounded border border-white/8 bg-black/18 px-1.5 py-1">
|
||||
{agentReferenceFrames.map((frame, index) => (
|
||||
<MediaAssetTile
|
||||
key={frame.index}
|
||||
@@ -4029,7 +4029,7 @@ function SourceSubjectPipeline({
|
||||
alt={`转换参考 ${index + 1}`}
|
||||
label={`参考 ${index + 1}`}
|
||||
meta={`${frame.timestamp.toFixed(1)}s`}
|
||||
className="aspect-[9/16] bg-black"
|
||||
className="aspect-[9/16] w-[44px] shrink-0 bg-black 2xl:w-[50px]"
|
||||
objectFit="contain"
|
||||
previewObjectFit="contain"
|
||||
previewPlacement="left"
|
||||
@@ -4041,7 +4041,7 @@ function SourceSubjectPipeline({
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex h-[116px] flex-col items-center justify-center rounded border border-dashed border-white/15 px-3 text-center text-[10px] leading-snug text-white/34">
|
||||
<div className="flex h-[72px] flex-col items-center justify-center rounded border border-dashed border-white/15 px-3 text-center text-[10px] leading-snug text-white/34">
|
||||
{agentReferenceUploadBusy ? <Loader2 className="mb-1.5 h-4 w-4 animate-spin text-cyan-100/80" /> : <Upload className="mb-1.5 h-4 w-4 text-cyan-100/55" />}
|
||||
<span className="font-semibold text-white/50">拖入参考帧或本地图片</span>
|
||||
<span className="mt-0.5 text-white/28">也可点左侧缩略图上的 +</span>
|
||||
@@ -4119,34 +4119,62 @@ function SourceSubjectPipeline({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-2 flex flex-wrap gap-1">
|
||||
{["复刻这个人的形象,生成6张", "参考创意但人物不同,生成6张", "卡通风格,生成6张", "人物更大,占画面90%"].map((text) => (
|
||||
<button
|
||||
key={text}
|
||||
type="button"
|
||||
onClick={() => setAgentInput(text)}
|
||||
className="rounded-full border border-white/10 bg-black/24 px-2 py-0.5 text-[9px] text-white/48 transition hover:border-white/22 hover:text-white/72"
|
||||
>
|
||||
{text}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-2 rounded-md border border-white/10 bg-black/35 p-1.5">
|
||||
<textarea
|
||||
value={agentInput}
|
||||
onChange={(event) => setAgentInput(event.target.value)}
|
||||
placeholder="例如:保留透明骨架和蓝色头带,但人物更大,服装统一,生成6张。"
|
||||
placeholder="直接描述:复刻这个人、参考创意换人物、卡通风格、人物占画面90%..."
|
||||
className="h-[72px] w-full resize-none rounded border border-transparent bg-transparent px-1 py-1 text-[10.5px] leading-snug text-white outline-none transition placeholder:text-white/24 focus:border-cyan-200/45"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void sendSubjectAgentRequirement()}
|
||||
disabled={!!subjectAgentBusy || (!agentInput.trim() && !agentRequirement.trim())}
|
||||
className="skg-primary-action mt-1 inline-flex h-8 w-full items-center justify-center gap-1.5 px-2 text-[10.5px] font-semibold transition disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
{subjectAgentBusy === "message" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Send className="h-3.5 w-3.5" />}
|
||||
发送消息
|
||||
</button>
|
||||
<div className="mt-1 flex items-center gap-1.5">
|
||||
<div className="flex h-8 shrink-0 items-center overflow-hidden rounded-md border border-white/10 bg-black/35">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setAgentQuantity((current) => clampNumber(current - 1, 1, 10))}
|
||||
disabled={agentQuantity <= 1 || !!subjectAgentBusy}
|
||||
className="inline-flex h-full w-7 items-center justify-center text-white/48 transition hover:bg-white/[0.06] hover:text-white/78 disabled:cursor-not-allowed disabled:opacity-30"
|
||||
title="减少生成数量"
|
||||
aria-label="减少生成数量"
|
||||
>
|
||||
<Minus className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
<label className="flex h-full items-center gap-1 border-x border-white/10 px-1.5 text-[9px] text-white/38">
|
||||
<span>张数</span>
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
max={10}
|
||||
value={agentQuantity}
|
||||
aria-label="生成张数"
|
||||
onChange={(event) => {
|
||||
const next = Number.parseInt(event.target.value, 10)
|
||||
setAgentQuantity(Number.isFinite(next) ? clampNumber(next, 1, 10) : 6)
|
||||
}}
|
||||
disabled={!!subjectAgentBusy}
|
||||
className="h-6 w-8 bg-transparent text-center text-[10px] font-semibold text-white outline-none disabled:opacity-45"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setAgentQuantity((current) => clampNumber(current + 1, 1, 10))}
|
||||
disabled={agentQuantity >= 10 || !!subjectAgentBusy}
|
||||
className="inline-flex h-full w-7 items-center justify-center text-white/48 transition hover:bg-white/[0.06] hover:text-white/78 disabled:cursor-not-allowed disabled:opacity-30"
|
||||
title="增加生成数量"
|
||||
aria-label="增加生成数量"
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void sendSubjectAgentRequirement()}
|
||||
disabled={!!subjectAgentBusy || (!agentInput.trim() && !agentRequirement.trim())}
|
||||
className="skg-primary-action inline-flex h-8 flex-1 items-center justify-center gap-1.5 px-2 text-[10.5px] font-semibold transition disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
{subjectAgentBusy === "message" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Send className="h-3.5 w-3.5" />}
|
||||
发送消息
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user