mirror of
https://github.com/JefferyHcool/BiliNote.git
synced 2026-09-05 23:56:59 +08:00
chore(release): merge hotfix/docker-pnpm-version into develop
This commit is contained in:
@@ -2,7 +2,8 @@
|
|||||||
# Tailwind v4 / Vite 6 需要 Node 20+,alpine + pnpm 会按 lockfile 拉 musl native binary。
|
# Tailwind v4 / Vite 6 需要 Node 20+,alpine + pnpm 会按 lockfile 拉 musl native binary。
|
||||||
FROM node:20-alpine AS builder
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
# pnpm pin 到 9.x:lockfile 是 v9 生成;pnpm 11 要求 Node 22+ 与 node:20 不兼容
|
||||||
|
RUN corepack enable && corepack prepare pnpm@9.15.0 --activate
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,15 @@
|
|||||||
|
|
||||||
本项目所有重要变更记录于此。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
本项目所有重要变更记录于此。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||||
|
|
||||||
|
## [2.2.1] - 2026-05-09
|
||||||
|
|
||||||
|
补 v2.2.0 ghcr.io 镜像构建失败。
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Docker 镜像构建失败:`v2.2.0` tag 触发的 ghcr.io 推送在 frontend-builder 第 5/7 步 `pnpm install --frozen-lockfile` 报 `ERR_UNKNOWN_BUILTIN_MODULE`。根因:`corepack prepare pnpm@latest` 拉到了 pnpm 11.0.9,而 pnpm 11 要求 Node 22+,跟我们的 `node:20-alpine` 不兼容。
|
||||||
|
- `Dockerfile.complete` 与 `BillNote_frontend/Dockerfile` 的 pnpm 版本 pin 到 `9.15.0`(lockfile 由 pnpm 9 生成,匹配 Node 20)
|
||||||
|
|
||||||
## [2.2.0] - 2026-05-09
|
## [2.2.0] - 2026-05-09
|
||||||
|
|
||||||
主线:浏览器插件功能与 web 端 NoteForm 完整对齐;桌面客户端 UX 与错误恢复一波重炼。
|
主线:浏览器插件功能与 web 端 NoteForm 完整对齐;桌面客户端 UX 与错误恢复一波重炼。
|
||||||
|
|||||||
+5
-1
@@ -30,7 +30,11 @@ COPY ./backend /tmp/backend
|
|||||||
# 升到 node:20-alpine。alpine 走 musl,pnpm 会按 lockfile 拉 *-linux-x64-musl native binary。
|
# 升到 node:20-alpine。alpine 走 musl,pnpm 会按 lockfile 拉 *-linux-x64-musl native binary。
|
||||||
FROM node:20-alpine AS frontend-builder
|
FROM node:20-alpine AS frontend-builder
|
||||||
|
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
# pnpm 版本 pin 到 9 系列:
|
||||||
|
# - lockfile (BillNote_frontend/pnpm-lock.yaml) 是 lockfileVersion '9.0',由 pnpm 9 生成
|
||||||
|
# - pnpm 11+ 要求 Node 22+,与 node:20 不兼容(ERR_UNKNOWN_BUILTIN_MODULE)
|
||||||
|
# - 不用 @latest 避免上游 pnpm 升级悄悄破坏 CI
|
||||||
|
RUN corepack enable && corepack prepare pnpm@9.15.0 --activate
|
||||||
|
|
||||||
WORKDIR /tmp/frontend
|
WORKDIR /tmp/frontend
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./doc/icon.svg" alt="BiliNote Banner" width="50" height="50" />
|
<img src="./doc/icon.svg" alt="BiliNote Banner" width="50" height="50" />
|
||||||
</p>
|
</p>
|
||||||
<h1 align="center" > BiliNote v2.2.0</h1>
|
<h1 align="center" > BiliNote v2.2.1</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p align="center"><i>AI 视频笔记生成工具 让 AI 为你的视频做笔记</i></p>
|
<p align="center"><i>AI 视频笔记生成工具 让 AI 为你的视频做笔记</i></p>
|
||||||
@@ -53,6 +53,10 @@ BiliNote 是一个开源的 AI 视频笔记助手,支持通过哔哩哔哩、Y
|
|||||||
- 笔记顶部视频封面 Banner 展示
|
- 笔记顶部视频封面 Banner 展示
|
||||||
- 工作区和生成历史面板支持折叠/展开
|
- 工作区和生成历史面板支持折叠/展开
|
||||||
|
|
||||||
|
### v2.2.1 修订
|
||||||
|
|
||||||
|
- 修复 v2.2.0 ghcr.io 镜像构建失败(pnpm@latest 拉到 11,与 Node 20 不兼容;pin 到 pnpm 9.15.0)
|
||||||
|
|
||||||
### v2.2.0 新增
|
### v2.2.0 新增
|
||||||
|
|
||||||
- **浏览器插件**笔记选项与 web 端完整对齐:style 9 个预设下拉、format 4 个 checkbox、extras 文本框、多模态视频理解开关
|
- **浏览器插件**笔记选项与 web 端完整对齐:style 9 个预设下拉、format 4 个 checkbox、extras 文本框、多模态视频理解开关
|
||||||
|
|||||||
@@ -87,13 +87,10 @@ _downloading: dict[str, str] = {} # model_size -> status ("downloading" | "done
|
|||||||
|
|
||||||
|
|
||||||
def _check_whisper_model_exists(model_size: str, subdir: str = "whisper") -> bool:
|
def _check_whisper_model_exists(model_size: str, subdir: str = "whisper") -> bool:
|
||||||
"""检查指定 whisper 模型是否已完整下载到本地。
|
"""检查指定 whisper 模型是否已下载到本地。"""
|
||||||
|
|
||||||
只看目录会把"上次下载中断剩下的空目录"误判为已下载;以 model.bin 落盘为准。
|
|
||||||
"""
|
|
||||||
model_dir = get_model_dir(subdir)
|
model_dir = get_model_dir(subdir)
|
||||||
model_path = Path(os.path.join(model_dir, f"whisper-{model_size}"))
|
model_path = os.path.join(model_dir, f"whisper-{model_size}")
|
||||||
return (model_path / "model.bin").exists()
|
return Path(model_path).exists()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/transcriber_models_status")
|
@router.get("/transcriber_models_status")
|
||||||
@@ -230,47 +227,28 @@ async def sys_check():
|
|||||||
|
|
||||||
@router.get("/deploy_status")
|
@router.get("/deploy_status")
|
||||||
async def deploy_status():
|
async def deploy_status():
|
||||||
"""返回部署监控所需的所有状态信息。
|
"""返回部署监控所需的所有状态信息"""
|
||||||
|
import torch
|
||||||
每一项都做容错:torch 没装 / Whisper 配置读取失败 / FFmpeg 不可用 都不应让整个
|
|
||||||
endpoint 500 把监控页打死。
|
|
||||||
"""
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# CUDA 状态:torch 是 fast-whisper 路径才需要的依赖;轻量部署可能没装
|
# CUDA 状态
|
||||||
cuda_info = {"available": False, "version": None, "gpu_name": None, "torch_installed": False}
|
cuda_available = torch.cuda.is_available()
|
||||||
try:
|
cuda_info = {
|
||||||
import torch
|
"available": cuda_available,
|
||||||
cuda_info["torch_installed"] = True
|
"version": torch.version.cuda if cuda_available else None,
|
||||||
cuda_available = torch.cuda.is_available()
|
"gpu_name": torch.cuda.get_device_name(0) if cuda_available else None,
|
||||||
cuda_info["available"] = cuda_available
|
}
|
||||||
if cuda_available:
|
|
||||||
cuda_info["version"] = torch.version.cuda
|
|
||||||
try:
|
|
||||||
cuda_info["gpu_name"] = torch.cuda.get_device_name(0)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"读取 GPU 名称失败: {e}")
|
|
||||||
except ImportError:
|
|
||||||
# torch 未安装:保持 available=False;插件 / web 监控页能识别
|
|
||||||
pass
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"CUDA 状态检测失败: {e}")
|
|
||||||
|
|
||||||
# Whisper 配置(任何失败回落到空,监控页不应被这个打死)
|
# Whisper 模型状态(从配置文件读取,与前端设置同步)
|
||||||
model_size = None
|
transcriber_cfg = transcriber_config_manager.get_config()
|
||||||
transcriber_type = None
|
model_size = transcriber_cfg["whisper_model_size"]
|
||||||
try:
|
transcriber_type = transcriber_cfg["transcriber_type"]
|
||||||
transcriber_cfg = transcriber_config_manager.get_config()
|
|
||||||
model_size = transcriber_cfg.get("whisper_model_size")
|
|
||||||
transcriber_type = transcriber_cfg.get("transcriber_type")
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"读取转写器配置失败: {e}")
|
|
||||||
|
|
||||||
# FFmpeg 状态
|
# FFmpeg 状态
|
||||||
try:
|
try:
|
||||||
ensure_ffmpeg_or_raise()
|
ensure_ffmpeg_or_raise()
|
||||||
ffmpeg_ok = True
|
ffmpeg_ok = True
|
||||||
except Exception:
|
except:
|
||||||
ffmpeg_ok = False
|
ffmpeg_ok = False
|
||||||
|
|
||||||
return R.success(data={
|
return R.success(data={
|
||||||
|
|||||||
@@ -50,20 +50,12 @@ class WhisperTranscriber(Transcriber):
|
|||||||
|
|
||||||
model_dir = get_model_dir("whisper")
|
model_dir = get_model_dir("whisper")
|
||||||
model_path = os.path.join(model_dir, f"whisper-{model_size}")
|
model_path = os.path.join(model_dir, f"whisper-{model_size}")
|
||||||
# 仅看目录存在不够:一次失败的 / 中断的下载会留下空 / 半成品目录,
|
if not Path(model_path).exists():
|
||||||
# 后面 WhisperModel 加载时会以 'Unable to open file model.bin' 抛错。
|
logger.info(f"模型 whisper-{model_size} 不存在,开始下载...")
|
||||||
# 必须以 model.bin 这个核心权重文件落盘为准。
|
|
||||||
model_bin = Path(model_path) / "model.bin"
|
|
||||||
if not model_bin.exists():
|
|
||||||
if Path(model_path).exists():
|
|
||||||
logger.warning(
|
|
||||||
f"检测到 {model_path} 目录存在但缺少 model.bin(可能上次下载中断),将重新拉取"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.info(f"模型 whisper-{model_size} 不存在,开始下载...")
|
|
||||||
repo_id = MODEL_MAP[model_size]
|
repo_id = MODEL_MAP[model_size]
|
||||||
model_path = snapshot_download(
|
model_path = snapshot_download(
|
||||||
repo_id,
|
repo_id,
|
||||||
|
|
||||||
local_dir=model_path,
|
local_dir=model_path,
|
||||||
)
|
)
|
||||||
logger.info("模型下载完成")
|
logger.info("模型下载完成")
|
||||||
|
|||||||
Reference in New Issue
Block a user