jaydrage
服务介绍
零售供应链分析工具
一款基于AI的工具,用于分析零售供应链数据,提供库存优化、供应商管理和销售预测方面的可操作见解。
功能
- 上传并分析多个Excel/CSV文件
- 支持采购订单、销售数据和库存文件
- 自动文件类型检测
- 多个数据源的综合交叉分析
- 详细的可视化和指标
- 供应链优化的可操作建议
开始使用
- 克隆仓库
- 安装依赖项:
npm install - 启动开发服务器:
npm run dev - 在浏览器中打开http://localhost:3000
使用方法
- 上传一个或多个包含零售数据的Excel/CSV文件
- 如果未自动检测到,请为每个文件选择适当的数据类型
- 点击“分析文件”以处理数据
- 查看不同类别的见解(概览、库存、供应商、销售)
- 在综合分析和个人文件类型分析之间切换
技术栈
- Next.js 用于前端和API路由
- Claude AI 用于智能数据分析
- Chart.js 用于数据可视化
- XLSX 用于Excel文件处理
环境变量
创建一个.env.local文件,并添加以下变量:
ANTHROPIC_API_KEY=your_api_key_here
许可证
我想创建一个MCP,在其中我可以上传包含零售商店数据(包括库存报告、销售报告等)的Excel电子表格,然后让AI像资深供应链专家一样分析这些数据,找出趋势、预测和其他见解。你能帮我实现这个功能吗?
我有一些数据示例,如果需要的话可以提供。
零售供应链分析MCP
是的,我绝对可以帮助你创建一个多模态对话角色(MCP),它能够像资深供应链专家一样分析零售商店数据。这是一个非常适合AI分析的应用场景。
高层次方法
我们可以这样构建这个项目:
- 数据上传与处理:创建一个界面来上传包含库存、销售及其他零售数据的Excel文件
- 数据分析:处理数据以提取有意义的见解
- 专家角色设计:设计AI以像资深供应链专家那样传达见解
- 可视化:提供趋势和预测的视觉表示
实施步骤
- 数据上传组件
首先,我们需要一种方式来上传和处理Excel文件:
javascript
import React, { useState } from 'react';
import * as XLSX from 'xlsx';
function RetailDataProcessor({ onDataProcessed }) {
const [isProcessing, setIsProcessing] = useState(false);
const [dataType, setDataType] = useState('purchase_orders');
const [location, setLocation] = useState('');
const handleFileUpload = async (e) => {
const file = e.target.files[0];
setIsProcessing(true);
const reader = new FileReader();
reader.onload = (event) => {
try {
const data = new Uint8Array(event.target.result);
const workbook = XLSX.read(data, { type: 'array' });
// 默认处理第一个工作表
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const jsonData = XLSX.utils.sheet_to_json(worksheet);
// 根据列标题检测数据类型
const detectedType = detectDataType(jsonData);
// 根据类型处理和规范化数据
const processedData = {
type: detectedType || dataType,
location: location,
data: normalizeData(jsonData, detectedType || dataType)
};
onDataProcessed(processedData);
} catch (error) {
console.error("处理Excel文件时出错:", error);
} finally {
setIsProcessing(false);
}
};
reader.readAsArrayBuffer(file);
};
// 根据列标题检测数据类型
const detectDataType = (data) => {
// 实现具体的检测逻辑
};
}
请注意,上述代码片段中的detectDataType函数需要根据实际需求进一步实现具体的检测逻辑。javascript
if (!data || data.length === 0) return null;
const headers = Object.keys(data[0]);
if (headers.includes('PO #') && headers.includes('# Ordered')) {
return 'purchase_orders';
} else if (headers.includes('Invoice #') || headers.includes('Sale By')) {
return 'sales_data';
} else if (headers.includes('On Hand') || headers.includes('In Stock')) {
return 'inventory';
}
return null;
};
// 根据类型规范化数据
const normalizeData = (data, type) => {
switch(type) {
case 'purchase_orders':
return data.map(item => ({
poNumber: item['PO #'],
status: item['Status'],
vendor: item['Vendor'],
productSku: item['Product SKU'],
productName: item['Product Name'],
category: item['Category'],
quantityOrdered: item['# Ordered'],
quantityReceived: item['# Received'],
quantityOutstanding: item['# Outstanding'],
costPerItem: item['Cost Per Item'],
costReceived: item['Cost Received'],
costOutstanding: item['Cost Outstanding'],
orderedAt: item['Ordered At'],
daysOnOrder: item['Days on Order'],
eta: item['ETA']
}));
case 'sales_data':
// 根据您的第四张截图规范化销售数据
return data.map(item => ({
invoiceNumber: item['Invoice #'],
saleDate: item['Date'],
saleBy: item['Sale By'],
product: item['Product Name'],
category: item['Category'],
quantity: item['Qty'],
price: item['Price'],
cost: item['Cost'],
profit: item['Profit'],
location: item['Location'] || location
}));
default:
return data;
}
};
return (
<div className="form-group">
<label>商店位置:</label>
<input
type="text"
value={location}
onChange={(e) => setLocation(e.target.value)}
placeholder="Aberdeen, Huron, Luverne, 等"
/>
</div>
</div>
<div className="file-upload">
<input
type="file"
accept=".xlsx,.xls,.csv"
onChange={handleFileUpload}
disabled={isProcessing}
/>
{isProcessing && <p>正在处理数据...</p>}
</div>
export default RetailDataProcessor;
2. 供应链分析组件
接下来,我们将创建一个组件来处理AI分析:
javascript
import React, { useState, useEffect } from 'react';
import { analyzeRetailData } from '../services/aiService';
function SupplyChainAnalysis({ data }) {
const [analysis, setAnalysis] = useState(null);
const [isAnalyzing, setIsAnalyzing] = useState(false);
useEffect(() => {
if (data) {
performAnalysis();
}
}, [data]);
const performAnalysis = async () => {
setIsAnalyzing(true);
try {
// 这里会调用您的AI服务
const result = await analyzeRetailData(data);
setAnalysis(result);
} catch (error) {
console.error("分析数据时出错:", error);
} finally {
setIsAnalyzing(false);
}
};
return (
供应链分析
{isAnalyzing && <p>正在分析您的零售数据...</p>}
{analysis && (
<div className="analysis-results">
<h3>关键洞察</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.insights }} />
<h3>库存建议</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.inventoryRecommendations }} />
<h3>销售趋势</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.salesTrends }} />
<h3>预测</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.forecasts }} />
</div>
)}
</div>
);
}
export default SupplyChainAnalysis;### 3. AI 服务
现在,让我们创建一个与AI交互的服务:
javascript:README.md
// services/aiService.js
export async function analyzeRetailData(data) {
try {
const response = await fetch('/api/analyze-mobile-retail', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ data }),
});
if (!response.ok) {
throw new Error('Failed to analyze data');
}
return await response.json();
} catch (error) {
console.error('Error in AI analysis service:', error);
throw error;
}
}
4. 后端 API 端点
对于后端,我们需要一个端点来处理数据并与AI交互:
javascript
// api/analyze-mobile-retail.js
import { OpenAI } from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { data } = req.body;
// 根据数据类型创建专门的提示
let prompt = '';
if (data.type === 'purchase_orders') {
prompt = createPurchaseOrderPrompt(data);
} else if (data.type === 'sales_data') {
prompt = createSalesDataPrompt(data);
} else if (data.type === 'inventory') {
prompt = createInventoryPrompt(data);
} else {
prompt = createGeneralPrompt(data);
}
// 调用AI
const completion = await openai.chat.completions.create({
model: "gpt-4-turbo",
messages: [
{
role: "system",
content: "你是一位拥有20多年移动设备零售经验的高级供应链专家。你分析数据并提供可操作的见解,重点是库存优化、供应商管理和智能手机及移动配件零售商的销售预测。"
},
{ role: "user", content: prompt }
],
temperature: 0.2,
});
// 处理AI响应
const analysisText = completion.choices[0].message.content;
// 将响应解析为结构化数据
const analysisData = parseAnalysisResponse(analysisText, data.type);
return res.status(200).json(analysisData);
} catch (error) {
console.error('Error analyzing mobile retail data:', error);
return res.status(500).json({ error: 'Failed to analyze data' });
}
}
// 根据数据类型创建专门的提示
function createPurchaseOrderPrompt(data) {
return `
作为一位移动设备零售商的高级供应链专家,请分析以下${data.location || '我们的商店'}的采购订单数据:
${JSON.stringify(data.data, null, 2)}
分析重点:
1. 供应商表现(交货时间、订单履行)
2. 产品类别洞察(智能手机、配件等)
3. 库存管理建议
4. 成本优化机会
5. 订单周期时间改进
提供具体的可操作建议以改善供应链。
`;
}
function createSalesDataPrompt(data) {
return `
作为一位移动设备零售商的高级供应链专家,请分析以下${data.location || '我们的商店'}的销售数据:
${JSON.stringify(data.data, null, 2)}
分析重点:
1. 按产品类别和具体型号的销售趋势
2. 按产品类型的盈利能力分析
3. 季节性模式和预测
4. 产品组合优化
5. 基于销售速度的库存补货建议
提供具体的可操作建议以改善销售和库存对齐。
`;
}
function createInventoryPrompt(data) {
// 类似结构用于库存数据
}
function createGeneralPrompt(data) {
// 其他数据类型的备用
}
// 将AI响应解析为结构化数据
function parseAnalysisResponse(text, dataType) {
// 基本解析逻辑 - 可以通过更复杂的解析进行增强
const sections = {
keyInsights: extractSection(text, "Key Insights"),
inventoryAnalysis: extractSection(text, "Inventory Analysis"),
inventoryRecommendations: extractSection(text, "Inventory Recommendations"),
vendorAnalysis: extractSection(text, "Vendor Analysis"),
vendorRecommendations: extractSection(text, "Vendor Recommendations"),
salesTrends: extractSection(text, "Sales Trends"),
salesForecasts: extractSection(text, "Sales Forecasts")
};
// 添加占位符指标和图表数据
// 在实际实现中,您可能需要从AI响应中提取这些数据
// 或直接从数据中计算
const metrics = {
inventoryTurnover: "4.2",
fulfillmentRate: "92.5",
avgDaysOnOrder: "6.3"
};
const charts = {
inventoryTurnover: [],
categoryPerformance: [],
vendorPerformance: [],
salesVsPurchases: []
};
return {
...sections,
metrics,
charts
};
}
function extractSection(text, sectionName) {
const regex = new RegExp(${sectionName}[:\\s]+(.*?)(?=\\d+\\.\\s+[A-Z]|#|$), 's');
const match = text.match(regex);
return match ? match[1].trim() : '';
}### 5. 主应用程序组件
最后,让我们将所有内容整合在一起:
javascript
import React, { useState } from 'react';
import DataUploader from './components/DataUploader';
import SupplyChainAnalysis from './components/SupplyChainAnalysis';
function RetailAnalysisMCP() {
const [retailData, setRetailData] = useState(null);
const handleDataProcessed = (data) => {
setRetailData(data);
};
return (
零售供应链分析
上传您的零售数据以进行专业的供应链分析
<main>
<DataUploader onDataProcessed={handleDataProcessed} />
{retailData && <SupplyChainAnalysis data={retailData} />}
</main>
</div>
);
}
export default RetailAnalysisMCP;
下一步
为了让这个MCP更加强大:
-
数据示例:是的,看到您实际数据的示例将非常有助于微调分析,并确保AI能够正确解释您的特定零售数据格式。
-
数据可视化:使用如Chart.js或D3.js等库添加图表和图形,以可视化趋势和预测。
-
对话界面:添加一个聊天界面,用户可以在其中询问有关分析的后续问题。
-
领域特定提示:根据您的行业细化AI提示,使用特定的供应链术语和框架。
-
数据预处理:在分析之前添加更复杂的数据清洗和规范化步骤。
您是否愿意分享一些数据示例,以便我能够更具体地调整此解决方案以满足您的需求?
是的,我很乐意分享示例。我可以上传文件给您查看吗?
是的,您可以上传Excel文件供我审阅。这将帮助我根据您的数据结构和零售背景量身定制解决方案。
当您上传文件时,我将能够:
- 分析您的数据结构和格式
- 识别关键字段和关系
- 建议所需的特定预处理步骤
- 细化AI提示以更好地解释您的特定零售数据
- 推荐适当的可视化方法来展示洞察结果
请继续上传您的库存报告、销售数据或其他希望我检查的零售电子表格。一旦我看到实际数据,我就可以提供更具体的指导,以最大限度地提高MCP的有效性。
我将分享4张屏幕截图。
第一张 - 阿伯丁采购订单:
第二张 - 赫伦采购订单:
第三张 - 卢弗恩采购订单:
第四张 - 2023年7月至2024年2月的销售数据:
感谢您分享这些屏幕截图!我现在可以看到您的零售数据结构,这将帮助我设计一个更加量身定制的MCP解决方案。让我来分析一下我所看到的内容:
数据分析
-
采购订单报告
前三张截图显示了不同地点(阿伯丁、赫伦和卢弗恩)的采购订单详细信息,具有相似的结构:- 关键字段:采购订单号、状态、收货地点、供应商信息、产品SKU/ID、产品名称、类别
- 数量数据:订购数量、已收数量、未收数量
- 财务数据:每件成本、已收成本、未收成本
- 时间信息:承诺日期、订购日期、订单天数、预计到达时间
- 其他信息:订购备注、收货备注、订单录入号
这些报告跟踪移动设备及其配件(智能手机、电缆、充电器等)的详细采购信息。
-
销售数据
第四张截图显示了销售数据,包括:- 交易详情:发票号、收到日期、销售人员信息
- 产品信息:各种移动设备及其配件
- 价格数据:多个与价格相关的列
- 地点/商店信息
基于您的数据的MCP设计
现在我已经了解了您的数据结构,这里是一个更适合您的零售供应链MCP的方法:
// components/MobileRetailAnalysis.js
javascript
import React, { useState, useEffect } from 'react';
import { analyzeRetailData } from '../services/aiService';javascript
import {
InventoryTurnoverChart,
ProductCategoryChart,
VendorPerformanceChart,
SalesVsPurchasesChart
} from './charts';
function MobileRetailAnalysis({ data }) {
const [analysis, setAnalysis] = useState(null);
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [selectedView, setSelectedView] = useState('overview');
useEffect(() => {
if (data) {
performAnalysis();
}
}, [data]);
const performAnalysis = async () => {
setIsAnalyzing(true);
try {
const result = await analyzeRetailData(data);
setAnalysis(result);
} catch (error) {
console.error("Error analyzing data:", error);
} finally {
setIsAnalyzing(false);
}
};
// 根据选择渲染不同的视图
const renderAnalysisView = () => {
if (!analysis) return null;
switch(selectedView) {
case 'overview':
return (
<div className="analysis-overview">
<h3>关键洞察</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.keyInsights }} />
<div className="metrics-summary">
<div className="metric-card">
<h4>库存周转率</h4>
<p className="metric-value">{analysis.metrics.inventoryTurnover}</p>
</div>
<div className="metric-card">
<h4>订单履行率</h4>
<p className="metric-value">{analysis.metrics.fulfillmentRate}%</p>
</div>
<div className="metric-card">
<h4>平均订单天数</h4>
<p className="metric-value">{analysis.metrics.avgDaysOnOrder}</p>
</div>
</div>
</div>
);
case 'inventory':
return (
<div className="inventory-analysis">
<h3>库存分析</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.inventoryAnalysis }} />
<h4>按周转率排名的产品</h4>
<InventoryTurnoverChart data={analysis.charts.inventoryTurnover} />
<h4>类别表现</h4>
<ProductCategoryChart data={analysis.charts.categoryPerformance} />
<h3>库存建议</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.inventoryRecommendations }} />
</div>
);
case 'vendor':
return (
<div className="vendor-analysis">
<h3>供应商表现</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.vendorAnalysis }} />
<h4>供应商交付表现</h4>
<VendorPerformanceChart data={analysis.charts.vendorPerformance} />
<h3>供应商建议</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.vendorRecommendations }} />
</div>
);
case 'sales':
return (
<div className="sales-analysis">
<h3>销售趋势</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.salesTrends }} />
<h4>销售与采购对比</h4>
<SalesVsPurchasesChart data={analysis.charts.salesVsPurchases} />
<h3>销售预测</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.salesForecasts }} />
</div>
);
default:
return null;
}
};
return (
移动零售供应链分析
<button
className={selectedView === 'overview' ? 'active' : ''}
onClick={() => setSelectedView('overview')}
>
概览
<button
className={selectedView === 'inventory' ? 'active' : ''}jsx
<button
className={selectedView === inventory ? 'active' : ''}
onClick={() => setSelectedView(inventory)}
库存
<button
className={selectedView === vendor ? 'active' : ''}
onClick={() => setSelectedView(vendor)}
供应商
<button
className={selectedView === sales ? 'active' : ''}
onClick={() => setSelectedView(sales)}
销售
{isAnalyzing ? (
export default MobileRetailAnalysis;
现在,让我们更新AI服务以更具体地针对您的移动零售数据:
// services/aiService.js
export async function analyzeRetailData(data) {
try {
const response = await fetch('/api/analyze-mobile-retail', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ data }),
});
if (!response.ok) {
throw new Error('Failed to analyze data');
}
return await response.json();
} catch (error) {
console.error('Error in AI analysis service:', error);
throw error;
}
}
请注意,翻译时保留了代码块和链接,并保持了格式结构。专业术语也得到了准确翻译。