Repository navigation
v0.4.0
從 0.3.0 升級:docker compose pull && docker compose up -d 就好;docker-compose.yml 與 .env 沒有變。
image 是 ghcr.io/1morr/berth:0.4.0,同時是 :0.4 與 :latest——固定在 :0.3 的不會自動升到這一版,要把
berth 的 image 改成 :0.4。下面改到的 API 只有 Berth 自己的畫面在用,升級之後重新整理一次頁面即可。
這一版有九個資料庫 migration(Berth 啟動時自動依序套用一次,各自寫在下面那一條);升級前備份一次
${CONFIG_ROOT}/berth。
這一版是 M5「AI 助理」:頁首多一個「助理」側面板,要先在設定 → AI 填你自己的模型服務(Anthropic 或 OpenAI 相容)
與 key;不填也照舊運作,只是沒有助理。選 OpenAI 相容接口時建議另填 Tavily key,整部系列與評價要用網路搜尋。
助理改東西(送單、訂閱、刪訂閱)一律先出確認卡,你按了才做。
Added
-
助理看得到 Jellyfin 裡已有的東西(M5 票 28):自己複製進 Jellyfin、或舊安裝入庫而 Berth 沒有紀錄的集,作品頁季表標成
「Jellyfin 已有」,不再算「缺」:「只看缺集」不列、缺集一鍵搜不搜,助理補缺集與整部系列也不會重下(要換版本照名字搜)。
側面板多一個讀取工具「用名字查媒體庫裡有沒有」(只找你在 Jellyfin 看得到的媒體庫),推薦新番時標出已經有的與已經訂閱的;
這類檔案很多時,助理建議到待處理按「從媒體庫重建帳本」。Jellyfin 連不上時作品頁照常打開,只是分不出這一種。
GET /api/media/{id}多jellyfin(found/absent/unknown),集的status多in_jellyfin。
Jellyfin 的集照播出日對 TMDB,不照它自己的季集號(它可能照 TVDB 編):對不上的照舊算缺、缺集搜尋照搜,季表上標
「Jellyfin 可能有」並說出是 Jellyfin 的哪幾集(jellyfin_unmatched、集的jellyfin_maybe)。送單確認卡逐列標出
作品已經有的集(「含已有的第 1 季第 4 集」,preview.held),由 Berth 算,不靠助理說。 -
助理的訂閱流程,搜尋一律多語言(M5 票 27):請助理訂閱一部還在播的作品時,它用原名、英文名與你說的語言的作品名搜
(中文另加字幕組常寫的簡體名;TMDB 沒有你那種語言的名字時用它自己知道的或網路搜尋,並說出來源),列一張字幕組比較表
(字幕語言、解析度、最新到第幾集與日期、平常比播出晚多久、做種數、Mikan 有沒有)、給一個建議,等你選了才出卡。選的字幕組
在 Mikan 上就訂 Mikan,不在才建關鍵字訂閱(例如英文字幕組);作品已經有訂閱時會問要不要先刪掉舊的;某個站連不上時說是哪一站、
建議稍後再試,不自己改走另一個來源。下載一季、補缺集、整部系列與推薦新番找發佈時也照同一套名字搜,結果不夠時自己換關鍵字,
字幕語言與字幕組照你說的挑;你沒說、找到的又有不同字幕語言時,先分語言列出候選、問你要哪種再出卡。整部系列每一部分
先只用一個名字搜,沒有才換一次,Re:Zero 這種長系列找來源那一輪的用量不會因此變多。 -
助理看得到、刪得掉作品的訂閱(M5 票 26):側面板多一個讀取工具「列出作品的訂閱」(哪一條 Feed、哪個站、哪個字幕組)
與一張「刪除訂閱」的確認卡(不可逆;已下載、入庫的檔案與綁定留著)。訂閱與加 Mikan 單一 feed 的卡片會說出這部作品已經有的
訂閱,要不要再訂一份由你決定。搜尋發佈給助理的結果多了發佈時間,它算得出各字幕組多久出一集。 -
側面板的停下、繼續與暫停,作品頁說得出為什麼缺(M5 票 22):防護讓一輪停下時,側面板畫成 Berth 說的一塊「停下」
(哪一條、做到哪),不再像助理自己的話;可以續的那一輪(只有最後一輪)下面有一顆「繼續」,按一次就沒了。按「停止」之後
「連線被關掉」那一則當場就看得到。AI 服務連續出錯被暫停時,面板頂上說暫停到幾點、到時間自動恢復(一般使用者也看得到,
管理員另有錯誤原文)。送單確認卡
重述第一次送單會寫死的資料夾名。作品頁季表「缺」「卡住」那一格多一顆「為什麼」,按了說出原因(待綁定、被排除、
停在審核、沒有來源……)與下一步。data-stop多note(說明的字),重新載入時說明那一則也是同一個data-stop;
GET /api/agent/conversations/{id}拿掉stop(看最後一則的data-stop)。 -
助理會推薦新番、整理整部系列(M5 票 16、23d):側面板多三個讀取工具——AniList 的當季清單(附打分人數)、
Bangumi 的本季放送表(中文名與評分票數)與 TMDB 本週趨勢。「推薦新番」與「整部系列」兩份流程因此上線(推薦新番要訂閱,
只給管理員)。整部系列用網路搜尋查各季、各 cour 的集數表,對照 TMDB 的季集表列出範圍;集數加不起來、季接著上一季編號,
或有第 0 集、.5 集、總集篇被 TMDB 放進特別篇時,那一季整季標「請確認」。沒有網路搜尋(OpenAI 相容接口沒填 Tavily key)
或搜不到時,照 TMDB 各集播出日的空檔切段,每一季都標「沒有網頁核對,請確認」,AI 設定頁也會建議填 Tavily key。
AniList 照它目前的上限每兩秒最多問一次、被限流就整個停到它說的時間,問過的記 6 小時。這幾個來源是社群編的資料:
卡片上原本的「出自網頁」標記改叫「出自外部來源」,從這些資料站抄來的字也會標。伺服器端網搜搜到的整頁只在下一步再送給模型一次,
找來源時每次搜尋只給模型看前 10 列與它們沒涵蓋到的集(其餘說有幾列),Re:Zero 這種長系列從列清單到出卡不再撞到每輪的用量上限。 -
助理可以訂閱與加 RSS Feed(M5 票 14):管理員可以請助理從 Mikan 訂閱一部作品(它搜番組、列字幕組,出一張確認卡)、
建 Nyaa / acg.rip 關鍵字訂閱(可逆,直接做),或加一個你貼的 RSS 網址(出卡)。補缺集時助理只搜缺的那幾集,
一般使用者也用得上「補缺集」這份流程。幾條硬規則不靠模型聽話:卡片上的作品、發佈、Route、番組、字幕組一定要是
這段對話裡工具查到的;Feed 的網址一定要是你自己打的字(叫它「上網找網址直接加」會被擋下);從網頁抄來的文字
(例如搜尋詞、Feed 名稱)在卡片上標「出自網頁」,原本直接做的關鍵字訂閱也因此改成要你確認。一張卡送出的 torrent 最多 13 個
(Mikan 訂閱照整季的集數算,單獨就超過或讀不到集數的訂閱自己一張),多的等你按了之後助理再提一張。Mikan 訂閱卡那一列寫明「會送出整季」與幾個 torrent(按下確認就送,不經第一批確認;
讀不到 Mikan 時說數量要送出時才知道)。側面板上被 Berth 擋下的工具呼叫顯示「沒成功」,不再是「完成」。
GET /api/proposals的preview多external_fields(逐列出自網頁的欄位)、held_back(留給下一張的列數)
與torrents(逐列會送出幾個 torrent)。 -
AI 用量頁與每一輪的步驟頁(M5 票 21):設定多一個「用量」分頁(只有管理員):近 30 天每天的 token(新的 input、快取讀、快取寫、
output)、快取命中率、估計費用、網搜次數,各種防護停下幾次、工具呼叫被擋下幾次,最近 20 輪,以及費用怎麼估(價目附查證日期)。
接口沒報的數字寫「—」、價目表上沒有的模型寫「未知」,不當 0。可以設每日提醒值;今天到了它,或是近 14 天有用量那幾天的中位數的
5 倍以上,用量頁與側面板(只給管理員)會提醒——只提醒,不會停用 AI,也不推 Discord。提醒只算得進有價目的費用:今天或前 14 天有費用未知的呼叫(有回應,但模型不在價目表上;出錯沒有回應的沒有花費,不算)時,兩處都明說有幾次沒算進去,「沒有提醒」不會看起來像沒事。側面板每一則回覆底下多一個「步驟」,
連到那一輪的步驟頁:每一次模型呼叫與它叫的工具、各自的 token、耗時、結果(含被擋的理由)與停止原因,被中止的那一輪也有。
一般使用者看得到自己的步驟頁,看不到用量頁。新增GET /api/settings/usage、PUT /api/settings/usage/alert、
GET /api/agent/runs/{id};GET /api/agent/status多spend(提醒與沒算進去的呼叫數,只給管理員),對話的每一則助理訊息帶metadata.runId。 -
助理的上下文壓縮與斜線指令(M5 票 18):對話一長,下一則開頭自動把較早的部分換成一段摘要
(佔到模型 context window 的六成時,留最後兩輪),助理照樣記得要的是哪部作品、送了什麼;等你確認的卡片不受影響。
摘要在對話開頭收成一行,展開看全文。輸入欄打/列出指令:/new新對話、/compact現在就壓縮(只留最後一輪)、
/usage這段對話用了多少(token、快取命中、網搜次數、估計費用)、/status模型與上下文用了多少、
/pending還在等你決定的確認卡(每一段對話的)、/skills助理會照著做的工作流程。指令不經過模型,結果只在這個分頁。
新增POST /api/agent/conversations/{id}/commands;以/開頭的訊息送進POST /api/agent/chat是 422slash_command。
資料庫 migratione6b2d9a4c731:ai_runs多一欄kind(chat/compaction),既有的列是chat。 -
助理可以替你送單,先出一張確認卡(M5 票 13):在側面板說「下載 ⋯⋯」,助理搜作品、搜發佈、選好 Route,
然後出一張卡:每一列是一個要送的 torrent(發佈名、大小、作品、Route),標著「會送出 torrent」與期限。
多列時逐列可取消勾選;按下確認就送出勾著的那幾列,每一列當場看得到結果(會部分成功),助理接著說它拿到的結果。
沒按就繼續聊也沒關係:卡片仍然有效,之後再按照樣執行,助理下一則會知道。卡片存在 Berth 的資料庫裡,
重新載入、換裝置、Berth 重啟之後都還按得下去,24 小時沒人按就過期。只有提出它的那個人(與管理員)按得到;
一般使用者也能請助理送自己的單。卡片上不會出現下載連結(帶著 Prowlarr 的 API key)。
資料庫 migrationd8a4f1c6e273:proposals多兩欄(提出它的那一次工具呼叫、脫離對話的時刻),既有的列是空的。 -
助理側面板(M5 票 12):每一頁的頁首多一顆「助理」,打開是一個對話面板——桌面在畫面右側一欄、頁面讓位,
兩邊都能操作;手機蓋滿整個畫面。可以問「某部作品為什麼還沒入庫」:助理查了什麼一行一個(展開看參數與結果),
回答說出結論。換頁、重新載入之後對話還在(存在 Berth 的資料庫,記在這個瀏覽器);「新對話」從空的開始。
回覆裡的圖片一律不載入,只印出網址(圖片網址是常見的外洩通道),原始 HTML 不渲染。AI 沒開時管理員看到
去設定頁的連結,其他人看到「管理員還沒設定」,其餘功能與之前完全一樣。
新增GET /api/agent/status(登入就讀得到,回 AI 開著沒有)。演練伺服器多一個agent情境(照腳本回答的
假模型,不需要金鑰)。 -
AI 對話的工作流程說明(skills)(M5 票 19):常見的幾種事 AI 照一份寫好的步驟做,平常只帶名稱與一句描述,
要用時才載入全文,不必每一輪都付整段流程的費用。第一批四份:為什麼沒入庫、補缺集、整理整個系列(含 TMDB 把好幾季併成一季時的集數換算)、
當季新番推薦(評分附評分人數,太少的標出來)。這一版只有「為什麼沒入庫」用得上,其餘三份等送單、訂閱與動漫資料來源的工具做好就自動出現。
skill 是berth/skills/底下的 Markdown 檔,只能寫步驟,不能附程式。 -
AI 對話的網路搜尋(M5 票 17):推薦新番、查系列順序時 AI 可以上網看評價。接口是 Anthropic Messages
(官方或 DeepSeek 這類相容端點)時用服務自己的網路搜尋,不用另外申請帳號;在設定 → AI 填了 Tavily key 的話,
兩種接口都多一個 Tavily 搜尋。只搜動漫與影視的資料站、維基百科與 Reddit,每則回覆最多搜 5 次,回覆引用的網頁附網址。
搜尋次數記在用量裡;Anthropic 官方端點每次估 $0.01,其他端點的網搜價格不知道,不算進估計費用。
資料庫 migrationc3e7a1f9d524:ai_calls、ai_runs多記網搜次數,既有的列補 0。 -
AI 對話的其餘防護(M5 票 20):模型在兩個呼叫之間來回而結果都沒變、或連續三次呼叫都沒拿到新東西時停下;
一筆工具結果太長時只交給模型前面一部分,並告訴它還有幾筆、怎麼縮小範圍再問。AI 服務連續 5 次出錯時暫停
15 分鐘(換了 key 或模型不用等),GET /api/agent/status說暫停到什麼時候(管理員另外看得到是什麼錯),一般使用者也看得到。
被防護停下的那一輪可以按一次「繼續」(POST /api/agent/chat帶continues),續的那一輪再停下就不能再續;
GET /api/agent/conversations/{id}多一格stop說最後一輪停在哪。每一種防護停下都記成自己的停止原因。
這一版還沒有畫面。資料庫 migrationc4e7a9d2b158:ai_runs與ai_tool_calls各加一欄。 -
AI 對話的後端(M5 票 11):
POST /api/agent/chat(Vercel AI SDK 的串流)與GET /api/agent/conversations/{id}。
對話存在 Berth 的資料庫,畫面送來的歷史不採用;AI 能用的只有幾支讀取命令(找作品、「為什麼沒入庫」、下載清單與時間線),
一般使用者只有前兩支。每一次模型呼叫的 token、快取讀寫與估計費用當場記下,被中止的那一輪也有。
防護:每次最多輸出 4096 token、每輪 20 次模型呼叫與 400K / 30K token、同一個呼叫第 2 次警告 / 第 3 次擋下 / 第 4 次中止
(失敗的重試不算)、每人同時一輪;停下來時對話裡留一則說明是哪一條、做到哪。畫面見上面的助理側面板。
資料庫 migration78a62163b817:新增四張表,既有的不動。 -
確認卡的後端(M5 票 08):要人確認的動作存成一筆資料,隔天按、換一台裝置按、Berth 重啟之後按都照樣有效,
沒人按的 24 小時後過期。按下確認時用伺服器存的那一份參數、先重新檢查一次,再逐列執行並記下每一列的結果
(一次送整個系列時會有幾列成功、幾列被拒);只有提出的人或管理員按得到,連按兩次只執行一次。
API:GET /api/proposals、POST /api/proposals/{id}/decide,狀態變更經GET /api/events/stream的
event: proposal推出去。這一版還沒有畫面,是之後 AI 側面板確認卡的資料來源。 -
「為什麼沒入庫」的讀取 API(M5 票 10):
GET /api/media/{id}/why-not,加?season=&episode=問一集。
一次回齊季表、相關的下載與最後幾筆時間線、開著的 Issue、RSS 那一側(綁了沒、被排除了沒),加一個結論:
入庫失敗、沒下載成、等審核、待綁定、被排除、沒有來源、還在下載、Jellyfin 還沒掃到、還沒播、已入庫。
一般使用者只看得到自己送的下載,看不到 Issue 與 RSS。這一版還沒有畫面,是之後 AI 側面板的資料來源。 -
設定 → AI(M5 票 09):接上你自己的模型服務。兩種接口各自記著 Base URL、API key 與模型名:
Anthropic Messages(官方或相容閘道)與 OpenAI 相容的 Chat Completions(OpenAI、OpenRouter、自架閘道、本機模型);
切換接口不會丟掉另一邊填好的。「測試連線」用表單上還沒存的值打一次最小呼叫,成功說哪個模型回話,失敗說是
key 被拒、模型或網址找不到、服務出錯、連不上還是網址指錯地方,並附上服務回的原文。key 存進去之後畫面只說
「已設定」,不回到瀏覽器、不進 log。已知價目的模型顯示每百萬 token 的價格與查證日期,認不得的寫「未知」。
另可填 Tavily key 給之後的網路搜尋工具。開關預設關著:不設定的話 Berth 與之前完全一樣。設定存在資料庫,
不讀環境變數。API:GET|PUT /api/settings/ai、POST /api/settings/ai/test、DELETE /api/settings/ai/keys/{key}。
Changed
- 訂閱的字幕組由你選(M5 票 26):Mikan 訂閱卡列出番組頁上的每個字幕組(筆數、最近更新、最新一筆),助理建議的
只是預選,可選的不只一個時沒選就沒有確認鍵;送出的集數跟著選的那一組。關鍵字訂閱(Nyaa / acg.rip)在側面板一律出卡、
在作品頁先搜:兩處都列出這一次搜到的字幕組,選一組、看它的第一批,再選「下載這些並追之後的」(預設)或「只追之後的」
(同 RSS 頁第一輪那兩顆),按下去才建,那條 Feed 只收這個字幕組的發佈,不必再到 RSS 頁選第一輪;讀不到搜尋就不建。
POST /api/rss/subscriptions/search的subgroup必填、多first_batch,新端點GET /api/rss/search/subgroups;卡片 API
多preview.subgroups、preview.existing、preview.first_batch與決定時的subgroups、first_batch
(subgroup_required、subgroup_not_offered、first_batch_not_offered);rss_feeds多subgroup(migration
d7e1b3a5c926)。已經綁了好幾個字幕組的舊 Feed 照舊運作。 - 重新整理頁面、關掉分頁,助理那一輪照樣跑完(M5 票 25):之前連線一斷那一輪就停在「連線被關掉」。現在它在伺服器上
跑到完,回到對話時接著顯示還在跑的那一輪,或直接看到跑完的結果;只有按「停止」會停(說明寫「你按了停止」,開著同一段
對話的每個分頁都收到)。另一個分頁正在答時送出,面板接上那一輪;在跑的是你的另一段對話(例如開了新對話)時,面板說是哪一段,可以點過去接上,或停掉那一輪再重送這一則(busy的 detail 是那一段對話的 id)。Berth 重新啟動時還在跑的那一輪記成「Berth 重新啟動時
中斷」並補一則說明,用量頁與步驟頁也這樣寫。新增GET /api/agent/conversations/{id}/stream?turn=<id>(重連,沒有在跑
是 204)與POST /api/agent/conversations/{id}/stop(沒有在跑是 409not_running);GET /api/agent/conversations/{id}
多running;停止原因多interrupted。 - 作品放得進的 Route 不只一條時,確認卡上要你選(M5 票 23b):助理出的送單卡與 Mikan、關鍵字訂閱卡,那部作品有兩條以上
啟用中、收這一種作品的 Route 時,那一列的 Route 換成必選的下拉,預選這部作品上次送單用的那一條(沒用過就不預選),
勾著的列沒選齊之前沒有確認鍵;助理不再在對話裡問 Route,它給的那一條也不會被預選。關鍵字訂閱(Nyaa / acg.rip)平常由助理
直接建,但作品放得進的 Route 不只一條、這部作品又沒送過單時,改成出卡讓你選。伺服器只收提出時存下的那份清單裡的
Route。只有一條時照舊直接帶入。API:GET /api/proposals的preview多逐列routes(可選清單與預選),卡片多routes
(核准時選的);POST /api/proposals/{id}/decide多選填的routes(與列對齊),要選的列沒選是 422route_required,
不在清單上是 422route_not_offered。資料庫 migrationc2f6a8d4e917:proposals多一欄routes_json,既有的列是NULL。 - AI 估計費用改用 genai-prices 查價,照端點網址認服務商(M5 票 21b):價目改由 Pydantic 維護的
genai-prices(隨 Berth 內附的 0.1.13)提供,先照 base URL 認出是哪一家,
所以「Anthropic 接口 + DeepSeek 端點」照 DeepSeek 的價算,不再照模型名套原廠價;DeepSeek 的尖峰離峰照每次呼叫當時的價。
網址認不得(自架閘道)時照接口種類查;都查不到的看 Berth 自己的補位表,再查不到照舊寫「未知」。查價不連網,價目跟著
Berth 的版本更新。AI 設定頁與用量頁的「查證日期」改成價目來源(genai-prices 的版本與它認出的服務商,或補位表的查證日期),
用量頁的價目改成每一組「端點 + 模型」各列一次,模型欄的建議改成這個端點查得到價的模型。既有呼叫的費用不重算,只影響之後的呼叫。
API:AiPriceOut.verified換成source(table、version、vendor、verified);AiOut.known_models搬到每個接口的
AiEndpointOut.known_models;GET /api/settings/usage的prices每列多base_url。
資料庫 migrationa9c3e5f1b742:ai_calls多一欄base_url(打的端點),既有的列是NULL。
Fixed
- Nyaa 上 scene 式的發佈名(
…H.264-VARYG (Tetsuryou! meet with Tetsudou Musume, Multi-Subs))把後面括號裡的別名讀進
字幕組名,關鍵字訂閱的字幕組清單上同一組變成兩個怪名字(M5 票 27)。現在組名是VARYG。 - 關掉分頁(或換頁、瀏覽器斷線)時,即時更新那條連線(
GET /api/events/stream)留下一個沒人收的背景 task,
log 偶爾出現「Task was destroyed but it is pending!」(M5 票 23)。現在斷線時一起收掉。
Removed
- 沒有呼叫端的
AiPlanner/NullAiPlanner介面(M5 票 09);AI 解析在 M6 重新設計(plan §4.5)。