feat(core): 添加模型下载路径配置功能
- 新增 get_default_save_dir Tauri 命令用于获取默认保存目录 - 修改 download_model 命令支持自定义保存路径参数 - 在模型页面集成本地存储的保存路径配置 - 添加 MSW 到 pnpm 工作区允许构建列表 feat(ui): 添加模型设置页面 - 创建新的设置页面用于配置模型下载路径 - 实现路径选择、保存和重置功能 - 集成到侧边栏导航菜单中 - 使用 localStorage 持久化保存用户配置 refactor(routes): 重构设置页面路由结构 - 移除旧的侧边栏导航组件 - 更新路由配置以支持新的模型设置页面 - 生成相应的路由类型定义更新 feat(server): 添加 OpenAI 兼容的模型接口 - 在 /v1 路径下添加 models 接口端点 - 提供与 OpenAI API 兼容的模型列表功能
This commit is contained in:
@@ -9,6 +9,8 @@ import { Main } from "@/components/layout/main"
|
||||
import { ProfileDropdown } from "@/components/profile-dropdown"
|
||||
import { ThemeSwitch } from "@/components/theme-switch"
|
||||
|
||||
const SAVE_DIR_KEY = "aha-model-save-dir"
|
||||
|
||||
interface ModelInfo {
|
||||
model_id: string
|
||||
owner: string
|
||||
@@ -67,7 +69,8 @@ export function ModelsPage() {
|
||||
setDownloading(modelId)
|
||||
setError(null)
|
||||
try {
|
||||
await invoke("download_model", { modelId })
|
||||
const saveDir = localStorage.getItem(SAVE_DIR_KEY) || null
|
||||
await invoke("download_model", { modelId, saveDir })
|
||||
await loadModels()
|
||||
} catch (e) {
|
||||
setError(String(e))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Outlet } from '@tanstack/react-router'
|
||||
import { Monitor, Bell, Palette, Wrench, UserCog } from 'lucide-react'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { ConfigDrawer } from '@/components/config-drawer'
|
||||
import { Header } from '@/components/layout/header'
|
||||
@@ -7,35 +6,6 @@ import { Main } from '@/components/layout/main'
|
||||
import { ProfileDropdown } from '@/components/profile-dropdown'
|
||||
import { Search } from '@/components/search'
|
||||
import { ThemeSwitch } from '@/components/theme-switch'
|
||||
import { SidebarNav } from './components/sidebar-nav'
|
||||
|
||||
const sidebarNavItems = [
|
||||
{
|
||||
title: 'Profile',
|
||||
href: '/settings',
|
||||
icon: <UserCog size={18} />,
|
||||
},
|
||||
{
|
||||
title: 'Account',
|
||||
href: '/settings/account',
|
||||
icon: <Wrench size={18} />,
|
||||
},
|
||||
{
|
||||
title: 'Appearance',
|
||||
href: '/settings/appearance',
|
||||
icon: <Palette size={18} />,
|
||||
},
|
||||
{
|
||||
title: 'Notifications',
|
||||
href: '/settings/notifications',
|
||||
icon: <Bell size={18} />,
|
||||
},
|
||||
{
|
||||
title: 'Display',
|
||||
href: '/settings/display',
|
||||
icon: <Monitor size={18} />,
|
||||
},
|
||||
]
|
||||
|
||||
export function Settings() {
|
||||
return (
|
||||
@@ -58,13 +28,8 @@ export function Settings() {
|
||||
</p>
|
||||
</div>
|
||||
<Separator className='my-4 lg:my-6' />
|
||||
<div className='flex flex-1 flex-col space-y-2 overflow-hidden md:space-y-2 lg:flex-row lg:space-y-0 lg:space-x-12'>
|
||||
<aside className='top-0 lg:sticky lg:w-1/5'>
|
||||
<SidebarNav items={sidebarNavItems} />
|
||||
</aside>
|
||||
<div className='flex w-full overflow-y-hidden p-1'>
|
||||
<Outlet />
|
||||
</div>
|
||||
<div className='flex w-full overflow-y-hidden p-1'>
|
||||
<Outlet />
|
||||
</div>
|
||||
</Main>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { useState, useEffect } from "react"
|
||||
import { invoke } from "@tauri-apps/api/core"
|
||||
import { FolderOpen } from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { ContentSection } from "../components/content-section"
|
||||
|
||||
const SAVE_DIR_KEY = "aha-model-save-dir"
|
||||
|
||||
export function SettingsModel() {
|
||||
const [saveDir, setSaveDir] = useState("")
|
||||
const [defaultDir, setDefaultDir] = useState("")
|
||||
const [saved, setSaved] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
invoke<string>("get_default_save_dir")
|
||||
.then(setDefaultDir)
|
||||
.catch(() => {})
|
||||
|
||||
const stored = localStorage.getItem(SAVE_DIR_KEY)
|
||||
if (stored) setSaveDir(stored)
|
||||
}, [])
|
||||
|
||||
const handleSave = () => {
|
||||
if (saveDir) {
|
||||
localStorage.setItem(SAVE_DIR_KEY, saveDir)
|
||||
} else {
|
||||
localStorage.removeItem(SAVE_DIR_KEY)
|
||||
}
|
||||
setSaved(true)
|
||||
setTimeout(() => setSaved(false), 2000)
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
setSaveDir("")
|
||||
localStorage.removeItem(SAVE_DIR_KEY)
|
||||
}
|
||||
|
||||
return (
|
||||
<ContentSection
|
||||
title='Model'
|
||||
desc='配置模型下载位置和相关设置'
|
||||
>
|
||||
<div className='space-y-6'>
|
||||
<div className='space-y-2'>
|
||||
<Label htmlFor='save-dir' className='flex items-center gap-1.5'>
|
||||
<FolderOpen className='w-4 h-4' />
|
||||
模型下载路径
|
||||
</Label>
|
||||
<Input
|
||||
id='save-dir'
|
||||
value={saveDir}
|
||||
onChange={(e) => setSaveDir(e.target.value)}
|
||||
placeholder={defaultDir || "~/.aha/"}
|
||||
/>
|
||||
<p className='text-xs text-muted-foreground'>
|
||||
留空则使用默认路径:{defaultDir || "~/.aha/"}
|
||||
。模型将下载到该目录下的 {`{model_id}`} 子文件夹中。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex gap-2'>
|
||||
<Button onClick={handleSave}>
|
||||
{saved ? "已保存" : "保存"}
|
||||
</Button>
|
||||
<Button variant='outline' onClick={handleReset}>
|
||||
恢复默认
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ContentSection>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user