feat: 优化分析中心图表生成&markdown内容显示
This commit is contained in:
parent
a191d88ef2
commit
7c2752d074
@ -85,6 +85,12 @@
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
|
||||
:global {
|
||||
.ant-list-item-meta {
|
||||
width: 40vw !important;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
background: #1890ff;
|
||||
}
|
||||
@ -92,6 +98,7 @@
|
||||
.chartContainer {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
width: 40vw;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
||||
|
@ -29,6 +29,7 @@ import type { UploadFile } from 'antd/es/upload/interface';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import styles from './index.less';
|
||||
import * as XLSX from 'xlsx';
|
||||
import { marked } from 'marked';
|
||||
|
||||
const { Option } = Select;
|
||||
const { Dragger } = Upload;
|
||||
@ -107,6 +108,85 @@ const AnalysisCenter: React.FC = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
};
|
||||
|
||||
const handleSend = async () => {
|
||||
if (!inputValue.trim()) return;
|
||||
|
||||
const userMessage: Message = {
|
||||
type: 'user',
|
||||
content: inputValue,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
setMessages([...messages, userMessage]);
|
||||
setInputValue('');
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch('https://aizex.top/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer sk-Bp4AtAw19a6lENrPUQeqfiS9KP46Z5A43j4QkNeX4NRnGKMU'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'gpt-4o',
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: '你是一个数据分析专家,请根据用户输入进行分析并生成分析报告和 ECharts 图表配置。图表配置需要包含在 ```json 代码块中。'
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `请对以下内容进行${analysisOptions.find(opt => opt.value === analysisType)?.label},并给出专业的分析见解。
|
||||
分析报告之后,请生成一个用于可视化的 ECharts 配置对象(使用 \`\`\`json 包裹),配置中需要包含:
|
||||
1. 标题、图例、提示框等基本配置
|
||||
2. 合适的图表类型(折线图、柱状图、饼图等)
|
||||
3. 坐标轴配置(如果适用)
|
||||
4. 数据系列配置
|
||||
5. 主题色彩配置
|
||||
|
||||
分析内容:${inputValue}`
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
max_tokens: 2000
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
let chartOption;
|
||||
|
||||
try {
|
||||
const matches = result.choices[0].message.content.match(/```json\n([\s\S]*?)\n```/);
|
||||
if (matches && matches[1]) {
|
||||
chartOption = JSON.parse(matches[1]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析图表配置失败:', error);
|
||||
chartOption = generateMockChart(analysisType);
|
||||
}
|
||||
|
||||
const assistantMessage: Message = {
|
||||
type: 'assistant',
|
||||
content: result.choices[0].message.content.replace(/```json\n[\s\S]*?\n```/g, '').trim(),
|
||||
timestamp: Date.now(),
|
||||
charts: chartOption,
|
||||
};
|
||||
|
||||
setMessages(prev => [...prev, assistantMessage]);
|
||||
setLoading(false);
|
||||
scrollToBottom();
|
||||
} catch (error) {
|
||||
message.error('分析请求失败');
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const handleFileAnalysis = async (file: File) => {
|
||||
try {
|
||||
const reader = new FileReader();
|
||||
@ -133,12 +213,24 @@ const AnalysisCenter: React.FC = () => {
|
||||
body: JSON.stringify({
|
||||
model: 'gpt-4o',
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: '你是一个数据分析专家,请根据用户输入的数据进行分析并生成分析报告和 ECharts 图表配置。图表配置需要包含在 ```json 代码块中。'
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `请对以下数据进行${analysisOptions.find(opt => opt.value === analysisType)?.label},并给出专业的分析见解:\n${textContent}`
|
||||
text: `请对以下数据进行${analysisOptions.find(opt => opt.value === analysisType)?.label},并给出专业的分析见解。
|
||||
分析报告之后,请生成一个用于可视化的 ECharts 配置对象(使用 \`\`\`json 包裹),配置中需要包含:
|
||||
1. 标题、图例、提示框等基本配置
|
||||
2. 合适的图表类型(折线图、柱状图、饼图等)
|
||||
3. 坐标轴配置(如果适用)
|
||||
4. 数据系列配置
|
||||
5. 主题色彩配置
|
||||
|
||||
数据内容:\n${textContent}`
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -148,6 +240,18 @@ const AnalysisCenter: React.FC = () => {
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
let chartOption;
|
||||
|
||||
try {
|
||||
const matches = result.choices[0].message.content.match(/```json\n([\s\S]*?)\n```/);
|
||||
if (matches && matches[1]) {
|
||||
chartOption = JSON.parse(matches[1]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析图表配置失败:', error);
|
||||
message.error('图表生成失败,使用默认图表');
|
||||
chartOption = generateMockChart(analysisType);
|
||||
}
|
||||
|
||||
const userMessage: Message = {
|
||||
type: 'user',
|
||||
@ -157,9 +261,12 @@ const AnalysisCenter: React.FC = () => {
|
||||
|
||||
const assistantMessage: Message = {
|
||||
type: 'assistant',
|
||||
content: result.choices[0].message.content,
|
||||
content: marked(result.choices[0].message.content
|
||||
.replace(/```json\n[\s\S]*?\n```/g, '') // 先移除 JSON 代码块
|
||||
.trim()
|
||||
),
|
||||
timestamp: Date.now(),
|
||||
charts: generateMockChart(analysisType),
|
||||
charts: chartOption,
|
||||
};
|
||||
|
||||
setMessages(prev => [...prev, userMessage, assistantMessage]);
|
||||
@ -179,41 +286,6 @@ const AnalysisCenter: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSend = async () => {
|
||||
if (!inputValue.trim()) return;
|
||||
|
||||
const userMessage: Message = {
|
||||
type: 'user',
|
||||
content: inputValue,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
setMessages([...messages, userMessage]);
|
||||
setInputValue('');
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
// 这里应该调用后端API进行分析
|
||||
// const response = await analyzeData({ type: analysisType, message: inputValue });
|
||||
|
||||
// 模拟API响应
|
||||
setTimeout(() => {
|
||||
const assistantMessage: Message = {
|
||||
type: 'assistant',
|
||||
content: generateMockResponse(analysisType),
|
||||
timestamp: Date.now(),
|
||||
charts: generateMockChart(analysisType),
|
||||
};
|
||||
setMessages(prev => [...prev, assistantMessage]);
|
||||
setLoading(false);
|
||||
scrollToBottom();
|
||||
}, 1500);
|
||||
} catch (error) {
|
||||
message.error('分析请求失败');
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const generateMockResponse = (type: string) => {
|
||||
const responses: { [key: string]: string } = {
|
||||
predictive: '根据历史数据分析,预计未来三个月的销售增长率将达到15%,主要增长点来自新市场的开拓。',
|
||||
@ -276,6 +348,7 @@ const AnalysisCenter: React.FC = () => {
|
||||
className={styles.messageList}
|
||||
itemLayout="horizontal"
|
||||
dataSource={messages}
|
||||
// 在 List 组件的 renderItem 部分修改
|
||||
renderItem={item => (
|
||||
<List.Item className={item.type === 'user' ? styles.userMessage : styles.assistantMessage}>
|
||||
<Card className={styles.messageCard}>
|
||||
@ -289,9 +362,10 @@ const AnalysisCenter: React.FC = () => {
|
||||
}
|
||||
title={item.type === 'user' ? '你' : 'AI 助手'}
|
||||
description={
|
||||
<div style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
|
||||
{item.content}
|
||||
</div>
|
||||
<div
|
||||
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
|
||||
dangerouslySetInnerHTML={{ __html: item.content }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{item.charts && (
|
||||
@ -338,4 +412,6 @@ const AnalysisCenter: React.FC = () => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default AnalysisCenter;
|
Loading…
x
Reference in New Issue
Block a user