44 KiB
44 KiB
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密钥
# 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依赖包
# 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 前端依赖包
{
"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)
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)
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)
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)
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)
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)
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)
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 (
<Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
<CircularProgress />
</Box>
);
}
if (error) {
return (
<Alert severity="error" action={
<Button color="inherit" size="small" onClick={loadTrends}>
重试
</Button>
}>
{error}
</Alert>
);
}
return (
<Box>
<Box display="flex" justifyContent="space-between" alignItems="center" mb={3}>
<Typography variant="h4" component="h1" gutterBottom>
<TrendingUp sx={{ mr: 1, verticalAlign: 'middle' }} />
热门趋势
</Typography>
<Button
variant="outlined"
startIcon={<Refresh />}
onClick={loadTrends}
disabled={loading}
>
刷新
</Button>
</Box>
<Grid container spacing={3}>
{trends.map((trend, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<Card
sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
'&:hover': {
transform: 'translateY(-4px)',
transition: 'transform 0.2s ease-in-out'
}
}}
>
<CardContent sx={{ flexGrow: 1 }}>
<Typography variant="h6" component="h2" gutterBottom>
{trend.name}
</Typography>
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
<Chip
label={`${formatVolume(trend.volume)} 推文`}
color="primary"
size="small"
/>
<Typography variant="body2" color="textSecondary">
#{index + 1}
</Typography>
</Box>
<Button
variant="contained"
fullWidth
onClick={() => handleGenerateDesign(trend.name)}
disabled={generatingDesign[trend.name]}
sx={{ mt: 2 }}
>
{generatingDesign[trend.name] ? (
<>
<CircularProgress size={16} sx={{ mr: 1 }} />
生成中...
</>
) : (
'生成设计'
)}
</Button>
</CardContent>
</Card>
</Grid>
))}
</Grid>
</Box>
);
};
export default TrendDashboard;
4.4 设计预览组件 (src/components/DesignPreview.js)
import React, { useState } from 'react';
import {
Box,
Card,
CardContent,
CardMedia,
Typography,
Button,
Chip,
Grid,
Accordion,
AccordionSummary,
AccordionDetails,
Alert
} from '@mui/material';
import { ExpandMore, Download, Share, ShoppingCart } from '@mui/icons-material';
const DesignPreview = ({ designData, onOrderClick }) => {
const [expanded, setExpanded] = useState('panel1');
const handleAccordionChange = (panel) => (event, isExpanded) => {
setExpanded(isExpanded ? panel : false);
};
if (!designData) {
return (
<Alert severity="info">
请从左侧选择一个趋势来生成设计
</Alert>
);
}
const { trend_data, design_prompt, image_url, appeal_analysis } = designData;
return (
<Box>
<Typography variant="h4" component="h1" gutterBottom>
设计预览
</Typography>
<Grid container spacing={3}>
{/* 设计图像 */}
<Grid item xs={12} md={6}>
<Card>
<CardMedia
component="img"
height="400"
image={image_url}
alt="设计预览"
sx={{ objectFit: 'contain', backgroundColor: '#f5f5f5' }}
/>
<CardContent>
<Box display="flex" gap={1} mb={2}>
<Button
variant="outlined"
startIcon={<Download />}
size="small"
>
下载
</Button>
<Button
variant="outlined"
startIcon={<Share />}
size="small"
>
分享
</Button>
<Button
variant="contained"
startIcon={<ShoppingCart />}
size="small"
onClick={() => onOrderClick(designData)}
>
立即定制
</Button>
</Box>
</CardContent>
</Card>
</Grid>
{/* 设计信息 */}
<Grid item xs={12} md={6}>
<Box>
{/* 趋势信息 */}
<Accordion
expanded={expanded === 'panel1'}
onChange={handleAccordionChange('panel1')}
>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography variant="h6">趋势信息</Typography>
</AccordionSummary>
<AccordionDetails>
<Box>
<Typography variant="subtitle1" gutterBottom>
<strong>趋势话题:</strong> {trend_data.name}
</Typography>
<Typography variant="body2" gutterBottom>
<strong>热度:</strong> {trend_data.volume} 条相关推文
</Typography>
{trend_data.sentiment && (
<Box mt={2}>
<Typography variant="subtitle2" gutterBottom>
情感分析:
</Typography>
<Box display="flex" gap={1} flexWrap="wrap">
<Chip
label={`正面 ${trend_data.sentiment.positive}%`}
color="success"
size="small"
/>
<Chip
label={`中性 ${trend_data.sentiment.neutral}%`}
color="default"
size="small"
/>
<Chip
label={`负面 ${trend_data.sentiment.negative}%`}
color="error"
size="small"
/>
</Box>
</Box>
)}
</Box>
</AccordionDetails>
</Accordion>
{/* 设计描述 */}
<Accordion
expanded={expanded === 'panel2'}
onChange={handleAccordionChange('panel2')}
>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography variant="h6">设计描述</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography variant="body2">
{design_prompt}
</Typography>
</AccordionDetails>
</Accordion>
{/* 市场分析 */}
{appeal_analysis && (
<Accordion
expanded={expanded === 'panel3'}
onChange={handleAccordionChange('panel3')}
>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography variant="h6">市场分析</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography variant="body2" component="pre" sx={{ whiteSpace: 'pre-wrap' }}>
{appeal_analysis.analysis}
</Typography>
</AccordionDetails>
</Accordion>
)}
</Box>
</Grid>
</Grid>
</Box>
);
};
export default DesignPreview;
4.5 主应用组件 (src/App.js)
import React, { useState } from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import {
CssBaseline,
AppBar,
Toolbar,
Typography,
Container,
Grid,
Box,
Fab
} from '@mui/material';
import { AutoAwesome } from '@mui/icons-material';
import TrendDashboard from './components/TrendDashboard';
import DesignPreview from './components/DesignPreview';
import './App.css';
const theme = createTheme({
palette: {
primary: {
main: '#6366f1',
},
secondary: {
main: '#ec4899',
},
},
typography: {
fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
},
});
function App() {
const [selectedDesign, setSelectedDesign] = useState(null);
const [showOrderForm, setShowOrderForm] = useState(false);
const handleTrendSelect = (designData) => {
setSelectedDesign(designData);
};
const handleOrderClick = (designData) => {
setShowOrderForm(true);
// 这里可以打开订单表单模态框
console.log('打开订单表单:', designData);
};
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<AppBar position="static" elevation={0}>
<Toolbar>
<AutoAwesome sx={{ mr: 2 }} />
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
HotTrend Tees - AI驱动的T-shirt定制平台
</Typography>
</Toolbar>
</AppBar>
<Container maxWidth="xl" sx={{ py: 4 }}>
<Grid container spacing={4}>
{/* 左侧:趋势面板 */}
<Grid item xs={12} lg={6}>
<TrendDashboard onTrendSelect={handleTrendSelect} />
</Grid>
{/* 右侧:设计预览 */}
<Grid item xs={12} lg={6}>
<DesignPreview
designData={selectedDesign}
onOrderClick={handleOrderClick}
/>
</Grid>
</Grid>
</Container>
{/* 浮动操作按钮 */}
<Fab
color="primary"
aria-label="刷新"
sx={{
position: 'fixed',
bottom: 16,
right: 16,
}}
onClick={() => window.location.reload()}
>
<AutoAwesome />
</Fab>
</ThemeProvider>
);
}
export default App;
5. AWS部署配置
5.1 Docker配置
后端Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
前端Dockerfile:
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
5.2 AWS ECS任务定义
{
"family": "hottrend-tees",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::ACCOUNT:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::ACCOUNT:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "backend",
"image": "your-account.dkr.ecr.region.amazonaws.com/hottrend-tees-backend:latest",
"portMappings": [
{
"containerPort": 8000,
"protocol": "tcp"
}
],
"environment": [
{
"name": "TWITTER_BEARER_TOKEN",
"value": "${TWITTER_BEARER_TOKEN}"
},
{
"name": "OPENAI_API_KEY",
"value": "${OPENAI_API_KEY}"
},
{
"name": "AWS_S3_BUCKET",
"value": "hottrend-tees-designs"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/hottrend-tees",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}
5.3 部署脚本
#!/bin/bash
# deploy.sh
# 设置变量
AWS_REGION="us-east-1"
ECR_REPO="your-account.dkr.ecr.us-east-1.amazonaws.com"
CLUSTER_NAME="hottrend-tees-cluster"
SERVICE_NAME="hottrend-tees-service"
# 构建和推送Docker镜像
echo "构建Docker镜像..."
docker build -t hottrend-tees-backend ./backend
docker build -t hottrend-tees-frontend ./frontend
# 标记镜像
docker tag hottrend-tees-backend:latest $ECR_REPO/hottrend-tees-backend:latest
docker tag hottrend-tees-frontend:latest $ECR_REPO/hottrend-tees-frontend:latest
# 登录ECR
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REPO
# 推送镜像
echo "推送镜像到ECR..."
docker push $ECR_REPO/hottrend-tees-backend:latest
docker push $ECR_REPO/hottrend-tees-frontend:latest
# 更新ECS服务
echo "更新ECS服务..."
aws ecs update-service \
--cluster $CLUSTER_NAME \
--service $SERVICE_NAME \
--force-new-deployment \
--region $AWS_REGION
echo "部署完成!"
6. 测试和监控
6.1 API测试脚本
# test_api.py
import asyncio
import aiohttp
import json
async def test_api():
base_url = "http://localhost:8000"
async with aiohttp.ClientSession() as session:
# 测试健康检查
print("测试健康检查...")
async with session.get(f"{base_url}/api/health") as resp:
health_data = await resp.json()
print(f"健康状态: {health_data}")
# 测试获取趋势
print("\n测试获取趋势...")
async with session.get(f"{base_url}/api/trends") as resp:
trends_data = await resp.json();
print(f"趋势数量: {len(trends_data.get('data', []))}");
if trends_data.get('data'):
first_trend = trends_data['data'][0]['name'];
print(f"第一个趋势: {first_trend}");
# 测试生成设计
print(f"\n测试生成设计: {first_trend}");
design_payload = {"trend_name": first_trend};
async with session.post(
f"{base_url}/api/designs/generate",
json=design_payload
) as resp:
design_data = await resp.json();
if design_data.get('success'):
print("设计生成成功!");
print(f"设计ID: {design_data['data']['design_id']}");
else:
print(f"设计生成失败: {design_data}");
};
if __name__ == "__main__":
asyncio.run(test_api());
6.2 CloudWatch监控配置
# cloudwatch-dashboard.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'HotTrend Tees监控仪表板'
Resources:
HotTrendTeesDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName: HotTrendTees-Monitor
DashboardBody: !Sub |
{
"widgets": [
{
"type": "metric",
"properties": {
"metrics": [
["AWS/ECS", "CPUUtilization", "ServiceName", "hottrend-tees-service"],
["AWS/ECS", "MemoryUtilization", "ServiceName", "hottrend-tees-service"]
],
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "ECS资源使用率"
}
},
{
"type": "metric",
"properties": {
"metrics": [
["AWS/ApplicationELB", "RequestCount", "LoadBalancer", "hottrend-tees-alb"],
["AWS/ApplicationELB", "ResponseTime", "LoadBalancer", "hottrend-tees-alb"]
],
"period": 300,
"stat": "Sum",
"region": "us-east-1",
"title": "API请求统计"
}
}
]
}
7. 原型验证清单
7.1 功能验证
-
Twitter API集成
- 获取热门趋势 ✓
- 搜索相关推文 ✓
- 情感分析 ✓
-
OpenAI集成
- 生成设计提示词 ✓
- 生成设计图像 ✓
- 设计变体生成 ✓
-
AWS服务
- S3图像存储 ✓
- ECS容器部署 ✓
- CloudWatch监控 ✓
-
前端功能
- 趋势展示 ✓
- 设计预览 ✓
- 用户交互 ✓
7.2 性能验证
-
响应时间
- API响应 < 5秒
- 图像生成 < 30秒
- 页面加载 < 3秒
-
并发处理
- 支持10个并发用户
- 稳定的资源使用
7.3 用户体验验证
-
易用性
- 直观的界面设计
- 清晰的操作流程
- 及时的反馈信息
-
设计质量
- 符合趋势主题
- 适合T-shirt印制
- 视觉效果良好
8. 下一步计划
8.1 短期优化(1-2周)
-
性能优化
- 添加Redis缓存
- 优化图像生成速度
- 实现异步任务队列
-
功能增强
- 添加用户认证
- 实现设计历史记录
- 增加更多设计风格
8.2 中期扩展(1-2月)
-
平台集成
- 集成更多社交媒体平台
- 添加中国本土平台支持
- 接入电商平台API
-
AI能力提升
- 集成更多AI模型
- 提升设计质量
- 增加个性化推荐
8.3 长期规划(3-6月)
-
商业化功能
- 完整的订单系统
- 支付集成
- 供应商对接
-
规模化部署
- 多区域部署
- 负载均衡优化
- 数据分析平台
9. 资源链接
9.1 官方文档
9.2 示例代码仓库
这个原型验证demo提供了完整的技术实现路径,可以快速验证HotTrend Tees平台的核心功能和商业可行性。