這個網站是怎麼運作的

從你按下「開始生成」到拿到影片,中間發生的每一件事,以及我們為什麼這樣設計。 這頁寫得比一般的「技術說明」細,因為裡面每一個決定都是踩過坑之後才定案的。

整條流程

  1. 照片上傳到本機伺服器,存進暫存資料夾
  2. 如果你選的是人像動作,先用 OpenCV 做一次人臉偵測
  3. 照片轉送到本機的 ComfyUI
  4. 一段文字指令 + 你的照片,交給 MiniMax H3 影像轉影片模型
  5. 模型產生 73 格畫面(3.04 秒 @ 24fps)
  6. ffmpeg 把影片接成「正放 + 倒放」的乒乓循環,並移除音軌
  7. 成品回傳給你,網頁再用 CSS 疊上相框

全部跑在同一台實體機器上。你的照片當然會經由網路傳到我們的伺服器 —— 這是任何網頁服務都免不了的 —— 但它不會再被送到任何第三方 AI API,中間沒有別的服務參與,處理完就只留在我們的硬碟上,七天後刪除。

為什麼是 73 格

MiniMax H3 的畫面數必須是 17n + 5。24fps 的 3 秒是 72 格,不符合, 往上進位到最近的合法值就是 73 格,也就是 3.04 秒。乒乓之後 146 格、6.08 秒。

指令裡一個字都不提鏡頭

這是最違反直覺的一條。模型有「畫面慢慢推近」的傾向,直覺的解法是在指令裡寫 「不要 zoom」「鎖死鏡頭」「static shot」。我們實際量過背景的位移量:

指令怎麼寫背景位移量(越小越穩)
完全不提鏡頭6.6
寫 static shot20.6
寫完整的鎖鏡頭句子39.2

寫得愈用力,畫面推得愈兇。原因大概是這類詞彙在訓練資料裡總是跟運鏡描述一起出現, 提到它反而是在提醒模型「這裡有鏡頭運動這回事」。所以現在的指令完全不出現 camera、shot、zoom 這些字。

相框不讓模型畫

同樣的道理。指令裡一提到 picture frame,模型就真的在畫面裡畫一個金色相框, 而且會歪、會抖、四個角對不齊。現在相框改由網頁用 CSS 疊在影片外面, 永遠是正的,換顏色也不用重跑。

主詞必須跟照片內容一致

人像動作的指令寫的是「The person…」。如果照片裡根本沒有人,模型不會忽略這個詞, 它會生一個人出來,還會把鏡頭推近到那張憑空出現的臉上。這是我們實際遇到的狀況。

解法是把動作分成兩組:動物組整段改用 the animal,並在結尾加上 No people appear。同一張照片、同一個模型,換了主詞就正常了。 另外上傳時的人臉偵測會攔一次,避免使用者不小心選錯。

為什麼要做成乒乓循環

如果直接把 3 秒影片設成 loop,播到結尾跳回開頭時會有一個明顯的跳格, 因為最後一格跟第一格對不起來。把影片倒放接在後面,接縫兩側是同一格, 循環就完全看不出接點 —— 代價是有方向性的動作(揮手)會有一點倒帶感。

速度:慢的其實不是運算

我們用 websocket 逐節點量過一支 3 秒影片的時間分布:

階段耗時
解讀照片內容(文字編碼器)約 17.7 秒
取樣(讓照片動起來)約 11 秒
VAE 解碼(沖洗畫面)約 11.4 秒
其餘把模型搬進顯示卡

顯示卡是 RTX 5070 Ti,只有 16GB 顯示記憶體,但這套模型光是文字編碼器加上主模型 就超過 30GB,塞不進去,每跑一次都得把權重串流進顯示卡。 所以真正的瓶頸是搬資料,不是計算。我們把文字編碼器換成更小的量化版本 (25.3GB → 14.6GB)、把取樣步數從 6 步降到 4 步(那個加速用的 LoRA 本來就是為 4 步設計的)、 再拿掉根本用不到的音訊解碼之後,單張從 60~80 秒(最糟到 137 秒)降到穩定的 42~45 秒, 畫質用同一組隨機種子比對過,看不出差別。

排隊與取消

只有一張顯示卡,所以工作是排隊處理的。首頁會顯示目前有幾件在排, 輪到你之前進度列會顯示「前面還有幾件」。按下取消時:如果你的工作還在排隊, 就直接從佇列移除;如果正在跑,會先確認正在跑的確實是你這一件,再送出中斷指令 —— 不會誤殺別人的工作。

斷線不會白做

工作狀態是寫在伺服器磁碟上的,不是只存在瀏覽器裡。你關掉分頁、重新整理、 手機把瀏覽器切到背景被系統凍結,回來都會自動接回進度。 即使伺服器本身重啟,重啟後也會去問 ComfyUI 那件工作跑完了沒,接著把成品收回來。

用到的東西

親自試一次