人生轨迹功能完善

This commit is contained in:
2025-12-23 22:10:25 +08:00
parent 97abbefaa3
commit 56cacb7163
12 changed files with 310 additions and 38 deletions
+1 -1
View File
@@ -7,8 +7,8 @@
<sourceOutputDir name="target/generated-sources/annotations" /> <sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" /> <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" /> <outputRelativeToContentRoot value="true" />
<module name="emotion-single" />
<module name="emotion-museum-backend" /> <module name="emotion-museum-backend" />
<module name="emotion-single" />
</profile> </profile>
<profile name="Annotation profile for emotion-museum-server" enabled="true"> <profile name="Annotation profile for emotion-museum-server" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" /> <sourceOutputDir name="target/generated-sources/annotations" />
+2 -2
View File
@@ -9,12 +9,12 @@
<remote-repository> <remote-repository>
<option name="id" value="central" /> <option name="id" value="central" />
<option name="name" value="Central Repository" /> <option name="name" value="Central Repository" />
<option name="url" value="https://maven.aliyun.com/nexus/content/groups/public/" /> <option name="url" value="https://repo.huaweicloud.com/repository/maven/" />
</remote-repository> </remote-repository>
<remote-repository> <remote-repository>
<option name="id" value="central" /> <option name="id" value="central" />
<option name="name" value="Central Repository" /> <option name="name" value="Central Repository" />
<option name="url" value="https://repo.huaweicloud.com/repository/maven/" /> <option name="url" value="https://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository> </remote-repository>
<remote-repository> <remote-repository>
<option name="id" value="spring-ai" /> <option name="id" value="spring-ai" />
@@ -68,4 +68,14 @@ public class EpicScriptCreateRequest extends BaseRequest {
* 是否当前选中 * 是否当前选中
*/ */
private Boolean isSelected; private Boolean isSelected;
/**
* 角色信息(前端传入,用于AI生成)
*/
private String characterInfo;
/**
* 过往经历关键词(前端传入,用于AI生成)
*/
private String lifeEventsSummary;
} }
@@ -158,7 +158,7 @@ public class EpicScriptServiceImpl extends ServiceImpl<EpicScriptMapper, EpicScr
if (plotJson == null) { if (plotJson == null) {
plotJson = new java.util.HashMap<>(); plotJson = new java.util.HashMap<>();
} }
plotJson.put("aiGeneratedContent", aiGeneratedContent); plotJson.put("fullContent", aiGeneratedContent);
script.setPlotJson(plotJson); script.setPlotJson(plotJson);
log.info("AI生成剧本内容成功,用户ID: {}, 内容长度: {}", currentUserId, aiGeneratedContent.length()); log.info("AI生成剧本内容成功,用户ID: {}, 内容长度: {}", currentUserId, aiGeneratedContent.length());
} }
@@ -203,6 +203,16 @@ public class EpicScriptServiceImpl extends ServiceImpl<EpicScriptMapper, EpicScr
private String assembleScriptInput(EpicScriptCreateRequest request) { private String assembleScriptInput(EpicScriptCreateRequest request) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
// 角色信息
if (StringUtils.hasText(request.getCharacterInfo())) {
sb.append("【角色信息】").append(request.getCharacterInfo()).append("\n");
}
// 过往经历
if (StringUtils.hasText(request.getLifeEventsSummary())) {
sb.append("【过往经历】").append(request.getLifeEventsSummary()).append("\n");
}
// 标题 // 标题
if (StringUtils.hasText(request.getTitle())) { if (StringUtils.hasText(request.getTitle())) {
sb.append("【剧本标题】").append(request.getTitle()).append("\n"); sb.append("【剧本标题】").append(request.getTitle()).append("\n");
@@ -12,6 +12,9 @@ import com.emotion.entity.LifeEvent;
import com.emotion.mapper.LifeEventMapper; import com.emotion.mapper.LifeEventMapper;
import com.emotion.service.LifeEventService; import com.emotion.service.LifeEventService;
import com.emotion.util.UserContextHolder; import com.emotion.util.UserContextHolder;
import com.emotion.service.AiChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@@ -29,6 +32,7 @@ import java.util.stream.Collectors;
* @date 2025-12-22 * @date 2025-12-22
*/ */
@Service @Service
@Slf4j
public class LifeEventServiceImpl extends ServiceImpl<LifeEventMapper, LifeEvent> public class LifeEventServiceImpl extends ServiceImpl<LifeEventMapper, LifeEvent>
implements LifeEventService { implements LifeEventService {
@@ -36,6 +40,14 @@ public class LifeEventServiceImpl extends ServiceImpl<LifeEventMapper, LifeEvent
private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME;
private static final DateTimeFormatter DATE_ONLY_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final DateTimeFormatter DATE_ONLY_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* Coze工作流配置键 - AI疗愈
*/
private static final String COZE_HEALING_CONFIG_KEY = "coze.user.dairy.summary";
@Autowired
private AiChatService aiChatService;
@Override @Override
public PageResult<LifeEventResponse> getPageByCurrentUser(LifeEventPageRequest request) { public PageResult<LifeEventResponse> getPageByCurrentUser(LifeEventPageRequest request) {
String currentUserId = UserContextHolder.getCurrentUserId(); String currentUserId = UserContextHolder.getCurrentUserId();
@@ -139,10 +151,74 @@ public class LifeEventServiceImpl extends ServiceImpl<LifeEventMapper, LifeEvent
event.setEmotionScore(BigDecimal.valueOf(request.getEmotionScore())); event.setEmotionScore(BigDecimal.valueOf(request.getEmotionScore()));
} }
// 调用Coze AI进行疗愈回复
String aiGeneratedContent = generateHealingByAi(request, currentUserId);
if (StringUtils.hasText(aiGeneratedContent)) {
event.setAiReply(aiGeneratedContent);
}
this.save(event); this.save(event);
return convertToResponse(event); return convertToResponse(event);
} }
/**
* 调用Coze AI生成疗愈内容
*
* @param request 创建请求
* @param userId 用户ID
* @return AI生成的疗愈内容,失败时返回null
*/
private String generateHealingByAi(LifeEventCreateRequest request, String userId) {
try {
// 组装AI输入
String input = assembleHealingInput(request);
log.info("开始调用AI生成疗愈回复,用户ID: {}, 输入长度: {}", userId, input.length());
// 调用Coze工作流
String result = aiChatService.callWorkflowByConfigKey(COZE_HEALING_CONFIG_KEY, input, userId);
log.info("AI生成疗愈回复完成,用户ID: {}, 结果长度: {}", userId, result != null ? result.length() : 0);
return result;
} catch (Exception e) {
log.error("AI生成疗愈回复失败,用户ID: {}, 错误: {}", userId, e.getMessage(), e);
// AI调用失败不影响事件创建,返回null
return null;
}
}
/**
* 组装AI疗愈输入内容
*
* @param request 创建请求
* @return 格式化的输入字符串
*/
private String assembleHealingInput(LifeEventCreateRequest request) {
StringBuilder sb = new StringBuilder();
// 标题
if (StringUtils.hasText(request.getTitle())) {
sb.append("【事件标题】").append(request.getTitle()).append("\n");
}
// 发生时间
if (StringUtils.hasText(request.getEventDate())) {
sb.append("【发生时间】").append(request.getEventDate()).append("\n");
}
// 经历详解
if (StringUtils.hasText(request.getContent())) {
sb.append("【经历详解】").append(request.getContent()).append("\n");
}
// 情绪类型
if (StringUtils.hasText(request.getEmotionType())) {
sb.append("【情绪类型】").append(request.getEmotionType()).append("\n");
}
return sb.toString().trim();
}
@Override @Override
public LifeEventResponse updateEvent(LifeEventUpdateRequest request) { public LifeEventResponse updateEvent(LifeEventUpdateRequest request) {
LifeEvent event = this.getById(request.getId()); LifeEvent event = this.getById(request.getId());
+44 -10
View File
@@ -71,20 +71,47 @@ def run_command(cmd, cwd=None, shell=True, capture=True):
return False, "", str(e) return False, "", str(e)
def exec_ssh_cmd(cmd): def exec_ssh_cmd(cmd, timeout=30):
"""通过SSH执行远程命令""" """通过SSH执行远程命令"""
ssh_cmd = f'ssh {USERNAME}@{SERVER_IP} "{cmd}"' ssh_cmd = f'ssh -o ConnectTimeout=10 -o BatchMode=yes {USERNAME}@{SERVER_IP} "{cmd}"'
return run_command(ssh_cmd) try:
result = subprocess.run(
ssh_cmd,
shell=True,
capture_output=True,
text=True,
timeout=timeout
)
return result.returncode == 0, result.stdout.strip(), result.stderr.strip()
except subprocess.TimeoutExpired:
log_error(f"SSH命令超时: {cmd}")
return False, "", "命令执行超时"
except Exception as e:
return False, "", str(e)
def scp_upload(local_path, remote_path, recursive=False): def scp_upload(local_path, remote_path, recursive=False):
"""通过SCP上传文件或目录""" """通过SCP上传文件或目录"""
r_flag = "-r" if recursive else "" r_flag = "-r" if recursive else ""
scp_cmd = f'scp {r_flag} "{local_path}" {USERNAME}@{SERVER_IP}:{remote_path}' scp_cmd = f'scp -o ConnectTimeout=10 -o BatchMode=yes {r_flag} "{local_path}" {USERNAME}@{SERVER_IP}:{remote_path}'
success, stdout, stderr = run_command(scp_cmd) try:
if not success: result = subprocess.run(
log_error(f"SCP上传失败: {stderr}") scp_cmd,
return success shell=True,
capture_output=True,
text=True,
timeout=120 # 上传文件给更长时间
)
if result.returncode != 0:
log_error(f"SCP上传失败: {result.stderr}")
return False
return True
except subprocess.TimeoutExpired:
log_error("SCP上传超时")
return False
except Exception as e:
log_error(f"SCP上传异常: {e}")
return False
def check_env(): def check_env():
@@ -136,11 +163,15 @@ def deploy():
# 1. 创建远程目录 # 1. 创建远程目录
log_info("创建远程目录...") log_info("创建远程目录...")
exec_ssh_cmd(f"mkdir -p {release_path}") success, _, err = exec_ssh_cmd(f"mkdir -p {release_path}")
if not success:
log_error(f"创建远程目录失败: {err}")
sys.exit(1)
# 2. 上传文件 # 2. 上传文件
log_info("上传文件到服务器...") log_info("上传文件到服务器...")
for item in DIST_DIR.iterdir(): for item in DIST_DIR.iterdir():
log_info(f" 上传: {item.name}")
if item.is_file(): if item.is_file():
if not scp_upload(item, f"{release_path}/"): if not scp_upload(item, f"{release_path}/"):
log_error("文件上传失败") log_error("文件上传失败")
@@ -160,7 +191,10 @@ def deploy():
# 检查目标路径是否为普通目录 # 检查目标路径是否为普通目录
exec_ssh_cmd(f"if [ -d '{LINK_PATH}' ] && [ ! -L '{LINK_PATH}' ]; then mv '{LINK_PATH}' '{LINK_PATH}_backup_$(date +%s)'; fi") exec_ssh_cmd(f"if [ -d '{LINK_PATH}' ] && [ ! -L '{LINK_PATH}' ]; then mv '{LINK_PATH}' '{LINK_PATH}_backup_$(date +%s)'; fi")
# 创建软链接 # 创建软链接
exec_ssh_cmd(f"ln -snf '{release_path}' '{LINK_PATH}'") success, _, err = exec_ssh_cmd(f"ln -snf '{release_path}' '{LINK_PATH}'")
if not success:
log_error(f"切换版本失败: {err}")
sys.exit(1)
log_info(f"部署完成!当前版本指向: {release_path}") log_info(f"部署完成!当前版本指向: {release_path}")
+55 -2
View File
@@ -98,7 +98,9 @@ const transformToBackendFormat = (frontendData) => {
style, style,
length, length,
content, content,
isSelected isSelected,
character,
events
} = frontendData; } = frontendData;
// 解析内容生成标题和各部分 // 解析内容生成标题和各部分
@@ -127,6 +129,55 @@ const transformToBackendFormat = (frontendData) => {
}); });
} }
// 格式化角色信息
let characterInfo = '';
if (character) {
const parts = [
`姓名:${character.nickname || '未设置'}`,
`性别:${character.gender || '未设置'}`,
`MBTI${character.mbti || '未设置'}`,
`星座:${character.zodiac || '未设置'}`,
`职业:${character.profession || '未设置'}`,
`兴趣爱好:${character.hobbies?.join(',') || '无'}`
];
if (character.future) {
if (character.future.vision) parts.push(`未来愿景:${character.future.vision}`);
if (character.future.ideal) parts.push(`理想生活:${character.future.ideal}`);
}
characterInfo = parts.join('\n');
}
// 格式化过往经历
let lifeEventsSummary = '';
const eventParts = [];
// 1. 核心记忆 (Childhood, Joy, Low from character data)
if (character) {
if (character.childhood?.text) {
eventParts.push(`【童年记忆】(${character.childhood.date || '未知时间'}): ${character.childhood.text}`);
}
if (character.joy?.text) {
eventParts.push(`【高光时刻】(${character.joy.date || '未知时间'}): ${character.joy.text}`);
}
if (character.low?.text) {
eventParts.push(`【至暗时刻】(${character.low.date || '未知时间'}): ${character.low.text}`);
}
}
// 2. 详细人生事件
if (events && Array.isArray(events)) {
events.forEach(e => {
const dateStr = e.time || e.eventDate || '未知时间';
const titleStr = e.title || '无标题';
const contentStr = e.content || '';
eventParts.push(`【人生事件】(${dateStr}) ${titleStr}${contentStr ? ': ' + contentStr : ''}`);
});
}
lifeEventsSummary = eventParts.join('\n');
return { return {
id, id,
title, title,
@@ -138,7 +189,9 @@ const transformToBackendFormat = (frontendData) => {
plotClimax, plotClimax,
plotEnding, plotEnding,
plotJson: content ? { fullContent: content } : null, plotJson: content ? { fullContent: content } : null,
isSelected isSelected,
characterInfo,
lifeEventsSummary
}; };
}; };
+8 -6
View File
@@ -2,7 +2,6 @@ import { useState, useEffect } from 'react';
import { UserCog, PenTool, Sparkles, BookOpen, Loader2 } from 'lucide-react'; import { UserCog, PenTool, Sparkles, BookOpen, Loader2 } from 'lucide-react';
import { GlassCard, GlassButton, GlassInput, GlassSelect } from '../components/ui'; import { GlassCard, GlassButton, GlassInput, GlassSelect } from '../components/ui';
import useStore from '../store/useStore'; import useStore from '../store/useStore';
import { generateEpicScript } from '../services/ai';
import { scriptStyles, scriptLengths } from '../utils/constants'; import { scriptStyles, scriptLengths } from '../utils/constants';
/** /**
@@ -48,12 +47,15 @@ const ScriptView = ({ onOpenProfile }) => {
setIsLoading(true); setIsLoading(true);
try { try {
const content = await generateEpicScript( // 直接调用后端创建接口,由后端调用AI生成
{ theme, style, length, character: registrationData }, await addScript({
lifeEvents theme,
); style,
length,
character: registrationData,
events: lifeEvents
});
addScript({ theme, style, length, content });
setTheme(''); setTheme('');
} catch (error) { } catch (error) {
console.error('Failed to generate script:', error); console.error('Failed to generate script:', error);
+76 -13
View File
@@ -3,7 +3,76 @@ import { Plus, Wind, Sparkles } from 'lucide-react';
import { GlassCard, GlassButton, GlassInput, GlassTextarea } from '../components/ui'; import { GlassCard, GlassButton, GlassInput, GlassTextarea } from '../components/ui';
import Modal from '../components/Modal'; import Modal from '../components/Modal';
import useStore from '../store/useStore'; import useStore from '../store/useStore';
import { analyzeLifeEvent } from '../services/ai';
/**
* 格式化 AI 反馈内容的组件
*/
const FeedbackContent = ({ content }) => {
if (!content) return null;
// 检查是否为结构化格式 (包含分隔符 --- 和标题标识 ####)
const isStructured = content.includes('---') && content.includes('####');
if (!isStructured) {
return (
<p className="text-xs italic text-white/50 leading-loose whitespace-pre-wrap">
{content}
</p>
);
}
// 解析结构化内容
const sections = content.split('---')
.map(s => s.trim())
.filter(s => s && s.length > 0);
return (
<div className="space-y-5 mt-2">
{sections.map((section, index) => {
// 移除 #### 前缀
const cleanSection = section.replace(/^####\s*/, '');
// 提取标题 (通常在 【】 中)
const titleMatch = cleanSection.match(/【(.*?)】/);
const title = titleMatch ? titleMatch[1] : '';
// 提取正文
let body = cleanSection;
if (titleMatch) {
body = cleanSection.replace(titleMatch[0], '').trim();
}
if (!title && !body) return null;
return (
<div key={index} className="text-xs leading-relaxed">
{title && (
<h5 className="text-orange-100 font-bold mb-2 flex items-center gap-2 text-[11px] tracking-wide">
{title}
</h5>
)}
<div className="text-white/60 pl-3 border-l-2 border-orange-200/10 space-y-1">
{body.split('\n').map((line, i) => {
const trimmedLine = line.trim();
if (!trimmedLine) return null;
// 简单的列表项处理
if (trimmedLine.startsWith('*') || trimmedLine.startsWith('-')) {
return (
<div key={i} className="flex gap-2 pl-1">
<span className="text-orange-200/40"></span>
<span>{trimmedLine.substring(1).trim()}</span>
</div>
);
}
return <p key={i}>{trimmedLine}</p>;
})}
</div>
</div>
);
})}
</div>
);
};
/** /**
* TimelineView 组件 * TimelineView 组件
@@ -42,20 +111,16 @@ const TimelineView = () => {
setIsLoading(true); setIsLoading(true);
try { try {
// 调用 AI 分析 // 直接调用后端添加事件,由后端调用AI进行疗愈分析
const aiFeedback = await analyzeLifeEvent(eventForm); await addLifeEvent({
...eventForm
// 添加事件
addLifeEvent({
...eventForm,
aiFeedback
}); });
// 重置表单并关闭模态框 // 重置表单并关闭模态框
setEventForm({ title: '', time: '', content: '' }); setEventForm({ title: '', time: '', content: '' });
setIsModalOpen(false); setIsModalOpen(false);
} catch (error) { } catch (error) {
console.error('Failed to analyze event:', error); console.error('Failed to add event:', error);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@@ -124,15 +189,13 @@ const TimelineView = () => {
{/* AI 反馈区域 - 仅在有反馈时显示 */} {/* AI 反馈区域 - 仅在有反馈时显示 */}
{event.aiFeedback && ( {event.aiFeedback && (
<div className="ai-glow-card p-5 rounded-2xl bg-orange-200/[0.02] border border-orange-200/5"> <div className="ai-glow-card p-5 rounded-2xl bg-orange-200/[0.02] border border-orange-200/5">
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-4">
<Sparkles className="w-3 h-3 text-orange-200" /> <Sparkles className="w-3 h-3 text-orange-200" />
<span className="text-[9px] uppercase tracking-[0.2em] text-orange-200/60 font-bold"> <span className="text-[9px] uppercase tracking-[0.2em] text-orange-200/60 font-bold">
引路人洞察 引路人洞察
</span> </span>
</div> </div>
<p className="text-xs italic text-white/50 leading-loose"> <FeedbackContent content={event.aiFeedback} />
{event.aiFeedback}
</p>
</div> </div>
)} )}
</GlassCard> </GlassCard>
+5 -1
View File
@@ -6,7 +6,11 @@ alter table emotion_museum.t_user_profile
alter table emotion_museum.t_user_profile alter table emotion_museum.t_user_profile
add profession varchar(100) null comment '职业'; add profession varchar(100) null comment '职业';
-- 职业 -- 消息
alter table emotion_museum.t_message
add message_order varchar(100) null comment '职业';
-- AI
alter table emotion_museum.t_ai_config alter table emotion_museum.t_ai_config
add client_id VARCHAR(200) COMMENT '客户端ID (OAuth认证)', add client_id VARCHAR(200) COMMENT '客户端ID (OAuth认证)',
add client_secret VARCHAR(500) COMMENT '客户端密钥 (OAuth认证,加密存储)', add client_secret VARCHAR(500) COMMENT '客户端密钥 (OAuth认证,加密存储)',
+21 -1
View File
@@ -70,4 +70,24 @@ INSERT INTO t_dictionary (
-- ============================================================================ -- ============================================================================
COMMIT; COMMIT;
SELECT '字典数据初始化完成' AS result; SELECT '字典数据初始化完成' AS result;
-- AI接口配置初始化脚本
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('3d895ae5b3ea11f0a59104d4c4548e0b', 'Coze开发环境测试配置', 'coze.chat.development', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', 'v3', null, '7523042446285439016', '7523047462895796287', 10000, 2, 500, 2000, 0.80, 1.00, 1, 1, 0, 0, 'chat', 80, 0.000500, 0.001000, 'USD', 120, 7200, 172800, 1, 0, 'development', '{"Content-Type": "application/json"}', '{"parameters": {}}', null, null, 5, 'Coze平台开发环境测试配置,用于开发和调试', '1. 开发环境专用配置
2. 较短的超时时间和更高的请求限制
3. 用于功能测试和调试', null, '2025-10-28 18:38:28', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 18:52:50', 1, null, null, null, null);
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('3d5cfb03b3ea11f0a59104d4c4548e0b', 'Coze聊天', 'coze.chat.default', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', '', '', '7523042446285439016', '7585860129955528710', 30000, 3, 1000, 4000, 0.70, 1.00, 1, 1, 0, 0, 'chat', 100, 0.001000, 0.002000, 'USD', 60, 3600, 86400, 1, 1, 'production', '{"Content-Type": "application/json"}', '{"parameters": {"input": "今天心情非常不好", "user_id": "19928748688"}}', '', '', 5, 'Coze平台的默认聊天机器人配置,用于日常情绪对话', '1. 需要配置有效的API Token
2. 需要配置Bot ID和Workflow ID
3. 支持流式输出和函数调用', null, '2025-10-28 18:38:28', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 19:03:39', 0, null, '', '', '');
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('261808289317130240', 'Coze人生剧本生成', 'coze.course.life.generate', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', '', '', '7523042446285439016', '7586262962160762926', 30000, 3, 1000, 4000, 0.70, 1.00, 1, 0, 0, 0, 'content_generation', 0, 0.000000, 0.000000, 'USD', 60, 3600, 86400, 1, 0, 'production', '{}', '{"bot_id": "7523042446285439016", "parameters": {"input": "成为超级大富翁", "user_id": "19928748688"}, "workflow_id": "7586262962160762926"}', '', '', 5, '', '', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 18:52:40', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 19:10:29', 0, null, '', '', '');
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('261823800167895040', 'Coze日记总结', 'coze.user.dairy.summary', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', '', '', '7529062814150295595', '7586224423528251402', 30000, 3, 1000, 4000, 0.70, 1.00, 1, 0, 0, 0, 'chat', 0, 0.000000, 0.000000, 'USD', 60, 3600, 86400, 1, 0, 'production', '{"Content-Type": "application/json"}', '{"parameters": {"input": "今天心情非常不好", "user_id": "19928748688"}}', '', '', 5, '', '', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 19:54:18', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 19:54:18', 0, null, '', '', '');
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('261824790673756160', 'Coze用户故事', 'coze.user.chose.story', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', '', '', '', '7585870811114766387', 30000, 3, 1000, 4000, 0.70, 1.00, 1, 0, 0, 0, 'content_generation', 0, 0.000000, 0.000000, 'USD', 60, 3600, 86400, 1, 0, 'production', '{}', '{"parameters": {"input": "今天心情非常不好", "user_id": "19928748688"}, "workflow_id": "7585870811114766387"}', '', '', 5, '', '', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 19:58:15', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 19:58:15', 0, null, '', '', '');
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('261825352626606080', 'Coze用户状态分析', 'coze.user.life.state', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', '', '', '', '7585860129955528710', 30000, 3, 1000, 4000, 0.70, 1.00, 1, 0, 0, 0, 'chat', 0, 0.000000, 0.000000, 'USD', 60, 3600, 86400, 1, 0, 'production', '{}', '{"parameters": {"input": "今天心情非常不好", "user_id": "19928748688"}, "workflow_id": "7585860129955528710"}', '', '', 5, '', '', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 20:00:29', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 20:00:29', 0, null, '', '', '');
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('3d7898a2b3ea11f0a59104d4c4548e0b', 'Coze情绪分析配置', 'coze.emotion_analysis.default', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', 'v3', null, '7529062814150295595', '7523047462895796287', 45000, 3, 1500, 6000, 0.20, 1.00, 0, 1, 0, 0, 'emotion_analysis', 95, 0.001000, 0.002000, 'USD', 20, 1200, 28800, 1, 1, 'production', null, null, null, null, 5, 'Coze平台的情绪分析配置,用于分析用户聊天记录的情绪状态', '1. 使用最低的temperature以获得准确的情绪分析
2. 支持函数调用以获取结构化的分析结果
3. 增加超时时间以处理复杂的情绪分析', null, '2025-10-28 18:38:28', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 20:04:28', 1, null, null, null, null);
INSERT INTO emotion_museum.t_ai_config (id, config_name, config_key, config_type, provider, api_base_url, api_token, api_version, model_name, bot_id, workflow_id, timeout_ms, retry_count, retry_delay_ms, max_tokens, temperature, top_p, support_stream, support_function_call, support_vision, support_file_upload, usage_scenario, priority, input_price_per_1k, output_price_per_1k, currency, rate_limit_per_minute, rate_limit_per_hour, rate_limit_per_day, is_enabled, is_default, environment, custom_headers, custom_params, webhook_url, health_check_url, health_check_interval_minutes, description, usage_notes, create_by, create_time, update_by, update_time, is_deleted, remarks, client_id, client_secret, grant_type) VALUES ('3d6be3b6b3ea11f0a59104d4c4548e0b', 'Coze对话总结配置', 'coze.summary.default', 'coze', 'coze', 'https://api.coze.cn/v1/workflow/stream_run', 'sat_or7exwGUw4FtwOCakp5e9vhnPJpIQBMjv8XofyMqdmA2LMiJ3jC900dLAaZ7hdjd', 'v3', null, '7529062814150295595', '7523047462895796287', 30000, 3, 1000, 8000, 0.30, 1.00, 0, 0, 0, 0, 'summary', 90, 0.001000, 0.002000, 'USD', 30, 1800, 43200, 1, 1, 'production', null, null, null, null, 5, 'Coze平台的对话总结配置,专门用于生成对话摘要和情绪分析', '1. 使用较低的temperature以获得更稳定的总结结果
2. 增加max_tokens以支持长文本总结
3. 不支持流式输出', null, '2025-10-28 18:38:28', 'adce16b80c81fa25b7aa13a050f822cc', '2025-12-23 20:04:31', 1, null, null, null, null);
@@ -1515,7 +1515,7 @@ const handleSaveTestConfig = async () => {
} }
// 调用更新接口 // 调用更新接口
const res = await updateAiConfigFromTest(updateData) const res = await updateAiConfigFromTest(updateData) as any
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('测试配置已保存') ElMessage.success('测试配置已保存')