✨ feat(playground): add role toggle feature for AI messages
- Add role toggle button in MessageActions component for assistant/system messages - Implement handleRoleToggle function in Playground component to switch between assistant and system roles - Add visual distinction for system messages with orange badge indicator - Update roleInfo configuration to use consistent avatars for assistant and system roles - Add proper tooltip texts and visual feedback for role switching - Ensure role toggle is disabled during message generation to prevent conflicts This feature allows users to easily switch message roles between assistant and system, providing better control over conversation flow and message categorization in the playground interface.
This commit is contained in:
@@ -7,15 +7,24 @@ import {
|
||||
RefreshCw,
|
||||
Copy,
|
||||
Trash2,
|
||||
UserCheck,
|
||||
} from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const MessageActions = ({ message, styleState, onMessageReset, onMessageCopy, onMessageDelete, isAnyMessageGenerating = false }) => {
|
||||
const MessageActions = ({
|
||||
message,
|
||||
styleState,
|
||||
onMessageReset,
|
||||
onMessageCopy,
|
||||
onMessageDelete,
|
||||
onRoleToggle,
|
||||
isAnyMessageGenerating = false
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isLoading = message.status === 'loading' || message.status === 'incomplete';
|
||||
|
||||
const shouldDisableActions = isAnyMessageGenerating;
|
||||
const canToggleRole = message.role === 'assistant' || message.role === 'system';
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-0.5">
|
||||
@@ -48,6 +57,30 @@ const MessageActions = ({ message, styleState, onMessageReset, onMessageCopy, on
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{canToggleRole && !isLoading && (
|
||||
<Tooltip
|
||||
content={
|
||||
shouldDisableActions
|
||||
? t('正在生成中,请稍候...')
|
||||
: message.role === 'assistant'
|
||||
? t('切换为System角色')
|
||||
: t('切换为Assistant角色')
|
||||
}
|
||||
position="top"
|
||||
>
|
||||
<Button
|
||||
theme="borderless"
|
||||
type="tertiary"
|
||||
size="small"
|
||||
icon={<UserCheck size={styleState.isMobile ? 12 : 14} />}
|
||||
onClick={() => !shouldDisableActions && onRoleToggle && onRoleToggle(message)}
|
||||
disabled={shouldDisableActions}
|
||||
className={`!rounded-md ${shouldDisableActions ? '!text-gray-300 !cursor-not-allowed' : message.role === 'system' ? '!text-purple-500 hover:!text-purple-700 hover:!bg-purple-50' : '!text-gray-400 hover:!text-purple-600 hover:!bg-purple-50'} ${styleState.isMobile ? '!w-6 !h-6' : '!w-7 !h-7'} !p-0 transition-all`}
|
||||
aria-label={message.role === 'assistant' ? t('切换为System角色') : t('切换为Assistant角色')}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{!isLoading && (
|
||||
<Tooltip content={shouldDisableActions ? t('正在生成中,请稍候...') : t('删除')} position="top">
|
||||
<Button
|
||||
|
||||
@@ -140,6 +140,20 @@ const MessageContent = ({ message, className, styleState, onToggleReasoningExpan
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{/* 为system角色添加特殊标识 */}
|
||||
{message.role === 'system' && (
|
||||
<div className="mb-2 sm:mb-4">
|
||||
<div className="flex items-center gap-2 p-2 sm:p-3 bg-gradient-to-r from-amber-50 to-orange-50 rounded-lg" style={{ border: '1px solid var(--semi-color-border)' }}>
|
||||
<div className="w-4 h-4 sm:w-5 sm:h-5 rounded-full bg-gradient-to-br from-amber-500 to-orange-600 flex items-center justify-center shadow-sm">
|
||||
<Typography.Text className="text-white text-xs font-bold">S</Typography.Text>
|
||||
</div>
|
||||
<Typography.Text className="text-amber-700 text-xs sm:text-sm font-medium">
|
||||
{t('系统消息')}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 渲染推理内容 */}
|
||||
{message.role === 'assistant' && finalExtractedThinkingContent && (
|
||||
<div className="bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 rounded-xl sm:rounded-2xl mb-2 sm:mb-4 overflow-hidden shadow-sm backdrop-blur-sm">
|
||||
|
||||
@@ -62,8 +62,7 @@ const Playground = () => {
|
||||
},
|
||||
system: {
|
||||
name: 'System',
|
||||
avatar:
|
||||
'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/other/logo.png',
|
||||
avatar: getLogo(),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1025,6 +1024,22 @@ const Playground = () => {
|
||||
});
|
||||
}, [setMessage, t]);
|
||||
|
||||
const handleRoleToggle = useCallback((targetMessage) => {
|
||||
setMessage(prevMessages => {
|
||||
return prevMessages.map(msg => {
|
||||
if (msg.id === targetMessage.id && (msg.role === 'assistant' || msg.role === 'system')) {
|
||||
const newRole = msg.role === 'assistant' ? 'system' : 'assistant';
|
||||
Toast.success({
|
||||
content: t(`已切换为${newRole === 'system' ? 'System' : 'Assistant'}角色`),
|
||||
duration: 2,
|
||||
});
|
||||
return { ...msg, role: newRole };
|
||||
}
|
||||
return msg;
|
||||
});
|
||||
});
|
||||
}, [setMessage, t]);
|
||||
|
||||
const onStopGenerator = useCallback(() => {
|
||||
if (sseSourceRef.current) {
|
||||
sseSourceRef.current.close();
|
||||
@@ -1127,10 +1142,11 @@ const Playground = () => {
|
||||
onMessageReset={handleMessageReset}
|
||||
onMessageCopy={handleMessageCopy}
|
||||
onMessageDelete={handleMessageDelete}
|
||||
onRoleToggle={handleRoleToggle}
|
||||
isAnyMessageGenerating={isAnyMessageGenerating}
|
||||
/>
|
||||
);
|
||||
}, [handleMessageReset, handleMessageCopy, handleMessageDelete, styleState, message]);
|
||||
}, [handleMessageReset, handleMessageCopy, handleMessageDelete, styleState, message, handleRoleToggle]);
|
||||
|
||||
return (
|
||||
<div className="h-full bg-gray-50">
|
||||
@@ -1189,6 +1205,7 @@ const Playground = () => {
|
||||
onMessageCopy={handleMessageCopy}
|
||||
onMessageReset={handleMessageReset}
|
||||
onMessageDelete={handleMessageDelete}
|
||||
onRoleToggle={handleRoleToggle}
|
||||
onStopGenerator={onStopGenerator}
|
||||
onClearMessages={() => setMessage([])}
|
||||
onToggleDebugPanel={() => setShowDebugPanel(!showDebugPanel)}
|
||||
|
||||
Reference in New Issue
Block a user