Add runtime mode selection to AssistantPage and configure allowed development origins
Introduced a new feature in AssistantPage allowing users to select between 'pipeline' and 'realtime' runtime modes, enhancing the flexibility of the assistant's functionality. Updated the configuration to include 'allowedDevOrigins' for local development. This change improves user experience by providing clear options for runtime configurations and streamlining the development process.
This commit is contained in:
@@ -2,6 +2,7 @@ import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
allowedDevOrigins: ["127.0.0.1"],
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
Check,
|
||||
Database,
|
||||
MessageSquareText,
|
||||
Mic,
|
||||
MoreHorizontal,
|
||||
Pencil,
|
||||
Plus,
|
||||
Rocket,
|
||||
Search,
|
||||
Sparkles,
|
||||
Trash2,
|
||||
@@ -48,10 +48,14 @@ import {
|
||||
} from "@/components/ui/card";
|
||||
import { useState } from "react";
|
||||
|
||||
type RuntimeMode = "pipeline" | "realtime";
|
||||
|
||||
type AssistantForm = {
|
||||
name: string;
|
||||
greeting: string;
|
||||
prompt: string;
|
||||
runtimeMode: RuntimeMode;
|
||||
realtimeModel: string;
|
||||
model: string;
|
||||
asr: string;
|
||||
voice: string;
|
||||
@@ -190,6 +194,8 @@ export function AssistantPage() {
|
||||
greeting: "您好,我是 AI 视频助手,请问有什么可以帮您?",
|
||||
prompt:
|
||||
"你是一名专业的政务视频咨询助手,负责为市民提供政策解读、办事指南和常见问题解答。\n\n请遵循以下原则:\n1. 回答准确、简洁,使用通俗易懂的语言\n2. 不确定的信息应明确告知,不编造政策内容\n3. 涉及具体办事流程时,引导用户前往官方渠道核实",
|
||||
runtimeMode: "pipeline",
|
||||
realtimeModel: "gpt-realtime-2",
|
||||
model: "DeepSeek-V3",
|
||||
asr: "SenseVoice",
|
||||
voice: "晓宁",
|
||||
@@ -686,6 +692,66 @@ export function AssistantPage() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-5">
|
||||
<SectionCard>
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updateForm("runtimeMode", "pipeline")}
|
||||
className={[
|
||||
"rounded-2xl border p-5 text-left transition-colors",
|
||||
form.runtimeMode === "pipeline"
|
||||
? "border-primary bg-primary/5 ring-1 ring-primary"
|
||||
: "border-hairline bg-canvas-soft hover:border-hairline-strong",
|
||||
].join(" ")}
|
||||
>
|
||||
<div className="mb-3 flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-surface-strong text-foreground">
|
||||
<Boxes size={18} />
|
||||
</div>
|
||||
<div className="font-medium text-foreground">Pipeline 模式</div>
|
||||
</div>
|
||||
{form.runtimeMode === "pipeline" && (
|
||||
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground">
|
||||
<Check size={14} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm leading-6 text-muted-foreground">
|
||||
通过 ASR、LLM 和 TTS 级联组成语音管线,灵活选配各模块。
|
||||
</p>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updateForm("runtimeMode", "realtime")}
|
||||
className={[
|
||||
"rounded-2xl border p-5 text-left transition-colors",
|
||||
form.runtimeMode === "realtime"
|
||||
? "border-primary bg-primary/5 ring-1 ring-primary"
|
||||
: "border-hairline bg-canvas-soft hover:border-hairline-strong",
|
||||
].join(" ")}
|
||||
>
|
||||
<div className="mb-3 flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-surface-strong text-foreground">
|
||||
<MessageSquareText size={18} />
|
||||
</div>
|
||||
<div className="font-medium text-foreground">Realtime 模式</div>
|
||||
</div>
|
||||
{form.runtimeMode === "realtime" && (
|
||||
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground">
|
||||
<Check size={14} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm leading-6 text-muted-foreground">
|
||||
使用原生实时语音模型,模型直接处理音频输入并生成语音回复。
|
||||
</p>
|
||||
</button>
|
||||
</div>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<Bot size={18} />}
|
||||
title="基础信息"
|
||||
@@ -714,18 +780,51 @@ export function AssistantPage() {
|
||||
/>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<Brain size={18} />}
|
||||
title="模型配置"
|
||||
description="选择大语言模型和知识库能力"
|
||||
>
|
||||
<SelectField
|
||||
label="大语言模型"
|
||||
value={form.model}
|
||||
onChange={(value) => updateForm("model", value)}
|
||||
options={["DeepSeek-V3", "Qwen-Max", "Kimi-K2", "Doubao-Pro", "GPT-4o"]}
|
||||
/>
|
||||
</SectionCard>
|
||||
{form.runtimeMode === "realtime" && (
|
||||
<SectionCard
|
||||
icon={<Brain size={18} />}
|
||||
title="Realtime 配置"
|
||||
description="当前模式下 ASR 与 TTS 由 Realtime 模型内置完成"
|
||||
>
|
||||
<SelectField
|
||||
label="Realtime 模型"
|
||||
value={form.realtimeModel}
|
||||
onChange={(value) => updateForm("realtimeModel", value)}
|
||||
options={["gpt-realtime-2", "gpt-realtime", "gpt-4o-realtime-preview"]}
|
||||
/>
|
||||
</SectionCard>
|
||||
)}
|
||||
|
||||
{form.runtimeMode === "pipeline" && (
|
||||
<SectionCard
|
||||
icon={<Brain size={18} />}
|
||||
title="Pipeline 配置"
|
||||
description="选择 ASR、LLM 和 TTS 组成级联语音管线"
|
||||
>
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||
<SelectField
|
||||
label="大语言模型"
|
||||
value={form.model}
|
||||
onChange={(value) => updateForm("model", value)}
|
||||
options={["DeepSeek-V3", "Qwen-Max", "Kimi-K2", "Doubao-Pro", "GPT-4o"]}
|
||||
/>
|
||||
|
||||
<SelectField
|
||||
label="语音识别"
|
||||
value={form.asr}
|
||||
onChange={(value) => updateForm("asr", value)}
|
||||
options={["SenseVoice", "Paraformer", "Whisper", "FunASR"]}
|
||||
/>
|
||||
|
||||
<SelectField
|
||||
label="播报声音"
|
||||
value={form.voice}
|
||||
onChange={(value) => updateForm("voice", value)}
|
||||
options={["晓宁", "晓美", "晓宇", "晓晨"]}
|
||||
/>
|
||||
</div>
|
||||
</SectionCard>
|
||||
)}
|
||||
|
||||
<SectionCard
|
||||
icon={<Database size={18} />}
|
||||
@@ -740,28 +839,6 @@ export function AssistantPage() {
|
||||
/>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<Mic size={18} />}
|
||||
title="语音配置"
|
||||
description="配置语音识别模型和播报声音"
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<SelectField
|
||||
label="语音识别"
|
||||
value={form.asr}
|
||||
onChange={(value) => updateForm("asr", value)}
|
||||
options={["SenseVoice", "Paraformer", "Whisper", "FunASR"]}
|
||||
/>
|
||||
|
||||
<SelectField
|
||||
label="播报声音"
|
||||
value={form.voice}
|
||||
onChange={(value) => updateForm("voice", value)}
|
||||
options={["晓宁", "晓美", "晓宇", "晓晨"]}
|
||||
/>
|
||||
</div>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<Sparkles size={18} />}
|
||||
title="交互策略"
|
||||
@@ -785,29 +862,39 @@ function SectionCard({
|
||||
description,
|
||||
children,
|
||||
}: {
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
description: string;
|
||||
icon?: React.ReactNode;
|
||||
title?: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const hasHeader = Boolean(title);
|
||||
|
||||
return (
|
||||
<Card className="rounded-2xl border-hairline bg-card text-card-foreground shadow-sm">
|
||||
<CardHeader>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-surface-strong text-foreground">
|
||||
{icon}
|
||||
</div>
|
||||
{hasHeader && (
|
||||
<CardHeader>
|
||||
<div className="flex items-start gap-3">
|
||||
{icon && (
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-surface-strong text-foreground">
|
||||
{icon}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<CardTitle className="text-base font-medium">{title}</CardTitle>
|
||||
<CardDescription className="mt-1 text-muted-foreground">
|
||||
{description}
|
||||
</CardDescription>
|
||||
<div>
|
||||
<CardTitle className="text-base font-medium">{title}</CardTitle>
|
||||
{description && (
|
||||
<CardDescription className="mt-1 text-muted-foreground">
|
||||
{description}
|
||||
</CardDescription>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
</CardHeader>
|
||||
)}
|
||||
|
||||
<CardContent className="space-y-4">{children}</CardContent>
|
||||
<CardContent className={hasHeader ? "space-y-4" : undefined}>
|
||||
{children}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user