소매 공급망 분석 도구
소매 공급망 데이터를 분석하고 재고 최적화, 공급업체 관리, 판매 예측을 위한 실행 가능한 통찰력을 제공하는 AI 기반 도구입니다.
특징
- 여러 개의 Excel/CSV 파일을 업로드하고 분석합니다.
- 구매 주문서, 판매 데이터 및 재고 파일 지원
- 자동 파일 유형 감지
- 여러 데이터 소스의 결합된 교차 분석
- 자세한 시각화 및 측정 항목
- 공급망 최적화를 위한 실행 가능한 권장 사항
시작하기
- 저장소를 복제합니다
- 종속성 설치:
npm install
- 개발 서버를 시작합니다:
npm run dev
- 브라우저에서 http://localhost:3000을 엽니다.
용법
- 소매 데이터가 포함된 하나 이상의 Excel/CSV 파일을 업로드하세요.
- 자동으로 감지되지 않으면 각 파일에 적합한 데이터 유형을 선택하십시오.
- 데이터를 처리하려면 "파일 분석"을 클릭하세요.
- 다양한 카테고리(개요, 재고, 공급업체, 판매)에 대한 통찰력 보기
- 결합 분석과 개별 파일 유형 분석 간 전환
기술
- 프런트엔드 및 API 경로를 위한 Next.js
- 지능형 데이터 분석을 위한 Claude AI
- 데이터 시각화를 위한 Chart.js
- Excel 파일 처리를 위한 XLSX
환경 변수
다음 변수를 사용하여 .env.local
파일을 만듭니다.
지엑스피1
특허
MIT
재고 보고서, 판매 보고서 등 소매점 데이터가 포함된 엑셀 스프레드시트를 업로드하면 AI가 마치 소매업체의 시니어 공급망 전문가처럼 데이터를 분석하여 추세, 예측 및 기타 통찰력을 제공하는 MCP를 만들고 싶습니다. 혹시 도와주실 수 있을까요?
도움이 된다면 데이터 예를 보여드리겠습니다.
소매 공급망 분석 MCP 네, 저는 확실히 여러분이 소매점 데이터를 마치 고위 공급망 전문가처럼 분석하는 다중 모드 대화형 페르소나(MCP)를 만드는 것을 도울 수 있습니다. 이는 AI 분석의 훌륭한 활용 사례입니다. 고차원적 접근 방식 이 프로젝트는 다음과 같이 구성될 수 있습니다. 데이터 업로드 및 처리: 재고, 매출 및 기타 소매 데이터가 포함된 Excel 파일을 업로드하는 인터페이스를 만듭니다. 데이터 분석: 의미 있는 인사이트를 추출하기 위해 데이터를 처리합니다. 전문가 페르소나: 고위 공급망 전문가처럼 인사이트를 전달하도록 AI를 설계합니다. 시각화: 추세 및 예측을 시각적으로 표현합니다.
구현 단계
- 데이터 업로드 구성 요소 먼저 Excel 파일을 업로드하고 처리할 방법이 필요합니다.
'react'에서 React를 가져오고, { useState }를 가져옵니다. 'xlsx'에서 *를 XLSX로 가져옵니다.
함수 RetailDataProcessor({onDataProcessed}) { const [처리 중임, 처리 중 설정] = useState(false); const [데이터 유형, 데이터 유형 설정] = useState('구매_주문'); const [위치, 위치 설정] = useState('');
const handleFileUpload = async (e) => { const 파일 = e.target.files[0]; 처리 중 설정(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);
};
// 열 머리글을 기준으로 데이터 유형 감지 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;
};
// 유형에 따라 데이터 정규화 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;
}
};
반환(데이터 유형: <select value={dataType} onChange={(e) => setDataType(e.target.value)} > 구매 주문 판매 데이터 재고
<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>
); }
기본 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개의 스크린샷을 공유해드리겠습니다.
1위 - 애버딘 PO: 2위 - 휴런 PO: 3위 - 루번 PO: 4위 - 2023년 7월부터 2024년 2월까지의 판매 데이터:
스크린샷을 공유해 주셔서 감사합니다! 이제 소매 데이터 구조를 확인할 수 있게 되어 더욱 맞춤화된 MCP 솔루션을 설계하는 데 도움이 될 것입니다. 제가 확인한 내용을 분석해 보겠습니다.
데이터 분석
- 구매 주문 보고서 처음 세 개의 스크린샷은 유사한 구조를 가진 다양한 위치(애버딘, 휴런, 루번)의 구매 주문 세부 정보를 보여줍니다. 주요 필드: 구매 주문 번호, 상태, 수령 장소, 공급업체 정보, 제품 SKU/ID, 제품 이름, 범주 수량 데이터: 주문 수, 수령 수, 미지급 수 재무 데이터: 품목당 비용, 수령 비용, 미지급 비용 타이밍 정보: 약정 날짜, 주문 장소, 주문 일수, 예상 도착 시간 추가 정보: 주문 주석, 수령 주석, 주문 입력 번호 이 보고서는 자세한 조달 정보와 함께 모바일 장치 및 액세서리(스마트폰, 케이블, 충전기 등)를 추적합니다.
- 판매 데이터 네 번째 스크린샷은 다음과 같은 판매 데이터를 보여줍니다. 거래 세부 정보: 송장 번호, 수령 날짜, 판매 정보 제품 정보: 다양한 모바일 장치 및 액세서리 가격 데이터: 여러 가격 관련 열 위치/매장 정보 귀하의 데이터에 따른 MCP 설계 이제 귀하의 데이터 구조를 이해했으므로 소매 공급망 MCP에 맞게 더욱 맞춤화된 접근 방식을 알려드리겠습니다.
// 구성요소/MobileRetailAnalysis.js import React, { useState, useEffect } from 'react'; import { analyzeRetailData } from '../services/aiService'; import { InventoryTurnoverChart, ProductCategoryChart, VendorPerformanceChart, SalesVsPurchasesChart } from './charts';
함수 MobileRetailAnalysis({데이터}) { const [분석, 분석 설정] = useState(null); const [분석 중임, 분석 중임 설정] = useState(false); const [선택된 뷰, 선택된 뷰 설정] = useState('개요');
useEffect(() => { if (데이터) { 수행분석(); } }, [데이터]);
const performAnalysis = async () => { setIsAnalyzing(true); try { const result = await analyzeRetailData(data); setAnalysis(result); } catch (error) { console.error("데이터 분석 오류:", error); } finally { setIsAnalyzing(false); } };
// 선택에 따라 다른 뷰를 렌더링합니다 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;
}
};
반환 ( 모바일 소매 공급망 분석 <button className={selectedView === 'overview' ? 'active' : ''} onClick={() => setSelectedView('overview')} > 개요 <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 ? (
<div className="loading">
<p>Analyzing your mobile retail data...</p>
</div>
) : renderAnalysisView()}
</div>
); }
기본 MobileRetailAnalysis를 내보냅니다.
이제 모바일 소매 데이터에 맞게 AI 서비스를 더욱 구체적으로 업데이트해 보겠습니다.
// 서비스/aiService.js 비동기 함수 내보내기 analyzeRetailData(데이터) { try { const response = await fetch('/api/analyze-mobile-retail', { 메서드: 'POST', 헤더: { 'Content-Type': 'application/json', }, 본문: JSON.stringify({ 데이터 }), });
if (!response.ok) {
throw new Error('Failed to analyze data');
}
return await response.json();
} catch (error) { console.error('AI 분석 서비스에서 오류 발생:', error); throw error; } }