Refactor personality and emoji configuration forms; add chat components
- Updated PersonalityForm to handle multiple reply styles and probabilities. - Removed unused fields from PersonalityConfig and adjusted default values. - Refactored loadPersonalityConfig and loadEmojiConfig to align with new structure. - Introduced ChatComposer, ChatHeaderBar, ChatWorkspaceSidebar, and MessageList components for improved chat interface. - Enhanced user experience with dynamic message rendering and connection status indicators. - Cleaned up API calls for saving configurations, focusing on essential fields. Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -313,6 +313,7 @@ interface PersonalityFormProps {
|
||||
|
||||
export function PersonalityForm({ config, onChange }: PersonalityFormProps) {
|
||||
const { t } = useTranslation()
|
||||
const multipleReplyStyleText = config.multiple_reply_style.join('\n')
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -345,48 +346,49 @@ export function PersonalityForm({ config, onChange }: PersonalityFormProps) {
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="interest">{t('setupPage.forms.personality.interest.label')}</Label>
|
||||
<Textarea
|
||||
id="interest"
|
||||
placeholder={t('setupPage.forms.personality.interest.placeholder')}
|
||||
value={config.interest}
|
||||
onChange={(e) => onChange({ ...config, interest: e.target.value })}
|
||||
rows={2}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t('setupPage.forms.personality.interest.description')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="plan_style">{t('setupPage.forms.personality.planStyle.label')}</Label>
|
||||
<Textarea
|
||||
id="plan_style"
|
||||
placeholder={t('setupPage.forms.personality.planStyle.placeholder')}
|
||||
value={config.plan_style}
|
||||
onChange={(e) => onChange({ ...config, plan_style: e.target.value })}
|
||||
rows={4}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t('setupPage.forms.personality.planStyle.description')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="private_plan_style">
|
||||
{t('setupPage.forms.personality.privatePlanStyle.label')}
|
||||
<Label htmlFor="multiple_reply_style">
|
||||
{t('setupPage.forms.personality.multipleReplyStyle.label')}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="private_plan_style"
|
||||
placeholder={t('setupPage.forms.personality.privatePlanStyle.placeholder')}
|
||||
value={config.private_plan_style}
|
||||
onChange={(e) => onChange({ ...config, private_plan_style: e.target.value })}
|
||||
rows={3}
|
||||
id="multiple_reply_style"
|
||||
placeholder={t('setupPage.forms.personality.multipleReplyStyle.placeholder')}
|
||||
value={multipleReplyStyleText}
|
||||
onChange={(e) =>
|
||||
onChange({
|
||||
...config,
|
||||
multiple_reply_style: e.target.value
|
||||
.split('\n')
|
||||
.map((style) => style.trim())
|
||||
.filter(Boolean),
|
||||
})
|
||||
}
|
||||
rows={5}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t('setupPage.forms.personality.privatePlanStyle.description')}
|
||||
{t('setupPage.forms.personality.multipleReplyStyle.description')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="multiple_probability">
|
||||
{t('setupPage.forms.personality.multipleProbability.label')}
|
||||
</Label>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{(config.multiple_probability * 100).toFixed(0)}%
|
||||
</span>
|
||||
</div>
|
||||
<Input
|
||||
id="multiple_probability"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.1"
|
||||
value={config.multiple_probability}
|
||||
onChange={(e) => onChange({ ...config, multiple_probability: Number(e.target.value) })}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t('setupPage.forms.personality.multipleProbability.description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -405,23 +407,17 @@ export function EmojiForm({ config, onChange }: EmojiFormProps) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="emoji_chance">{t('setupPage.forms.emoji.emojiChance.label')}</Label>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{(config.emoji_chance * 100).toFixed(0)}%
|
||||
</span>
|
||||
</div>
|
||||
<Label htmlFor="emoji_send_num">{t('setupPage.forms.emoji.emojiSendNum.label')}</Label>
|
||||
<Input
|
||||
id="emoji_chance"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.1"
|
||||
value={config.emoji_chance}
|
||||
onChange={(e) => onChange({ ...config, emoji_chance: Number(e.target.value) })}
|
||||
id="emoji_send_num"
|
||||
type="number"
|
||||
min="1"
|
||||
max="64"
|
||||
value={config.emoji_send_num}
|
||||
onChange={(e) => onChange({ ...config, emoji_send_num: Number(e.target.value) })}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t('setupPage.forms.emoji.emojiChance.description')}
|
||||
{t('setupPage.forms.emoji.emojiSendNum.description')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -532,22 +528,6 @@ export function OtherBasicForm({ config, onChange }: OtherBasicFormProps) {
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="enable_tool">{t('setupPage.forms.other.enableTool.label')}</Label>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t('setupPage.forms.other.enableTool.description')}
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
id="enable_tool"
|
||||
checked={config.enable_tool}
|
||||
onCheckedChange={(checked) => onChange({ ...config, enable_tool: checked })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="all_global">{t('setupPage.forms.other.allGlobal.label')}</Label>
|
||||
|
||||
@@ -51,9 +51,8 @@ export async function loadPersonalityConfig(): Promise<PersonalityConfig> {
|
||||
return {
|
||||
personality: personalityConfig.personality || '',
|
||||
reply_style: personalityConfig.reply_style || '',
|
||||
interest: personalityConfig.interest || '',
|
||||
plan_style: personalityConfig.plan_style || '',
|
||||
private_plan_style: personalityConfig.private_plan_style || '',
|
||||
multiple_reply_style: personalityConfig.multiple_reply_style || [],
|
||||
multiple_probability: personalityConfig.multiple_probability ?? 0.2,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +70,8 @@ export async function loadEmojiConfig(): Promise<EmojiConfig> {
|
||||
const emojiConfig = (data.config.emoji || {}) as Partial<EmojiConfig>
|
||||
|
||||
return {
|
||||
emoji_chance: emojiConfig.emoji_chance ?? 0.4,
|
||||
max_reg_num: emojiConfig.max_reg_num ?? 40,
|
||||
emoji_send_num: emojiConfig.emoji_send_num ?? 25,
|
||||
max_reg_num: emojiConfig.max_reg_num ?? 64,
|
||||
do_replace: emojiConfig.do_replace ?? true,
|
||||
check_interval: emojiConfig.check_interval ?? 10,
|
||||
steal_emoji: emojiConfig.steal_emoji ?? true,
|
||||
@@ -90,18 +89,15 @@ export async function loadOtherBasicConfig(): Promise<OtherBasicConfig> {
|
||||
|
||||
const result = await parseResponse<{
|
||||
config: {
|
||||
tool?: { enable_tool?: boolean }
|
||||
expression?: { all_global_jargon?: boolean }
|
||||
}
|
||||
}>(response)
|
||||
const data = throwIfError(result)
|
||||
const config = data.config
|
||||
|
||||
const toolConfig = config.tool || {}
|
||||
const expressionConfig = config.expression || {}
|
||||
|
||||
return {
|
||||
enable_tool: toolConfig.enable_tool ?? true,
|
||||
all_global: expressionConfig.all_global_jargon ?? true,
|
||||
}
|
||||
}
|
||||
@@ -169,38 +165,16 @@ export async function saveEmojiConfig(config: EmojiConfig) {
|
||||
return throwIfError(result)
|
||||
}
|
||||
|
||||
// 保存其他基础配置(工具、情绪、黑话)
|
||||
// 保存其他基础配置(黑话)
|
||||
export async function saveOtherBasicConfig(config: OtherBasicConfig) {
|
||||
// 需要分别保存到不同的section
|
||||
const promises = []
|
||||
const response = await fetchWithAuth('/api/webui/config/bot/section/expression', {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify({ all_global_jargon: config.all_global }),
|
||||
})
|
||||
|
||||
// 保存tool配置
|
||||
promises.push(
|
||||
fetchWithAuth('/api/webui/config/bot/section/tool', {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify({ enable_tool: config.enable_tool }),
|
||||
})
|
||||
)
|
||||
|
||||
// 保存expression配置中的all_global_jargon
|
||||
promises.push(
|
||||
fetchWithAuth('/api/webui/config/bot/section/expression', {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify({ all_global_jargon: config.all_global }),
|
||||
})
|
||||
)
|
||||
|
||||
const results = await Promise.all(promises)
|
||||
|
||||
// 检查所有请求是否成功
|
||||
for (const response of results) {
|
||||
const result = await parseResponse(response)
|
||||
throwIfError(result)
|
||||
}
|
||||
|
||||
return { success: true }
|
||||
const result = await parseResponse(response)
|
||||
return throwIfError(result)
|
||||
}
|
||||
|
||||
// 保存硅基流动API配置
|
||||
|
||||
@@ -95,13 +95,17 @@ function SetupPageContent() {
|
||||
const createDefaultPersonalityConfig = (): PersonalityConfig => ({
|
||||
personality: t('setupPage.defaults.personality.personality'),
|
||||
reply_style: t('setupPage.defaults.personality.replyStyle'),
|
||||
interest: t('setupPage.defaults.personality.interest'),
|
||||
plan_style: t('setupPage.defaults.personality.planStyle'),
|
||||
private_plan_style: t('setupPage.defaults.personality.privatePlanStyle'),
|
||||
multiple_reply_style: [
|
||||
t('setupPage.defaults.personality.multipleReplyStyles.plain'),
|
||||
t('setupPage.defaults.personality.multipleReplyStyles.shortText'),
|
||||
t('setupPage.defaults.personality.multipleReplyStyles.shortSymbol'),
|
||||
t('setupPage.defaults.personality.multipleReplyStyles.translation'),
|
||||
],
|
||||
multiple_probability: 0.2,
|
||||
})
|
||||
const createDefaultEmojiConfig = (): EmojiConfig => ({
|
||||
emoji_chance: 0.4,
|
||||
max_reg_num: 40,
|
||||
emoji_send_num: 25,
|
||||
max_reg_num: 64,
|
||||
do_replace: true,
|
||||
check_interval: 10,
|
||||
steal_emoji: true,
|
||||
@@ -132,7 +136,6 @@ function SetupPageContent() {
|
||||
|
||||
// 步骤4:其他基础配置
|
||||
const [otherBasic, setOtherBasic] = useState<OtherBasicConfig>({
|
||||
enable_tool: true,
|
||||
all_global: true,
|
||||
})
|
||||
|
||||
|
||||
@@ -20,14 +20,13 @@ export interface BotBasicConfig {
|
||||
export interface PersonalityConfig {
|
||||
personality: string
|
||||
reply_style: string
|
||||
interest: string
|
||||
plan_style: string
|
||||
private_plan_style: string
|
||||
multiple_reply_style: string[]
|
||||
multiple_probability: number
|
||||
}
|
||||
|
||||
// 步骤3:表情包配置
|
||||
export interface EmojiConfig {
|
||||
emoji_chance: number
|
||||
emoji_send_num: number
|
||||
max_reg_num: number
|
||||
do_replace: boolean
|
||||
check_interval: number
|
||||
@@ -38,7 +37,6 @@ export interface EmojiConfig {
|
||||
|
||||
// 步骤4:其他基础配置
|
||||
export interface OtherBasicConfig {
|
||||
enable_tool: boolean
|
||||
all_global: boolean // 全局黑话模式(expression.all_global_jargon)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user