对标 Khanmigo/Duolingo Max/Squirrel AI/Century Tech 实现: - SSE 流式响应:createAiChatCompletionStream AsyncGenerator + /api/ai/chat/stream SSE 端点 + useAiChatStream hook(AbortController 停止生成 + localStorage 持久化) - Markdown 渲染:AiMarkdownRenderer(react-markdown + remark-gfm + 代码块/表格/列表 + hover 复制按钮) - 全局 AI 助手:AiAssistantWidget 浮动按钮 + Sheet 侧抽屉 + usePathname 路由推断上下文(7 类场景系统提示)+ dashboard layout 全局注入 AiClientProvider - 内容安全:content-safety.ts 多层过滤(输入/输出安全过滤 + 每日限制 student 50/teacher 200/parent 30/admin 500 + 学生苏格拉底模式),COPPA/FERPA K12 合规 - 多角色 AI 覆盖:家长端 AiChildSummary(学情摘要)+ 管理员端 AiUsageDashboard(使用监控)+ 学生端 AiStudyPath(个性化学习路径) - i18n 修复:8 处错误键引用 + zh-CN/en ai.json 全面扩展 - 架构文档 004/005 同步更新
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import { AppSidebar } from "@/modules/layout/components/app-sidebar"
|
|
import { SidebarProvider } from "@/modules/layout/components/sidebar-provider"
|
|
import { SiteHeader } from "@/modules/layout/components/site-header"
|
|
import {
|
|
AiClientProvider,
|
|
} from "@/modules/ai/context/ai-client-provider"
|
|
import { AiAssistantWidget } from "@/modules/ai/components/ai-assistant-widget"
|
|
import {
|
|
aiChatAction,
|
|
suggestSimilarQuestionsAction,
|
|
suggestGradingAction,
|
|
generateLessonContentAction,
|
|
generateQuestionVariantAction,
|
|
analyzeWeaknessAction,
|
|
generateChildSummaryAction,
|
|
recommendStudyPathAction,
|
|
getAiUsageStatsAction,
|
|
} from "@/modules/ai/actions"
|
|
import type { AiClientService } from "@/modules/ai/types"
|
|
|
|
const aiClientService: AiClientService = {
|
|
chat: aiChatAction,
|
|
suggestSimilarQuestions: suggestSimilarQuestionsAction,
|
|
suggestGrading: suggestGradingAction,
|
|
generateLessonContent: generateLessonContentAction,
|
|
generateQuestionVariant: generateQuestionVariantAction,
|
|
analyzeWeakness: analyzeWeaknessAction,
|
|
generateChildSummary: generateChildSummaryAction,
|
|
recommendStudyPath: recommendStudyPathAction,
|
|
getAiUsageStats: getAiUsageStatsAction,
|
|
}
|
|
|
|
export default function DashboardLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode
|
|
}) {
|
|
return (
|
|
<AiClientProvider service={aiClientService}>
|
|
<SidebarProvider sidebar={<AppSidebar />}>
|
|
<a href="#main-content" className="sr-only focus:not-sr-only focus:absolute focus:z-50 focus:p-4 focus:bg-background focus:text-foreground focus:border focus:border-border focus:rounded-md focus:m-2">
|
|
Skip to main content
|
|
</a>
|
|
<SiteHeader />
|
|
<main id="main-content" className="flex-1 overflow-auto p-6">
|
|
{children}
|
|
</main>
|
|
<AiAssistantWidget />
|
|
</SidebarProvider>
|
|
</AiClientProvider>
|
|
)
|
|
}
|