mirror of
https://github.com/JefferyHcool/BiliNote.git
synced 2026-07-12 16:11:34 +08:00
Compare commits
13 Commits
v2.1.3
...
revert-353
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81d254fcb7 | ||
|
|
f6d299ce48 | ||
|
|
ed1ee0a151 | ||
|
|
a7c717abbd | ||
|
|
799ab64a28 | ||
|
|
c0837e0132 | ||
|
|
c9497b502c | ||
|
|
1aea86a8d6 | ||
|
|
9237cac9c3 | ||
|
|
f97ab0b7bc | ||
|
|
ac72cc6d6e | ||
|
|
7358cd0123 | ||
|
|
80f081613b |
2
.github/workflows/commitlint.yml
vendored
2
.github/workflows/commitlint.yml
vendored
@@ -26,7 +26,5 @@ jobs:
|
|||||||
uses: wagoid/commitlint-github-action@v6
|
uses: wagoid/commitlint-github-action@v6
|
||||||
with:
|
with:
|
||||||
configFile: .commitlintrc.json
|
configFile: .commitlintrc.json
|
||||||
# PR 上检查 base..head 之间所有 commit;push 上只校验最新 commit
|
|
||||||
firstParent: false
|
|
||||||
failOnWarnings: false
|
failOnWarnings: false
|
||||||
helpURL: https://github.com/JefferyHcool/BiliNote/blob/develop/CONTRIBUTING.md#5-提交规范
|
helpURL: https://github.com/JefferyHcool/BiliNote/blob/develop/CONTRIBUTING.md#5-提交规范
|
||||||
|
|||||||
12
.github/workflows/main.yml
vendored
12
.github/workflows/main.yml
vendored
@@ -13,8 +13,6 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- platform: macos-latest
|
- platform: macos-latest
|
||||||
target: universal-apple-darwin
|
target: universal-apple-darwin
|
||||||
- platform: ubuntu-22.04
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
- platform: windows-latest
|
- platform: windows-latest
|
||||||
target: x86_64-pc-windows-msvc
|
target: x86_64-pc-windows-msvc
|
||||||
|
|
||||||
@@ -24,13 +22,6 @@ jobs:
|
|||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# Linux 系统依赖(Tauri 需要)
|
|
||||||
- name: Install Linux Dependencies
|
|
||||||
if: matrix.platform == 'ubuntu-22.04'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
|
||||||
|
|
||||||
# 设置 Python 环境(带 pip 缓存)
|
# 设置 Python 环境(带 pip 缓存)
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
@@ -103,9 +94,6 @@ jobs:
|
|||||||
# Windows: .msi, .exe (NSIS)
|
# Windows: .msi, .exe (NSIS)
|
||||||
find "$BUNDLE_DIR" -name "*.msi" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
find "$BUNDLE_DIR" -name "*.msi" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
||||||
find "$BUNDLE_DIR/nsis" -name "*.exe" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
find "$BUNDLE_DIR/nsis" -name "*.exe" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
||||||
# Linux: .deb, .AppImage
|
|
||||||
find "$BUNDLE_DIR" -name "*.deb" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
|
||||||
find "$BUNDLE_DIR" -name "*.AppImage" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
|
||||||
|
|
||||||
echo "=== Collected artifacts ==="
|
echo "=== Collected artifacts ==="
|
||||||
ls -lh release-artifacts/
|
ls -lh release-artifacts/
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ async function startTask(url: string): Promise<{ ok: boolean, taskId?: string, e
|
|||||||
// B 站:先在浏览器里抓字幕(带本地登录态 cookie),随提交带过去
|
// B 站:先在浏览器里抓字幕(带本地登录态 cookie),随提交带过去
|
||||||
const prefetched = platform === 'bilibili' ? await fetchBilibiliSubtitle(url) : null
|
const prefetched = platform === 'bilibili' ? await fetchBilibiliSubtitle(url) : null
|
||||||
|
|
||||||
|
const formats = settings.formats || []
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${backend}/api/generate_note`, {
|
const res = await fetch(`${backend}/api/generate_note`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -80,13 +81,12 @@ async function startTask(url: string): Promise<{ ok: boolean, taskId?: string, e
|
|||||||
quality: settings.quality,
|
quality: settings.quality,
|
||||||
provider_id: settings.providerId,
|
provider_id: settings.providerId,
|
||||||
model_name: settings.modelName,
|
model_name: settings.modelName,
|
||||||
screenshot: settings.screenshot,
|
// backend 同时接受 format 数组与 screenshot/link 单独布尔;从 formats 派生保持单一真相源
|
||||||
link: settings.link,
|
format: [...formats],
|
||||||
|
screenshot: formats.includes('screenshot'),
|
||||||
|
link: formats.includes('link'),
|
||||||
style: settings.style || undefined,
|
style: settings.style || undefined,
|
||||||
format: [
|
extras: settings.extras || undefined,
|
||||||
...(settings.screenshot ? ['screenshot'] : []),
|
|
||||||
...(settings.link ? ['link'] : []),
|
|
||||||
],
|
|
||||||
prefetched_transcript: prefetched ?? undefined,
|
prefetched_transcript: prefetched ?? undefined,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ export const DEFAULT_SETTINGS: Settings = {
|
|||||||
providerId: '',
|
providerId: '',
|
||||||
modelName: '',
|
modelName: '',
|
||||||
quality: 'medium',
|
quality: 'medium',
|
||||||
|
formats: ['toc', 'summary'],
|
||||||
screenshot: false,
|
screenshot: false,
|
||||||
link: false,
|
link: false,
|
||||||
style: '',
|
style: 'minimal',
|
||||||
|
extras: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MAX_TASKS = 30
|
export const MAX_TASKS = 30
|
||||||
|
|||||||
@@ -78,14 +78,45 @@ export interface TaskRecord {
|
|||||||
result?: NoteResult
|
result?: NoteResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 与 backend/app/gpt/prompt_builder.py note_styles 一一对齐
|
||||||
|
export type NoteStyle =
|
||||||
|
| 'minimal' | 'detailed' | 'academic' | 'tutorial'
|
||||||
|
| 'xiaohongshu' | 'life_journal' | 'task_oriented'
|
||||||
|
| 'business' | 'meeting_minutes'
|
||||||
|
|
||||||
|
// 与 backend/app/gpt/prompt_builder.py note_formats 一一对齐
|
||||||
|
export type NoteFormat = 'toc' | 'link' | 'screenshot' | 'summary'
|
||||||
|
|
||||||
|
export const NOTE_STYLES: Array<{ value: NoteStyle, label: string }> = [
|
||||||
|
{ value: 'minimal', label: '精简' },
|
||||||
|
{ value: 'detailed', label: '详细' },
|
||||||
|
{ value: 'tutorial', label: '教程' },
|
||||||
|
{ value: 'academic', label: '学术' },
|
||||||
|
{ value: 'xiaohongshu', label: '小红书' },
|
||||||
|
{ value: 'life_journal', label: '生活向' },
|
||||||
|
{ value: 'task_oriented', label: '任务导向' },
|
||||||
|
{ value: 'business', label: '商业风格' },
|
||||||
|
{ value: 'meeting_minutes', label: '会议纪要' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const NOTE_FORMATS: Array<{ value: NoteFormat, label: string }> = [
|
||||||
|
{ value: 'toc', label: '目录' },
|
||||||
|
{ value: 'summary', label: 'AI 总结' },
|
||||||
|
{ value: 'screenshot', label: '原片截图' },
|
||||||
|
{ value: 'link', label: '原片跳转' },
|
||||||
|
]
|
||||||
|
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
backendUrl: string
|
backendUrl: string
|
||||||
providerId: string
|
providerId: string
|
||||||
modelName: string
|
modelName: string
|
||||||
quality: Quality
|
quality: Quality
|
||||||
|
// 输出 format 的 toggle 集合(screenshot / link 与下方两个布尔保持联动)
|
||||||
|
formats: NoteFormat[]
|
||||||
screenshot: boolean
|
screenshot: boolean
|
||||||
link: boolean
|
link: boolean
|
||||||
style: string
|
style: NoteStyle
|
||||||
|
extras: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProviderUpdatePayload {
|
export interface ProviderUpdatePayload {
|
||||||
|
|||||||
@@ -3,9 +3,16 @@ import { onMounted, ref } from 'vue'
|
|||||||
import { getProviders, ping } from '~/logic/api'
|
import { getProviders, ping } from '~/logic/api'
|
||||||
import { settings, settingsReady } from '~/logic/storage'
|
import { settings, settingsReady } from '~/logic/storage'
|
||||||
import { getModelsByProvider } from '~/logic/api'
|
import { getModelsByProvider } from '~/logic/api'
|
||||||
import type { Model, Provider } from '~/logic/types'
|
import { NOTE_FORMATS, NOTE_STYLES, type Model, type NoteFormat, type Provider } from '~/logic/types'
|
||||||
import { watch } from 'vue'
|
import { watch } from 'vue'
|
||||||
|
|
||||||
|
function toggleFormat(value: NoteFormat, checked: boolean) {
|
||||||
|
const cur = settings.value.formats || []
|
||||||
|
settings.value.formats = checked
|
||||||
|
? Array.from(new Set([...cur, value]))
|
||||||
|
: cur.filter(v => v !== value)
|
||||||
|
}
|
||||||
|
|
||||||
const providers = ref<Provider[]>([])
|
const providers = ref<Provider[]>([])
|
||||||
const models = ref<Model[]>([])
|
const models = ref<Model[]>([])
|
||||||
const status = ref<{ kind: 'idle' | 'ok' | 'err', text: string }>({ kind: 'idle', text: '' })
|
const status = ref<{ kind: 'idle' | 'ok' | 'err', text: string }>({ kind: 'idle', text: '' })
|
||||||
@@ -128,15 +135,35 @@ onMounted(async () => {
|
|||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1">
|
||||||
<span class="text-gray-600">笔记风格</span>
|
<span class="text-gray-600">笔记风格</span>
|
||||||
<input v-model="settings.style" class="input" placeholder="留空使用默认">
|
<select v-model="settings.style" class="input">
|
||||||
</label>
|
<option v-for="s in NOTE_STYLES" :key="s.value" :value="s.value">{{ s.label }}</option>
|
||||||
<label class="flex items-center gap-2">
|
</select>
|
||||||
<input v-model="settings.screenshot" type="checkbox"> 自动插入截图
|
|
||||||
</label>
|
|
||||||
<label class="flex items-center gap-2">
|
|
||||||
<input v-model="settings.link" type="checkbox"> 插入原片跳转链接
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1 text-sm">
|
||||||
|
<span class="text-gray-600">输出形式(与 web 端 NoteForm 对齐)</span>
|
||||||
|
<div class="flex flex-wrap gap-x-4 gap-y-2">
|
||||||
|
<label v-for="f in NOTE_FORMATS" :key="f.value" class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="(settings.formats || []).includes(f.value)"
|
||||||
|
@change="toggleFormat(f.value, ($event.target as HTMLInputElement).checked)"
|
||||||
|
>
|
||||||
|
{{ f.label }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label class="flex flex-col gap-1 text-sm">
|
||||||
|
<span class="text-gray-600">额外提示词(追加到 prompt 末尾)</span>
|
||||||
|
<textarea
|
||||||
|
v-model="settings.extras"
|
||||||
|
class="input resize-y"
|
||||||
|
rows="3"
|
||||||
|
placeholder="例如:重点关注游戏开发部分;保留所有专业术语原文"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { detectPlatform } from '~/logic/platform'
|
|||||||
import { settings, settingsReady, tasks, tasksReady, upsertTask } from '~/logic/storage'
|
import { settings, settingsReady, tasks, tasksReady, upsertTask } from '~/logic/storage'
|
||||||
import { generateNote, getTaskStatus, resolveImageUrl } from '~/logic/api'
|
import { generateNote, getTaskStatus, resolveImageUrl } from '~/logic/api'
|
||||||
import { fetchBilibiliSubtitle } from '~/logic/bilibili-subtitle'
|
import { fetchBilibiliSubtitle } from '~/logic/bilibili-subtitle'
|
||||||
import type { TaskRecord } from '~/logic/types'
|
import { NOTE_FORMATS, NOTE_STYLES, type NoteFormat, type TaskRecord } from '~/logic/types'
|
||||||
|
|
||||||
const tabUrl = ref<string>('')
|
const tabUrl = ref<string>('')
|
||||||
const tabTitle = ref<string>('')
|
const tabTitle = ref<string>('')
|
||||||
@@ -67,19 +67,19 @@ async function start() {
|
|||||||
try {
|
try {
|
||||||
// B 站:在用户浏览器里直接抓字幕(带本地登录态 cookie),跳过后端的 download_subtitles 与音频转写
|
// B 站:在用户浏览器里直接抓字幕(带本地登录态 cookie),跳过后端的 download_subtitles 与音频转写
|
||||||
const prefetched = platform.value === 'bilibili' ? await fetchBilibiliSubtitle(tabUrl.value) : null
|
const prefetched = platform.value === 'bilibili' ? await fetchBilibiliSubtitle(tabUrl.value) : null
|
||||||
|
const formats = settings.value.formats || []
|
||||||
const { task_id } = await generateNote({
|
const { task_id } = await generateNote({
|
||||||
video_url: tabUrl.value,
|
video_url: tabUrl.value,
|
||||||
platform: platform.value!,
|
platform: platform.value!,
|
||||||
quality: settings.value.quality,
|
quality: settings.value.quality,
|
||||||
provider_id: settings.value.providerId,
|
provider_id: settings.value.providerId,
|
||||||
model_name: settings.value.modelName,
|
model_name: settings.value.modelName,
|
||||||
screenshot: settings.value.screenshot,
|
// backend VideoRequest 同时接受 format 数组与 screenshot/link 单独布尔,从 formats 派生保持单一真相源
|
||||||
link: settings.value.link,
|
format: [...formats],
|
||||||
|
screenshot: formats.includes('screenshot'),
|
||||||
|
link: formats.includes('link'),
|
||||||
style: settings.value.style || undefined,
|
style: settings.value.style || undefined,
|
||||||
format: [
|
extras: settings.value.extras || undefined,
|
||||||
...(settings.value.screenshot ? ['screenshot'] : []),
|
|
||||||
...(settings.value.link ? ['link'] : []),
|
|
||||||
],
|
|
||||||
prefetched_transcript: prefetched ?? undefined,
|
prefetched_transcript: prefetched ?? undefined,
|
||||||
})
|
})
|
||||||
activeTaskId.value = task_id
|
activeTaskId.value = task_id
|
||||||
@@ -108,6 +108,13 @@ function openOptions() {
|
|||||||
browser.runtime.openOptionsPage()
|
browser.runtime.openOptionsPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleFormat(value: NoteFormat, checked: boolean) {
|
||||||
|
const cur = settings.value.formats || []
|
||||||
|
settings.value.formats = checked
|
||||||
|
? Array.from(new Set([...cur, value]))
|
||||||
|
: cur.filter(v => v !== value)
|
||||||
|
}
|
||||||
|
|
||||||
async function openSidePanel() {
|
async function openSidePanel() {
|
||||||
// 只能在用户操作触发的同步上下文里调,且需要明确的 tabId
|
// 只能在用户操作触发的同步上下文里调,且需要明确的 tabId
|
||||||
try {
|
try {
|
||||||
@@ -176,7 +183,7 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset class="border rounded p-2 flex flex-col gap-2" :disabled="!supported || submitting">
|
<fieldset class="border rounded p-2 flex flex-col gap-2" :disabled="!supported || submitting">
|
||||||
<div class="grid grid-cols-3 gap-2 text-xs">
|
<div class="grid grid-cols-2 gap-2 text-xs">
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1">
|
||||||
<span class="text-gray-600">画质</span>
|
<span class="text-gray-600">画质</span>
|
||||||
<select v-model="settings.quality" class="border rounded px-1 py-0.5">
|
<select v-model="settings.quality" class="border rounded px-1 py-0.5">
|
||||||
@@ -185,14 +192,41 @@ onUnmounted(() => {
|
|||||||
<option value="slow">高质</option>
|
<option value="slow">高质</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-1 mt-4">
|
<label class="flex flex-col gap-1">
|
||||||
<input v-model="settings.screenshot" type="checkbox"> 截图
|
<span class="text-gray-600">笔记风格</span>
|
||||||
</label>
|
<select v-model="settings.style" class="border rounded px-1 py-0.5">
|
||||||
<label class="flex items-center gap-1 mt-4">
|
<option v-for="s in NOTE_STYLES" :key="s.value" :value="s.value">{{ s.label }}</option>
|
||||||
<input v-model="settings.link" type="checkbox"> 跳转
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1 text-xs">
|
||||||
|
<span class="text-gray-600">输出形式</span>
|
||||||
|
<div class="flex flex-wrap gap-x-3 gap-y-1">
|
||||||
|
<label v-for="f in NOTE_FORMATS" :key="f.value" class="flex items-center gap-1">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="(settings.formats || []).includes(f.value)"
|
||||||
|
@change="toggleFormat(f.value, ($event.target as HTMLInputElement).checked)"
|
||||||
|
>
|
||||||
|
{{ f.label }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<details class="text-xs">
|
||||||
|
<summary class="cursor-pointer text-gray-500">高级</summary>
|
||||||
|
<label class="flex flex-col gap-1 mt-2">
|
||||||
|
<span class="text-gray-600">额外提示词(追加到 prompt 末尾)</span>
|
||||||
|
<textarea
|
||||||
|
v-model="settings.extras"
|
||||||
|
class="border rounded px-1 py-1 resize-y"
|
||||||
|
rows="2"
|
||||||
|
placeholder="例如:重点关注游戏开发部分;保留所有专业术语原文"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</details>
|
||||||
|
|
||||||
<div class="text-xs text-gray-600">
|
<div class="text-xs text-gray-600">
|
||||||
<span v-if="settings.providerId && settings.modelName">
|
<span v-if="settings.providerId && settings.modelName">
|
||||||
模型:{{ settings.modelName }}
|
模型:{{ settings.modelName }}
|
||||||
|
|||||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
本项目所有重要变更记录于此。格式参考 [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.1.4] - 2026-05-07
|
||||||
|
|
||||||
|
CI 工程化修复,无运行时行为变化。
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
|
||||||
|
- 桌面端 Tauri 构建矩阵去掉 Linux(`ubuntu-22.04 / x86_64-unknown-linux-gnu`)。Linux 桌面端构建持续 17m+,且无对应分发渠道;Linux 用户继续可以走 Docker 镜像 (`ghcr.io/jefferyhcool/bilinote`)
|
||||||
|
- commitlint workflow 去掉无效的 `firstParent` input(wagoid/commitlint-github-action@v6 不支持,被忽略并打 warn)
|
||||||
|
- 规范 release merge commit 标题:`chore(release): vX.Y.Z`(合 master)/ `chore(release): merge release/X.Y.Z back into develop`(回灌 develop),让 commitlint 能正确识别。`RELEASING.md` §3 与 `CONTRIBUTING.md` §6.3 同步更新
|
||||||
|
|
||||||
## [2.1.3] - 2026-05-07
|
## [2.1.3] - 2026-05-07
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ chore(ci): 优化 docker 构建缓存
|
|||||||
|
|
||||||
- `feature/*` / `fix/*` 合入 `develop`:推荐 **Squash and merge**,保持 develop 历史线性。
|
- `feature/*` / `fix/*` 合入 `develop`:推荐 **Squash and merge**,保持 develop 历史线性。
|
||||||
- `release/*` 合入 `master` 与回灌 `develop`:使用 **Merge commit (--no-ff)**,保留发版结构。
|
- `release/*` 合入 `master` 与回灌 `develop`:使用 **Merge commit (--no-ff)**,保留发版结构。
|
||||||
|
· merge commit 标题用 `chore(release): vX.Y.Z`(合 master)或 `chore(release): merge release/X.Y.Z back into develop`(回灌 develop),保证 commitlint 通过。
|
||||||
- `hotfix/*` 同上 release。
|
- `hotfix/*` 同上 release。
|
||||||
|
|
||||||
### 6.4 合并后
|
### 6.4 合并后
|
||||||
|
|||||||
@@ -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.1.3</h1>
|
<h1 align="center" > BiliNote v2.1.4</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p align="center"><i>AI 视频笔记生成工具 让 AI 为你的视频做笔记</i></p>
|
<p align="center"><i>AI 视频笔记生成工具 让 AI 为你的视频做笔记</i></p>
|
||||||
@@ -53,6 +53,11 @@ BiliNote 是一个开源的 AI 视频笔记助手,支持通过哔哩哔哩、Y
|
|||||||
- 笔记顶部视频封面 Banner 展示
|
- 笔记顶部视频封面 Banner 展示
|
||||||
- 工作区和生成历史面板支持折叠/展开
|
- 工作区和生成历史面板支持折叠/展开
|
||||||
|
|
||||||
|
### v2.1.4 修订
|
||||||
|
|
||||||
|
- CI:桌面端 Tauri 构建去掉 Linux(17m+ 慢线退役;Linux 用户继续走 Docker 镜像)
|
||||||
|
- CI:commitlint workflow 修复 + 规范 release merge commit 标题约定
|
||||||
|
|
||||||
### v2.1.3 修订
|
### v2.1.3 修订
|
||||||
|
|
||||||
- 修复 DeepSeek 等非多模态供应商被 400 拒绝的问题(issue #282):`UniversalGPT` 的 message builder 按是否带图切换 string / 多模态数组形态
|
- 修复 DeepSeek 等非多模态供应商被 400 拒绝的问题(issue #282):`UniversalGPT` 的 message builder 按是否带图切换 string / 多模态数组形态
|
||||||
|
|||||||
11
RELEASING.md
11
RELEASING.md
@@ -42,10 +42,13 @@ git push -u origin release/X.Y.Z
|
|||||||
|
|
||||||
在 GitHub 上发起两个 PR:
|
在 GitHub 上发起两个 PR:
|
||||||
|
|
||||||
| PR | base | 合并方式 |
|
| PR | base | 合并方式 | 合并后 commit 标题 |
|
||||||
|---|---|---|
|
|---|---|---|---|
|
||||||
| `release/X.Y.Z` → `master` | `master` | **Merge commit (--no-ff)** |
|
| `release/X.Y.Z` → `master` | `master` | **Merge commit (--no-ff)** | `chore(release): vX.Y.Z` |
|
||||||
| `release/X.Y.Z` → `develop` | `develop` | **Merge commit (--no-ff)** |
|
| `release/X.Y.Z` → `develop` | `develop` | **Merge commit (--no-ff)** | `chore(release): merge release/X.Y.Z back into develop` |
|
||||||
|
|
||||||
|
> ⚠️ Merge commit 的标题**必须**符合 `type(scope): subject` 格式(commitlint 在 push 到 master/develop 时会校验)。
|
||||||
|
> 历史上用过 `Release vX.Y.Z` 这种形式,会被 commitlint 报 `type-empty` / `subject-empty`。
|
||||||
|
|
||||||
`master` 分支保护要求 review 通过。回灌 `develop` 是为了把发版冻结期内的小修同步回来。
|
`master` 分支保护要求 review 通过。回灌 `develop` 是为了把发版冻结期内的小修同步回来。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user