Files
pub/2. 原型验证指南.md
T
2025-07-03 15:44:27 +08:00

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周)

  1. 性能优化

    • 添加Redis缓存
    • 优化图像生成速度
    • 实现异步任务队列
  2. 功能增强

    • 添加用户认证
    • 实现设计历史记录
    • 增加更多设计风格

8.2 中期扩展(1-2月)

  1. 平台集成

    • 集成更多社交媒体平台
    • 添加中国本土平台支持
    • 接入电商平台API
  2. AI能力提升

    • 集成更多AI模型
    • 提升设计质量
    • 增加个性化推荐

8.3 长期规划(3-6月)

  1. 商业化功能

    • 完整的订单系统
    • 支付集成
    • 供应商对接
  2. 规模化部署

    • 多区域部署
    • 负载均衡优化
    • 数据分析平台

9. 资源链接

9.1 官方文档

9.2 示例代码仓库

这个原型验证demo提供了完整的技术实现路径,可以快速验证HotTrend Tees平台的核心功能和商业可行性。