feat: add admin usage statistics and LLM configuration management
This commit is contained in:
@@ -11,7 +11,8 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/u
|
||||
import { Navbar } from '@/components/Navbar'
|
||||
import { AudioPlayer } from '@/components/AudioPlayer'
|
||||
import { audiobookApi, type AudiobookProject, type AudiobookProjectDetail, type AudiobookCharacter, type AudiobookSegment } from '@/lib/api/audiobook'
|
||||
import apiClient, { formatApiError } from '@/lib/api'
|
||||
import apiClient, { formatApiError, adminApi } from '@/lib/api'
|
||||
import { useAuth } from '@/contexts/AuthContext'
|
||||
|
||||
function LazyAudioPlayer({ audioUrl, jobId }: { audioUrl: string; jobId: number }) {
|
||||
const [visible, setVisible] = useState(false)
|
||||
@@ -223,7 +224,7 @@ function LLMConfigDialog({ open, onClose }: { open: boolean; onClose: () => void
|
||||
const [existing, setExisting] = useState<{ base_url?: string; model?: string; has_key: boolean } | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (open) audiobookApi.getLLMConfig().then(setExisting).catch(() => {})
|
||||
if (open) adminApi.getLLMConfig().then(setExisting).catch(() => {})
|
||||
}, [open])
|
||||
|
||||
const handleSave = async () => {
|
||||
@@ -233,10 +234,10 @@ function LLMConfigDialog({ open, onClose }: { open: boolean; onClose: () => void
|
||||
}
|
||||
setLoading(true)
|
||||
try {
|
||||
await audiobookApi.setLLMConfig({ base_url: baseUrl, api_key: apiKey, model })
|
||||
await adminApi.setLLMConfig({ base_url: baseUrl, api_key: apiKey, model })
|
||||
toast.success(t('llmConfigPanel.savedSuccess'))
|
||||
setApiKey('')
|
||||
const updated = await audiobookApi.getLLMConfig()
|
||||
const updated = await adminApi.getLLMConfig()
|
||||
setExisting(updated)
|
||||
onClose()
|
||||
} catch (e: any) {
|
||||
@@ -360,6 +361,7 @@ function ProjectListSidebar({
|
||||
loading,
|
||||
collapsed,
|
||||
onToggle,
|
||||
isSuperuser,
|
||||
}: {
|
||||
projects: AudiobookProject[]
|
||||
selectedId: number | null
|
||||
@@ -369,6 +371,7 @@ function ProjectListSidebar({
|
||||
loading: boolean
|
||||
collapsed: boolean
|
||||
onToggle: () => void
|
||||
isSuperuser?: boolean
|
||||
}) {
|
||||
const { t } = useTranslation('audiobook')
|
||||
return (
|
||||
@@ -387,9 +390,11 @@ function ProjectListSidebar({
|
||||
{!collapsed && (
|
||||
<>
|
||||
<div className="flex items-center justify-end px-2 pb-1 gap-0.5 shrink-0">
|
||||
<Button size="icon" variant="ghost" className="h-7 w-7" onClick={onLLM} title={t('llmConfig')}>
|
||||
<Settings2 className="h-4 w-4" />
|
||||
</Button>
|
||||
{isSuperuser && (
|
||||
<Button size="icon" variant="ghost" className="h-7 w-7" onClick={onLLM} title={t('llmConfig')}>
|
||||
<Settings2 className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
<Button size="icon" variant="ghost" className="h-7 w-7" onClick={onNew} title={t('newProject')}>
|
||||
<Plus className="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -1066,6 +1071,7 @@ function ChaptersPanel({
|
||||
|
||||
export default function Audiobook() {
|
||||
const { t } = useTranslation('audiobook')
|
||||
const { user } = useAuth()
|
||||
const [projects, setProjects] = useState<AudiobookProject[]>([])
|
||||
const [selectedProjectId, setSelectedProjectId] = useState<number | null>(null)
|
||||
const [detail, setDetail] = useState<AudiobookProjectDetail | null>(null)
|
||||
@@ -1447,6 +1453,7 @@ export default function Audiobook() {
|
||||
loading={loading}
|
||||
collapsed={!sidebarOpen}
|
||||
onToggle={() => setSidebarOpen(v => !v)}
|
||||
isSuperuser={user?.is_superuser}
|
||||
/>
|
||||
<div className="flex-1 flex flex-col overflow-hidden bg-muted/30">
|
||||
<Navbar />
|
||||
|
||||
Reference in New Issue
Block a user