feat: 新增模型管理和供应商配置功能

### v1.1.0
- #### Added
  - 新增 AI 笔记风格选择
  - 新增 AI 笔记返回格式选择
  - 添加 AI 自定义笔记备注 Prompt
  - 添加任务失败重试
  - 添加全局设置页,可在设置页进行模型设置

- #### Optimize
  - 优化前端样式,优化用户体验
  - 增加生成中间产物,可用于失败后加快生成速度
- #### Fix
  - 修复视频截图视频过早删除错误
This commit is contained in:
思诺特
2025-04-26 23:40:17 +08:00
parent 1323cfd1ec
commit 171dea5e0d
51 changed files with 2511 additions and 414 deletions

View File

@@ -0,0 +1,25 @@
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
interface SystemState {
showFeatureHint: boolean // ✅ 是否显示功能提示
setShowFeatureHint: (value: boolean) => void
// 后续如果有其他全局状态,可以继续加
sidebarCollapsed: boolean // ✅ 侧边栏是否收起
setSidebarCollapsed: (value: boolean) => void
}
// 暂不启用
export const useSystemStore = create<SystemState>()(
persist(
set => ({
showFeatureHint: true,
setShowFeatureHint: value => set({ showFeatureHint: value }),
sidebarCollapsed: false,
setSidebarCollapsed: value => set({ sidebarCollapsed: value }),
}),
{
name: 'system-store', // 本地存储的 key
}
)
)

View File

@@ -0,0 +1,101 @@
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'
import { fetchModels, addModel, fetchEnableModels } from '@/services/model.ts'
interface IModel {
id: string
created: number
object: string
owned_by: string
permission: string
root: string
}
interface ModelStore {
models: IModel[]
modelList: []
loading: boolean
selectedModel: string
loadModels: (providerId: string) => Promise<void>
loadEnabledModels: () => Promise<void>
addNewModel: (providerId: string, modelId: string) => Promise<void>
setSelectedModel: (modelId: string) => void
clearModels: () => void
}
export const useModelStore = create<ModelStore>()(
devtools(set => ({
models: [],
loading: false,
selectedModel: '',
modelList: [],
loadEnabledModels: async () => {
try {
set({ loading: true })
const res = await fetchEnableModels()
if (res.data.code === 0 && res.data.data.length > 0) {
set({ modelList: res.data.data })
} else {
set({ modelList: [] })
console.error('模型列表加载失败')
}
} catch (error) {
set({ modelList: [] })
console.error('加载模型出错', error)
}
},
// 加载模型列表
loadModels: async (providerId: string) => {
try {
set({ loading: true })
const res = await fetchModels(providerId)
if (res.data.code === 0 && res.data.data.models.data.length > 0) {
set({ models: res.data.data.models.data })
} else {
set({ models: [] })
console.error('模型列表加载失败')
}
} catch (error) {
set({ models: [] })
console.error('加载模型出错', error)
} finally {
set({ loading: false })
}
},
// 新增模型
addNewModel: async (providerId: string, modelId: string) => {
try {
const res = await addModel({ provider_id: providerId, model_name: modelId })
if (res.code === 0) {
console.log('新增模型成功:', modelId)
// ✅ 新增成功以后,前端直接追加一条到 models 列表
set(state => ({
models: [
...state.models,
{
id: modelId,
created: Date.now(),
object: 'model',
owned_by: '',
permission: '',
root: '',
},
],
}))
} else {
console.error('新增模型失败')
}
} catch (error) {
console.error('添加模型出错', error)
}
},
// 设置选中的模型
setSelectedModel: modelId => set({ selectedModel: modelId }),
// 清空
clearModels: () => set({ models: [], selectedModel: '' }),
}))
)

View File

@@ -1,6 +1,11 @@
import { create } from 'zustand'
import { IProvider } from '@/types'
import { getProviderList } from '@/services/model.ts'
import {
addProvider,
getProviderById,
getProviderList,
updateProviderById,
} from '@/services/model.ts'
interface ProviderStore {
provider: IProvider[]
@@ -9,12 +14,14 @@ interface ProviderStore {
getProviderById: (id: number) => IProvider | undefined
getProviderList: () => IProvider[]
fetchProviderList: () => Promise<void>
loadProviderById: (id: string) => Promise<void>
addNewProvider: (provider: IProvider) => Promise<void>
updateProvider: (provider: IProvider) => Promise<void>
}
export const useProviderStore = create<ProviderStore>((set, get) => ({
provider: [],
// 添加或更新一个 provider
setProvider: newProvider =>
set(state => {
@@ -30,10 +37,60 @@ export const useProviderStore = create<ProviderStore>((set, get) => ({
// 设置整个 provider 列表
setAllProviders: providers => set({ provider: providers }),
loadProviderById: async (id: string) => {
const res = await getProviderById(id)
if (res.data.code === 0) {
const item = res.data.data
console.log('Provider ', item)
return {
id: item.id,
name: item.name,
logo: item.logo,
apiKey: item.api_key,
baseUrl: item.base_url,
type: item.type,
enabled: item.enabled,
}
} else {
console.log('Provider not found')
}
},
addNewProvider: async (provider: IProvider) => {
const payload = {
...provider,
api_key: provider.apiKey,
base_url: provider.baseUrl,
}
try {
const res = await addProvider(payload)
if (res.data.code === 0) {
const item = res.data.data
console.log('Provider ', item)
await get().fetchProviderList()
}
} catch (error) {
console.error('Error fetching provider:', error)
}
},
// 按 id 获取单个 provider
getProviderById: id => get().provider.find(p => p.id === id),
updateProvider: async (provider: IProvider) => {
try {
const data = {
...provider,
api_key: provider.apiKey,
base_url: provider.baseUrl,
}
const res = await updateProviderById(data)
if (res.data.code === 0) {
const item = res.data.data
console.log('Provider ', item)
await get().fetchProviderList()
}
} catch (error) {
console.error('Error fetching provider:', error)
}
},
getProviderList: () => get().provider,
fetchProviderList: async () => {
try {
@@ -55,6 +112,7 @@ export const useProviderStore = create<ProviderStore>((set, get) => ({
apiKey: item.api_key,
baseUrl: item.base_url,
type: item.type,
enabled: item.enabled,
}
}
),

View File

@@ -1,6 +1,6 @@
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import { delete_task } from '@/services/note.ts'
import { delete_task, generateNote } from '@/services/note.ts'
export type TaskStatus = 'PENDING' | 'RUNNING' | 'SUCCESS' | 'FAILD'
@@ -34,6 +34,15 @@ export interface Task {
status: TaskStatus
audioMeta: AudioMeta
createdAt: string
formData: {
video_url: string
link: undefined | boolean
screenshot: undefined | boolean
platform: string
quality: string
model_name: string
provider_id: string
}
}
interface TaskStore {
@@ -45,6 +54,7 @@ interface TaskStore {
clearTasks: () => void
setCurrentTask: (taskId: string | null) => void
getCurrentTask: () => Task | null
retryTask: (id: string) => void
}
export const useTaskStore = create<TaskStore>()(
@@ -53,10 +63,11 @@ export const useTaskStore = create<TaskStore>()(
tasks: [],
currentTaskId: null,
addPendingTask: (taskId: string, platform: string) =>
addPendingTask: (taskId: string, platform: string, formData: any) =>
set(state => ({
tasks: [
{
formData: formData,
id: taskId,
status: 'PENDING',
markdown: '',
@@ -91,6 +102,17 @@ export const useTaskStore = create<TaskStore>()(
const currentTaskId = get().currentTaskId
return get().tasks.find(task => task.id === currentTaskId) || null
},
retryTask: async (id: string) => {
const task = get().tasks.find(task => task.id === id).formData
await generateNote({
task_id: id,
...task,
})
set(state => ({
tasks: state.tasks.map(task => (task.id === id ? { ...task, status: 'PENDING' } : task)),
}))
},
removeTask: async id => {
const task = get().tasks.find(t => t.id === id)