Refactor assistant greeting logic to conditionally use system prompt for generated openers. Update related tests to verify new behavior and ensure correct metadata handling in API responses. Enhance UI to reflect changes in opener management based on generated opener settings.
This commit is contained in:
@@ -889,25 +889,26 @@ export const AssistantsPage: React.FC = () => {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Input
|
||||
{selectedAssistant.generatedOpenerEnabled === true ? (
|
||||
<div className="rounded-md border border-dashed border-white/15 bg-white/5 px-3 py-2 text-xs text-muted-foreground">
|
||||
自动生成模式下不使用固定开场白文本,仅依据系统提示词生成首句。
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative">
|
||||
<Input
|
||||
value={selectedAssistant.opener}
|
||||
onChange={(e) => {
|
||||
const next = e.target.value;
|
||||
updateAssistant('opener', next);
|
||||
if (selectedAssistant.generatedOpenerEnabled === true) return;
|
||||
updateTemplateSuggestionState('opener', next, e.currentTarget.selectionStart, e.currentTarget);
|
||||
}}
|
||||
onKeyUp={(e) => {
|
||||
if (selectedAssistant.generatedOpenerEnabled === true) return;
|
||||
updateTemplateSuggestionState('opener', e.currentTarget.value, e.currentTarget.selectionStart, e.currentTarget);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
if (selectedAssistant.generatedOpenerEnabled === true) return;
|
||||
updateTemplateSuggestionState('opener', e.currentTarget.value, e.currentTarget.selectionStart, e.currentTarget);
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
if (selectedAssistant.generatedOpenerEnabled === true) return;
|
||||
updateTemplateSuggestionState('opener', e.currentTarget.value, e.currentTarget.selectionStart, e.currentTarget);
|
||||
}}
|
||||
onBlur={() => {
|
||||
@@ -915,40 +916,39 @@ export const AssistantsPage: React.FC = () => {
|
||||
setTemplateSuggestion((prev) => (prev?.field === 'opener' ? null : prev));
|
||||
}, 120);
|
||||
}}
|
||||
placeholder={selectedAssistant.generatedOpenerEnabled === true ? '将基于提示词自动生成开场白' : '例如:您好,我是您的专属AI助手...'}
|
||||
disabled={selectedAssistant.generatedOpenerEnabled === true}
|
||||
className="bg-white/5 border-white/10 focus:border-primary/50 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
/>
|
||||
{templateSuggestion?.field === 'opener' &&
|
||||
filteredSystemTemplateVariables.length > 0 &&
|
||||
selectedAssistant.generatedOpenerEnabled !== true &&
|
||||
typeof document !== 'undefined' &&
|
||||
createPortal(
|
||||
<div
|
||||
className="fixed z-[100] w-[320px] max-w-[calc(100vw-1rem)] rounded-md border border-white/15 bg-black/95 shadow-xl backdrop-blur-md max-h-48 overflow-auto"
|
||||
style={{
|
||||
left: templateSuggestion.anchorLeft,
|
||||
top: templateSuggestion.anchorTop,
|
||||
}}
|
||||
>
|
||||
{filteredSystemTemplateVariables.map((item) => (
|
||||
<button
|
||||
key={item.key}
|
||||
type="button"
|
||||
className="w-full text-left px-3 py-2 hover:bg-white/10 transition-colors"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
applySystemTemplateVariable('opener', item.key);
|
||||
}}
|
||||
>
|
||||
<div className="text-xs text-cyan-100">{`{{${item.key}}}`}</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-0.5">{item.description}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>,
|
||||
document.body
|
||||
)}
|
||||
</div>
|
||||
placeholder="例如:您好,我是您的专属AI助手..."
|
||||
className="bg-white/5 border-white/10 focus:border-primary/50"
|
||||
/>
|
||||
{templateSuggestion?.field === 'opener' &&
|
||||
filteredSystemTemplateVariables.length > 0 &&
|
||||
typeof document !== 'undefined' &&
|
||||
createPortal(
|
||||
<div
|
||||
className="fixed z-[100] w-[320px] max-w-[calc(100vw-1rem)] rounded-md border border-white/15 bg-black/95 shadow-xl backdrop-blur-md max-h-48 overflow-auto"
|
||||
style={{
|
||||
left: templateSuggestion.anchorLeft,
|
||||
top: templateSuggestion.anchorTop,
|
||||
}}
|
||||
>
|
||||
{filteredSystemTemplateVariables.map((item) => (
|
||||
<button
|
||||
key={item.key}
|
||||
type="button"
|
||||
className="w-full text-left px-3 py-2 hover:bg-white/10 transition-colors"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
applySystemTemplateVariable('opener', item.key);
|
||||
}}
|
||||
>
|
||||
<div className="text-xs text-cyan-100">{`{{${item.key}}}`}</div>
|
||||
<div className="text-[10px] text-muted-foreground mt-0.5">{item.description}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>,
|
||||
document.body
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{selectedAssistant.generatedOpenerEnabled === true
|
||||
? '通话接通后将根据提示词自动生成开场白。'
|
||||
@@ -2139,10 +2139,13 @@ export const DebugDrawer: React.FC<{
|
||||
|| textSessionStarted;
|
||||
const requiredTemplateVariableKeys = useMemo(() => {
|
||||
const keys = new Set<string>();
|
||||
const includeOpenerTemplate = assistant.generatedOpenerEnabled !== true;
|
||||
extractDynamicTemplateKeys(String(assistant.prompt || '')).forEach((key) => keys.add(key));
|
||||
extractDynamicTemplateKeys(String(assistant.opener || '')).forEach((key) => keys.add(key));
|
||||
if (includeOpenerTemplate) {
|
||||
extractDynamicTemplateKeys(String(assistant.opener || '')).forEach((key) => keys.add(key));
|
||||
}
|
||||
return Array.from(keys).sort();
|
||||
}, [assistant.opener, assistant.prompt]);
|
||||
}, [assistant.generatedOpenerEnabled, assistant.opener, assistant.prompt]);
|
||||
const missingRequiredDynamicVariableKeys = useMemo(() => {
|
||||
const valuesByKey = new Map<string, string>();
|
||||
for (const row of dynamicVariables) {
|
||||
@@ -3142,6 +3145,7 @@ export const DebugDrawer: React.FC<{
|
||||
const buildLocalResolvedRuntime = () => {
|
||||
const warnings: string[] = [];
|
||||
const ttsEnabled = Boolean(textTtsEnabled);
|
||||
const generatedOpenerEnabled = assistant.generatedOpenerEnabled === true;
|
||||
const knowledgeBaseId = String(assistant.knowledgeBaseId || '').trim();
|
||||
const knowledge = knowledgeBaseId
|
||||
? { enabled: true, kbId: knowledgeBaseId, nResults: 5 }
|
||||
@@ -3156,8 +3160,8 @@ export const DebugDrawer: React.FC<{
|
||||
},
|
||||
systemPrompt: assistant.prompt || '',
|
||||
firstTurnMode: assistant.firstTurnMode || 'bot_first',
|
||||
greeting: assistant.opener || '',
|
||||
generatedOpenerEnabled: assistant.generatedOpenerEnabled === true,
|
||||
greeting: generatedOpenerEnabled ? '' : (assistant.opener || ''),
|
||||
generatedOpenerEnabled,
|
||||
bargeIn: {
|
||||
enabled: assistant.botCannotBeInterrupted !== true,
|
||||
minDurationMs: Math.max(0, Number(assistant.interruptionSensitivity ?? 180)),
|
||||
@@ -3965,7 +3969,7 @@ export const DebugDrawer: React.FC<{
|
||||
className="h-6 px-2 text-[10px]"
|
||||
onClick={importDynamicVariablesFromPlaceholders}
|
||||
disabled={isDynamicVariablesLocked || requiredTemplateVariableKeys.length === 0 || dynamicVariables.length >= DYNAMIC_VARIABLE_MAX_ITEMS}
|
||||
title="Import keys from {{placeholder}} in prompt/opener"
|
||||
title={`Import keys from {{placeholder}} in prompt${assistant.generatedOpenerEnabled === true ? '' : '/opener'}`}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
@@ -3982,7 +3986,7 @@ export const DebugDrawer: React.FC<{
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
Use placeholders like {'{{customer_name}}'} in prompt/opener.
|
||||
Use placeholders like {'{{customer_name}}'} in prompt{assistant.generatedOpenerEnabled === true ? '' : '/opener'}.
|
||||
</p>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
Built-in system vars: {'{{system__time}}'}, {'{{system_utc}}'}, {'{{system_timezone}}'}.
|
||||
|
||||
Reference in New Issue
Block a user