Files
breakpilot-lehrer/website/app/admin/voice/page.tsx
Benjamin Admin 451365a312 [split-required] Split remaining 500-680 LOC files (final batch)
website (17 pages + 3 components):
- multiplayer/wizard, middleware/wizard+test-wizard, communication
- builds/wizard, staff-search, voice, sbom/wizard
- foerderantrag, mail/tasks, tools/communication, sbom
- compliance/evidence, uni-crawler, brandbook (already done)
- CollectionsTab, IngestionTab, RiskHeatmap

backend-lehrer (5 files):
- letters_api (641 → 2), certificates_api (636 → 2)
- alerts_agent/db/models (636 → 3)
- llm_gateway/communication_service (614 → 2)
- game/database already done in prior batch

klausur-service (2 files):
- hybrid_vocab_extractor (664 → 2)
- klausur-service/frontend: api.ts (620 → 3), EHUploadWizard (591 → 2)

voice-service (3 files):
- bqas/rag_judge (618 → 3), runner (529 → 2)
- enhanced_task_orchestrator (519 → 2)

studio-v2 (6 files):
- korrektur/[klausurId] (578 → 4), fairness (569 → 2)
- AlertsWizard (552 → 2), OnboardingWizard (513 → 2)
- korrektur/api.ts (506 → 3), geo-lernwelt (501 → 2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 08:56:45 +02:00

91 lines
4.7 KiB
TypeScript

'use client'
/**
* Voice Service Admin Page
*
* Displays:
* - Voice-First Architecture Overview
* - Developer Guide Content
* - Live Voice Demo (embedded from studio-v2)
* - Task State Machine Documentation
* - DSGVO Compliance Information
*/
import { useState } from 'react'
import AdminLayout from '@/components/admin/AdminLayout'
import Link from 'next/link'
import { TabType, TABS } from './_components/constants'
import { TabOverview } from './_components/TabOverview'
import { TabDemo, TabTasks, TabIntents, TabDsgvo, TabApi } from './_components/TabContent'
export default function VoicePage() {
const [activeTab, setActiveTab] = useState<TabType>('overview')
return (
<AdminLayout title="Voice Service" description="Voice-First Interface mit PersonaPlex-7B & TaskOrchestrator">
{/* Quick Links */}
<div className="mb-6 flex flex-wrap gap-3">
<Link href="/voice-test" target="_blank" className="flex items-center gap-2 px-4 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 transition-colors">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" />
</svg>
Voice Test (Studio)
</Link>
<a href="http://localhost:8091/health" target="_blank" rel="noopener noreferrer" className="flex items-center gap-2 px-4 py-2 bg-green-100 text-green-700 rounded-lg hover:bg-green-200 transition-colors">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Health Check
</a>
<Link href="/admin/docs" className="flex items-center gap-2 px-4 py-2 bg-slate-100 text-slate-700 rounded-lg hover:bg-slate-200 transition-colors">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Developer Docs
</Link>
</div>
{/* Stats Overview */}
<div className="grid grid-cols-2 md:grid-cols-6 gap-4 mb-6">
<div className="bg-white rounded-lg shadow p-4"><div className="text-3xl font-bold text-teal-600">8091</div><div className="text-sm text-slate-500">Port</div></div>
<div className="bg-white rounded-lg shadow p-4"><div className="text-3xl font-bold text-blue-600">22</div><div className="text-sm text-slate-500">Task Types</div></div>
<div className="bg-white rounded-lg shadow p-4"><div className="text-3xl font-bold text-purple-600">9</div><div className="text-sm text-slate-500">Task States</div></div>
<div className="bg-white rounded-lg shadow p-4"><div className="text-3xl font-bold text-green-600">24kHz</div><div className="text-sm text-slate-500">Audio Rate</div></div>
<div className="bg-white rounded-lg shadow p-4"><div className="text-3xl font-bold text-orange-600">80ms</div><div className="text-sm text-slate-500">Frame Size</div></div>
<div className="bg-white rounded-lg shadow p-4"><div className="text-3xl font-bold text-red-600">0</div><div className="text-sm text-slate-500">Audio Persist</div></div>
</div>
{/* Tabs */}
<div className="bg-white rounded-lg shadow mb-6">
<div className="border-b border-slate-200 px-4">
<div className="flex gap-1 overflow-x-auto">
{TABS.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as TabType)}
className={`px-4 py-3 text-sm font-medium whitespace-nowrap transition-colors border-b-2 ${
activeTab === tab.id
? 'border-teal-600 text-teal-600'
: 'border-transparent text-slate-500 hover:text-slate-700'
}`}
>
<span className="mr-2">{tab.icon}</span>
{tab.name}
</button>
))}
</div>
</div>
<div className="p-6">
{activeTab === 'overview' && <TabOverview />}
{activeTab === 'demo' && <TabDemo />}
{activeTab === 'tasks' && <TabTasks />}
{activeTab === 'intents' && <TabIntents />}
{activeTab === 'dsgvo' && <TabDsgvo />}
{activeTab === 'api' && <TabApi />}
</div>
</div>
</AdminLayout>
)
}