diff --git a/2. 原型验证指南.md b/2. 原型验证指南.md
new file mode 100644
index 0000000..889f4a2
--- /dev/null
+++ b/2. 原型验证指南.md
@@ -0,0 +1,1506 @@
+# HotTrend Tees 原型验证指南
+
+## 技术栈:Twitter API v2 + OpenAI + AWS
+
+本文档提供了HotTrend Tees AI驱动T-shirt定制平台的完整原型验证demo实现方案。
+
+## 1. 系统架构概览
+
+```
+┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ Twitter API │ │ OpenAI API │ │ AWS Services │
+│ (趋势数据) │ │ (图像生成) │ │ (云基础设施) │
+└─────────────────┘ └─────────────────┘ └─────────────────┘
+ │ │ │
+ ▼ ▼ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ HotTrend Tees 原型系统 │
+├─────────────────────────────────────────────────────────────────┤
+│ 前端 (React) │ 后端 (FastAPI) │ 数据库 (RDS) │
+│ - 趋势展示界面 │ - 趋势分析服务 │ - 用户数据 │
+│ - 设计预览界面 │ - 图像生成服务 │ - 设计历史 │
+│ - 订单管理界面 │ - 订单处理服务 │ - 订单记录 │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+## 2. 环境准备
+
+### 2.1 必需的API密钥
+
+```bash
+# Twitter API v2
+TWITTER_BEARER_TOKEN=your_twitter_bearer_token
+TWITTER_API_KEY=your_twitter_api_key
+TWITTER_API_SECRET=your_twitter_api_secret
+TWITTER_ACCESS_TOKEN=your_twitter_access_token
+TWITTER_ACCESS_TOKEN_SECRET=your_twitter_access_token_secret
+
+# OpenAI API
+OPENAI_API_KEY=your_openai_api_key
+
+# AWS 配置
+AWS_ACCESS_KEY_ID=your_aws_access_key
+AWS_SECRET_ACCESS_KEY=your_aws_secret_key
+AWS_REGION=us-east-1
+```
+
+### 2.2 Python依赖包
+
+```bash
+# requirements.txt
+fastapi==0.104.1
+uvicorn==0.24.0
+tweepy==4.14.0
+openai==1.3.7
+boto3==1.29.7
+sqlalchemy==2.0.23
+psycopg2-binary==2.9.9
+redis==5.0.1
+celery==5.3.4
+python-multipart==0.0.6
+python-dotenv==1.0.0
+requests==2.31.0
+pillow==10.1.0
+```
+
+### 2.3 前端依赖包
+
+```json
+{
+ "name": "hottrend-tees-frontend",
+ "version": "1.0.0",
+ "dependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.8.0",
+ "axios": "^1.6.2",
+ "styled-components": "^6.1.1",
+ "@mui/material": "^5.14.20",
+ "@mui/icons-material": "^5.14.19",
+ "recharts": "^2.8.0"
+ }
+}
+```
+
+## 3. 核心后端实现
+
+### 3.1 项目结构
+
+```
+backend/
+├── app/
+│ ├── __init__.py
+│ ├── main.py
+│ ├── config.py
+│ ├── models/
+│ │ ├── __init__.py
+│ │ ├── user.py
+│ │ ├── design.py
+│ │ └── trend.py
+│ ├── services/
+│ │ ├── __init__.py
+│ │ ├── twitter_service.py
+│ │ ├── openai_service.py
+│ │ └── design_service.py
+│ ├── api/
+│ │ ├── __init__.py
+│ │ ├── trends.py
+│ │ ├── designs.py
+│ │ └── orders.py
+│ └── utils/
+│ ├── __init__.py
+│ └── helpers.py
+├── requirements.txt
+└── Dockerfile
+```
+
+### 3.2 配置文件 (app/config.py)
+
+```python
+import os
+from pydantic_settings import BaseSettings
+
+class Settings(BaseSettings):
+ # Twitter API 配置
+ twitter_bearer_token: str = os.getenv("TWITTER_BEARER_TOKEN")
+ twitter_api_key: str = os.getenv("TWITTER_API_KEY")
+ twitter_api_secret: str = os.getenv("TWITTER_API_SECRET")
+ twitter_access_token: str = os.getenv("TWITTER_ACCESS_TOKEN")
+ twitter_access_token_secret: str = os.getenv("TWITTER_ACCESS_TOKEN_SECRET")
+
+ # OpenAI API 配置
+ openai_api_key: str = os.getenv("OPENAI_API_KEY")
+
+ # AWS 配置
+ aws_access_key_id: str = os.getenv("AWS_ACCESS_KEY_ID")
+ aws_secret_access_key: str = os.getenv("AWS_SECRET_ACCESS_KEY")
+ aws_region: str = os.getenv("AWS_REGION", "us-east-1")
+ aws_s3_bucket: str = os.getenv("AWS_S3_BUCKET", "hottrend-tees-designs")
+
+ # 数据库配置
+ database_url: str = os.getenv("DATABASE_URL", "postgresql://user:password@localhost/hottrend_tees")
+
+ # Redis 配置
+ redis_url: str = os.getenv("REDIS_URL", "redis://localhost:6379")
+
+ class Config:
+ env_file = ".env"
+
+settings = Settings()
+```
+
+### 3.3 Twitter趋势服务 (app/services/twitter_service.py)
+
+```python
+import tweepy
+import json
+from typing import List, Dict
+from app.config import settings
+
+class TwitterService:
+ def __init__(self):
+ self.client = tweepy.Client(
+ bearer_token=settings.twitter_bearer_token,
+ consumer_key=settings.twitter_api_key,
+ consumer_secret=settings.twitter_api_secret,
+ access_token=settings.twitter_access_token,
+ access_token_secret=settings.twitter_access_token_secret,
+ wait_on_rate_limit=True
+ )
+
+ async def get_trending_topics(self, location_id: int = 1) -> List[Dict]:
+ """获取热门话题"""
+ try:
+ # 获取全球热门话题
+ trends = self.client.get_trending_topics(id=location_id)
+
+ trending_topics = []
+ for trend in trends[0].trends:
+ if trend.tweet_volume:
+ trending_topics.append({
+ "name": trend.name,
+ "volume": trend.tweet_volume,
+ "url": trend.url
+ })
+
+ # 按热度排序
+ trending_topics.sort(key=lambda x: x["volume"], reverse=True)
+ return trending_topics[:20] # 返回前20个热门话题
+
+ except Exception as e:
+ print(f"获取热门话题失败: {e}")
+ return []
+
+ async def search_recent_tweets(self, query: str, max_results: int = 100) -> List[Dict]:
+ """搜索相关推文"""
+ try:
+ tweets = self.client.search_recent_tweets(
+ query=query,
+ max_results=max_results,
+ tweet_fields=['created_at', 'public_metrics', 'author_id']
+ )
+
+ if not tweets.data:
+ return []
+
+ tweet_data = []
+ for tweet in tweets.data:
+ tweet_data.append({
+ "id": tweet.id,
+ "text": tweet.text,
+ "created_at": tweet.created_at.isoformat(),
+ "metrics": {
+ "retweet_count": tweet.public_metrics["retweet_count"],
+ "like_count": tweet.public_metrics["like_count"],
+ "reply_count": tweet.public_metrics["reply_count"]
+ }
+ })
+
+ return tweet_data
+
+ except Exception as e:
+ print(f"搜索推文失败: {e}")
+ return []
+
+ async def analyze_trend_sentiment(self, tweets: List[Dict]) -> Dict:
+ """分析趋势情感"""
+ if not tweets:
+ return {"positive": 0, "neutral": 0, "negative": 0}
+
+ # 简单的情感分析(实际项目中建议使用更专业的NLP服务)
+ positive_keywords = ["love", "great", "amazing", "awesome", "good", "best"]
+ negative_keywords = ["hate", "bad", "terrible", "awful", "worst", "sucks"]
+
+ sentiment_counts = {"positive": 0, "neutral": 0, "negative": 0}
+
+ for tweet in tweets:
+ text = tweet["text"].lower()
+ positive_score = sum(1 for word in positive_keywords if word in text)
+ negative_score = sum(1 for word in negative_keywords if word in text)
+
+ if positive_score > negative_score:
+ sentiment_counts["positive"] += 1
+ elif negative_score > positive_score:
+ sentiment_counts["negative"] += 1
+ else:
+ sentiment_counts["neutral"] += 1
+
+ total = len(tweets)
+ return {
+ "positive": round(sentiment_counts["positive"] / total * 100, 2),
+ "neutral": round(sentiment_counts["neutral"] / total * 100, 2),
+ "negative": round(sentiment_counts["negative"] / total * 100, 2)
+ }
+```
+
+### 3.4 OpenAI设计服务 (app/services/openai_service.py)
+
+```python
+import openai
+import base64
+import requests
+from typing import Dict, List
+from app.config import settings
+
+class OpenAIService:
+ def __init__(self):
+ openai.api_key = settings.openai_api_key
+ self.client = openai.OpenAI(api_key=settings.openai_api_key)
+
+ async def generate_design_prompt(self, trend_data: Dict) -> str:
+ """基于趋势数据生成设计提示词"""
+ try:
+ messages = [
+ {
+ "role": "system",
+ "content": """你是一个专业的T-shirt设计师和创意总监。基于提供的趋势数据,
+ 生成适合T-shirt印花的创意设计提示词。设计应该:
+ 1. 符合当前流行趋势
+ 2. 视觉冲击力强
+ 3. 适合年轻人群体
+ 4. 可以印制在T-shirt上
+ 5. 避免版权问题
+
+ 请用英文生成详细的设计描述,包括视觉元素、颜色搭配、风格等。"""
+ },
+ {
+ "role": "user",
+ "content": f"""趋势话题: {trend_data.get('name', '')}
+ 热度: {trend_data.get('volume', 0)}
+ 相关内容情感: 正面{trend_data.get('sentiment', {}).get('positive', 0)}%,
+ 中性{trend_data.get('sentiment', {}).get('neutral', 0)}%,
+ 负面{trend_data.get('sentiment', {}).get('negative', 0)}%
+
+ 请为这个趋势设计一个T-shirt图案。"""
+ }
+ ]
+
+ response = self.client.chat.completions.create(
+ model="gpt-4",
+ messages=messages,
+ max_tokens=500,
+ temperature=0.8
+ )
+
+ return response.choices[0].message.content
+
+ except Exception as e:
+ print(f"生成设计提示词失败: {e}")
+ return "A trendy, modern T-shirt design with bold graphics and vibrant colors"
+
+ async def generate_design_image(self, prompt: str, style: str = "minimalist") -> Dict:
+ """生成T-shirt设计图像"""
+ try:
+ # 优化提示词以适合T-shirt设计
+ enhanced_prompt = f"""T-shirt design: {prompt}.
+ Style: {style}. Clean background, high contrast,
+ suitable for printing on fabric, vector-style graphics,
+ centered composition, no text unless specifically requested."""
+
+ response = self.client.images.generate(
+ model="dall-e-3",
+ prompt=enhanced_prompt,
+ size="1024x1024",
+ quality="standard",
+ n=1
+ )
+
+ image_url = response.data[0].url
+
+ # 下载图像数据
+ image_response = requests.get(image_url)
+ image_data = base64.b64encode(image_response.content).decode()
+
+ return {
+ "success": True,
+ "image_url": image_url,
+ "image_data": image_data,
+ "prompt": enhanced_prompt
+ }
+
+ except Exception as e:
+ print(f"生成设计图像失败: {e}")
+ return {
+ "success": False,
+ "error": str(e)
+ }
+
+ async def generate_design_variations(self, original_prompt: str, count: int = 3) -> List[Dict]:
+ """生成设计变体"""
+ variations = []
+
+ styles = ["minimalist", "vintage", "modern", "abstract", "geometric"]
+
+ for i in range(min(count, len(styles))):
+ style = styles[i]
+ variation = await self.generate_design_image(original_prompt, style)
+ if variation["success"]:
+ variation["style"] = style
+ variations.append(variation)
+
+ return variations
+
+ async def analyze_design_appeal(self, design_prompt: str, target_audience: str = "young adults") -> Dict:
+ """分析设计的市场吸引力"""
+ try:
+ messages = [
+ {
+ "role": "system",
+ "content": """你是一个市场分析专家,专门分析时尚产品的市场潜力。
+ 请分析提供的T-shirt设计在指定目标受众中的吸引力,
+ 并给出1-10分的评分和详细分析。"""
+ },
+ {
+ "role": "user",
+ "content": f"""设计描述: {design_prompt}
+ 目标受众: {target_audience}
+
+ 请分析这个设计的:
+ 1. 市场吸引力 (1-10分)
+ 2. 目标受众匹配度 (1-10分)
+ 3. 趋势符合度 (1-10分)
+ 4. 商业潜力 (1-10分)
+ 5. 具体优缺点分析
+
+ 请用JSON格式返回结果。"""
+ }
+ ]
+
+ response = self.client.chat.completions.create(
+ model="gpt-4",
+ messages=messages,
+ max_tokens=800,
+ temperature=0.3
+ )
+
+ # 解析响应(实际项目中需要更严格的JSON解析)
+ content = response.choices[0].message.content
+
+ return {
+ "analysis": content,
+ "timestamp": "2025-07-03T00:00:00Z"
+ }
+
+ except Exception as e:
+ print(f"分析设计吸引力失败: {e}")
+ return {
+ "analysis": "分析暂时不可用",
+ "timestamp": "2025-07-03T00:00:00Z"
+ }
+```
+
+### 3.5 设计管理服务 (app/services/design_service.py)
+
+```python
+import boto3
+import uuid
+from typing import Dict, List
+from app.config import settings
+from app.services.twitter_service import TwitterService
+from app.services.openai_service import OpenAIService
+
+class DesignService:
+ def __init__(self):
+ self.twitter_service = TwitterService()
+ self.openai_service = OpenAIService()
+ self.s3_client = boto3.client(
+ 's3',
+ aws_access_key_id=settings.aws_access_key_id,
+ aws_secret_access_key=settings.aws_secret_access_key,
+ region_name=settings.aws_region
+ )
+
+ async def create_trend_based_design(self, trend_name: str) -> Dict:
+ """基于趋势创建设计"""
+ try:
+ # 1. 获取趋势相关推文
+ tweets = await self.twitter_service.search_recent_tweets(
+ query=trend_name,
+ max_results=50
+ )
+
+ # 2. 分析趋势情感
+ sentiment = await self.twitter_service.analyze_trend_sentiment(tweets)
+
+ # 3. 构建趋势数据
+ trend_data = {
+ "name": trend_name,
+ "volume": len(tweets),
+ "sentiment": sentiment,
+ "tweets": tweets[:5] # 取前5条推文作为参考
+ }
+
+ # 4. 生成设计提示词
+ design_prompt = await self.openai_service.generate_design_prompt(trend_data)
+
+ # 5. 生成设计图像
+ design_result = await self.openai_service.generate_design_image(design_prompt)
+
+ if not design_result["success"]:
+ return {"success": False, "error": "设计生成失败"}
+
+ # 6. 上传图像到S3
+ design_id = str(uuid.uuid4())
+ s3_key = f"designs/{design_id}.png"
+
+ try:
+ import base64
+ image_data = base64.b64decode(design_result["image_data"])
+ self.s3_client.put_object(
+ Bucket=settings.aws_s3_bucket,
+ Key=s3_key,
+ Body=image_data,
+ ContentType='image/png'
+ )
+
+ s3_url = f"https://{settings.aws_s3_bucket}.s3.{settings.aws_region}.amazonaws.com/{s3_key}"
+
+ except Exception as e:
+ print(f"上传到S3失败: {e}")
+ s3_url = design_result["image_url"] # 使用OpenAI的临时URL
+
+ # 7. 分析设计吸引力
+ appeal_analysis = await self.openai_service.analyze_design_appeal(design_prompt)
+
+ # 8. 返回完整结果
+ return {
+ "success": True,
+ "design_id": design_id,
+ "trend_data": trend_data,
+ "design_prompt": design_prompt,
+ "image_url": s3_url,
+ "appeal_analysis": appeal_analysis,
+ "created_at": "2025-07-03T00:00:00Z"
+ }
+
+ except Exception as e:
+ print(f"创建趋势设计失败: {e}")
+ return {"success": False, "error": str(e)}
+
+ async def generate_design_batch(self, trend_names: List[str]) -> List[Dict]:
+ """批量生成设计"""
+ results = []
+
+ for trend_name in trend_names:
+ result = await self.create_trend_based_design(trend_name)
+ results.append({
+ "trend_name": trend_name,
+ "result": result
+ })
+
+ return results
+
+ async def get_trending_designs(self, limit: int = 10) -> List[Dict]:
+ """获取热门趋势设计"""
+ try:
+ # 1. 获取当前热门话题
+ trending_topics = await self.twitter_service.get_trending_topics()
+
+ # 2. 为每个话题生成设计预览
+ trending_designs = []
+
+ for topic in trending_topics[:limit]:
+ design_result = await self.create_trend_based_design(topic["name"])
+
+ if design_result["success"]:
+ trending_designs.append({
+ "topic": topic,
+ "design": design_result
+ })
+
+ return trending_designs
+
+ except Exception as e:
+ print(f"获取热门设计失败: {e}")
+ return []
+```
+
+### 3.6 主应用文件 (app/main.py)
+
+```python
+from fastapi import FastAPI, HTTPException
+from fastapi.middleware.cors import CORSMiddleware
+from fastapi.responses import JSONResponse
+from typing import List, Dict
+import uvicorn
+
+from app.services.design_service import DesignService
+from app.services.twitter_service import TwitterService
+from app.services.openai_service import OpenAIService
+
+app = FastAPI(
+ title="HotTrend Tees API",
+ description="AI驱动的T-shirt定制平台原型API",
+ version="1.0.0"
+)
+
+# CORS中间件
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=["*"], # 生产环境中应该指定具体域名
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+# 初始化服务
+design_service = DesignService()
+twitter_service = TwitterService()
+openai_service = OpenAIService()
+
+@app.get("/")
+async def root():
+ return {"message": "HotTrend Tees API v1.0.0"}
+
+@app.get("/api/trends")
+async def get_trends():
+ """获取当前热门趋势"""
+ try:
+ trends = await twitter_service.get_trending_topics()
+ return {"success": True, "data": trends}
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
+@app.get("/api/trends/{trend_name}/tweets")
+async def get_trend_tweets(trend_name: str, max_results: int = 50):
+ """获取趋势相关推文"""
+ try:
+ tweets = await twitter_service.search_recent_tweets(trend_name, max_results)
+ sentiment = await twitter_service.analyze_trend_sentiment(tweets)
+
+ return {
+ "success": True,
+ "data": {
+ "trend_name": trend_name,
+ "tweets": tweets,
+ "sentiment": sentiment,
+ "total": len(tweets)
+ }
+ }
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
+@app.post("/api/designs/generate")
+async def generate_design(request: Dict):
+ """生成基于趋势的设计"""
+ try:
+ trend_name = request.get("trend_name")
+ if not trend_name:
+ raise HTTPException(status_code=400, detail="trend_name is required")
+
+ result = await design_service.create_trend_based_design(trend_name)
+
+ if result["success"]:
+ return {"success": True, "data": result}
+ else:
+ raise HTTPException(status_code=500, detail=result.get("error", "设计生成失败"))
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
+@app.get("/api/designs/trending")
+async def get_trending_designs(limit: int = 10):
+ """获取热门趋势设计"""
+ try:
+ designs = await design_service.get_trending_designs(limit)
+ return {"success": True, "data": designs}
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
+@app.post("/api/designs/batch")
+async def generate_design_batch(request: Dict):
+ """批量生成设计"""
+ try:
+ trend_names = request.get("trend_names", [])
+ if not trend_names:
+ raise HTTPException(status_code=400, detail="trend_names is required")
+
+ results = await design_service.generate_design_batch(trend_names)
+ return {"success": True, "data": results}
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
+
+@app.get("/api/health")
+async def health_check():
+ """健康检查"""
+ return {
+ "status": "healthy",
+ "timestamp": "2025-07-03T00:00:00Z",
+ "services": {
+ "twitter_api": "connected",
+ "openai_api": "connected",
+ "aws_s3": "connected"
+ }
+ }
+
+if __name__ == "__main__":
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+## 4. 前端实现
+
+### 4.1 项目结构
+
+```
+frontend/
+├── public/
+│ └── index.html
+├── src/
+│ ├── components/
+│ │ ├── TrendDashboard.js
+│ │ ├── DesignGallery.js
+│ │ ├── DesignPreview.js
+│ │ └── OrderForm.js
+│ ├── services/
+│ │ └── api.js
+│ ├── App.js
+│ ├── App.css
+│ └── index.js
+├── package.json
+└── Dockerfile
+```
+
+### 4.2 API服务 (src/services/api.js)
+
+```javascript
+import axios from 'axios';
+
+const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000';
+
+const api = axios.create({
+ baseURL: API_BASE_URL,
+ timeout: 30000,
+});
+
+export const trendAPI = {
+ // 获取热门趋势
+ getTrends: async () => {
+ const response = await api.get('/api/trends');
+ return response.data;
+ },
+
+ // 获取趋势推文
+ getTrendTweets: async (trendName, maxResults = 50) => {
+ const response = await api.get(`/api/trends/${encodeURIComponent(trendName)}/tweets`, {
+ params: { max_results: maxResults }
+ });
+ return response.data;
+ }
+};
+
+export const designAPI = {
+ // 生成设计
+ generateDesign: async (trendName) => {
+ const response = await api.post('/api/designs/generate', {
+ trend_name: trendName
+ });
+ return response.data;
+ },
+
+ // 获取热门设计
+ getTrendingDesigns: async (limit = 10) => {
+ const response = await api.get('/api/designs/trending', {
+ params: { limit }
+ });
+ return response.data;
+ },
+
+ // 批量生成设计
+ generateBatchDesigns: async (trendNames) => {
+ const response = await api.post('/api/designs/batch', {
+ trend_names: trendNames
+ });
+ return response.data;
+ }
+};
+
+export const healthAPI = {
+ // 健康检查
+ checkHealth: async () => {
+ const response = await api.get('/api/health');
+ return response.data;
+ }
+};
+```
+
+### 4.3 趋势仪表板组件 (src/components/TrendDashboard.js)
+
+```javascript
+import React, { useState, useEffect } from 'react';
+import {
+ Box,
+ Card,
+ CardContent,
+ Typography,
+ Grid,
+ Button,
+ Chip,
+ CircularProgress,
+ Alert
+} from '@mui/material';
+import { TrendingUp, Refresh } from '@mui/icons-material';
+import { trendAPI, designAPI } from '../services/api';
+
+const TrendDashboard = ({ onTrendSelect }) => {
+ const [trends, setTrends] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [generatingDesign, setGeneratingDesign] = useState({});
+
+ useEffect(() => {
+ loadTrends();
+ }, []);
+
+ const loadTrends = async () => {
+ try {
+ setLoading(true);
+ const response = await trendAPI.getTrends();
+ if (response.success) {
+ setTrends(response.data);
+ }
+ } catch (err) {
+ setError('加载趋势数据失败');
+ console.error('加载趋势失败:', err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const handleGenerateDesign = async (trendName) => {
+ try {
+ setGeneratingDesign(prev => ({ ...prev, [trendName]: true }));
+
+ const response = await designAPI.generateDesign(trendName);
+
+ if (response.success) {
+ onTrendSelect(response.data);
+ } else {
+ alert('设计生成失败');
+ }
+ } catch (err) {
+ console.error('生成设计失败:', err);
+ alert('设计生成失败');
+ } finally {
+ setGeneratingDesign(prev => ({ ...prev, [trendName]: false }));
+ }
+ };
+
+ const formatVolume = (volume) => {
+ if (volume >= 1000000) {
+ return `${(volume / 1000000).toFixed(1)}M`;
+ } else if (volume >= 1000) {
+ return `${(volume / 1000).toFixed(1)}K`;
+ }
+ return volume.toString();
+ };
+
+ if (loading) {
+ return (
+