Retail Supply Chain Analysis MCP
使用户能够上传零售数据,分析趋势,优化库存,并使用人工智能驱动的洞察预测销售额,相当于一位资深供应链专家。
README
# 零售供应链分析工具
一个由 AI 驱动的工具,用于分析零售供应链数据,为库存优化、供应商管理和销售预测提供可操作的见解。
## 功能
- 上传和分析多个 Excel/CSV 文件
- 支持采购订单、销售数据和库存文件
- 自动文件类型检测
- 多个数据源的组合交叉分析
- 详细的可视化和指标
- 针对供应链优化的可操作建议
## 快速上手
1. 克隆存储库
2. 安装依赖项:`npm install`
3. 启动开发服务器:`npm run dev`
4. 在浏览器中打开 [http://localhost:3000](http://localhost:3000)
## 用法
1. 上传一个或多个包含零售数据的 Excel/CSV 文件
2. 如果未自动检测到,请为每个文件选择适当的数据类型
3. 点击“分析文件”以处理数据
4. 查看不同类别(概览、库存、供应商、销售)的见解
5. 在组合分析和单个文件类型分析之间切换
## 技术栈
- Next.js 用于前端和 API 路由
- Claude AI 用于智能数据分析
- Chart.js 用于数据可视化
- XLSX 用于 Excel 文件处理
## 环境变量
创建一个包含以下变量的 `.env.local` 文件:
ANTHROPIC_API_KEY=your_api_key_here
## 许可证
[MIT](LICENSE)
我想创建一个 MCP,我可以上传包含零售商店数据的 Excel 电子表格,包括库存报告、销售报告等,然后让 AI 分析数据以获取趋势、预测和其他见解,就像 AI 是零售商的高级供应链专家一样。 你能帮我吗?
如果需要,我可以提供数据示例。
###
零售供应链分析 MCP
是的,我绝对可以帮助您创建一个多模态对话式角色 (MCP),像高级供应链专家一样分析零售商店数据。 这是 AI 分析的一个极好的用例。
高层次方法
以下是我们如何构建这个项目:
数据上传和处理:创建一个界面来上传包含库存、销售和其他零售数据的 Excel 文件
数据分析:处理数据以提取有意义的见解
专家角色:设计 AI 以像高级供应链专家一样传达见解
可视化:提供趋势和预测的可视化表示
实施步骤
1. 数据上传组件
首先,我们需要一种上传和处理 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' });
// Process the first sheet by default
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const jsonData = XLSX.utils.sheet_to_json(worksheet);
// Detect data type based on column headers
const detectedType = detectDataType(jsonData);
// Process and normalize the data based on type
const processedData = {
type: detectedType || dataType,
location: location,
data: normalizeData(jsonData, detectedType || dataType)
};
onDataProcessed(processedData);
} catch (error) {
console.error("Error processing Excel file:", error);
} finally {
setIsProcessing(false);
}
};
reader.readAsArrayBuffer(file);
};
// Detect data type based on column headers
const detectDataType = (data) => {
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;
};
// Normalize data based on type
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':
// Normalize sales data based on your fourth screenshot
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="data-processor">
<div className="form-controls">
<div className="form-group">
<label>Data Type:</label>
<select
value={dataType}
onChange={(e) => setDataType(e.target.value)}
>
<option value="purchase_orders">Purchase Orders</option>
<option value="sales_data">Sales Data</option>
<option value="inventory">Inventory</option>
</select>
</div>
<div className="form-group">
<label>Store Location:</label>
<input
type="text"
value={location}
onChange={(e) => setLocation(e.target.value)}
placeholder="Aberdeen, Huron, Luverne, etc."
/>
</div>
</div>
<div className="file-upload">
<input
type="file"
accept=".xlsx,.xls,.csv"
onChange={handleFileUpload}
disabled={isProcessing}
/>
{isProcessing && <p>Processing data...</p>}
</div>
</div>
);
}
export default RetailDataProcessor;
2. 供应链分析组件
接下来,我们将创建一个组件来处理 AI 分析:
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 {
// This would call your AI service
const result = await analyzeRetailData(data);
setAnalysis(result);
} catch (error) {
console.error("Error analyzing data:", error);
} finally {
setIsAnalyzing(false);
}
};
return (
<div className="analysis-container">
<h2>Supply Chain Analysis</h2>
{isAnalyzing && <p>Analyzing your retail data...</p>}
{analysis && (
<div className="analysis-results">
<h3>Key Insights</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.insights }} />
<h3>Inventory Recommendations</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.inventoryRecommendations }} />
<h3>Sales Trends</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.salesTrends }} />
<h3>Forecasts</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.forecasts }} />
</div>
)}
</div>
);
}
export default SupplyChainAnalysis;
3. AI 服务
现在,让我们创建一个服务来与 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;
}
}
4. 后端 API 端点
对于后端,我们需要一个端点来处理数据并与 AI 交互:
// 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;
// Create a specialized prompt based on data type
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);
}
// Call the AI
const completion = await openai.chat.completions.create({
model: "gpt-4-turbo",
messages: [
{
role: "system",
content: "You are a senior supply chain expert with 20+ years of experience in mobile device retail. You analyze data and provide actionable insights with a focus on inventory optimization, vendor management, and sales forecasting for smartphone and mobile accessory retailers."
},
{ role: "user", content: prompt }
],
temperature: 0.2,
});
// Process the AI response
const analysisText = completion.choices[0].message.content;
// Parse the response into structured data
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' });
}
}
// Create specialized prompts based on data type
function createPurchaseOrderPrompt(data) {
return `
As a senior supply chain expert for a mobile device retailer, analyze the following purchase order data for ${data.location || 'our stores'}:
${JSON.stringify(data.data, null, 2)}
Focus your analysis on:
1. Vendor performance (delivery times, order fulfillment)
2. Product category insights (smartphones, accessories, etc.)
3. Inventory management recommendations
4. Cost optimization opportunities
5. Order cycle time improvements
Provide specific actionable recommendations for improving the supply chain.
`;
}
function createSalesDataPrompt(data) {
return `
As a senior supply chain expert for a mobile device retailer, analyze the following sales data for ${data.location || 'our stores'}:
${JSON.stringify(data.data, null, 2)}
Focus your analysis on:
1. Sales trends by product category and specific models
2. Profitability analysis by product type
3. Seasonal patterns and forecasting
4. Product mix optimization
5. Inventory replenishment recommendations based on sales velocity
Provide specific actionable recommendations for improving sales and inventory alignment.
`;
}
function createInventoryPrompt(data) {
// Similar structure for inventory data
}
function createGeneralPrompt(data) {
// Fallback for other data types
}
// Parse the AI response into structured data
function parseAnalysisResponse(text, dataType) {
// Basic parsing logic - this could be enhanced with more sophisticated parsing
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")
};
// Add placeholder metrics and chart data
// In a real implementation, you might extract these from the AI response
// or calculate them directly from the data
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. 主应用程序组件
最后,让我们将它们放在一起:
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 (
<div className="retail-analysis-app">
<header>
<h1>Retail Supply Chain Analysis</h1>
<p>Upload your retail data for expert supply chain analysis</p>
</header>
<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
import React, { useState, useEffect } from 'react';
import { analyzeRetailData } from '../services/aiService';
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);
}
};
// Render different views based on selection
const renderAnalysisView = () => {
if (!analysis) return null;
switch(selectedView) {
case 'overview':
return (
<div className="analysis-overview">
<h3>Key Insights</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.keyInsights }} />
<div className="metrics-summary">
<div className="metric-card">
<h4>Inventory Turnover</h4>
<p className="metric-value">{analysis.metrics.inventoryTurnover}</p>
</div>
<div className="metric-card">
<h4>Order Fulfillment Rate</h4>
<p className="metric-value">{analysis.metrics.fulfillmentRate}%</p>
</div>
<div className="metric-card">
<h4>Average Days on Order</h4>
<p className="metric-value">{analysis.metrics.avgDaysOnOrder}</p>
</div>
</div>
</div>
);
case 'inventory':
return (
<div className="inventory-analysis">
<h3>Inventory Analysis</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.inventoryAnalysis }} />
<h4>Top Products by Turnover</h4>
<InventoryTurnoverChart data={analysis.charts.inventoryTurnover} />
<h4>Category Performance</h4>
<ProductCategoryChart data={analysis.charts.categoryPerformance} />
<h3>Inventory Recommendations</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.inventoryRecommendations }} />
</div>
);
case 'vendor':
return (
<div className="vendor-analysis">
<h3>Vendor Performance</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.vendorAnalysis }} />
<h4>Vendor Delivery Performance</h4>
<VendorPerformanceChart data={analysis.charts.vendorPerformance} />
<h3>Vendor Recommendations</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.vendorRecommendations }} />
</div>
);
case 'sales':
return (
<div className="sales-analysis">
<h3>Sales Trends</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.salesTrends }} />
<h4>Sales vs Purchases</h4>
<SalesVsPurchasesChart data={analysis.charts.salesVsPurchases} />
<h3>Sales Forecasts</h3>
<div dangerouslySetInnerHTML={{ __html: analysis.salesForecasts }} />
</div>
);
default:
return null;
}
};
return (
<div className="mobile-retail-analysis">
<div className="analysis-header">
<h2>Mobile Retail Supply Chain Analysis</h2>
<div className="view-selector">
<button
className={selectedView === 'overview' ? 'active' : ''}
onClick={() => setSelectedView('overview')}
>
Overview
</button>
<button
className={selectedView === 'inventory' ? 'active' : ''}
onClick={() => setSelectedView('inventory')}
>
Inventory
</button>
<button
className={selectedView === 'vendor' ? 'active' : ''}
onClick={() => setSelectedView('vendor')}
>
Vendor
</button>
<button
className={selectedView === 'sales' ? 'active' : ''}
onClick={() => setSelectedView('sales')}
>
Sales
</button>
</div>
</div>
{isAnalyzing ? (
<div className="loading">
<p>Analyzing your mobile retail data...</p>
</div>
) : renderAnalysisView()}
</div>
);
}
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;
}
}
推荐服务器
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
AIO-MCP Server
🚀 集成了 AI 搜索、RAG 和多服务(GitLab/Jira/Confluence/YouTube)的一体化 MCP 服务器,旨在增强 AI 驱动的开发工作流程。来自 Folk。
Hyperbrowser
欢迎来到 Hyperbrowser,人工智能的互联网。Hyperbrowser 是下一代平台,旨在增强人工智能代理的能力,并实现轻松、可扩展的浏览器自动化。它专为人工智能开发者打造,消除了本地基础设施和性能瓶颈带来的麻烦,让您能够:
BigQuery MCP Server
这是一个服务器,可以让你的大型语言模型(LLM,比如Claude)直接与你的BigQuery数据对话!可以把它想象成一个友好的翻译器,它位于你的AI助手和数据库之间,确保它们可以安全高效地进行交流。
MCP Web Research Server
一个模型上下文协议服务器,使 Claude 能够通过集成 Google 搜索、提取网页内容和捕获屏幕截图来进行网络研究。
mcp-perplexity
Perplexity API 的 MCP 服务器。
MySQL MCP Server
允许人工智能助手通过受控界面列出表格、读取数据和执行 SQL 查询,从而使数据库探索和分析更安全、更有条理。
mcp-codex-keeper
作为开发知识的守护者,为 AI 助手提供精心策划的最新文档和最佳实践访问权限。
MCP Etherscan Server
通过 Etherscan 的 API 促进与以太坊区块链数据的交互,提供对余额、交易、代币转移、合约 ABI、gas 价格和 ENS 名称解析的实时访问。
Perplexity Deep Research MCP
一个服务器,它允许 AI 助手使用 Perplexity 的 sonar-deep-research 模型进行网络搜索,并提供引用支持。