Add first turn option

This commit is contained in:
Xin Wang
2026-02-12 15:23:32 +08:00
parent 56ca95c200
commit edcbc2cec7
9 changed files with 97 additions and 24 deletions

View File

@@ -117,6 +117,7 @@ export const AssistantsPage: React.FC = () => {
const handleCreate = async () => {
const newAssistantPayload: Partial<Assistant> = {
name: 'New Assistant',
firstTurnMode: 'bot_first',
opener: '',
generatedOpenerEnabled: false,
prompt: '',
@@ -247,6 +248,7 @@ export const AssistantsPage: React.FC = () => {
const isExternalConfig = selectedAssistant?.configMode === 'dify' || selectedAssistant?.configMode === 'fastgpt';
const isNoneConfig = selectedAssistant?.configMode === 'none' || !selectedAssistant?.configMode;
const canAdjustInterruptionSensitivity = selectedAssistant?.botCannotBeInterrupted !== true;
const isBotFirstTurn = selectedAssistant?.firstTurnMode !== 'user_first';
return (
<div className="flex h-full min-h-0 gap-6 animate-in fade-in">
@@ -522,28 +524,63 @@ export const AssistantsPage: React.FC = () => {
<div className="space-y-2">
<div className="flex items-center justify-between gap-3">
<label className="text-sm font-medium text-white flex items-center">
<PhoneCall className="w-4 h-4 mr-2 text-primary"/>
</label>
<div className="inline-flex rounded-lg border border-white/10 bg-white/5 p-1">
<button
type="button"
onClick={() => updateAssistant('firstTurnMode', 'bot_first')}
className={`px-3 py-1 text-xs rounded-md transition-colors ${
isBotFirstTurn
? 'bg-primary text-primary-foreground shadow-sm'
: 'text-muted-foreground hover:text-foreground'
}`}
>
</button>
<button
type="button"
onClick={() => updateAssistant('firstTurnMode', 'user_first')}
className={`px-3 py-1 text-xs rounded-md transition-colors ${
isBotFirstTurn
? 'text-muted-foreground hover:text-foreground'
: 'bg-primary text-primary-foreground shadow-sm'
}`}
>
</button>
</div>
</div>
<p className="text-xs text-muted-foreground"></p>
</div>
<div className={`space-y-2 transition-opacity ${isBotFirstTurn ? 'opacity-100' : 'opacity-60'}`}>
<div className="flex items-center justify-between gap-3">
<label className={`text-sm font-medium flex items-center ${isBotFirstTurn ? 'text-white' : 'text-muted-foreground'}`}>
<MessageSquare className="w-4 h-4 mr-2 text-primary"/>
</label>
<div className="inline-flex rounded-lg border border-white/10 bg-white/5 p-1">
<button
type="button"
disabled={!isBotFirstTurn}
onClick={() => updateAssistant('generatedOpenerEnabled', false)}
className={`px-3 py-1 text-xs rounded-md transition-colors ${
selectedAssistant.generatedOpenerEnabled === true
? 'text-muted-foreground hover:text-foreground'
: 'bg-primary text-primary-foreground shadow-sm'
}`}
} disabled:opacity-50 disabled:cursor-not-allowed`}
>
</button>
<button
type="button"
disabled={!isBotFirstTurn}
onClick={() => updateAssistant('generatedOpenerEnabled', true)}
className={`px-3 py-1 text-xs rounded-md transition-colors ${
selectedAssistant.generatedOpenerEnabled === true
? 'bg-primary text-primary-foreground shadow-sm'
: 'text-muted-foreground hover:text-foreground'
}`}
} disabled:opacity-50 disabled:cursor-not-allowed`}
>
</button>
@@ -552,14 +589,22 @@ export const AssistantsPage: React.FC = () => {
<Input
value={selectedAssistant.opener}
onChange={(e) => updateAssistant('opener', e.target.value)}
placeholder={selectedAssistant.generatedOpenerEnabled === true ? '将基于提示词自动生成开场白' : '例如您好我是您的专属AI助手...'}
disabled={selectedAssistant.generatedOpenerEnabled === true}
placeholder={
!isBotFirstTurn
? '当前为用户先说,开场白不会在首轮触发'
: selectedAssistant.generatedOpenerEnabled === true
? '将基于提示词自动生成开场白'
: '例如您好我是您的专属AI助手...'
}
disabled={!isBotFirstTurn || selectedAssistant.generatedOpenerEnabled === true}
className="bg-white/5 border-white/10 focus:border-primary/50 disabled:opacity-50 disabled:cursor-not-allowed"
/>
<p className="text-xs text-muted-foreground">
{selectedAssistant.generatedOpenerEnabled === true
? '通话接通后将根据提示词自动生成开场白。'
: '接通通话后的第一句话。'}
{!isBotFirstTurn
? '已切换为“用户先说”,首轮不会发送开场白。'
: selectedAssistant.generatedOpenerEnabled === true
? '通话接通后将根据提示词自动生成开场白。'
: '接通通话后的第一句话。'}
</p>
</div>
@@ -1836,6 +1881,7 @@ export const DebugDrawer: React.FC<{
mode: ttsEnabled ? 'audio' : 'text',
},
systemPrompt: assistant.prompt || '',
firstTurnMode: assistant.firstTurnMode || 'bot_first',
greeting: assistant.opener || '',
generatedOpenerEnabled: assistant.generatedOpenerEnabled === true,
bargeIn: {

View File

@@ -29,6 +29,7 @@ const mapAssistant = (raw: AnyRecord): Assistant => ({
id: String(readField(raw, ['id'], '')),
name: readField(raw, ['name'], ''),
callCount: Number(readField(raw, ['callCount', 'call_count'], 0)),
firstTurnMode: readField(raw, ['firstTurnMode', 'first_turn_mode'], 'bot_first') as 'bot_first' | 'user_first',
opener: readField(raw, ['opener'], ''),
generatedOpenerEnabled: Boolean(readField(raw, ['generatedOpenerEnabled', 'generated_opener_enabled'], false)),
prompt: readField(raw, ['prompt'], ''),
@@ -213,6 +214,7 @@ export const fetchAssistants = async (): Promise<Assistant[]> => {
export const createAssistant = async (data: Partial<Assistant>): Promise<Assistant> => {
const payload = {
name: data.name || 'New Assistant',
firstTurnMode: data.firstTurnMode || 'bot_first',
opener: data.opener || '',
generatedOpenerEnabled: data.generatedOpenerEnabled ?? false,
prompt: data.prompt || '',
@@ -240,6 +242,7 @@ export const createAssistant = async (data: Partial<Assistant>): Promise<Assista
export const updateAssistant = async (id: string, data: Partial<Assistant>): Promise<Assistant> => {
const payload = {
name: data.name,
firstTurnMode: data.firstTurnMode,
opener: data.opener,
generatedOpenerEnabled: data.generatedOpenerEnabled,
prompt: data.prompt,

View File

@@ -3,6 +3,7 @@ export interface Assistant {
id: string;
name: string;
callCount: number;
firstTurnMode?: 'bot_first' | 'user_first';
opener: string;
generatedOpenerEnabled?: boolean;
prompt: string;