Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	
		Junhui Ji
		
	commited on
		
		
					Commit 
							
							·
						
						3394804
	
1
								Parent(s):
							
							e4b0841
								
init
Browse files- Dockerfile +38 -0
 - README.md +4 -3
 - cache/.temp +0 -0
 - docker-compose.yml +20 -0
 - main.py +345 -0
 - requirements.txt +9 -0
 - service_readme.md +176 -0
 - static/feedback.html +121 -0
 - static/index.html +79 -0
 - static/script.js +946 -0
 - static/styles.css +927 -0
 - static/upload.html +35 -0
 
    	
        Dockerfile
    ADDED
    
    | 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            FROM python:3.9-slim
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            # 安装系统依赖
         
     | 
| 4 | 
         
            +
            RUN apt-get update \
         
     | 
| 5 | 
         
            +
                && apt-get install -y wget gnupg \
         
     | 
| 6 | 
         
            +
                && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
         
     | 
| 7 | 
         
            +
                && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
         
     | 
| 8 | 
         
            +
                && apt-get update \
         
     | 
| 9 | 
         
            +
                && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
         
     | 
| 10 | 
         
            +
                  --no-install-recommends \
         
     | 
| 11 | 
         
            +
                && rm -rf /var/lib/apt/lists/*
         
     | 
| 12 | 
         
            +
             
     | 
| 13 | 
         
            +
            # 设置工作目录
         
     | 
| 14 | 
         
            +
            WORKDIR /app
         
     | 
| 15 | 
         
            +
             
     | 
| 16 | 
         
            +
            # 复制依赖文件
         
     | 
| 17 | 
         
            +
            COPY requirements.txt .
         
     | 
| 18 | 
         
            +
             
     | 
| 19 | 
         
            +
            # 安装 Python 依赖
         
     | 
| 20 | 
         
            +
            RUN pip install --no-cache-dir -r requirements.txt
         
     | 
| 21 | 
         
            +
             
     | 
| 22 | 
         
            +
            # 安装 Playwright 浏览器
         
     | 
| 23 | 
         
            +
            RUN playwright install chromium
         
     | 
| 24 | 
         
            +
             
     | 
| 25 | 
         
            +
            # 复制应用代码
         
     | 
| 26 | 
         
            +
            COPY . .
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
            # 创建缓存目录
         
     | 
| 29 | 
         
            +
            RUN mkdir -p cache
         
     | 
| 30 | 
         
            +
             
     | 
| 31 | 
         
            +
            # 暴露端口
         
     | 
| 32 | 
         
            +
            EXPOSE 7860
         
     | 
| 33 | 
         
            +
             
     | 
| 34 | 
         
            +
            # 设置环境变量
         
     | 
| 35 | 
         
            +
            ENV PYTHONUNBUFFERED=1
         
     | 
| 36 | 
         
            +
             
     | 
| 37 | 
         
            +
            # 启动应用
         
     | 
| 38 | 
         
            +
            CMD ["python", "main.py"] 
         
     | 
    	
        README.md
    CHANGED
    
    | 
         @@ -1,10 +1,11 @@ 
     | 
|
| 1 | 
         
             
            ---
         
     | 
| 2 | 
         
             
            title: Boss Translator
         
     | 
| 3 | 
         
            -
            emoji:  
     | 
| 4 | 
         
            -
            colorFrom:  
     | 
| 5 | 
         
            -
            colorTo:  
     | 
| 6 | 
         
             
            sdk: docker
         
     | 
| 7 | 
         
             
            pinned: false
         
     | 
| 
         | 
|
| 8 | 
         
             
            ---
         
     | 
| 9 | 
         | 
| 10 | 
         
             
            Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
         
     | 
| 
         | 
|
| 1 | 
         
             
            ---
         
     | 
| 2 | 
         
             
            title: Boss Translator
         
     | 
| 3 | 
         
            +
            emoji: 🏃
         
     | 
| 4 | 
         
            +
            colorFrom: purple
         
     | 
| 5 | 
         
            +
            colorTo: blue
         
     | 
| 6 | 
         
             
            sdk: docker
         
     | 
| 7 | 
         
             
            pinned: false
         
     | 
| 8 | 
         
            +
            app_port: 7860
         
     | 
| 9 | 
         
             
            ---
         
     | 
| 10 | 
         | 
| 11 | 
         
             
            Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
         
     | 
    	
        cache/.temp
    ADDED
    
    | 
         
            File without changes
         
     | 
    	
        docker-compose.yml
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            version: '3'
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            services:
         
     | 
| 4 | 
         
            +
              screenshot-service:
         
     | 
| 5 | 
         
            +
                build: .
         
     | 
| 6 | 
         
            +
                container_name: screenshot-service
         
     | 
| 7 | 
         
            +
                restart: unless-stopped
         
     | 
| 8 | 
         
            +
                ports:
         
     | 
| 9 | 
         
            +
                  - "7860:7860"
         
     | 
| 10 | 
         
            +
                volumes:
         
     | 
| 11 | 
         
            +
                  - ./cache:/app/cache
         
     | 
| 12 | 
         
            +
                environment:
         
     | 
| 13 | 
         
            +
                  - NODE_ENV=production
         
     | 
| 14 | 
         
            +
                  - PORT=7860
         
     | 
| 15 | 
         
            +
                healthcheck:
         
     | 
| 16 | 
         
            +
                  test: ["CMD", "curl", "-f", "http://localhost:7860/health"]
         
     | 
| 17 | 
         
            +
                  interval: 30s
         
     | 
| 18 | 
         
            +
                  timeout: 10s
         
     | 
| 19 | 
         
            +
                  retries: 3
         
     | 
| 20 | 
         
            +
                  start_period: 20s 
         
     | 
    	
        main.py
    ADDED
    
    | 
         @@ -0,0 +1,345 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from fastapi import FastAPI, HTTPException
         
     | 
| 2 | 
         
            +
            from fastapi.staticfiles import StaticFiles
         
     | 
| 3 | 
         
            +
            from fastapi.responses import FileResponse
         
     | 
| 4 | 
         
            +
            from fastapi.responses import JSONResponse
         
     | 
| 5 | 
         
            +
            from pydantic import BaseModel
         
     | 
| 6 | 
         
            +
            from playwright.async_api import async_playwright
         
     | 
| 7 | 
         
            +
            import os
         
     | 
| 8 | 
         
            +
            import time
         
     | 
| 9 | 
         
            +
            from urllib.parse import urlparse
         
     | 
| 10 | 
         
            +
            from typing import Optional, Dict, List
         
     | 
| 11 | 
         
            +
            import logging
         
     | 
| 12 | 
         
            +
            import json
         
     | 
| 13 | 
         
            +
            import base64
         
     | 
| 14 | 
         
            +
            from io import BytesIO
         
     | 
| 15 | 
         
            +
            import aiohttp
         
     | 
| 16 | 
         
            +
            import traceback
         
     | 
| 17 | 
         
            +
            import requests
         
     | 
| 18 | 
         
            +
            from openai import OpenAI
         
     | 
| 19 | 
         
            +
             
     | 
| 20 | 
         
            +
             
     | 
| 21 | 
         
            +
            app = FastAPI()
         
     | 
| 22 | 
         
            +
             
     | 
| 23 | 
         
            +
            # 确保缓存目录存在
         
     | 
| 24 | 
         
            +
            CACHE_DIR = "cache"
         
     | 
| 25 | 
         
            +
            os.makedirs(CACHE_DIR, exist_ok=True)
         
     | 
| 26 | 
         
            +
             
     | 
| 27 | 
         
            +
            # 挂载静态文件目录
         
     | 
| 28 | 
         
            +
            app.mount("/screenshots", StaticFiles(directory=CACHE_DIR), name="screenshots")
         
     | 
| 29 | 
         
            +
            app.mount("/static", StaticFiles(directory="static"), name="static")
         
     | 
| 30 | 
         
            +
             
     | 
| 31 | 
         
            +
            # API Keys
         
     | 
| 32 | 
         
            +
            OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
         
     | 
| 33 | 
         
            +
            OPENAI_API_IMAGE_EDIT_KEY = os.getenv("OPENAI_API_IMAGE_EDIT_KEY")
         
     | 
| 34 | 
         
            +
            GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
         
     | 
| 35 | 
         
            +
            SEARCH_ENGINE_ID = os.getenv("SEARCH_ENGINE_ID", "27acb0d55ad504716")
         
     | 
| 36 | 
         
            +
            print(OPENAI_API_KEY)
         
     | 
| 37 | 
         
            +
            print(OPENAI_API_IMAGE_EDIT_KEY)
         
     | 
| 38 | 
         
            +
            print(GOOGLE_API_KEY)
         
     | 
| 39 | 
         
            +
             
     | 
| 40 | 
         
            +
            class ScreenshotRequest(BaseModel):
         
     | 
| 41 | 
         
            +
                url: str
         
     | 
| 42 | 
         
            +
                width: Optional[int] = 1024
         
     | 
| 43 | 
         
            +
                height: Optional[int] = 768
         
     | 
| 44 | 
         
            +
                format: Optional[str] = "png"
         
     | 
| 45 | 
         
            +
                custom_headers: Optional[Dict[str, str]] = {}
         
     | 
| 46 | 
         
            +
             
     | 
| 47 | 
         
            +
            class AnalysisRequest(BaseModel):
         
     | 
| 48 | 
         
            +
                text: str
         
     | 
| 49 | 
         
            +
                image_data: Optional[str] = None
         
     | 
| 50 | 
         
            +
                request_model_id: str = 'gpt-4.1-mini'
         
     | 
| 51 | 
         
            +
             
     | 
| 52 | 
         
            +
            class OptimizationRequest(BaseModel):
         
     | 
| 53 | 
         
            +
                text: str
         
     | 
| 54 | 
         
            +
                image_data: str
         
     | 
| 55 | 
         
            +
                suggestions: List[str]
         
     | 
| 56 | 
         
            +
                request_model_id: str = 'gpt-image-1'
         
     | 
| 57 | 
         
            +
             
     | 
| 58 | 
         
            +
            class TextOptimizationRequest(BaseModel):
         
     | 
| 59 | 
         
            +
                original_feedback: str
         
     | 
| 60 | 
         
            +
                user_input: str
         
     | 
| 61 | 
         
            +
                request_model_id: str = 'gpt-4.1-mini'
         
     | 
| 62 | 
         
            +
             
     | 
| 63 | 
         
            +
            class SearchRequest(BaseModel):
         
     | 
| 64 | 
         
            +
                query: str
         
     | 
| 65 | 
         
            +
                num_results: Optional[int] = 2
         
     | 
| 66 | 
         
            +
             
     | 
| 67 | 
         
            +
            @app.post("/capture")
         
     | 
| 68 | 
         
            +
            async def capture_screenshot(request: ScreenshotRequest):
         
     | 
| 69 | 
         
            +
                try:
         
     | 
| 70 | 
         
            +
                    if not request.url:
         
     | 
| 71 | 
         
            +
                        raise HTTPException(status_code=400, detail="需要提供URL参数")
         
     | 
| 72 | 
         
            +
             
     | 
| 73 | 
         
            +
                    # 生成唯一的文件名
         
     | 
| 74 | 
         
            +
                    domain = urlparse(request.url).netloc.replace(".", "_")
         
     | 
| 75 | 
         
            +
                    timestamp = int(time.time() * 1000)
         
     | 
| 76 | 
         
            +
                    filename = f"{domain}_{timestamp}.{request.format}"
         
     | 
| 77 | 
         
            +
                    filepath = os.path.join(CACHE_DIR, filename)
         
     | 
| 78 | 
         
            +
             
     | 
| 79 | 
         
            +
                    logging.log(logging.INFO, f"开始为 {request.url} 生成截图...")
         
     | 
| 80 | 
         
            +
             
     | 
| 81 | 
         
            +
                    # 默认请求头
         
     | 
| 82 | 
         
            +
                    default_headers = {
         
     | 
| 83 | 
         
            +
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
         
     | 
| 84 | 
         
            +
                        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
         
     | 
| 85 | 
         
            +
                        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
         
     | 
| 86 | 
         
            +
                        "Connection": "keep-alive",
         
     | 
| 87 | 
         
            +
                        "Cache-Control": "max-age=0",
         
     | 
| 88 | 
         
            +
                        "Sec-Fetch-Dest": "document",
         
     | 
| 89 | 
         
            +
                        "Sec-Fetch-Mode": "navigate",
         
     | 
| 90 | 
         
            +
                        "Sec-Fetch-Site": "none",
         
     | 
| 91 | 
         
            +
                        "Sec-Fetch-User": "?1",
         
     | 
| 92 | 
         
            +
                        "Upgrade-Insecure-Requests": "1"
         
     | 
| 93 | 
         
            +
                    }
         
     | 
| 94 | 
         
            +
             
     | 
| 95 | 
         
            +
                    # 合并默认请求头和自定义请求头
         
     | 
| 96 | 
         
            +
                    headers = {**default_headers, **(request.custom_headers or {})}
         
     | 
| 97 | 
         
            +
             
     | 
| 98 | 
         
            +
                    async with async_playwright() as p:
         
     | 
| 99 | 
         
            +
                        browser = await p.chromium.launch()
         
     | 
| 100 | 
         
            +
                        page = await browser.new_page()
         
     | 
| 101 | 
         
            +
                        
         
     | 
| 102 | 
         
            +
                        # 设置视口大小
         
     | 
| 103 | 
         
            +
                        await page.set_viewport_size({
         
     | 
| 104 | 
         
            +
                            "width": request.width,
         
     | 
| 105 | 
         
            +
                            "height": request.height
         
     | 
| 106 | 
         
            +
                        })
         
     | 
| 107 | 
         
            +
             
     | 
| 108 | 
         
            +
                        # 设置请求头
         
     | 
| 109 | 
         
            +
                        await page.set_extra_http_headers(headers)
         
     | 
| 110 | 
         
            +
             
     | 
| 111 | 
         
            +
                        # 访问页面
         
     | 
| 112 | 
         
            +
                        await page.goto(request.url, wait_until="networkidle")
         
     | 
| 113 | 
         
            +
                        
         
     | 
| 114 | 
         
            +
                        # 生成截图
         
     | 
| 115 | 
         
            +
                        await page.screenshot(path=filepath, type=request.format)
         
     | 
| 116 | 
         
            +
                        
         
     | 
| 117 | 
         
            +
                        await browser.close()
         
     | 
| 118 | 
         
            +
             
     | 
| 119 | 
         
            +
                    logging.log(logging.DEBUG, f"截图完成: {filepath}")
         
     | 
| 120 | 
         
            +
             
     | 
| 121 | 
         
            +
                    # 返回截图URL
         
     | 
| 122 | 
         
            +
                    screenshot_url = f"/screenshots/{filename}"
         
     | 
| 123 | 
         
            +
                    
         
     | 
| 124 | 
         
            +
                    return JSONResponse({
         
     | 
| 125 | 
         
            +
                        "success": True,
         
     | 
| 126 | 
         
            +
                        "imageUrl": screenshot_url,
         
     | 
| 127 | 
         
            +
                        "filename": filename
         
     | 
| 128 | 
         
            +
                    })
         
     | 
| 129 | 
         
            +
             
     | 
| 130 | 
         
            +
                except Exception as e:
         
     | 
| 131 | 
         
            +
                    logging.error(f"截图过程中出错: {str(e)}")
         
     | 
| 132 | 
         
            +
                    raise HTTPException(status_code=500, detail=f"截图生成失败: {str(e)}")
         
     | 
| 133 | 
         
            +
             
     | 
| 134 | 
         
            +
             
     | 
| 135 | 
         
            +
            @app.get("/health")
         
     | 
| 136 | 
         
            +
            async def health_check():
         
     | 
| 137 | 
         
            +
                return {"status": "ok"}
         
     | 
| 138 | 
         
            +
             
     | 
| 139 | 
         
            +
             
     | 
| 140 | 
         
            +
            @app.get("/")
         
     | 
| 141 | 
         
            +
            def index() -> FileResponse:
         
     | 
| 142 | 
         
            +
                return FileResponse(path="static/index.html", media_type="text/html")
         
     | 
| 143 | 
         
            +
             
     | 
| 144 | 
         
            +
             
     | 
| 145 | 
         
            +
            @app.post("/api/analyze")
         
     | 
| 146 | 
         
            +
            async def analyze_feedback(request: AnalysisRequest):
         
     | 
| 147 | 
         
            +
                try:
         
     | 
| 148 | 
         
            +
                    context = "以下是老板对设计的反馈内容:\n" + request.text
         
     | 
| 149 | 
         
            +
                    
         
     | 
| 150 | 
         
            +
                    if request.image_data:
         
     | 
| 151 | 
         
            +
                        context += "\n\n用户还上传了设计图片作为参考:"
         
     | 
| 152 | 
         
            +
                    
         
     | 
| 153 | 
         
            +
                    # 调用OpenAI API进行分析
         
     | 
| 154 | 
         
            +
                    response = await call_openai_api(
         
     | 
| 155 | 
         
            +
                        system_prompt='你是一位专业的设计顾问,擅长分析客户反馈,提取关键信息,并提供专业建议。请根据老板的���馈分析情绪值(用emoji表示),并结合给出的设计稿,给出三个具体的修改建议。每个建议应该包含一个标题和详细描述。首先你需要对老板的情绪进行解读,使用"情绪值:"开头并分为五类:1. 非常满意-😊😊😊 2. 比较满意-🙂🙂🙂 3. 一般般-😐😐😐 4. 不太满意-🙁🙁🙁 5. 非常不满意-😠😠😠,然后在下一行用一句话分析老板的情绪,以"情绪分析:"开头。随后,请以"修改建议:\n"开头,并以有序列表分三行说明三个具体建议,比如:"1. 提高对比度:xxx\n 2. ...\n 3. ...\n"。记得结合图片进行分析和提出修改建议。最后,你需要使用网页搜索来获取合适的参考UI设计案例。请在新的一行以"搜索内容:"开头,给出合适的搜索内容,以获取合适的参考设计案例,注意,你只能搜索UI设计案例。',
         
     | 
| 156 | 
         
            +
                        user_content=[
         
     | 
| 157 | 
         
            +
                            {"type": "input_text", "text": context},
         
     | 
| 158 | 
         
            +
                            *([{"type": "input_image", "image_url": request.image_data}] if request.image_data else [])
         
     | 
| 159 | 
         
            +
                        ],
         
     | 
| 160 | 
         
            +
                        request_model_id=request.request_model_id
         
     | 
| 161 | 
         
            +
                    )
         
     | 
| 162 | 
         
            +
                    return JSONResponse(response)
         
     | 
| 163 | 
         
            +
                except Exception as e:
         
     | 
| 164 | 
         
            +
                    logging.error(f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 165 | 
         
            +
                    raise HTTPException(status_code=500, detail=f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 166 | 
         
            +
             
     | 
| 167 | 
         
            +
            @app.post("/api/optimize-design")
         
     | 
| 168 | 
         
            +
            async def optimize_design(request: OptimizationRequest):
         
     | 
| 169 | 
         
            +
                try:
         
     | 
| 170 | 
         
            +
                    # 构建图像生成提示词
         
     | 
| 171 | 
         
            +
                    prompt = f"基于以下设计反馈优化UI设计: {', '.join(request.suggestions)}"
         
     | 
| 172 | 
         
            +
                    
         
     | 
| 173 | 
         
            +
                    # 处理图片数据
         
     | 
| 174 | 
         
            +
                    image_data = request.image_data
         
     | 
| 175 | 
         
            +
                    
         
     | 
| 176 | 
         
            +
                    # 调用OpenAI图像编辑API
         
     | 
| 177 | 
         
            +
                    response = await call_openai_image_api(
         
     | 
| 178 | 
         
            +
                        image_data=image_data,
         
     | 
| 179 | 
         
            +
                        prompt=prompt,
         
     | 
| 180 | 
         
            +
                        request_model_id=request.request_model_id
         
     | 
| 181 | 
         
            +
                    )
         
     | 
| 182 | 
         
            +
                    
         
     | 
| 183 | 
         
            +
                    return JSONResponse(response)
         
     | 
| 184 | 
         
            +
                except Exception as e:
         
     | 
| 185 | 
         
            +
                    logging.error(f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 186 | 
         
            +
                    raise HTTPException(status_code=500, detail=f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 187 | 
         
            +
             
     | 
| 188 | 
         
            +
            @app.post("/api/optimize-text")
         
     | 
| 189 | 
         
            +
            async def optimize_text(request: TextOptimizationRequest):
         
     | 
| 190 | 
         
            +
                try:
         
     | 
| 191 | 
         
            +
                    response = await call_openai_api(
         
     | 
| 192 | 
         
            +
                        system_prompt="你是一个专业的文案优化助手,擅长将简单直接的反馈转换为礼貌、专业且保持原意的表达方式。",
         
     | 
| 193 | 
         
            +
                        user_content=[{
         
     | 
| 194 | 
         
            +
                            "type": "input_text",
         
     | 
| 195 | 
         
            +
                            "text": f"原始反馈内容:{request.original_feedback}\n\n我想回复:{request.user_input}\n\n请优化我的回复内容,使其更加礼貌、专业,同时保持原始意思,增加一些共情和专业术语。"
         
     | 
| 196 | 
         
            +
                        }],
         
     | 
| 197 | 
         
            +
                        request_model_id=request.request_model_id
         
     | 
| 198 | 
         
            +
                    )
         
     | 
| 199 | 
         
            +
                    
         
     | 
| 200 | 
         
            +
                    return JSONResponse(response)
         
     | 
| 201 | 
         
            +
                except Exception as e:
         
     | 
| 202 | 
         
            +
                    logging.error(f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 203 | 
         
            +
                    raise HTTPException(status_code=500, detail=f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 204 | 
         
            +
             
     | 
| 205 | 
         
            +
            @app.post("/api/search")
         
     | 
| 206 | 
         
            +
            async def search_design_examples(request: SearchRequest):
         
     | 
| 207 | 
         
            +
                try:
         
     | 
| 208 | 
         
            +
                    # 构建搜索查询
         
     | 
| 209 | 
         
            +
                    search_query = f"{request.query} UI设计"
         
     | 
| 210 | 
         
            +
                    
         
     | 
| 211 | 
         
            +
                    # 调用Google Custom Search API
         
     | 
| 212 | 
         
            +
                    async with aiohttp.ClientSession() as session:
         
     | 
| 213 | 
         
            +
                        async with session.get(
         
     | 
| 214 | 
         
            +
                            "https://customsearch.googleapis.com/customsearch/v1",
         
     | 
| 215 | 
         
            +
                            params={
         
     | 
| 216 | 
         
            +
                                "key": GOOGLE_API_KEY,
         
     | 
| 217 | 
         
            +
                                "q": search_query,
         
     | 
| 218 | 
         
            +
                                "cx": SEARCH_ENGINE_ID,
         
     | 
| 219 | 
         
            +
                                "num": request.num_results
         
     | 
| 220 | 
         
            +
                            }
         
     | 
| 221 | 
         
            +
                        ) as response:
         
     | 
| 222 | 
         
            +
                            if response.status != 200:
         
     | 
| 223 | 
         
            +
                                raise HTTPException(status_code=response.status, detail="Google Search API调用失败")
         
     | 
| 224 | 
         
            +
                            
         
     | 
| 225 | 
         
            +
                            search_data = await response.json()
         
     | 
| 226 | 
         
            +
                            
         
     | 
| 227 | 
         
            +
                            if not search_data.get("items"):
         
     | 
| 228 | 
         
            +
                                return JSONResponse({"items": []})
         
     | 
| 229 | 
         
            +
                            
         
     | 
| 230 | 
         
            +
                            # 处理搜索结果
         
     | 
| 231 | 
         
            +
                            results = []
         
     | 
| 232 | 
         
            +
                            for item in search_data["items"]:
         
     | 
| 233 | 
         
            +
                                result = {
         
     | 
| 234 | 
         
            +
                                    "title": item["title"].replace("</?b>", ""),
         
     | 
| 235 | 
         
            +
                                    "link": item["link"],
         
     | 
| 236 | 
         
            +
                                    "snippet": item.get("snippet", ""),
         
     | 
| 237 | 
         
            +
                                    "image": None
         
     | 
| 238 | 
         
            +
                                }
         
     | 
| 239 | 
         
            +
                                
         
     | 
| 240 | 
         
            +
                                # 尝试获取图片URL
         
     | 
| 241 | 
         
            +
                                if "pagemap" in item:
         
     | 
| 242 | 
         
            +
                                    if "cse_image" in item["pagemap"]:
         
     | 
| 243 | 
         
            +
                                        result["image"] = item["pagemap"]["cse_image"][0]["src"]
         
     | 
| 244 | 
         
            +
                                    elif "cse_thumbnail" in item["pagemap"]:
         
     | 
| 245 | 
         
            +
                                        result["image"] = item["pagemap"]["cse_thumbnail"][0]["src"]
         
     | 
| 246 | 
         
            +
                                
         
     | 
| 247 | 
         
            +
                                # 如果没有图片,使用截图服务
         
     | 
| 248 | 
         
            +
                                if not result["image"]:
         
     | 
| 249 | 
         
            +
                                    try:
         
     | 
| 250 | 
         
            +
                                        screenshot_response = await capture_screenshot(ScreenshotRequest(
         
     | 
| 251 | 
         
            +
                                            url=result["link"],
         
     | 
| 252 | 
         
            +
                                            width=1024,
         
     | 
| 253 | 
         
            +
                                            height=768,
         
     | 
| 254 | 
         
            +
                                            format="png"
         
     | 
| 255 | 
         
            +
                                        ))
         
     | 
| 256 | 
         
            +
                                        if isinstance(screenshot_response, dict) and "imageUrl" in screenshot_response:
         
     | 
| 257 | 
         
            +
                                            result["image"] = screenshot_response["imageUrl"]
         
     | 
| 258 | 
         
            +
                                    except Exception as e:
         
     | 
| 259 | 
         
            +
                                        print(f"获取截图失败: {str(e)}")
         
     | 
| 260 | 
         
            +
                                        # 使用默认图片
         
     | 
| 261 | 
         
            +
                                        result["image"] = "https://img.freepik.com/free-vector/gradient-ui-ux-background_23-2149052117.jpg"
         
     | 
| 262 | 
         
            +
                                
         
     | 
| 263 | 
         
            +
                                results.append(result)
         
     | 
| 264 | 
         
            +
                            
         
     | 
| 265 | 
         
            +
                            return JSONResponse({"items": results})
         
     | 
| 266 | 
         
            +
                            
         
     | 
| 267 | 
         
            +
                except Exception as e:
         
     | 
| 268 | 
         
            +
                    logging.error(f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 269 | 
         
            +
                    raise HTTPException(status_code=500, detail=f'Error: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 270 | 
         
            +
             
     | 
| 271 | 
         
            +
            async def call_openai_api(system_prompt: str, user_content: List[Dict], request_model_id='gpt-4.1-nano'):
         
     | 
| 272 | 
         
            +
                headers = {
         
     | 
| 273 | 
         
            +
                    "Authorization": f"Bearer {OPENAI_API_KEY}",
         
     | 
| 274 | 
         
            +
                    "Content-Type": "application/json"
         
     | 
| 275 | 
         
            +
                }
         
     | 
| 276 | 
         
            +
                
         
     | 
| 277 | 
         
            +
                data = {
         
     | 
| 278 | 
         
            +
                    "model": request_model_id,
         
     | 
| 279 | 
         
            +
                    "input": [
         
     | 
| 280 | 
         
            +
                        {
         
     | 
| 281 | 
         
            +
                            "role": "system",
         
     | 
| 282 | 
         
            +
                            "content": [{"type": "input_text", "text": system_prompt}]
         
     | 
| 283 | 
         
            +
                        },
         
     | 
| 284 | 
         
            +
                        {
         
     | 
| 285 | 
         
            +
                            "role": "user",
         
     | 
| 286 | 
         
            +
                            "content": user_content
         
     | 
| 287 | 
         
            +
                        }
         
     | 
| 288 | 
         
            +
                    ]
         
     | 
| 289 | 
         
            +
                }
         
     | 
| 290 | 
         
            +
                
         
     | 
| 291 | 
         
            +
                async with aiohttp.ClientSession() as session:
         
     | 
| 292 | 
         
            +
                    async with session.post("https://api.openai.com/v1/responses", headers=headers, json=data) as response:
         
     | 
| 293 | 
         
            +
                        if response.status != 200:
         
     | 
| 294 | 
         
            +
                            resp = await response.json()
         
     | 
| 295 | 
         
            +
                            logging.error(f'response: {resp}')
         
     | 
| 296 | 
         
            +
                            raise HTTPException(status_code=response.status, detail=f"OpenAI API调用失败, response: {resp}")
         
     | 
| 297 | 
         
            +
                        return await response.json()
         
     | 
| 298 | 
         
            +
             
     | 
| 299 | 
         
            +
            async def call_openai_image_api(image_data: str, prompt: str, request_model_id='gpt-image-1'):
         
     | 
| 300 | 
         
            +
                try:
         
     | 
| 301 | 
         
            +
                    # 从base64字符串中提取纯base64数据(如果包含前缀)
         
     | 
| 302 | 
         
            +
                    if image_data and 'base64,' in image_data:
         
     | 
| 303 | 
         
            +
                        image_data = image_data.split('base64,')[1]
         
     | 
| 304 | 
         
            +
                    
         
     | 
| 305 | 
         
            +
                    logging.log(logging.INFO, f"Processing image data (first 100 chars): {image_data[:100]}")
         
     | 
| 306 | 
         
            +
                    
         
     | 
| 307 | 
         
            +
                    # 将base64图片数据转换为文件对象
         
     | 
| 308 | 
         
            +
                    image_bytes = base64.b64decode(image_data)
         
     | 
| 309 | 
         
            +
                    image_file = BytesIO(image_bytes)
         
     | 
| 310 | 
         
            +
                    image_file.name = "original-design.png"  # 设置文件名,与JS代码一致
         
     | 
| 311 | 
         
            +
                    
         
     | 
| 312 | 
         
            +
                    # 创建OpenAI客户端
         
     | 
| 313 | 
         
            +
                    client = OpenAI(api_key=OPENAI_API_IMAGE_EDIT_KEY)
         
     | 
| 314 | 
         
            +
                    
         
     | 
| 315 | 
         
            +
                    # 调用图像编辑API
         
     | 
| 316 | 
         
            +
                    response = client.images.edit(
         
     | 
| 317 | 
         
            +
                        model=request_model_id,
         
     | 
| 318 | 
         
            +
                        image=image_file,
         
     | 
| 319 | 
         
            +
                        prompt=prompt # 明确要求返回base64格式
         
     | 
| 320 | 
         
            +
                    )
         
     | 
| 321 | 
         
            +
                    
         
     | 
| 322 | 
         
            +
                    # 获取生成的图片数据
         
     | 
| 323 | 
         
            +
                    if not response.data or len(response.data) == 0:
         
     | 
| 324 | 
         
            +
                        raise ValueError("No image data returned from API")
         
     | 
| 325 | 
         
            +
                        
         
     | 
| 326 | 
         
            +
                    image_result = response.data[0]
         
     | 
| 327 | 
         
            +
                    
         
     | 
| 328 | 
         
            +
                    # 返回与JS代码一致的格式
         
     | 
| 329 | 
         
            +
                    return {
         
     | 
| 330 | 
         
            +
                        "data": [{
         
     | 
| 331 | 
         
            +
                            "url": f"data:image/png;base64,{image_result.b64_json}",
         
     | 
| 332 | 
         
            +
                            "b64_json": image_result.b64_json
         
     | 
| 333 | 
         
            +
                        }]
         
     | 
| 334 | 
         
            +
                    }
         
     | 
| 335 | 
         
            +
                    
         
     | 
| 336 | 
         
            +
                except Exception as e:
         
     | 
| 337 | 
         
            +
                    logging.error(f'Error in call_openai_image_api: {e}, traceback: {traceback.format_exc()}')
         
     | 
| 338 | 
         
            +
                    raise HTTPException(
         
     | 
| 339 | 
         
            +
                        status_code=500, 
         
     | 
| 340 | 
         
            +
                        detail=f'Error processing image: {str(e)}'
         
     | 
| 341 | 
         
            +
                    )
         
     | 
| 342 | 
         
            +
             
     | 
| 343 | 
         
            +
            if __name__ == "__main__":
         
     | 
| 344 | 
         
            +
                import uvicorn
         
     | 
| 345 | 
         
            +
                uvicorn.run(app, host="0.0.0.0", port=7860)
         
     | 
    	
        requirements.txt
    ADDED
    
    | 
         @@ -0,0 +1,9 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            fastapi==0.104.1
         
     | 
| 2 | 
         
            +
            uvicorn==0.24.0
         
     | 
| 3 | 
         
            +
            python-multipart==0.0.6
         
     | 
| 4 | 
         
            +
            aiohttp==3.9.1
         
     | 
| 5 | 
         
            +
            playwright==1.40.0
         
     | 
| 6 | 
         
            +
            python-dotenv==1.0.0
         
     | 
| 7 | 
         
            +
            pydantic==2.5.2
         
     | 
| 8 | 
         
            +
            requests==2.31.0
         
     | 
| 9 | 
         
            +
            openai
         
     | 
    	
        service_readme.md
    ADDED
    
    | 
         @@ -0,0 +1,176 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            # 网站截图服务
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            这是一个使用 FastAPI 和 Playwright 构建的简单网站截图服务,可以生成任何网页的高质量截图。
         
     | 
| 4 | 
         
            +
             
     | 
| 5 | 
         
            +
            ## 功能特点
         
     | 
| 6 | 
         
            +
             
     | 
| 7 | 
         
            +
            - 支持任何公开可访问的网页截图
         
     | 
| 8 | 
         
            +
            - 可自定义截图尺寸
         
     | 
| 9 | 
         
            +
            - 支持 PNG 格式输出
         
     | 
| 10 | 
         
            +
            - 自动缓存生成的截图
         
     | 
| 11 | 
         
            +
            - 提供 REST API 接口
         
     | 
| 12 | 
         
            +
            - 异步处理,高性能
         
     | 
| 13 | 
         
            +
             
     | 
| 14 | 
         
            +
            ## 系统要求
         
     | 
| 15 | 
         
            +
             
     | 
| 16 | 
         
            +
            - Python 3.9 或更高版本
         
     | 
| 17 | 
         
            +
            - pip 包管理器
         
     | 
| 18 | 
         
            +
             
     | 
| 19 | 
         
            +
            ## 安装步骤
         
     | 
| 20 | 
         
            +
             
     | 
| 21 | 
         
            +
            1. 克隆或下载本项目
         
     | 
| 22 | 
         
            +
             
     | 
| 23 | 
         
            +
            2. 安装依赖
         
     | 
| 24 | 
         
            +
            ```bash
         
     | 
| 25 | 
         
            +
            pip install -r requirements.txt
         
     | 
| 26 | 
         
            +
            playwright install chromium
         
     | 
| 27 | 
         
            +
            ```
         
     | 
| 28 | 
         
            +
             
     | 
| 29 | 
         
            +
            3. 启动服务
         
     | 
| 30 | 
         
            +
            ```bash
         
     | 
| 31 | 
         
            +
            python screenshot_service.py
         
     | 
| 32 | 
         
            +
            ```
         
     | 
| 33 | 
         
            +
             
     | 
| 34 | 
         
            +
            服务将在 `http://localhost:7860` 启动。
         
     | 
| 35 | 
         
            +
             
     | 
| 36 | 
         
            +
            ## API 使用说明
         
     | 
| 37 | 
         
            +
             
     | 
| 38 | 
         
            +
            ### 生成网页截图
         
     | 
| 39 | 
         
            +
             
     | 
| 40 | 
         
            +
            **请求**:
         
     | 
| 41 | 
         
            +
             
     | 
| 42 | 
         
            +
            ```
         
     | 
| 43 | 
         
            +
            POST /capture
         
     | 
| 44 | 
         
            +
            Content-Type: application/json
         
     | 
| 45 | 
         
            +
            ```
         
     | 
| 46 | 
         
            +
             
     | 
| 47 | 
         
            +
            **请求体**:
         
     | 
| 48 | 
         
            +
             
     | 
| 49 | 
         
            +
            ```json
         
     | 
| 50 | 
         
            +
            {
         
     | 
| 51 | 
         
            +
              "url": "https://example.com",
         
     | 
| 52 | 
         
            +
              "width": 1024,
         
     | 
| 53 | 
         
            +
              "height": 768,
         
     | 
| 54 | 
         
            +
              "format": "png",
         
     | 
| 55 | 
         
            +
              "custom_headers": {
         
     | 
| 56 | 
         
            +
                "User-Agent": "Custom User Agent"
         
     | 
| 57 | 
         
            +
              }
         
     | 
| 58 | 
         
            +
            }
         
     | 
| 59 | 
         
            +
            ```
         
     | 
| 60 | 
         
            +
             
     | 
| 61 | 
         
            +
            参数说明:
         
     | 
| 62 | 
         
            +
            - `url`: 必填,要截图的网页地址
         
     | 
| 63 | 
         
            +
            - `width`: 可选,截图宽度,默认 1024
         
     | 
| 64 | 
         
            +
            - `height`: 可选,截图高度,默认 768
         
     | 
| 65 | 
         
            +
            - `format`: 可选,图片格式,目前支持 png,默认为 png
         
     | 
| 66 | 
         
            +
            - `custom_headers`: 可选,自定义请求头
         
     | 
| 67 | 
         
            +
             
     | 
| 68 | 
         
            +
            **成功响应**:
         
     | 
| 69 | 
         
            +
             
     | 
| 70 | 
         
            +
            ```json
         
     | 
| 71 | 
         
            +
            {
         
     | 
| 72 | 
         
            +
              "success": true,
         
     | 
| 73 | 
         
            +
              "imageUrl": "http://localhost:7860/screenshots/example_com_1633456789.png",
         
     | 
| 74 | 
         
            +
              "filename": "example_com_1633456789.png"
         
     | 
| 75 | 
         
            +
            }
         
     | 
| 76 | 
         
            +
            ```
         
     | 
| 77 | 
         
            +
             
     | 
| 78 | 
         
            +
            **错误响应**:
         
     | 
| 79 | 
         
            +
             
     | 
| 80 | 
         
            +
            ```json
         
     | 
| 81 | 
         
            +
            {
         
     | 
| 82 | 
         
            +
              "detail": "截图生成失败: 导航超时,网页加载时间过长"
         
     | 
| 83 | 
         
            +
            }
         
     | 
| 84 | 
         
            +
            ```
         
     | 
| 85 | 
         
            +
             
     | 
| 86 | 
         
            +
            ### 检查服务健康状态
         
     | 
| 87 | 
         
            +
             
     | 
| 88 | 
         
            +
            **请求**:
         
     | 
| 89 | 
         
            +
             
     | 
| 90 | 
         
            +
            ```
         
     | 
| 91 | 
         
            +
            GET /health
         
     | 
| 92 | 
         
            +
            ```
         
     | 
| 93 | 
         
            +
             
     | 
| 94 | 
         
            +
            **响应**:
         
     | 
| 95 | 
         
            +
             
     | 
| 96 | 
         
            +
            ```json
         
     | 
| 97 | 
         
            +
            {
         
     | 
| 98 | 
         
            +
              "status": "ok"
         
     | 
| 99 | 
         
            +
            }
         
     | 
| 100 | 
         
            +
            ```
         
     | 
| 101 | 
         
            +
             
     | 
| 102 | 
         
            +
            ## 在你的应用中使用
         
     | 
| 103 | 
         
            +
             
     | 
| 104 | 
         
            +
            在客户端 JavaScript 中调用服务:
         
     | 
| 105 | 
         
            +
             
     | 
| 106 | 
         
            +
            ```javascript
         
     | 
| 107 | 
         
            +
            async function getScreenshot(url) {
         
     | 
| 108 | 
         
            +
              try {
         
     | 
| 109 | 
         
            +
                const response = await fetch('http://localhost:7860/capture', {
         
     | 
| 110 | 
         
            +
                  method: 'POST',
         
     | 
| 111 | 
         
            +
                  headers: {
         
     | 
| 112 | 
         
            +
                    'Content-Type': 'application/json'
         
     | 
| 113 | 
         
            +
                  },
         
     | 
| 114 | 
         
            +
                  body: JSON.stringify({
         
     | 
| 115 | 
         
            +
                    url: url,
         
     | 
| 116 | 
         
            +
                    width: 1024,
         
     | 
| 117 | 
         
            +
                    height: 768
         
     | 
| 118 | 
         
            +
                  })
         
     | 
| 119 | 
         
            +
                });
         
     | 
| 120 | 
         
            +
                
         
     | 
| 121 | 
         
            +
                const data = await response.json();
         
     | 
| 122 | 
         
            +
                return data.imageUrl;
         
     | 
| 123 | 
         
            +
              } catch (error) {
         
     | 
| 124 | 
         
            +
                console.error('截图服务请求失败:', error);
         
     | 
| 125 | 
         
            +
                return null;
         
     | 
| 126 | 
         
            +
              }
         
     | 
| 127 | 
         
            +
            }
         
     | 
| 128 | 
         
            +
            ```
         
     | 
| 129 | 
         
            +
             
     | 
| 130 | 
         
            +
            在 Python 中调用服务:
         
     | 
| 131 | 
         
            +
             
     | 
| 132 | 
         
            +
            ```python
         
     | 
| 133 | 
         
            +
            import requests
         
     | 
| 134 | 
         
            +
             
     | 
| 135 | 
         
            +
            def get_screenshot(url):
         
     | 
| 136 | 
         
            +
                try:
         
     | 
| 137 | 
         
            +
                    response = requests.post(
         
     | 
| 138 | 
         
            +
                        'http://localhost:7860/capture',
         
     | 
| 139 | 
         
            +
                        json={
         
     | 
| 140 | 
         
            +
                            'url': url,
         
     | 
| 141 | 
         
            +
                            'width': 1024,
         
     | 
| 142 | 
         
            +
                            'height': 768
         
     | 
| 143 | 
         
            +
                        }
         
     | 
| 144 | 
         
            +
                    )
         
     | 
| 145 | 
         
            +
                    data = response.json()
         
     | 
| 146 | 
         
            +
                    return data['imageUrl']
         
     | 
| 147 | 
         
            +
                except Exception as e:
         
     | 
| 148 | 
         
            +
                    print(f'截图服务请求失败: {str(e)}')
         
     | 
| 149 | 
         
            +
                    return None
         
     | 
| 150 | 
         
            +
            ```
         
     | 
| 151 | 
         
            +
             
     | 
| 152 | 
         
            +
            ## 部署建议
         
     | 
| 153 | 
         
            +
             
     | 
| 154 | 
         
            +
            在生产环境部署时,建议:
         
     | 
| 155 | 
         
            +
             
     | 
| 156 | 
         
            +
            1. 使用 Docker 容器化部署
         
     | 
| 157 | 
         
            +
            2. 使用 Gunicorn 或 Uvicorn 作为生产级 ASGI 服务器
         
     | 
| 158 | 
         
            +
            3. 设置合适的超时时间和内存限制
         
     | 
| 159 | 
         
            +
            4. 配置 HTTPS 以保证安全性
         
     | 
| 160 | 
         
            +
            5. 添加访问限制或身份验证
         
     | 
| 161 | 
         
            +
             
     | 
| 162 | 
         
            +
            ## Docker 部署
         
     | 
| 163 | 
         
            +
             
     | 
| 164 | 
         
            +
            1. 构建镜像
         
     | 
| 165 | 
         
            +
            ```bash
         
     | 
| 166 | 
         
            +
            docker build -t screenshot-service .
         
     | 
| 167 | 
         
            +
            ```
         
     | 
| 168 | 
         
            +
             
     | 
| 169 | 
         
            +
            2. 运行容器
         
     | 
| 170 | 
         
            +
            ```bash
         
     | 
| 171 | 
         
            +
            docker run -p 7860:7860 screenshot-service
         
     | 
| 172 | 
         
            +
            ```
         
     | 
| 173 | 
         
            +
             
     | 
| 174 | 
         
            +
            ## 许可证
         
     | 
| 175 | 
         
            +
             
     | 
| 176 | 
         
            +
            MIT 
         
     | 
    	
        static/feedback.html
    ADDED
    
    | 
         @@ -0,0 +1,121 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            <!DOCTYPE html>
         
     | 
| 2 | 
         
            +
            <html lang="zh-CN">
         
     | 
| 3 | 
         
            +
            <head>
         
     | 
| 4 | 
         
            +
                <meta charset="UTF-8">
         
     | 
| 5 | 
         
            +
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
         
     | 
| 6 | 
         
            +
                <title>反馈建议 - 解语花</title>
         
     | 
| 7 | 
         
            +
                <link rel="stylesheet" href="/static/styles.css">
         
     | 
| 8 | 
         
            +
            </head>
         
     | 
| 9 | 
         
            +
            <body>
         
     | 
| 10 | 
         
            +
                <div class="dark-container">
         
     | 
| 11 | 
         
            +
                    <header>
         
     | 
| 12 | 
         
            +
                        <div class="logo"><a href="/static/index.html">解语花</a></div>
         
     | 
| 13 | 
         
            +
                    </header>
         
     | 
| 14 | 
         
            +
                    
         
     | 
| 15 | 
         
            +
                    <main class="feedback-page">
         
     | 
| 16 | 
         
            +
                        <section class="feedback-section">
         
     | 
| 17 | 
         
            +
                            <h2 class="section-title">情绪值</h2>
         
     | 
| 18 | 
         
            +
                            <div class="emotion-card">
         
     | 
| 19 | 
         
            +
                                <div class="emotion-icons">
         
     | 
| 20 | 
         
            +
                                    <span class="emoji">😠</span>
         
     | 
| 21 | 
         
            +
                                    <span class="emoji">😠</span>
         
     | 
| 22 | 
         
            +
                                    <span class="emoji">😠</span>
         
     | 
| 23 | 
         
            +
                                </div>
         
     | 
| 24 | 
         
            +
                                <div class="emotion-text">老板对设计非常不满意,建议全面改进</div>
         
     | 
| 25 | 
         
            +
                            </div>
         
     | 
| 26 | 
         
            +
                        </section>
         
     | 
| 27 | 
         
            +
                        
         
     | 
| 28 | 
         
            +
                        <section class="feedback-section">
         
     | 
| 29 | 
         
            +
                            <h2 class="section-title">修改建议</h2>
         
     | 
| 30 | 
         
            +
                            <div class="suggestions-container">
         
     | 
| 31 | 
         
            +
                                <div class="suggestion-card yellow-top">
         
     | 
| 32 | 
         
            +
                                    <h3 class="suggestion-title">色彩调整</h3>
         
     | 
| 33 | 
         
            +
                                    <p class="suggestion-text">在保持整体色调的基础上,加入一些明亮的点缀色,如淡黄色、淡紫蓝、淡红蓝微粉等。用于按钮、图标或重要文本,以增加吸引力。</p>
         
     | 
| 34 | 
         
            +
                                </div>
         
     | 
| 35 | 
         
            +
                                
         
     | 
| 36 | 
         
            +
                                <div class="suggestion-card cyan-top">
         
     | 
| 37 | 
         
            +
                                    <h3 class="suggestion-title">增加层级感</h3>
         
     | 
| 38 | 
         
            +
                                    <p class="suggestion-text">利用饱和度(Glassmorphism)效果,为卡片/重要框添加模糊背景和阴影,营造出浮起感,引入3D元素或深浅变化,增加页面的深度和空间感。</p>
         
     | 
| 39 | 
         
            +
                                </div>
         
     | 
| 40 | 
         
            +
                                
         
     | 
| 41 | 
         
            +
                                <div class="suggestion-card purple-top">
         
     | 
| 42 | 
         
            +
                                    <h3 class="suggestion-title">增加互动性</h3>
         
     | 
| 43 | 
         
            +
                                    <p class="suggestion-text">为按钮和图标添加悬停动画或点击动画,提供用户及时反馈。引入微动画(Micro-interactions),如加载动画、切换动画等等,使页面更具活力。</p>
         
     | 
| 44 | 
         
            +
                                </div>
         
     | 
| 45 | 
         
            +
                            </div>
         
     | 
| 46 | 
         
            +
                        </section>
         
     | 
| 47 | 
         
            +
                        
         
     | 
| 48 | 
         
            +
                        <section class="feedback-section">
         
     | 
| 49 | 
         
            +
                            <h2 class="section-title">参考案例</h2>
         
     | 
| 50 | 
         
            +
                            <div class="examples-container">
         
     | 
| 51 | 
         
            +
                                <div class="example-card">
         
     | 
| 52 | 
         
            +
                                    <img class="example-image" src="" alt="参考案例1">
         
     | 
| 53 | 
         
            +
                                    <div class="example-content">
         
     | 
| 54 | 
         
            +
                                        <p class="example-desc">加载中...</p>
         
     | 
| 55 | 
         
            +
                                        <div class="example-source">来源: <a href="#" target="_blank">加载中...</a></div>
         
     | 
| 56 | 
         
            +
                                    </div>
         
     | 
| 57 | 
         
            +
                                </div>
         
     | 
| 58 | 
         
            +
                                <div class="example-card">
         
     | 
| 59 | 
         
            +
                                    <img class="example-image" src="" alt="参考案例2">
         
     | 
| 60 | 
         
            +
                                    <div class="example-content">
         
     | 
| 61 | 
         
            +
                                        <p class="example-desc">加载中...</p>
         
     | 
| 62 | 
         
            +
                                        <div class="example-source">来源: <a href="#" target="_blank">加载中...</a></div>
         
     | 
| 63 | 
         
            +
                                    </div>
         
     | 
| 64 | 
         
            +
                                </div>
         
     | 
| 65 | 
         
            +
                            </div>
         
     | 
| 66 | 
         
            +
                        </section>
         
     | 
| 67 | 
         
            +
                        
         
     | 
| 68 | 
         
            +
                        <section class="feedback-section">
         
     | 
| 69 | 
         
            +
                            <h2 class="section-title">优化方案</h2>
         
     | 
| 70 | 
         
            +
                            <div class="optimization-container">
         
     | 
| 71 | 
         
            +
                                <div class="optimization-card">
         
     | 
| 72 | 
         
            +
                                    <div class="optimization-header">
         
     | 
| 73 | 
         
            +
                                        <h3 class="optimization-title">方案一:GPT优化</h3>
         
     | 
| 74 | 
         
            +
                                        <button class="generate-btn" id="gpt4-btn">生成优化</button>
         
     | 
| 75 | 
         
            +
                                    </div>
         
     | 
| 76 | 
         
            +
                                    <div class="optimization-content" id="gpt4-content">
         
     | 
| 77 | 
         
            +
                                        <div class="optimization-placeholder">
         
     | 
| 78 | 
         
            +
                                            <p>基于GPT-4o的智能优化,结合老板反馈进行针对性修改</p>
         
     | 
| 79 | 
         
            +
                                        </div>
         
     | 
| 80 | 
         
            +
                                    </div>
         
     | 
| 81 | 
         
            +
                                </div>
         
     | 
| 82 | 
         
            +
                                
         
     | 
| 83 | 
         
            +
                                <div class="optimization-card">
         
     | 
| 84 | 
         
            +
                                    <div class="optimization-header">
         
     | 
| 85 | 
         
            +
                                        <h3 class="optimization-title">方案二:Dalle优化</h3>
         
     | 
| 86 | 
         
            +
                                        <button class="generate-btn" id="mj-btn">生成创意</button>
         
     | 
| 87 | 
         
            +
                                    </div>
         
     | 
| 88 | 
         
            +
                                    <div class="optimization-content" id="mj-content">
         
     | 
| 89 | 
         
            +
                                        <div class="optimization-placeholder">
         
     | 
| 90 | 
         
            +
                                            <p>基于Dalle的创意重构,提供全新设计灵感</p>
         
     | 
| 91 | 
         
            +
                                        </div>
         
     | 
| 92 | 
         
            +
                                    </div>
         
     | 
| 93 | 
         
            +
                                </div>
         
     | 
| 94 | 
         
            +
                            </div>
         
     | 
| 95 | 
         
            +
                        </section>
         
     | 
| 96 | 
         
            +
                        
         
     | 
| 97 | 
         
            +
                        <section class="feedback-section">
         
     | 
| 98 | 
         
            +
                            <h2 class="section-title">润色</h2>
         
     | 
| 99 | 
         
            +
                            <div class="polished-card">
         
     | 
| 100 | 
         
            +
                                <textarea placeholder="输入你要回复老板的话" id="userInput"></textarea>
         
     | 
| 101 | 
         
            +
                            </div>
         
     | 
| 102 | 
         
            +
                            
         
     | 
| 103 | 
         
            +
                            <!-- 生成后的文案框,初始隐藏 -->
         
     | 
| 104 | 
         
            +
                            <div class="result-card" id="resultCard" style="display: none;">
         
     | 
| 105 | 
         
            +
                                <div class="result-title">优化后的文案</div>
         
     | 
| 106 | 
         
            +
                                <div class="result-content" id="resultContent"></div>
         
     | 
| 107 | 
         
            +
                            </div>
         
     | 
| 108 | 
         
            +
                        </section>
         
     | 
| 109 | 
         
            +
                        
         
     | 
| 110 | 
         
            +
                        <div class="button-container">
         
     | 
| 111 | 
         
            +
                            <button type="button" class="generate-button" id="generateBtn">生成</button>
         
     | 
| 112 | 
         
            +
                        </div>
         
     | 
| 113 | 
         
            +
                        
         
     | 
| 114 | 
         
            +
                        <!-- Toast提示 -->
         
     | 
| 115 | 
         
            +
                        <div class="toast" id="toast">生成中...</div>
         
     | 
| 116 | 
         
            +
                    </main>
         
     | 
| 117 | 
         
            +
                </div>
         
     | 
| 118 | 
         
            +
                
         
     | 
| 119 | 
         
            +
                <script src="/static/script.js"></script>
         
     | 
| 120 | 
         
            +
            </body>
         
     | 
| 121 | 
         
            +
            </html> 
         
     | 
    	
        static/index.html
    ADDED
    
    | 
         @@ -0,0 +1,79 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            <!DOCTYPE html>
         
     | 
| 2 | 
         
            +
            <html lang="zh-CN">
         
     | 
| 3 | 
         
            +
            <head>
         
     | 
| 4 | 
         
            +
                <meta charset="UTF-8">
         
     | 
| 5 | 
         
            +
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
         
     | 
| 6 | 
         
            +
                <title>解语花 - AI驱动的文案优化平台</title>
         
     | 
| 7 | 
         
            +
                <link rel="stylesheet" href="/static/styles.css">
         
     | 
| 8 | 
         
            +
            </head>
         
     | 
| 9 | 
         
            +
            <body>
         
     | 
| 10 | 
         
            +
               
         
     | 
| 11 | 
         
            +
                <div class="landing-container">
         
     | 
| 12 | 
         
            +
                    <header>
         
     | 
| 13 | 
         
            +
                        <div class="logo">解语花</div>
         
     | 
| 14 | 
         
            +
                    </header>
         
     | 
| 15 | 
         
            +
                    
         
     | 
| 16 | 
         
            +
                    <main class="landing-content">
         
     | 
| 17 | 
         
            +
                        <div class="floating-avatar">
         
     | 
| 18 | 
         
            +
                            <div class="avatar-icon">
         
     | 
| 19 | 
         
            +
                                <img src="/static/assets/avatar.svg" alt="头像" class="avatar-img">
         
     | 
| 20 | 
         
            +
                            </div>
         
     | 
| 21 | 
         
            +
                            <div class="dynamic-text" id="dynamic-text">"丑"</div>
         
     | 
| 22 | 
         
            +
                        </div>
         
     | 
| 23 | 
         
            +
                        
         
     | 
| 24 | 
         
            +
                        <div class="floating-feature">
         
     | 
| 25 | 
         
            +
                            <div class="feature-icon">
         
     | 
| 26 | 
         
            +
                                <img src="/static/assets/biao.png" alt="解码潜台词图标">
         
     | 
| 27 | 
         
            +
                            </div>
         
     | 
| 28 | 
         
            +
                            <div class="feature-text">解码潜台词</div>
         
     | 
| 29 | 
         
            +
                        </div>
         
     | 
| 30 | 
         
            +
                        
         
     | 
| 31 | 
         
            +
                        <div class="flower-container">
         
     | 
| 32 | 
         
            +
                            <img src="/static/assets/flower.webp" alt="花朵" class="flower-img">
         
     | 
| 33 | 
         
            +
                        </div>
         
     | 
| 34 | 
         
            +
                  
         
     | 
| 35 | 
         
            +
                     
         
     | 
| 36 | 
         
            +
                        
         
     | 
| 37 | 
         
            +
                        <div class="hero-title">
         
     | 
| 38 | 
         
            +
                            <div class="biao-container">
         
     | 
| 39 | 
         
            +
                                <img src="/static/assets/biao.png" alt="花朵" class="biao-img">
         
     | 
| 40 | 
         
            +
                            </div>
         
     | 
| 41 | 
         
            +
                            <p class="description">
         
     | 
| 42 | 
         
            +
                                「AI解码潜台词,揭穿《求生欲不强》,让您既能察言观色时,也能随心所欲地表达」<br>
         
     | 
| 43 | 
         
            +
                                翻译准确率99.9%,比谷歌不少点艺术,多点幽默。
         
     | 
| 44 | 
         
            +
                            </p>
         
     | 
| 45 | 
         
            +
                            <a href="/static/upload.html" class="cta-button">一键体验</a>
         
     | 
| 46 | 
         
            +
                        </div>
         
     | 
| 47 | 
         
            +
                        
         
     | 
| 48 | 
         
            +
                        <div class="showcase-section">
         
     | 
| 49 | 
         
            +
                            <div class="device-wrapper">
         
     | 
| 50 | 
         
            +
                                <div class="showcase-device device1">
         
     | 
| 51 | 
         
            +
                                    <img src="/static/assets/device1.jpg" alt="设备展示1">
         
     | 
| 52 | 
         
            +
                                </div>
         
     | 
| 53 | 
         
            +
                                <div class="showcase-device device2">
         
     | 
| 54 | 
         
            +
                                    <img src="/static/assets/device2.jpg" alt="设备展示2">
         
     | 
| 55 | 
         
            +
                                </div>
         
     | 
| 56 | 
         
            +
                                <div class="showcase-device device3">
         
     | 
| 57 | 
         
            +
                                    <img src="/static/assets/device3.jpg" alt="设备展示3">
         
     | 
| 58 | 
         
            +
                                </div>
         
     | 
| 59 | 
         
            +
                                <div class="showcase-device device4">
         
     | 
| 60 | 
         
            +
                                    <img src="/static/assets/device4.jpg" alt="3D展示">
         
     | 
| 61 | 
         
            +
                                </div>
         
     | 
| 62 | 
         
            +
                            </div>
         
     | 
| 63 | 
         
            +
                        </div>
         
     | 
| 64 | 
         
            +
                        
         
     | 
| 65 | 
         
            +
                        <div class="bottom-section">
         
     | 
| 66 | 
         
            +
                            <div class="subtitle-text">改稿PTSD? 不存在的!</div>
         
     | 
| 67 | 
         
            +
                            <h2 class="secondary-title">不同设计类型-AI老中医都能治</h2>
         
     | 
| 68 | 
         
            +
                            <p class="description-secondary">
         
     | 
| 69 | 
         
            +
                                「「UI界面逻辑混乱?品牌视觉割裂?营销图转化率低?
         
     | 
| 70 | 
         
            +
                                AI设计老中医上线——把脉图层结构,透视视觉动线,专治设计『我以为这样能过稿』综合症」
         
     | 
| 71 | 
         
            +
                            </p>
         
     | 
| 72 | 
         
            +
                            <a href="/static/upload.html" class="cta-button secondary-button">一键体验</a>
         
     | 
| 73 | 
         
            +
                        </div>
         
     | 
| 74 | 
         
            +
                    </main>
         
     | 
| 75 | 
         
            +
                </div>
         
     | 
| 76 | 
         
            +
                
         
     | 
| 77 | 
         
            +
                <script src="/static/script.js"></script>
         
     | 
| 78 | 
         
            +
            </body>
         
     | 
| 79 | 
         
            +
            </html> 
         
     | 
    	
        static/script.js
    ADDED
    
    | 
         @@ -0,0 +1,946 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            document.addEventListener('DOMContentLoaded', function() {
         
     | 
| 2 | 
         
            +
                // 添加基础URL配置
         
     | 
| 3 | 
         
            +
                const BASE_URL = 'https://jasonnoy-url-thumbnail.hf.space/';  // 空字符串表示使用相对路径
         
     | 
| 4 | 
         
            +
                
         
     | 
| 5 | 
         
            +
                // 动态文案循环显示 - 打字机效果
         
     | 
| 6 | 
         
            +
                const dynamicText = document.getElementById('dynamic-text');
         
     | 
| 7 | 
         
            +
                if (dynamicText) {
         
     | 
| 8 | 
         
            +
                    const texts = ['"丑"', '"不高级"', '"再试试"'];
         
     | 
| 9 | 
         
            +
                    let currentIndex = 0;
         
     | 
| 10 | 
         
            +
                    let isDeleting = false;
         
     | 
| 11 | 
         
            +
                    let charIndex = 0;
         
     | 
| 12 | 
         
            +
                    let typingSpeed = 150; // 打字速度
         
     | 
| 13 | 
         
            +
                    let pauseTime = 2000; // 完成后暂停时间,调整为2秒
         
     | 
| 14 | 
         
            +
                    
         
     | 
| 15 | 
         
            +
                    function typeEffect() {
         
     | 
| 16 | 
         
            +
                        const currentText = texts[currentIndex];
         
     | 
| 17 | 
         
            +
                        
         
     | 
| 18 | 
         
            +
                        if (!isDeleting) {
         
     | 
| 19 | 
         
            +
                            // 打字阶段
         
     | 
| 20 | 
         
            +
                            if (charIndex < currentText.length) {
         
     | 
| 21 | 
         
            +
                                dynamicText.textContent = currentText.substring(0, charIndex + 1);
         
     | 
| 22 | 
         
            +
                                charIndex++;
         
     | 
| 23 | 
         
            +
                                setTimeout(typeEffect, typingSpeed);
         
     | 
| 24 | 
         
            +
                            } else {
         
     | 
| 25 | 
         
            +
                                // 完成打字,等待删除
         
     | 
| 26 | 
         
            +
                                setTimeout(() => {
         
     | 
| 27 | 
         
            +
                                    isDeleting = true;
         
     | 
| 28 | 
         
            +
                                    typeEffect();
         
     | 
| 29 | 
         
            +
                                }, pauseTime);
         
     | 
| 30 | 
         
            +
                            }
         
     | 
| 31 | 
         
            +
                        } else {
         
     | 
| 32 | 
         
            +
                            // 删除阶段
         
     | 
| 33 | 
         
            +
                            if (charIndex > 0) {
         
     | 
| 34 | 
         
            +
                                dynamicText.textContent = currentText.substring(0, charIndex);
         
     | 
| 35 | 
         
            +
                                charIndex--;
         
     | 
| 36 | 
         
            +
                                setTimeout(typeEffect, typingSpeed / 2);
         
     | 
| 37 | 
         
            +
                            } else {
         
     | 
| 38 | 
         
            +
                                // 完成删除,切换到下一个文案
         
     | 
| 39 | 
         
            +
                                isDeleting = false;
         
     | 
| 40 | 
         
            +
                                currentIndex = (currentIndex + 1) % texts.length;
         
     | 
| 41 | 
         
            +
                                setTimeout(typeEffect, 500);
         
     | 
| 42 | 
         
            +
                            }
         
     | 
| 43 | 
         
            +
                        }
         
     | 
| 44 | 
         
            +
                    }
         
     | 
| 45 | 
         
            +
                    
         
     | 
| 46 | 
         
            +
                    // 开始打字机效果
         
     | 
| 47 | 
         
            +
                    typeEffect();
         
     | 
| 48 | 
         
            +
                }
         
     | 
| 49 | 
         
            +
                
         
     | 
| 50 | 
         
            +
                // 添加花朵的微小浮动动画
         
     | 
| 51 | 
         
            +
                const flowerImg = document.querySelector('.flower-img');
         
     | 
| 52 | 
         
            +
                if (flowerImg) {
         
     | 
| 53 | 
         
            +
                    flowerImg.style.animation = 'floatFlower 4s ease-in-out infinite alternate';
         
     | 
| 54 | 
         
            +
                }
         
     | 
| 55 | 
         
            +
                
         
     | 
| 56 | 
         
            +
                // 添加浮动动画的CSS
         
     | 
| 57 | 
         
            +
                const style = document.createElement('style');
         
     | 
| 58 | 
         
            +
                style.textContent = `
         
     | 
| 59 | 
         
            +
                    @keyframes floatFlower {
         
     | 
| 60 | 
         
            +
                        0% {
         
     | 
| 61 | 
         
            +
                            transform: translateY(0) rotate(0);
         
     | 
| 62 | 
         
            +
                        }
         
     | 
| 63 | 
         
            +
                        100% {
         
     | 
| 64 | 
         
            +
                            transform: translateY(-15px) rotate(2deg);
         
     | 
| 65 | 
         
            +
                        }
         
     | 
| 66 | 
         
            +
                    }
         
     | 
| 67 | 
         
            +
                `;
         
     | 
| 68 | 
         
            +
                document.head.appendChild(style);
         
     | 
| 69 | 
         
            +
                
         
     | 
| 70 | 
         
            +
                // 图片上传处理
         
     | 
| 71 | 
         
            +
                const imageUploadArea = document.getElementById('image-upload');
         
     | 
| 72 | 
         
            +
                const imageInput = document.getElementById('image-input');
         
     | 
| 73 | 
         
            +
                
         
     | 
| 74 | 
         
            +
                if (imageUploadArea && imageInput) {
         
     | 
| 75 | 
         
            +
                    imageUploadArea.addEventListener('click', function() {
         
     | 
| 76 | 
         
            +
                        imageInput.click();
         
     | 
| 77 | 
         
            +
                    });
         
     | 
| 78 | 
         
            +
                    
         
     | 
| 79 | 
         
            +
                    imageInput.addEventListener('change', function() {
         
     | 
| 80 | 
         
            +
                        if (this.files && this.files[0]) {
         
     | 
| 81 | 
         
            +
                            const reader = new FileReader();
         
     | 
| 82 | 
         
            +
                            
         
     | 
| 83 | 
         
            +
                            reader.onload = function(e) {
         
     | 
| 84 | 
         
            +
                                // 移除上传按钮
         
     | 
| 85 | 
         
            +
                                while (imageUploadArea.firstChild) {
         
     | 
| 86 | 
         
            +
                                    imageUploadArea.removeChild(imageUploadArea.firstChild);
         
     | 
| 87 | 
         
            +
                                }
         
     | 
| 88 | 
         
            +
                                
         
     | 
| 89 | 
         
            +
                                // 添加预览图片
         
     | 
| 90 | 
         
            +
                                const img = document.createElement('img');
         
     | 
| 91 | 
         
            +
                                img.src = e.target.result;
         
     | 
| 92 | 
         
            +
                                imageUploadArea.appendChild(img);
         
     | 
| 93 | 
         
            +
                                imageUploadArea.classList.add('with-image');
         
     | 
| 94 | 
         
            +
                                
         
     | 
| 95 | 
         
            +
                                // 存储图片数据到 sessionStorage 以便在反馈页面使用
         
     | 
| 96 | 
         
            +
                                sessionStorage.setItem('uploadedImage', e.target.result);
         
     | 
| 97 | 
         
            +
                            };
         
     | 
| 98 | 
         
            +
                            
         
     | 
| 99 | 
         
            +
                            reader.readAsDataURL(this.files[0]);
         
     | 
| 100 | 
         
            +
                        }
         
     | 
| 101 | 
         
            +
                    });
         
     | 
| 102 | 
         
            +
                    
         
     | 
| 103 | 
         
            +
                    // 拖放上传功能
         
     | 
| 104 | 
         
            +
                    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
         
     | 
| 105 | 
         
            +
                        imageUploadArea.addEventListener(eventName, preventDefaults, false);
         
     | 
| 106 | 
         
            +
                    });
         
     | 
| 107 | 
         
            +
                    
         
     | 
| 108 | 
         
            +
                    function preventDefaults(e) {
         
     | 
| 109 | 
         
            +
                        e.preventDefault();
         
     | 
| 110 | 
         
            +
                        e.stopPropagation();
         
     | 
| 111 | 
         
            +
                    }
         
     | 
| 112 | 
         
            +
                    
         
     | 
| 113 | 
         
            +
                    ['dragenter', 'dragover'].forEach(eventName => {
         
     | 
| 114 | 
         
            +
                        imageUploadArea.addEventListener(eventName, function() {
         
     | 
| 115 | 
         
            +
                            imageUploadArea.classList.add('highlight');
         
     | 
| 116 | 
         
            +
                        }, false);
         
     | 
| 117 | 
         
            +
                    });
         
     | 
| 118 | 
         
            +
                    
         
     | 
| 119 | 
         
            +
                    ['dragleave', 'drop'].forEach(eventName => {
         
     | 
| 120 | 
         
            +
                        imageUploadArea.addEventListener(eventName, function() {
         
     | 
| 121 | 
         
            +
                            imageUploadArea.classList.remove('highlight');
         
     | 
| 122 | 
         
            +
                        }, false);
         
     | 
| 123 | 
         
            +
                    });
         
     | 
| 124 | 
         
            +
                    
         
     | 
| 125 | 
         
            +
                    imageUploadArea.addEventListener('drop', function(e) {
         
     | 
| 126 | 
         
            +
                        const dt = e.dataTransfer;
         
     | 
| 127 | 
         
            +
                        const files = dt.files;
         
     | 
| 128 | 
         
            +
                        
         
     | 
| 129 | 
         
            +
                        if (files && files[0]) {
         
     | 
| 130 | 
         
            +
                            imageInput.files = files;
         
     | 
| 131 | 
         
            +
                            
         
     | 
| 132 | 
         
            +
                            const reader = new FileReader();
         
     | 
| 133 | 
         
            +
                            
         
     | 
| 134 | 
         
            +
                            reader.onload = function(e) {
         
     | 
| 135 | 
         
            +
                                // 移除上传按钮
         
     | 
| 136 | 
         
            +
                                while (imageUploadArea.firstChild) {
         
     | 
| 137 | 
         
            +
                                    imageUploadArea.removeChild(imageUploadArea.firstChild);
         
     | 
| 138 | 
         
            +
                                }
         
     | 
| 139 | 
         
            +
                                
         
     | 
| 140 | 
         
            +
                                // 添加预览图片
         
     | 
| 141 | 
         
            +
                                const img = document.createElement('img');
         
     | 
| 142 | 
         
            +
                                img.src = e.target.result;
         
     | 
| 143 | 
         
            +
                                imageUploadArea.appendChild(img);
         
     | 
| 144 | 
         
            +
                                imageUploadArea.classList.add('with-image');
         
     | 
| 145 | 
         
            +
                                
         
     | 
| 146 | 
         
            +
                                sessionStorage.setItem('uploadedImage', e.target.result);
         
     | 
| 147 | 
         
            +
                                console.log("image uploaded")
         
     | 
| 148 | 
         
            +
                            };
         
     | 
| 149 | 
         
            +
                            
         
     | 
| 150 | 
         
            +
                            reader.readAsDataURL(files[0]);
         
     | 
| 151 | 
         
            +
                        }
         
     | 
| 152 | 
         
            +
                    }, false);
         
     | 
| 153 | 
         
            +
                }
         
     | 
| 154 | 
         
            +
                
         
     | 
| 155 | 
         
            +
                // 解析按钮处理
         
     | 
| 156 | 
         
            +
                const resolveButton = document.getElementById('resolve-button');
         
     | 
| 157 | 
         
            +
                const textInput = document.getElementById('text-input');
         
     | 
| 158 | 
         
            +
             
     | 
| 159 | 
         
            +
                
         
     | 
| 160 | 
         
            +
                if (resolveButton && textInput) {
         
     | 
| 161 | 
         
            +
                    resolveButton.addEventListener('click', function() {
         
     | 
| 162 | 
         
            +
                        const text = textInput.value.trim();
         
     | 
| 163 | 
         
            +
                        // 检查是否有文本输入
         
     | 
| 164 | 
         
            +
                        if (text === '') {
         
     | 
| 165 | 
         
            +
                            alert('请输入老板反馈内容');
         
     | 
| 166 | 
         
            +
                            return;
         
     | 
| 167 | 
         
            +
                        }
         
     | 
| 168 | 
         
            +
                        
         
     | 
| 169 | 
         
            +
                        // 显示加载状态
         
     | 
| 170 | 
         
            +
                        resolveButton.disabled = true;
         
     | 
| 171 | 
         
            +
                        
         
     | 
| 172 | 
         
            +
                        // 有趣的加载文案
         
     | 
| 173 | 
         
            +
                        const loadingTexts = [
         
     | 
| 174 | 
         
            +
                            "检测到甲方第8版需求残留怨气...正在召唤阴阳师修改图层结界",
         
     | 
| 175 | 
         
            +
                            "监控到大象对话框散发红光!自动生成24K纯杠精防护罩..."
         
     | 
| 176 | 
         
            +
                        ];
         
     | 
| 177 | 
         
            +
                        
         
     | 
| 178 | 
         
            +
                        // 随机选择一个文案作为起点
         
     | 
| 179 | 
         
            +
                        let currentTextIndex = Math.floor(Math.random() * loadingTexts.length);
         
     | 
| 180 | 
         
            +
                        let currentText = loadingTexts[currentTextIndex];
         
     | 
| 181 | 
         
            +
                        let charIndex = 0;
         
     | 
| 182 | 
         
            +
                        let typingSpeed = 100; // 打字速度,从50ms增加到100ms
         
     | 
| 183 | 
         
            +
                        
         
     | 
| 184 | 
         
            +
                        // 添加弹跳动画的CSS
         
     | 
| 185 | 
         
            +
                        if (!document.getElementById('bounce-animation-style')) {
         
     | 
| 186 | 
         
            +
                            const bounceStyle = document.createElement('style');
         
     | 
| 187 | 
         
            +
                            bounceStyle.id = 'bounce-animation-style';
         
     | 
| 188 | 
         
            +
                            bounceStyle.textContent = `
         
     | 
| 189 | 
         
            +
                                .wave-container {
         
     | 
| 190 | 
         
            +
                                    position: relative;
         
     | 
| 191 | 
         
            +
                                    white-space: nowrap;
         
     | 
| 192 | 
         
            +
                                }
         
     | 
| 193 | 
         
            +
                                .bounce-text {
         
     | 
| 194 | 
         
            +
                                    display: inline-block;
         
     | 
| 195 | 
         
            +
                                    position: relative;
         
     | 
| 196 | 
         
            +
                                    transition: transform 0.3s ease-out;
         
     | 
| 197 | 
         
            +
                                }
         
     | 
| 198 | 
         
            +
                            `;
         
     | 
| 199 | 
         
            +
                            document.head.appendChild(bounceStyle);
         
     | 
| 200 | 
         
            +
                        }
         
     | 
| 201 | 
         
            +
                        
         
     | 
| 202 | 
         
            +
                        // 创建一个容器来包含所有字符
         
     | 
| 203 | 
         
            +
                        const waveContainer = document.createElement('div');
         
     | 
| 204 | 
         
            +
                        waveContainer.className = 'wave-container';
         
     | 
| 205 | 
         
            +
                        resolveButton.innerHTML = '';
         
     | 
| 206 | 
         
            +
                        resolveButton.appendChild(waveContainer);
         
     | 
| 207 | 
         
            +
                        
         
     | 
| 208 | 
         
            +
                        // 跟踪波峰位置
         
     | 
| 209 | 
         
            +
                        let peakPosition = -1;
         
     | 
| 210 | 
         
            +
                        let waveInterval;
         
     | 
| 211 | 
         
            +
                        
         
     | 
| 212 | 
         
            +
                        // 打字机效果函数
         
     | 
| 213 | 
         
            +
                        function typeLoadingText() {
         
     | 
| 214 | 
         
            +
                            if (charIndex < currentText.length) {
         
     | 
| 215 | 
         
            +
                                // 创建一个span元素包装字符
         
     | 
| 216 | 
         
            +
                                const charSpan = document.createElement('span');
         
     | 
| 217 | 
         
            +
                                charSpan.className = 'bounce-text';
         
     | 
| 218 | 
         
            +
                                charSpan.textContent = currentText.charAt(charIndex);
         
     | 
| 219 | 
         
            +
                                
         
     | 
| 220 | 
         
            +
                                // 添加到容器
         
     | 
| 221 | 
         
            +
                                waveContainer.appendChild(charSpan);
         
     | 
| 222 | 
         
            +
                                
         
     | 
| 223 | 
         
            +
                                charIndex++;
         
     | 
| 224 | 
         
            +
                                setTimeout(typeLoadingText, typingSpeed);
         
     | 
| 225 | 
         
            +
                                
         
     | 
| 226 | 
         
            +
                                // 如果这是第一个字符,开始波动动画
         
     | 
| 227 | 
         
            +
                                if (charIndex === 1) {
         
     | 
| 228 | 
         
            +
                                    startWaveAnimation();
         
     | 
| 229 | 
         
            +
                                }
         
     | 
| 230 | 
         
            +
                            } else {
         
     | 
| 231 | 
         
            +
                                // 当前文案打完,等待一段时间后切换到下一个文案
         
     | 
| 232 | 
         
            +
                                setTimeout(() => {
         
     | 
| 233 | 
         
            +
                                    // 清除波动动画
         
     | 
| 234 | 
         
            +
                                    if (waveInterval) {
         
     | 
| 235 | 
         
            +
                                        clearInterval(waveInterval);
         
     | 
| 236 | 
         
            +
                                        waveInterval = null;
         
     | 
| 237 | 
         
            +
                                    }
         
     | 
| 238 | 
         
            +
                                    
         
     | 
| 239 | 
         
            +
                                    // 切换到下一个文案
         
     | 
| 240 | 
         
            +
                                    charIndex = 0;
         
     | 
| 241 | 
         
            +
                                    currentTextIndex = (currentTextIndex + 1) % loadingTexts.length;
         
     | 
| 242 | 
         
            +
                                    currentText = loadingTexts[currentTextIndex];
         
     | 
| 243 | 
         
            +
                                    
         
     | 
| 244 | 
         
            +
                                    // 清空容器,准备下一个文案
         
     | 
| 245 | 
         
            +
                                    waveContainer.innerHTML = '';
         
     | 
| 246 | 
         
            +
                                    
         
     | 
| 247 | 
         
            +
                                    typeLoadingText();
         
     | 
| 248 | 
         
            +
                                }, 4000); // 完整显示时间
         
     | 
| 249 | 
         
            +
                            }
         
     | 
| 250 | 
         
            +
                        }
         
     | 
| 251 | 
         
            +
                        
         
     | 
| 252 | 
         
            +
                        // 波动动画函数
         
     | 
| 253 | 
         
            +
                        function startWaveAnimation() {
         
     | 
| 254 | 
         
            +
                            // 清除���前的间隔
         
     | 
| 255 | 
         
            +
                            if (waveInterval) clearInterval(waveInterval);
         
     | 
| 256 | 
         
            +
                            
         
     | 
| 257 | 
         
            +
                            // 启动波动动画
         
     | 
| 258 | 
         
            +
                            waveInterval = setInterval(() => {
         
     | 
| 259 | 
         
            +
                                // 获取所有字符
         
     | 
| 260 | 
         
            +
                                const chars = waveContainer.querySelectorAll('.bounce-text');
         
     | 
| 261 | 
         
            +
                                if (chars.length === 0) return;
         
     | 
| 262 | 
         
            +
                                
         
     | 
| 263 | 
         
            +
                                // 移动波峰位置
         
     | 
| 264 | 
         
            +
                                peakPosition = (peakPosition + 1) % chars.length;
         
     | 
| 265 | 
         
            +
                                
         
     | 
| 266 | 
         
            +
                                // 应用变换
         
     | 
| 267 | 
         
            +
                                chars.forEach((char, index) => {
         
     | 
| 268 | 
         
            +
                                    if (index === peakPosition) {
         
     | 
| 269 | 
         
            +
                                        // 波峰位置
         
     | 
| 270 | 
         
            +
                                        char.style.transform = 'translateY(-8px)';
         
     | 
| 271 | 
         
            +
                                    } else if (Math.abs(index - peakPosition) === 1) {
         
     | 
| 272 | 
         
            +
                                        // 波峰旁边的字符稍微上移
         
     | 
| 273 | 
         
            +
                                        char.style.transform = 'translateY(-4px)';
         
     | 
| 274 | 
         
            +
                                    } else {
         
     | 
| 275 | 
         
            +
                                        // 其他字符回到原位
         
     | 
| 276 | 
         
            +
                                        char.style.transform = 'translateY(0)';
         
     | 
| 277 | 
         
            +
                                    }
         
     | 
| 278 | 
         
            +
                                });
         
     | 
| 279 | 
         
            +
                            }, 100); // 每100ms更新一次波峰位置
         
     | 
| 280 | 
         
            +
                        }
         
     | 
| 281 | 
         
            +
                        
         
     | 
| 282 | 
         
            +
                        // 开始打字机效果
         
     | 
| 283 | 
         
            +
                        typeLoadingText();
         
     | 
| 284 | 
         
            +
                        
         
     | 
| 285 | 
         
            +
                        // 存储文本到 sessionStorage
         
     | 
| 286 | 
         
            +
                        sessionStorage.setItem('uploadedText', text);
         
     | 
| 287 | 
         
            +
                        console.log(text)
         
     | 
| 288 | 
         
            +
                        
         
     | 
| 289 | 
         
            +
                        // 获取上传的图片数据
         
     | 
| 290 | 
         
            +
                        const uploadedImage = sessionStorage.getItem('uploadedImage');
         
     | 
| 291 | 
         
            +
                        // 分析反馈内容,生成解读结果
         
     | 
| 292 | 
         
            +
                        analyzeUserInput(text, uploadedImage).then(() => {
         
     | 
| 293 | 
         
            +
                            // 解读完成后跳转到反馈页面
         
     | 
| 294 | 
         
            +
                            window.location.href = 'feedback.html';
         
     | 
| 295 | 
         
            +
                        }).catch(error => {
         
     | 
| 296 | 
         
            +
                            console.error('解读失败:', error);
         
     | 
| 297 | 
         
            +
                            alert('解读失败,请重试');
         
     | 
| 298 | 
         
            +
                            resolveButton.disabled = false;
         
     | 
| 299 | 
         
            +
                            resolveButton.textContent = '一键解读';
         
     | 
| 300 | 
         
            +
                        });
         
     | 
| 301 | 
         
            +
                    });
         
     | 
| 302 | 
         
            +
                }
         
     | 
| 303 | 
         
            +
             
     | 
| 304 | 
         
            +
             
     | 
| 305 | 
         
            +
                // 分析用户输入和图片的函数
         
     | 
| 306 | 
         
            +
                async function analyzeUserInput(text, imageData) {
         
     | 
| 307 | 
         
            +
                    try {
         
     | 
| 308 | 
         
            +
                        const health = await fetch(`${BASE_URL}health`)
         
     | 
| 309 | 
         
            +
                        console.log(health)
         
     | 
| 310 | 
         
            +
                        const response = await fetch(`${BASE_URL}api/analyze`, {
         
     | 
| 311 | 
         
            +
                            method: 'POST',
         
     | 
| 312 | 
         
            +
                            headers: {
         
     | 
| 313 | 
         
            +
                                'Content-Type': 'application/json'
         
     | 
| 314 | 
         
            +
                            },
         
     | 
| 315 | 
         
            +
                            body: JSON.stringify({
         
     | 
| 316 | 
         
            +
                                text: text,
         
     | 
| 317 | 
         
            +
                                image_data: imageData,
         
     | 
| 318 | 
         
            +
                                request_model_id: 'gpt-4.1-mini'
         
     | 
| 319 | 
         
            +
                            })
         
     | 
| 320 | 
         
            +
                        });
         
     | 
| 321 | 
         
            +
                        console.log(response)
         
     | 
| 322 | 
         
            +
                        const data = await response.json();
         
     | 
| 323 | 
         
            +
                        console.log(data)
         
     | 
| 324 | 
         
            +
                        const rep = data['output'][0]['content'][0]['text'];
         
     | 
| 325 | 
         
            +
                        sessionStorage.setItem('analysisResult', rep);
         
     | 
| 326 | 
         
            +
                    } catch (error) {
         
     | 
| 327 | 
         
            +
                        console.error('分析失败:', error);
         
     | 
| 328 | 
         
            +
                        // 使用默认的分析结果
         
     | 
| 329 | 
         
            +
                        const defaultAnalysis = `情绪值:😠😠😠\n\n
         
     | 
| 330 | 
         
            +
            修改建议:
         
     | 
| 331 | 
         
            +
            1. 色彩调整:在保持整体色调的基础上,加入一些明亮的点缀色,如淡黄色、淡紫蓝、淡红蓝微粉等。用于按钮、图标或重要文本,以增加吸引力。
         
     | 
| 332 | 
         
            +
            2. 增加层级感:利用饱和度(Glassmorphism)效果,为卡片/重要框添加模糊背景和阴影,营造出浮起感,引入3D元素或深浅变化,增加页面的深度和空间感。
         
     | 
| 333 | 
         
            +
            3. 增加互动性:为按钮和图标添加悬停动画或点击动画,提供用户及时反馈。引入微动画(Micro-interactions),如加载动画、切换动画等等,使页面更具活力。`;
         
     | 
| 334 | 
         
            +
                        
         
     | 
| 335 | 
         
            +
                        sessionStorage.setItem('analysisResult', defaultAnalysis);
         
     | 
| 336 | 
         
            +
                    }
         
     | 
| 337 | 
         
            +
                }
         
     | 
| 338 | 
         
            +
                
         
     | 
| 339 | 
         
            +
                // 示例图片添加到参考案例
         
     | 
| 340 | 
         
            +
                const exampleCards = document.querySelectorAll('.example-card');
         
     | 
| 341 | 
         
            +
                if (exampleCards.length > 0) {
         
     | 
| 342 | 
         
            +
                    // 为示例卡片添加示例图片背景
         
     | 
| 343 | 
         
            +
                    const exampleBgs = [
         
     | 
| 344 | 
         
            +
                        'linear-gradient(45deg, #2d2d4e, #1e1e30)',
         
     | 
| 345 | 
         
            +
                        'linear-gradient(45deg, #2e2e2e, #1a1a1a)',
         
     | 
| 346 | 
         
            +
                        'linear-gradient(45deg, #332e42, #1f1b30)'
         
     | 
| 347 | 
         
            +
                    ];
         
     | 
| 348 | 
         
            +
                    
         
     | 
| 349 | 
         
            +
                    exampleCards.forEach((card, index) => {
         
     | 
| 350 | 
         
            +
                        card.style.background = exampleBgs[index % exampleBgs.length];
         
     | 
| 351 | 
         
            +
                    });
         
     | 
| 352 | 
         
            +
                }
         
     | 
| 353 | 
         
            +
                
         
     | 
| 354 | 
         
            +
                // 加载并显示反馈页面的分析结果
         
     | 
| 355 | 
         
            +
                function loadAnalysisResult() {
         
     | 
| 356 | 
         
            +
                    const analysisResult = sessionStorage.getItem('analysisResult');
         
     | 
| 357 | 
         
            +
                    console.log(analysisResult)
         
     | 
| 358 | 
         
            +
                    if (!analysisResult) return;
         
     | 
| 359 | 
         
            +
                    
         
     | 
| 360 | 
         
            +
                    try {
         
     | 
| 361 | 
         
            +
                        // 设置情绪值
         
     | 
| 362 | 
         
            +
                        if (analysisResult) {
         
     | 
| 363 | 
         
            +
                            const emotionIcons = document.querySelector('.emotion-icons');
         
     | 
| 364 | 
         
            +
                            const emotionText = document.querySelector('.emotion-text');
         
     | 
| 365 | 
         
            +
                            
         
     | 
| 366 | 
         
            +
                            if (emotionIcons && emotionText) {
         
     | 
| 367 | 
         
            +
                                // 清空图标区域
         
     | 
| 368 | 
         
            +
                                emotionIcons.innerHTML = '';
         
     | 
| 369 | 
         
            +
                                
         
     | 
| 370 | 
         
            +
                                // 提取情绪值部分
         
     | 
| 371 | 
         
            +
                                const emojiText = analysisResult.split('情绪值:')[1].split('\n')[0];
         
     | 
| 372 | 
         
            +
                                
         
     | 
| 373 | 
         
            +
                                const emotionAnalyse = analysisResult.split('情绪分析:')[1].split('\n')[0];
         
     | 
| 374 | 
         
            +
             
     | 
| 375 | 
         
            +
                                // 提取emoji
         
     | 
| 376 | 
         
            +
                                const emojis = [emojiText.codePointAt(0), emojiText.codePointAt(2), emojiText.codePointAt(4)];
         
     | 
| 377 | 
         
            +
                                console.log(emojis)
         
     | 
| 378 | 
         
            +
                                emojis.forEach(emoji => {
         
     | 
| 379 | 
         
            +
                                    console.log(emoji)
         
     | 
| 380 | 
         
            +
                                })
         
     | 
| 381 | 
         
            +
                                
         
     | 
| 382 | 
         
            +
                                if (emojis) {
         
     | 
| 383 | 
         
            +
                                    // 只显示3个emoji,确保一致性
         
     | 
| 384 | 
         
            +
                                    const displayEmojis = emojis.slice(0, 3);
         
     | 
| 385 | 
         
            +
                                    displayEmojis.forEach(emoji => {
         
     | 
| 386 | 
         
            +
                                        const span = document.createElement('span');
         
     | 
| 387 | 
         
            +
                                        span.className = 'emoji';
         
     | 
| 388 | 
         
            +
                                        span.textContent = String.fromCodePoint(emoji);
         
     | 
| 389 | 
         
            +
                                        emotionIcons.appendChild(span);
         
     | 
| 390 | 
         
            +
                                    });
         
     | 
| 391 | 
         
            +
                                } else {
         
     | 
| 392 | 
         
            +
                                    // 默认情绪
         
     | 
| 393 | 
         
            +
                                    for (let i = 0; i < 3; i++) {
         
     | 
| 394 | 
         
            +
                                        const span = document.createElement('span');
         
     | 
| 395 | 
         
            +
                                        span.className = 'emoji';
         
     | 
| 396 | 
         
            +
                                        span.textContent = '😠';
         
     | 
| 397 | 
         
            +
                                        emotionIcons.appendChild(span);
         
     | 
| 398 | 
         
            +
                                    }
         
     | 
| 399 | 
         
            +
                                }
         
     | 
| 400 | 
         
            +
                                
         
     | 
| 401 | 
         
            +
                                // 设置文字描述
         
     | 
| 402 | 
         
            +
                                // 查找"情绪分析:"部分
         
     | 
| 403 | 
         
            +
                                let textDescription = '';
         
     | 
| 404 | 
         
            +
                                if (emotionAnalyse) {
         
     | 
| 405 | 
         
            +
                                    textDescription = emotionAnalyse.trim();
         
     | 
| 406 | 
         
            +
                                } else {
         
     | 
| 407 | 
         
            +
                                    // 如果没有情绪分析部分,根据emoji生成默认文本
         
     | 
| 408 | 
         
            +
                                    if (emojis && emojis[0] === '😠') {
         
     | 
| 409 | 
         
            +
                                        textDescription = '老板对设计非常不满意,建议全面改进';
         
     | 
| 410 | 
         
            +
                                    } else if (emojis && emojis[0] === '🙁') {
         
     | 
| 411 | 
         
            +
                                        textDescription = '老板对设计不太满意,需要较多改进';
         
     | 
| 412 | 
         
            +
                                    } else if (emojis && emojis[0] === '😐') {
         
     | 
| 413 | 
         
            +
                                        textDescription = '老板对设计感觉一般,有改进空间';
         
     | 
| 414 | 
         
            +
                                    } else if (emojis && emojis[0] === '🙂') {
         
     | 
| 415 | 
         
            +
                                        textDescription = '老板对设计比较满意,小幅改进即可';
         
     | 
| 416 | 
         
            +
                                    } else if (emojis && emojis[0] === '😊') {
         
     | 
| 417 | 
         
            +
                                        textDescription = '老板对设计非常满意,细节优化即可';
         
     | 
| 418 | 
         
            +
                                    } else {
         
     | 
| 419 | 
         
            +
                                        textDescription = '需要基于反馈进行改进';
         
     | 
| 420 | 
         
            +
                                    }
         
     | 
| 421 | 
         
            +
                                }
         
     | 
| 422 | 
         
            +
                                
         
     | 
| 423 | 
         
            +
                                emotionText.textContent = textDescription;
         
     | 
| 424 | 
         
            +
                            }
         
     | 
| 425 | 
         
            +
                        }
         
     | 
| 426 | 
         
            +
                        
         
     | 
| 427 | 
         
            +
                        // 提取修改建议
         
     | 
| 428 | 
         
            +
                        const suggestionsContainer = document.querySelector('.suggestions-container');
         
     | 
| 429 | 
         
            +
                        if (suggestionsContainer) {
         
     | 
| 430 | 
         
            +
                            try {
         
     | 
| 431 | 
         
            +
                                // 使用split提取修改建议部分
         
     | 
| 432 | 
         
            +
                                const suggestionsText = analysisResult.split('修改建议:')[1].split('搜索内容:')[0];
         
     | 
| 433 | 
         
            +
                                
         
     | 
| 434 | 
         
            +
                                if (suggestionsText) {
         
     | 
| 435 | 
         
            +
                                    // 提取三个建议
         
     | 
| 436 | 
         
            +
                                    const suggestionLines = suggestionsText.trim().split('\n');
         
     | 
| 437 | 
         
            +
                                    const suggestions = [];
         
     | 
| 438 | 
         
            +
                                    
         
     | 
| 439 | 
         
            +
                                    // 处理每一行建议
         
     | 
| 440 | 
         
            +
                                    for (let i = 0; i < suggestionLines.length; i++) {
         
     | 
| 441 | 
         
            +
                                        const line = suggestionLines[i].trim();
         
     | 
| 442 | 
         
            +
                                        if (line.match(/^\d+\.\s/)) {
         
     | 
| 443 | 
         
            +
                                            // 找到了序号开头的行,这是建议的标题和内容
         
     | 
| 444 | 
         
            +
                                            const suggestionText = line.replace(/^\d+\.\s/, '');
         
     | 
| 445 | 
         
            +
                                            
         
     | 
| 446 | 
         
            +
                                            // 拆分标题和内容(假设冒号或:分隔)
         
     | 
| 447 | 
         
            +
                                            let title = suggestionText;
         
     | 
| 448 | 
         
            +
                                            let content = '';
         
     | 
| 449 | 
         
            +
                                            
         
     | 
| 450 | 
         
            +
                                            if (suggestionText.includes(':')) {
         
     | 
| 451 | 
         
            +
                                                [title, content] = suggestionText.split(':', 2);
         
     | 
| 452 | 
         
            +
                                            } else if (suggestionText.includes(':')) {
         
     | 
| 453 | 
         
            +
                                                [title, content] = suggestionText.split(':', 2);
         
     | 
| 454 | 
         
            +
                                            }
         
     | 
| 455 | 
         
            +
                                            
         
     | 
| 456 | 
         
            +
                                            suggestions.push({
         
     | 
| 457 | 
         
            +
                                                title: title.trim(),
         
     | 
| 458 | 
         
            +
                                                content: content.trim()
         
     | 
| 459 | 
         
            +
                                            });
         
     | 
| 460 | 
         
            +
                                            
         
     | 
| 461 | 
         
            +
                                            // 最多收集三个建议
         
     | 
| 462 | 
         
            +
                                            if (suggestions.length >= 3) break;
         
     | 
| 463 | 
         
            +
                                        }
         
     | 
| 464 | 
         
            +
                                    }
         
     | 
| 465 | 
         
            +
                                    
         
     | 
| 466 | 
         
            +
                                    // 更新建议卡片
         
     | 
| 467 | 
         
            +
                                    if (suggestions.length > 0) {
         
     | 
| 468 | 
         
            +
                                        const cardStyles = ['yellow-top', 'cyan-top', 'purple-top'];
         
     | 
| 469 | 
         
            +
                                        suggestionsContainer.innerHTML = '';
         
     | 
| 470 | 
         
            +
                                        
         
     | 
| 471 | 
         
            +
                                        suggestions.forEach((suggestion, index) => {
         
     | 
| 472 | 
         
            +
                                            const cardStyle = cardStyles[index % cardStyles.length];
         
     | 
| 473 | 
         
            +
                                            const card = document.createElement('div');
         
     | 
| 474 | 
         
            +
                                            card.className = `suggestion-card ${cardStyle}`;
         
     | 
| 475 | 
         
            +
                                            
         
     | 
| 476 | 
         
            +
                                            const titleElement = document.createElement('h3');
         
     | 
| 477 | 
         
            +
                                            titleElement.className = 'suggestion-title';
         
     | 
| 478 | 
         
            +
                                            titleElement.textContent = suggestion.title;
         
     | 
| 479 | 
         
            +
                                            
         
     | 
| 480 | 
         
            +
                                            const textElement = document.createElement('p');
         
     | 
| 481 | 
         
            +
                                            textElement.className = 'suggestion-text';
         
     | 
| 482 | 
         
            +
                                            textElement.textContent = suggestion.content;
         
     | 
| 483 | 
         
            +
                                            
         
     | 
| 484 | 
         
            +
                                            card.appendChild(titleElement);
         
     | 
| 485 | 
         
            +
                                            card.appendChild(textElement);
         
     | 
| 486 | 
         
            +
                                            suggestionsContainer.appendChild(card);
         
     | 
| 487 | 
         
            +
                                        });
         
     | 
| 488 | 
         
            +
                                        
         
     | 
| 489 | 
         
            +
                                        // 加载参考案例
         
     | 
| 490 | 
         
            +
                                        loadReferenceExamples(suggestions);
         
     | 
| 491 | 
         
            +
                                    }
         
     | 
| 492 | 
         
            +
                                }
         
     | 
| 493 | 
         
            +
                            } catch (error) {
         
     | 
| 494 | 
         
            +
                                console.error('解析建议失败:', error);
         
     | 
| 495 | 
         
            +
                            }
         
     | 
| 496 | 
         
            +
                        }
         
     | 
| 497 | 
         
            +
                    } catch (error) {
         
     | 
| 498 | 
         
            +
                        console.error('解析分析结果失败:', error);
         
     | 
| 499 | 
         
            +
                    }
         
     | 
| 500 | 
         
            +
                }
         
     | 
| 501 | 
         
            +
                
         
     | 
| 502 | 
         
            +
                // 根据建议加载参考案例
         
     | 
| 503 | 
         
            +
                async function loadReferenceExamples(suggestions) {
         
     | 
| 504 | 
         
            +
                    const analysisResult = sessionStorage.getItem('analysisResult');
         
     | 
| 505 | 
         
            +
                    const searchContent = analysisResult.split('搜索内容:')[1].trim();
         
     | 
| 506 | 
         
            +
                    const examplesContainer = document.querySelector('.examples-container');
         
     | 
| 507 | 
         
            +
                    if (!examplesContainer) return;
         
     | 
| 508 | 
         
            +
                    
         
     | 
| 509 | 
         
            +
                    // 获取现有的示例卡片元素
         
     | 
| 510 | 
         
            +
                    const exampleCards = examplesContainer.querySelectorAll('.example-card');
         
     | 
| 511 | 
         
            +
                    if (exampleCards.length !== 2) {
         
     | 
| 512 | 
         
            +
                        console.error('未找到预期的两个示例卡片元素');
         
     | 
| 513 | 
         
            +
                        return;
         
     | 
| 514 | 
         
            +
                    }
         
     | 
| 515 | 
         
            +
                    
         
     | 
| 516 | 
         
            +
                    try {
         
     | 
| 517 | 
         
            +
                        // 显示加载状态
         
     | 
| 518 | 
         
            +
                        exampleCards.forEach(card => {
         
     | 
| 519 | 
         
            +
                            const img = card.querySelector('.example-image');
         
     | 
| 520 | 
         
            +
                            const desc = card.querySelector('.example-desc');
         
     | 
| 521 | 
         
            +
                            const sourceLink = card.querySelector('.example-source a');
         
     | 
| 522 | 
         
            +
                            
         
     | 
| 523 | 
         
            +
                            if (img) img.src = '';
         
     | 
| 524 | 
         
            +
                            if (desc) desc.textContent = '正在搜索设计参考案例...';
         
     | 
| 525 | 
         
            +
                            if (sourceLink) {
         
     | 
| 526 | 
         
            +
                                sourceLink.href = '#';
         
     | 
| 527 | 
         
            +
                                sourceLink.textContent = '加载中...';
         
     | 
| 528 | 
         
            +
                            }
         
     | 
| 529 | 
         
            +
                        });
         
     | 
| 530 | 
         
            +
                        
         
     | 
| 531 | 
         
            +
                        // 获取原始反馈文本和上传的图片
         
     | 
| 532 | 
         
            +
                        const uploadedText = sessionStorage.getItem('uploadedText') || '';
         
     | 
| 533 | 
         
            +
                        const uploadedImage = sessionStorage.getItem('uploadedImage');
         
     | 
| 534 | 
         
            +
                        
         
     | 
| 535 | 
         
            +
                        // 调用后端搜索API
         
     | 
| 536 | 
         
            +
                        const response = await fetch(`${BASE_URL}api/search`, {
         
     | 
| 537 | 
         
            +
                            method: 'POST',
         
     | 
| 538 | 
         
            +
                            headers: {
         
     | 
| 539 | 
         
            +
                                'Content-Type': 'application/json'
         
     | 
| 540 | 
         
            +
                            },
         
     | 
| 541 | 
         
            +
                            body: JSON.stringify({
         
     | 
| 542 | 
         
            +
                                query: searchContent,
         
     | 
| 543 | 
         
            +
                                num_results: 2
         
     | 
| 544 | 
         
            +
                            })
         
     | 
| 545 | 
         
            +
                        });
         
     | 
| 546 | 
         
            +
             
     | 
| 547 | 
         
            +
                        if (!response.ok) {
         
     | 
| 548 | 
         
            +
                            throw new Error('搜索请求失败');
         
     | 
| 549 | 
         
            +
                        }
         
     | 
| 550 | 
         
            +
             
     | 
| 551 | 
         
            +
                        const searchData = await response.json();
         
     | 
| 552 | 
         
            +
                        
         
     | 
| 553 | 
         
            +
                        if (!searchData.items || searchData.items.length === 0) {
         
     | 
| 554 | 
         
            +
                            throw new Error('未找到搜索结果');
         
     | 
| 555 | 
         
            +
                        }
         
     | 
| 556 | 
         
            +
                        
         
     | 
| 557 | 
         
            +
                        // 处理搜索结果
         
     | 
| 558 | 
         
            +
                        const examples = searchData.items.map(result => ({
         
     | 
| 559 | 
         
            +
                            title: result.title,
         
     | 
| 560 | 
         
            +
                            sourceUrl: result.link,
         
     | 
| 561 | 
         
            +
                            description: result.snippet || '',
         
     | 
| 562 | 
         
            +
                            image: result.image || ''
         
     | 
| 563 | 
         
            +
                        }));
         
     | 
| 564 | 
         
            +
                        
         
     | 
| 565 | 
         
            +
                        // 使用GPT生成描述
         
     | 
| 566 | 
         
            +
                        for (let i = 0; i < examples.length; i++) {
         
     | 
| 567 | 
         
            +
                            const example = examples[i];
         
     | 
| 568 | 
         
            +
                            try {
         
     | 
| 569 | 
         
            +
                                const response = await fetch(`${BASE_URL}api/optimize-text`, {
         
     | 
| 570 | 
         
            +
                                    method: 'POST',
         
     | 
| 571 | 
         
            +
                                    headers: {
         
     | 
| 572 | 
         
            +
                                        'Content-Type': 'application/json'
         
     | 
| 573 | 
         
            +
                                    },
         
     | 
| 574 | 
         
            +
                                    body: JSON.stringify({
         
     | 
| 575 | 
         
            +
                                        original_feedback: uploadedText,
         
     | 
| 576 | 
         
            +
                                        user_input: `请分析这个设计案例:${example.title}\n${example.description}\n\n基于原始设计反馈和修改建议,详细分析为什么这个设计案例可以解决用户面临的设计问题。描述要专业、具体,并关注设计细节。`,
         
     | 
| 577 | 
         
            +
                                        request_model_id: 'gpt-4.1-mini'
         
     | 
| 578 | 
         
            +
                                    })
         
     | 
| 579 | 
         
            +
                                });
         
     | 
| 580 | 
         
            +
             
     | 
| 581 | 
         
            +
                                if (response.ok) {
         
     | 
| 582 | 
         
            +
                                    const data = await response.json();
         
     | 
| 583 | 
         
            +
                                    if (data.output && data.output[0].content[0].text) {
         
     | 
| 584 | 
         
            +
                                        example.description = data.output[0].content[0].text.trim();
         
     | 
| 585 | 
         
            +
                                    }
         
     | 
| 586 | 
         
            +
                                }
         
     | 
| 587 | 
         
            +
                            } catch (gptError) {
         
     | 
| 588 | 
         
            +
                                console.error('生成案例描述失败:', gptError);
         
     | 
| 589 | 
         
            +
                                // 使用默认描述
         
     | 
| 590 | 
         
            +
                                example.description = i === 0 ?
         
     | 
| 591 | 
         
            +
                                    '这个案例展示了清晰的视觉层次结构和吸引人的色彩搭配,能有效解决原设计中的平面感问题。通过对比度增强和微妙的动效,它能提高用户体验和互动性,同时保持整体设计的专业性。' :
         
     | 
| 592 | 
         
            +
                                    '该设计运用了精细的色彩渐变和现代化的UI元素,完美解决了原始设计中的视觉单调问题。透过精心安排的布局和适当的留白,创造出流畅的用户浏览体验,同时增加了设计的精致感和专业度。';
         
     | 
| 593 | 
         
            +
                            }
         
     | 
| 594 | 
         
            +
                        }
         
     | 
| 595 | 
         
            +
                        
         
     | 
| 596 | 
         
            +
                        // 更新UI
         
     | 
| 597 | 
         
            +
                        examples.forEach((example, index) => {
         
     | 
| 598 | 
         
            +
                            const card = exampleCards[index];
         
     | 
| 599 | 
         
            +
                            if (!card) return;
         
     | 
| 600 | 
         
            +
                            
         
     | 
| 601 | 
         
            +
                            const img = card.querySelector('.example-image');
         
     | 
| 602 | 
         
            +
                            const desc = card.querySelector('.example-desc');
         
     | 
| 603 | 
         
            +
                            const source = card.querySelector('.example-source');
         
     | 
| 604 | 
         
            +
                            
         
     | 
| 605 | 
         
            +
                            if (img) {
         
     | 
| 606 | 
         
            +
                                img.src = example.image;
         
     | 
| 607 | 
         
            +
                                img.alt = example.title;
         
     | 
| 608 | 
         
            +
                            }
         
     | 
| 609 | 
         
            +
                            
         
     | 
| 610 | 
         
            +
                            if (desc) {
         
     | 
| 611 | 
         
            +
                                desc.textContent = example.description;
         
     | 
| 612 | 
         
            +
                            }
         
     | 
| 613 | 
         
            +
                            
         
     | 
| 614 | 
         
            +
                            if (source) {
         
     | 
| 615 | 
         
            +
                                const sourceLink = source.querySelector('a');
         
     | 
| 616 | 
         
            +
                                if (sourceLink) {
         
     | 
| 617 | 
         
            +
                                    sourceLink.href = example.sourceUrl;
         
     | 
| 618 | 
         
            +
                                    sourceLink.textContent = example.title;
         
     | 
| 619 | 
         
            +
                                }
         
     | 
| 620 | 
         
            +
                            }
         
     | 
| 621 | 
         
            +
                        });
         
     | 
| 622 | 
         
            +
                        
         
     | 
| 623 | 
         
            +
                    } catch (error) {
         
     | 
| 624 | 
         
            +
                        console.error('加载参考案例失败:', error);
         
     | 
| 625 | 
         
            +
                        
         
     | 
| 626 | 
         
            +
                        // 在错误情况下更新UI
         
     | 
| 627 | 
         
            +
                        exampleCards.forEach(card => {  
         
     | 
| 628 | 
         
            +
                            const desc = card.querySelector('.example-desc');
         
     | 
| 629 | 
         
            +
                            if (desc) {
         
     | 
| 630 | 
         
            +
                                desc.textContent = '加载参考案例失败,请刷新重试';
         
     | 
| 631 | 
         
            +
                                desc.style.color = '#ff6b6b';
         
     | 
| 632 | 
         
            +
                            }
         
     | 
| 633 | 
         
            +
                        });
         
     | 
| 634 | 
         
            +
                    }
         
     | 
| 635 | 
         
            +
                }
         
     | 
| 636 | 
         
            +
                
         
     | 
| 637 | 
         
            +
                // 当在反馈页面时,加载分析结果
         
     | 
| 638 | 
         
            +
                if (window.location.pathname.includes('feedback.html')) {
         
     | 
| 639 | 
         
            +
                    loadAnalysisResult();
         
     | 
| 640 | 
         
            +
                    
         
     | 
| 641 | 
         
            +
                    // 优化方案功能
         
     | 
| 642 | 
         
            +
                    setupOptimizationButtons();
         
     | 
| 643 | 
         
            +
                }
         
     | 
| 644 | 
         
            +
                
         
     | 
| 645 | 
         
            +
                // 设置优化方案按钮功能
         
     | 
| 646 | 
         
            +
                function setupOptimizationButtons() {
         
     | 
| 647 | 
         
            +
                    const gpt4Button = document.getElementById('gpt4-btn');
         
     | 
| 648 | 
         
            +
                    const mjButton = document.getElementById('mj-btn');
         
     | 
| 649 | 
         
            +
                    
         
     | 
| 650 | 
         
            +
                    if (gpt4Button) {
         
     | 
| 651 | 
         
            +
                        gpt4Button.addEventListener('click', function() {
         
     | 
| 652 | 
         
            +
                            generateGPT4Optimization();
         
     | 
| 653 | 
         
            +
                        });
         
     | 
| 654 | 
         
            +
                    }
         
     | 
| 655 | 
         
            +
                    
         
     | 
| 656 | 
         
            +
                    if (mjButton) {
         
     | 
| 657 | 
         
            +
                        mjButton.addEventListener('click', function() {
         
     | 
| 658 | 
         
            +
                            generateDalleOptimization();
         
     | 
| 659 | 
         
            +
                        });
         
     | 
| 660 | 
         
            +
                    }
         
     | 
| 661 | 
         
            +
                }
         
     | 
| 662 | 
         
            +
                
         
     | 
| 663 | 
         
            +
                // 使用GPT-4生成优化方案
         
     | 
| 664 | 
         
            +
                async function generateGPT4Optimization() {
         
     | 
| 665 | 
         
            +
                    const gpt4Button = document.getElementById('gpt4-btn');
         
     | 
| 666 | 
         
            +
                    const gpt4Content = document.getElementById('gpt4-content');
         
     | 
| 667 | 
         
            +
                    
         
     | 
| 668 | 
         
            +
                    if (!gpt4Button || !gpt4Content) return;
         
     | 
| 669 | 
         
            +
                    
         
     | 
| 670 | 
         
            +
                    try {
         
     | 
| 671 | 
         
            +
                        // 禁用按钮
         
     | 
| 672 | 
         
            +
                        gpt4Button.disabled = true;
         
     | 
| 673 | 
         
            +
                        gpt4Button.textContent = '生成中...';
         
     | 
| 674 | 
         
            +
                        
         
     | 
| 675 | 
         
            +
                        // 显示加载动画
         
     | 
| 676 | 
         
            +
                        showLoadingState(gpt4Content, '正在生成优化方案,请稍候...');
         
     | 
| 677 | 
         
            +
                        
         
     | 
| 678 | 
         
            +
                        // 获取原始反馈和图片
         
     | 
| 679 | 
         
            +
                        const uploadedText = sessionStorage.getItem('uploadedText') || '';
         
     | 
| 680 | 
         
            +
                        const uploadedImage = sessionStorage.getItem('uploadedImage');
         
     | 
| 681 | 
         
            +
                        const analysisResult = sessionStorage.getItem('analysisResult') || '';
         
     | 
| 682 | 
         
            +
                        
         
     | 
| 683 | 
         
            +
                        if (!uploadedImage) {
         
     | 
| 684 | 
         
            +
                            throw new Error('未找到原始设计图片');
         
     | 
| 685 | 
         
            +
                        }
         
     | 
| 686 | 
         
            +
                        
         
     | 
| 687 | 
         
            +
                        // 提取修改建议
         
     | 
| 688 | 
         
            +
                        let suggestions = [];
         
     | 
| 689 | 
         
            +
                        if (analysisResult.includes('修改建议:')) {
         
     | 
| 690 | 
         
            +
                            const suggestionsText = analysisResult.split('修改建议:')[1].split('搜索内容:')[0];
         
     | 
| 691 | 
         
            +
                            suggestions = suggestionsText
         
     | 
| 692 | 
         
            +
                                .split('\n')
         
     | 
| 693 | 
         
            +
                                .filter(line => line.match(/^\d+\./))
         
     | 
| 694 | 
         
            +
                                .map(line => line.replace(/^\d+\.\s+/, '').trim());
         
     | 
| 695 | 
         
            +
                        }
         
     | 
| 696 | 
         
            +
                        
         
     | 
| 697 | 
         
            +
                        // 调用后端API
         
     | 
| 698 | 
         
            +
                        const response = await fetch(`${BASE_URL}api/optimize-design`, {
         
     | 
| 699 | 
         
            +
                            method: 'POST',
         
     | 
| 700 | 
         
            +
                            headers: {
         
     | 
| 701 | 
         
            +
                                'Content-Type': 'application/json'
         
     | 
| 702 | 
         
            +
                            },
         
     | 
| 703 | 
         
            +
                            body: JSON.stringify({
         
     | 
| 704 | 
         
            +
                                text: uploadedText,
         
     | 
| 705 | 
         
            +
                                image_data: uploadedImage,
         
     | 
| 706 | 
         
            +
                                suggestions: suggestions,
         
     | 
| 707 | 
         
            +
                                request_model_id: 'gpt-image-1'
         
     | 
| 708 | 
         
            +
                            })
         
     | 
| 709 | 
         
            +
                        });
         
     | 
| 710 | 
         
            +
             
     | 
| 711 | 
         
            +
                        if (!response.ok) {
         
     | 
| 712 | 
         
            +
                            throw new Error('优化请求失败');
         
     | 
| 713 | 
         
            +
                        }
         
     | 
| 714 | 
         
            +
             
     | 
| 715 | 
         
            +
                        const data = await response.json();
         
     | 
| 716 | 
         
            +
                        
         
     | 
| 717 | 
         
            +
                        if (data.data && data.data[0] && data.data[0].url) {
         
     | 
| 718 | 
         
            +
                            // 展示生成的图片
         
     | 
| 719 | 
         
            +
                            showOptimizationResult(gpt4Content, data.data[0].url);
         
     | 
| 720 | 
         
            +
                            gpt4Button.disabled = false;
         
     | 
| 721 | 
         
            +
                            gpt4Button.textContent = '重新生成';
         
     | 
| 722 | 
         
            +
                        } else {
         
     | 
| 723 | 
         
            +
                            throw new Error('API未返回图片数据');
         
     | 
| 724 | 
         
            +
                        }
         
     | 
| 725 | 
         
            +
                        
         
     | 
| 726 | 
         
            +
                    } catch (error) {
         
     | 
| 727 | 
         
            +
                        console.error('生成优化方案失败:', error);
         
     | 
| 728 | 
         
            +
                        gpt4Content.innerHTML = `
         
     | 
| 729 | 
         
            +
                            <div class="optimization-placeholder">
         
     | 
| 730 | 
         
            +
                                <p style="color: #ff6b6b;">生成失败: ${error.message || '请稍后重试'}</p>
         
     | 
| 731 | 
         
            +
                            </div>
         
     | 
| 732 | 
         
            +
                        `;
         
     | 
| 733 | 
         
            +
                        gpt4Button.disabled = false;
         
     | 
| 734 | 
         
            +
                        gpt4Button.textContent = '重试';
         
     | 
| 735 | 
         
            +
                    }
         
     | 
| 736 | 
         
            +
                }
         
     | 
| 737 | 
         
            +
                
         
     | 
| 738 | 
         
            +
                async function generateDalleOptimization() {
         
     | 
| 739 | 
         
            +
                    const mjButton = document.getElementById('mj-btn');
         
     | 
| 740 | 
         
            +
                    const mjContent = document.getElementById('mj-content');
         
     | 
| 741 | 
         
            +
                    if (!mjButton || !mjContent) return;
         
     | 
| 742 | 
         
            +
                
         
     | 
| 743 | 
         
            +
                    try {
         
     | 
| 744 | 
         
            +
                        mjButton.disabled = true;
         
     | 
| 745 | 
         
            +
                        mjButton.textContent = '生成中...';
         
     | 
| 746 | 
         
            +
                        showLoadingState(mjContent, '正在优化设计,请稍候...');
         
     | 
| 747 | 
         
            +
                
         
     | 
| 748 | 
         
            +
                        // 获取原始反馈和建议
         
     | 
| 749 | 
         
            +
                        const analysisResult = sessionStorage.getItem('analysisResult') || '';
         
     | 
| 750 | 
         
            +
                        let suggestions = [];
         
     | 
| 751 | 
         
            +
                        if (analysisResult.includes('修改建议:')) {
         
     | 
| 752 | 
         
            +
                            const suggestionsText = analysisResult.split('修改建议:')[1].split('搜索内容:')[0];
         
     | 
| 753 | 
         
            +
                            suggestions = suggestionsText
         
     | 
| 754 | 
         
            +
                                .split('\n')
         
     | 
| 755 | 
         
            +
                                .filter(line => line.match(/^\d+\./))
         
     | 
| 756 | 
         
            +
                                .map(line => line.replace(/^\d+\.\s+/, '').trim());
         
     | 
| 757 | 
         
            +
                        }
         
     | 
| 758 | 
         
            +
                        
         
     | 
| 759 | 
         
            +
                        // 获取原始图片
         
     | 
| 760 | 
         
            +
                        const uploadedImage = sessionStorage.getItem('uploadedImage');
         
     | 
| 761 | 
         
            +
                        if (!uploadedImage) {
         
     | 
| 762 | 
         
            +
                            throw new Error('未找到原始设计图片');
         
     | 
| 763 | 
         
            +
                        }
         
     | 
| 764 | 
         
            +
             
     | 
| 765 | 
         
            +
                        // 构建提示词
         
     | 
| 766 | 
         
            +
                        const prompt = `基于以下设计反馈优化UI设计: ${suggestions.join(', ')}`;
         
     | 
| 767 | 
         
            +
                        
         
     | 
| 768 | 
         
            +
                        // 调用后端API
         
     | 
| 769 | 
         
            +
                        const response = await fetch(`${BASE_URL}api/optimize-design`, {
         
     | 
| 770 | 
         
            +
                            method: 'POST',
         
     | 
| 771 | 
         
            +
                            headers: {
         
     | 
| 772 | 
         
            +
                                'Content-Type': 'application/json'
         
     | 
| 773 | 
         
            +
                            },
         
     | 
| 774 | 
         
            +
                            body: JSON.stringify({
         
     | 
| 775 | 
         
            +
                                text: analysisResult,
         
     | 
| 776 | 
         
            +
                                image_data: uploadedImage,
         
     | 
| 777 | 
         
            +
                                suggestions: suggestions,
         
     | 
| 778 | 
         
            +
                                request_model_id: 'dall-e-2'
         
     | 
| 779 | 
         
            +
                            })
         
     | 
| 780 | 
         
            +
                        });
         
     | 
| 781 | 
         
            +
             
     | 
| 782 | 
         
            +
                        if (!response.ok) {
         
     | 
| 783 | 
         
            +
                            throw new Error('优化请求失败');
         
     | 
| 784 | 
         
            +
                        }
         
     | 
| 785 | 
         
            +
             
     | 
| 786 | 
         
            +
                        const data = await response.json();
         
     | 
| 787 | 
         
            +
                        
         
     | 
| 788 | 
         
            +
                        if (data.data && data.data[0] && data.data[0].url) {
         
     | 
| 789 | 
         
            +
                            // 展示生成的图片
         
     | 
| 790 | 
         
            +
                            showOptimizationResult(mjContent, data.data[0].url);
         
     | 
| 791 | 
         
            +
                            mjButton.disabled = false;
         
     | 
| 792 | 
         
            +
                            mjButton.textContent = '重新生成';
         
     | 
| 793 | 
         
            +
                        } else {
         
     | 
| 794 | 
         
            +
                            throw new Error('API未返回图片数据');
         
     | 
| 795 | 
         
            +
                        }
         
     | 
| 796 | 
         
            +
                
         
     | 
| 797 | 
         
            +
                    } catch (error) {
         
     | 
| 798 | 
         
            +
                        console.error('生成优化方案失败:', error);
         
     | 
| 799 | 
         
            +
                        mjContent.innerHTML = `
         
     | 
| 800 | 
         
            +
                            <div class="optimization-placeholder">
         
     | 
| 801 | 
         
            +
                                <p style="color: #ff6b6b;">生成失败: ${error.message || '请稍后重试'}</p>
         
     | 
| 802 | 
         
            +
                            </div>
         
     | 
| 803 | 
         
            +
                        `;
         
     | 
| 804 | 
         
            +
                        mjButton.disabled = false;
         
     | 
| 805 | 
         
            +
                        mjButton.textContent = '重试';
         
     | 
| 806 | 
         
            +
                    }
         
     | 
| 807 | 
         
            +
                }
         
     | 
| 808 | 
         
            +
                
         
     | 
| 809 | 
         
            +
                // 显示加载状态
         
     | 
| 810 | 
         
            +
                function showLoadingState(container, message) {
         
     | 
| 811 | 
         
            +
                    container.innerHTML = `
         
     | 
| 812 | 
         
            +
                        <div class="optimization-loading">
         
     | 
| 813 | 
         
            +
                            <div class="loading-spinner"></div>
         
     | 
| 814 | 
         
            +
                            <div class="loading-text">${message}</div>
         
     | 
| 815 | 
         
            +
                        </div>
         
     | 
| 816 | 
         
            +
                        <div class="optimization-placeholder">
         
     | 
| 817 | 
         
            +
                            <p>生成中���请稍候...</p>
         
     | 
| 818 | 
         
            +
                        </div>
         
     | 
| 819 | 
         
            +
                    `;
         
     | 
| 820 | 
         
            +
                }
         
     | 
| 821 | 
         
            +
                
         
     | 
| 822 | 
         
            +
                // 显示优化结果
         
     | 
| 823 | 
         
            +
                function showOptimizationResult(container, imageUrl) {
         
     | 
| 824 | 
         
            +
                    container.innerHTML = `
         
     | 
| 825 | 
         
            +
                        <div class="optimization-result">
         
     | 
| 826 | 
         
            +
                            <img src="${imageUrl}" alt="优化方案" />
         
     | 
| 827 | 
         
            +
                        </div>
         
     | 
| 828 | 
         
            +
                    `;
         
     | 
| 829 | 
         
            +
                }
         
     | 
| 830 | 
         
            +
                
         
     | 
| 831 | 
         
            +
                // 润色功能
         
     | 
| 832 | 
         
            +
                const generateBtn = document.getElementById('generateBtn');
         
     | 
| 833 | 
         
            +
                if (generateBtn) {
         
     | 
| 834 | 
         
            +
                    generateBtn.addEventListener('click', function() {
         
     | 
| 835 | 
         
            +
                        const userInput = document.getElementById('userInput').value.trim();
         
     | 
| 836 | 
         
            +
                        if (!userInput) {
         
     | 
| 837 | 
         
            +
                            alert('请输入需要润色的内容');
         
     | 
| 838 | 
         
            +
                            return;
         
     | 
| 839 | 
         
            +
                        }
         
     | 
| 840 | 
         
            +
                        
         
     | 
| 841 | 
         
            +
                        // 显示Toast提示
         
     | 
| 842 | 
         
            +
                        const toast = document.getElementById('toast');
         
     | 
| 843 | 
         
            +
                        toast.style.display = 'block';
         
     | 
| 844 | 
         
            +
                        
         
     | 
| 845 | 
         
            +
                        // 调用OpenAI API
         
     | 
| 846 | 
         
            +
                        callOptimizeText(userInput);
         
     | 
| 847 | 
         
            +
                    });
         
     | 
| 848 | 
         
            +
                }
         
     | 
| 849 | 
         
            +
                
         
     | 
| 850 | 
         
            +
                // OpenAI API调用函数
         
     | 
| 851 | 
         
            +
                async function callOptimizeText(inputText) {
         
     | 
| 852 | 
         
            +
                    try {
         
     | 
| 853 | 
         
            +
                        // 获取原始反馈文本
         
     | 
| 854 | 
         
            +
                        const originalFeedback = sessionStorage.getItem('uploadedText') || '';
         
     | 
| 855 | 
         
            +
                        
         
     | 
| 856 | 
         
            +
                        const response = await fetch(`${BASE_URL}api/optimize-text`, {
         
     | 
| 857 | 
         
            +
                            method: 'POST',
         
     | 
| 858 | 
         
            +
                            headers: {
         
     | 
| 859 | 
         
            +
                                'Content-Type': 'application/json'
         
     | 
| 860 | 
         
            +
                            },
         
     | 
| 861 | 
         
            +
                            body: JSON.stringify({
         
     | 
| 862 | 
         
            +
                                original_feedback: originalFeedback,
         
     | 
| 863 | 
         
            +
                                user_input: inputText,
         
     | 
| 864 | 
         
            +
                                request_model_id: 'gpt-4.1-mini'
         
     | 
| 865 | 
         
            +
                            })
         
     | 
| 866 | 
         
            +
                        });
         
     | 
| 867 | 
         
            +
             
     | 
| 868 | 
         
            +
                        if (!response.ok) {
         
     | 
| 869 | 
         
            +
                            throw new Error('文本优化请求失败');
         
     | 
| 870 | 
         
            +
                        }
         
     | 
| 871 | 
         
            +
             
     | 
| 872 | 
         
            +
                        const data = await response.json();
         
     | 
| 873 | 
         
            +
                        
         
     | 
| 874 | 
         
            +
                        // 隐藏Toast
         
     | 
| 875 | 
         
            +
                        const toast = document.getElementById('toast');
         
     | 
| 876 | 
         
            +
                        toast.style.display = 'none';
         
     | 
| 877 | 
         
            +
                        
         
     | 
| 878 | 
         
            +
                        if (data.output && data.output[0].content[0].text.length > 0) {
         
     | 
| 879 | 
         
            +
                            // 显示API返回的结果
         
     | 
| 880 | 
         
            +
                            const optimizedText = data['output'][0]['content'][0]['text'];
         
     | 
| 881 | 
         
            +
                            const resultContent = document.getElementById('resultContent');
         
     | 
| 882 | 
         
            +
                            const resultCard = document.getElementById('resultCard');
         
     | 
| 883 | 
         
            +
                            
         
     | 
| 884 | 
         
            +
                            resultContent.innerText = optimizedText;
         
     | 
| 885 | 
         
            +
                            resultCard.style.display = 'block';
         
     | 
| 886 | 
         
            +
                            
         
     | 
| 887 | 
         
            +
                            // 平滑滚动到结果区域
         
     | 
| 888 | 
         
            +
                            resultCard.scrollIntoView({ behavior: 'smooth' });
         
     | 
| 889 | 
         
            +
                        } else {
         
     | 
| 890 | 
         
            +
                            handleAPIError('未获取到有效响应');
         
     | 
| 891 | 
         
            +
                        }
         
     | 
| 892 | 
         
            +
                    } catch (error) {
         
     | 
| 893 | 
         
            +
                        handleAPIError(error);
         
     | 
| 894 | 
         
            +
                    }
         
     | 
| 895 | 
         
            +
                }
         
     | 
| 896 | 
         
            +
                
         
     | 
| 897 | 
         
            +
                // 处理API错误
         
     | 
| 898 | 
         
            +
                function handleAPIError(error) {
         
     | 
| 899 | 
         
            +
                    console.error('API调用失败:', error);
         
     | 
| 900 | 
         
            +
                    
         
     | 
| 901 | 
         
            +
                    // 隐藏Toast
         
     | 
| 902 | 
         
            +
                    const toast = document.getElementById('toast');
         
     | 
| 903 | 
         
            +
                    toast.style.display = 'none';
         
     | 
| 904 | 
         
            +
                    
         
     | 
| 905 | 
         
            +
                    // 显示错误信息,同时提供备选方案
         
     | 
| 906 | 
         
            +
                    const resultContent = document.getElementById('resultContent');
         
     | 
| 907 | 
         
            +
                    const resultCard = document.getElementById('resultCard');
         
     | 
| 908 | 
         
            +
                    
         
     | 
| 909 | 
         
            +
                    // 备选文案,当API调用失败时使用
         
     | 
| 910 | 
         
            +
                    const userInput = document.getElementById('userInput').value.trim();
         
     | 
| 911 | 
         
            +
                    let fallbackText = '';
         
     | 
| 912 | 
         
            +
                    if (userInput.includes('不行') || userInput.includes('不能')) {
         
     | 
| 913 | 
         
            +
                        fallbackText = '感谢您的建议,我们团队已经考虑过这个方案,但受到一些技术限制,暂时无法实现。我们已经记录下您的想法,并会在后续版本中尝试优化解决。';
         
     | 
| 914 | 
         
            +
                    } else if (userInput.includes('丑') || userInput.includes('难看')) {
         
     | 
| 915 | 
         
            +
                        fallbackText = '非常感谢您的审美建议!我们设计团队正在不断优化视觉体验,您提出的这些意见非常有价值,我们会在下一版本中优先考虑调整。';
         
     | 
| 916 | 
         
            +
                    } else {
         
     | 
| 917 | 
         
            +
                        fallbackText = '您的意见我们已经记录,团队会认真研究并在后续迭代中考虑采纳。感谢您的宝贵反馈,这对我们产品的完善非常重要!';
         
     | 
| 918 | 
         
            +
                    }
         
     | 
| 919 | 
         
            +
                    
         
     | 
| 920 | 
         
            +
                    resultContent.innerText = fallbackText;
         
     | 
| 921 | 
         
            +
                    resultCard.style.display = 'block';
         
     | 
| 922 | 
         
            +
                    
         
     | 
| 923 | 
         
            +
                    // 平滑滚动到结果区域
         
     | 
| 924 | 
         
            +
                    resultCard.scrollIntoView({ behavior: 'smooth' });
         
     | 
| 925 | 
         
            +
                }
         
     | 
| 926 | 
         
            +
             
     | 
| 927 | 
         
            +
                // 添加图片转base64函数
         
     | 
| 928 | 
         
            +
                async function convertImageToBase64(imageUrl) {
         
     | 
| 929 | 
         
            +
                    try {
         
     | 
| 930 | 
         
            +
                        const response = await fetch(imageUrl);
         
     | 
| 931 | 
         
            +
                        const blob = await response.blob();
         
     | 
| 932 | 
         
            +
                        return new Promise((resolve, reject) => {
         
     | 
| 933 | 
         
            +
                            const reader = new FileReader();
         
     | 
| 934 | 
         
            +
                            reader.onloadend = () => {
         
     | 
| 935 | 
         
            +
                                // 返回完整的Data URL
         
     | 
| 936 | 
         
            +
                                resolve(reader.result);
         
     | 
| 937 | 
         
            +
                            };
         
     | 
| 938 | 
         
            +
                            reader.onerror = reject;
         
     | 
| 939 | 
         
            +
                            reader.readAsDataURL(blob);
         
     | 
| 940 | 
         
            +
                        });
         
     | 
| 941 | 
         
            +
                    } catch (error) {
         
     | 
| 942 | 
         
            +
                        console.error('转换图片为base64失败:', error);
         
     | 
| 943 | 
         
            +
                        return imageUrl; // 如果失败,返回原始URL
         
     | 
| 944 | 
         
            +
                    }
         
     | 
| 945 | 
         
            +
                }
         
     | 
| 946 | 
         
            +
            }); 
         
     | 
    	
        static/styles.css
    ADDED
    
    | 
         @@ -0,0 +1,927 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            /* 全局样式 */
         
     | 
| 2 | 
         
            +
            * {
         
     | 
| 3 | 
         
            +
                margin: 0;
         
     | 
| 4 | 
         
            +
                padding: 0;
         
     | 
| 5 | 
         
            +
                box-sizing: border-box;
         
     | 
| 6 | 
         
            +
            }
         
     | 
| 7 | 
         
            +
             
     | 
| 8 | 
         
            +
            body {
         
     | 
| 9 | 
         
            +
                font-family: 'Helvetica Neue', Arial, sans-serif;
         
     | 
| 10 | 
         
            +
                line-height: 1.6;
         
     | 
| 11 | 
         
            +
                color: #fff;
         
     | 
| 12 | 
         
            +
                background-color: #121212;
         
     | 
| 13 | 
         
            +
             
     | 
| 14 | 
         
            +
            }
         
     | 
| 15 | 
         
            +
             
     | 
| 16 | 
         
            +
            a {
         
     | 
| 17 | 
         
            +
                text-decoration: none;
         
     | 
| 18 | 
         
            +
                color: inherit;
         
     | 
| 19 | 
         
            +
            }
         
     | 
| 20 | 
         
            +
             
     | 
| 21 | 
         
            +
            /* 登录页样式 */
         
     | 
| 22 | 
         
            +
            .landing-container {
         
     | 
| 23 | 
         
            +
                min-height: 100vh;
         
     | 
| 24 | 
         
            +
                width: 100%;
         
     | 
| 25 | 
         
            +
                position: relative;
         
     | 
| 26 | 
         
            +
                overflow: hidden;
         
     | 
| 27 | 
         
            +
                background:  url(/static/assets/beijing.png),
         
     | 
| 28 | 
         
            +
                url(/static/assets/beijing2.png),
         
     | 
| 29 | 
         
            +
                url(/static/assets/beijing3.png),
         
     | 
| 30 | 
         
            +
                linear-gradient(to bottom right, #080618, #080618);
         
     | 
| 31 | 
         
            +
                background-size: 50% 50%,80% 80%,80% 80%,100% 100%;
         
     | 
| 32 | 
         
            +
                background-position: 0 0,90% 10%,-120% 260%, 0 0;
         
     | 
| 33 | 
         
            +
                background-repeat: no-repeat,no-repeat,no-repeat;
         
     | 
| 34 | 
         
            +
            }
         
     | 
| 35 | 
         
            +
             
     | 
| 36 | 
         
            +
            header {
         
     | 
| 37 | 
         
            +
                padding: 20px 40px;
         
     | 
| 38 | 
         
            +
                z-index: 2;
         
     | 
| 39 | 
         
            +
            }
         
     | 
| 40 | 
         
            +
             
     | 
| 41 | 
         
            +
            .logo {
         
     | 
| 42 | 
         
            +
                font-size: 1.5rem;
         
     | 
| 43 | 
         
            +
                font-weight: bold;
         
     | 
| 44 | 
         
            +
                color: #fff;
         
     | 
| 45 | 
         
            +
            }
         
     | 
| 46 | 
         
            +
             
     | 
| 47 | 
         
            +
            .logo a {
         
     | 
| 48 | 
         
            +
                color: #fff;
         
     | 
| 49 | 
         
            +
                text-decoration: none;
         
     | 
| 50 | 
         
            +
                transition: opacity 0.3s;
         
     | 
| 51 | 
         
            +
            }
         
     | 
| 52 | 
         
            +
             
     | 
| 53 | 
         
            +
            .logo a:hover {
         
     | 
| 54 | 
         
            +
                opacity: 0.8;
         
     | 
| 55 | 
         
            +
            }
         
     | 
| 56 | 
         
            +
             
     | 
| 57 | 
         
            +
            .landing-content {
         
     | 
| 58 | 
         
            +
                position: relative;
         
     | 
| 59 | 
         
            +
                min-height: calc(100vh - 80px);
         
     | 
| 60 | 
         
            +
                padding: 20px;
         
     | 
| 61 | 
         
            +
                display: flex;
         
     | 
| 62 | 
         
            +
                flex-direction: column;
         
     | 
| 63 | 
         
            +
                align-items: center;
         
     | 
| 64 | 
         
            +
                z-index: 2;
         
     | 
| 65 | 
         
            +
              
         
     | 
| 66 | 
         
            +
            }
         
     | 
| 67 | 
         
            +
             
     | 
| 68 | 
         
            +
            /* 浮动元素 */
         
     | 
| 69 | 
         
            +
            .floating-avatar {
         
     | 
| 70 | 
         
            +
                position: absolute;
         
     | 
| 71 | 
         
            +
                left: 24%;
         
     | 
| 72 | 
         
            +
                top: 15%;
         
     | 
| 73 | 
         
            +
                z-index: 10;
         
     | 
| 74 | 
         
            +
                background: #fff;
         
     | 
| 75 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 76 | 
         
            +
                padding: 10px 20px;
         
     | 
| 77 | 
         
            +
                border-radius: 20px;
         
     | 
| 78 | 
         
            +
                display: flex;
         
     | 
| 79 | 
         
            +
                align-items: center;
         
     | 
| 80 | 
         
            +
            }
         
     | 
| 81 | 
         
            +
             
     | 
| 82 | 
         
            +
            .avatar-icon {
         
     | 
| 83 | 
         
            +
                width: 45px;
         
     | 
| 84 | 
         
            +
                height: 45px;
         
     | 
| 85 | 
         
            +
                border-radius: 50%;
         
     | 
| 86 | 
         
            +
                background: #333;
         
     | 
| 87 | 
         
            +
                display: flex;
         
     | 
| 88 | 
         
            +
                align-items: center;
         
     | 
| 89 | 
         
            +
                justify-content: center;
         
     | 
| 90 | 
         
            +
                margin-right: 12px;
         
     | 
| 91 | 
         
            +
                overflow: hidden;
         
     | 
| 92 | 
         
            +
            }
         
     | 
| 93 | 
         
            +
             
     | 
| 94 | 
         
            +
            .avatar-img {
         
     | 
| 95 | 
         
            +
                width: 100%;
         
     | 
| 96 | 
         
            +
                height: 100%;
         
     | 
| 97 | 
         
            +
                object-fit: cover;
         
     | 
| 98 | 
         
            +
            }
         
     | 
| 99 | 
         
            +
             
     | 
| 100 | 
         
            +
            .dynamic-text {
         
     | 
| 101 | 
         
            +
                font-size: 18px;
         
     | 
| 102 | 
         
            +
                font-weight: 500;
         
     | 
| 103 | 
         
            +
                color: #333;
         
     | 
| 104 | 
         
            +
                position: relative;
         
     | 
| 105 | 
         
            +
                display: inline-block;
         
     | 
| 106 | 
         
            +
            }
         
     | 
| 107 | 
         
            +
             
     | 
| 108 | 
         
            +
            .floating-feature {
         
     | 
| 109 | 
         
            +
                position: absolute;
         
     | 
| 110 | 
         
            +
                right: 24%;
         
     | 
| 111 | 
         
            +
                top: 15%;
         
     | 
| 112 | 
         
            +
                z-index: 10;
         
     | 
| 113 | 
         
            +
                background: #fff;
         
     | 
| 114 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 115 | 
         
            +
                padding: 10px 20px;
         
     | 
| 116 | 
         
            +
                border-radius: 20px;
         
     | 
| 117 | 
         
            +
                display: flex;
         
     | 
| 118 | 
         
            +
                align-items: center;
         
     | 
| 119 | 
         
            +
            }
         
     | 
| 120 | 
         
            +
             
     | 
| 121 | 
         
            +
            .feature-icon {
         
     | 
| 122 | 
         
            +
                width: 45px;
         
     | 
| 123 | 
         
            +
                height: 45px;
         
     | 
| 124 | 
         
            +
                border-radius: 50%;
         
     | 
| 125 | 
         
            +
                display: flex;
         
     | 
| 126 | 
         
            +
                align-items: center;
         
     | 
| 127 | 
         
            +
                justify-content: center;
         
     | 
| 128 | 
         
            +
                margin-right: 12px;
         
     | 
| 129 | 
         
            +
                overflow: hidden;
         
     | 
| 130 | 
         
            +
            }
         
     | 
| 131 | 
         
            +
             
     | 
| 132 | 
         
            +
            .feature-icon img {
         
     | 
| 133 | 
         
            +
                width: 100%;
         
     | 
| 134 | 
         
            +
                height: 100%;
         
     | 
| 135 | 
         
            +
                object-fit: cover;
         
     | 
| 136 | 
         
            +
            }
         
     | 
| 137 | 
         
            +
             
     | 
| 138 | 
         
            +
            .feature-text {
         
     | 
| 139 | 
         
            +
                white-space: nowrap;
         
     | 
| 140 | 
         
            +
                font-size: 16px;
         
     | 
| 141 | 
         
            +
                color: #333;
         
     | 
| 142 | 
         
            +
                font-weight: 500;
         
     | 
| 143 | 
         
            +
            }
         
     | 
| 144 | 
         
            +
             
     | 
| 145 | 
         
            +
            /* 花朵容器 */
         
     | 
| 146 | 
         
            +
            .flower-container {
         
     | 
| 147 | 
         
            +
                position: relative;
         
     | 
| 148 | 
         
            +
                margin-top: 0%;
         
     | 
| 149 | 
         
            +
                z-index: 2;
         
     | 
| 150 | 
         
            +
                width: 100%;
         
     | 
| 151 | 
         
            +
                display: flex;
         
     | 
| 152 | 
         
            +
                justify-content: center;
         
     | 
| 153 | 
         
            +
            }
         
     | 
| 154 | 
         
            +
            .ti-container {
         
     | 
| 155 | 
         
            +
                position: relative;
         
     | 
| 156 | 
         
            +
                margin-top: 4%;
         
     | 
| 157 | 
         
            +
                z-index: 2;
         
     | 
| 158 | 
         
            +
                width: 100%;
         
     | 
| 159 | 
         
            +
                display: flex;
         
     | 
| 160 | 
         
            +
                justify-content: center;
         
     | 
| 161 | 
         
            +
            }
         
     | 
| 162 | 
         
            +
            .biao-container {
         
     | 
| 163 | 
         
            +
                position: relative;
         
     | 
| 164 | 
         
            +
                margin-top: 6%;
         
     | 
| 165 | 
         
            +
                z-index: 2;
         
     | 
| 166 | 
         
            +
                width: 100%;
         
     | 
| 167 | 
         
            +
                display: flex;
         
     | 
| 168 | 
         
            +
                justify-content: center;
         
     | 
| 169 | 
         
            +
            }
         
     | 
| 170 | 
         
            +
            .beijing-container {
         
     | 
| 171 | 
         
            +
                position: relative;
         
     | 
| 172 | 
         
            +
                margin-top: 0%;
         
     | 
| 173 | 
         
            +
                z-index: 5;
         
     | 
| 174 | 
         
            +
                width: 100%;
         
     | 
| 175 | 
         
            +
                display: flex;
         
     | 
| 176 | 
         
            +
                justify-content: left;
         
     | 
| 177 | 
         
            +
            }
         
     | 
| 178 | 
         
            +
            .ti-img {
         
     | 
| 179 | 
         
            +
                width: 600px;
         
     | 
| 180 | 
         
            +
                height: auto;
         
     | 
| 181 | 
         
            +
                max-width: 90%;
         
     | 
| 182 | 
         
            +
            }
         
     | 
| 183 | 
         
            +
             
     | 
| 184 | 
         
            +
            .flower-img {
         
     | 
| 185 | 
         
            +
                width: 700px;
         
     | 
| 186 | 
         
            +
                height: auto;
         
     | 
| 187 | 
         
            +
                max-width: 90%;
         
     | 
| 188 | 
         
            +
            }
         
     | 
| 189 | 
         
            +
             
     | 
| 190 | 
         
            +
            .beijing-img {
         
     | 
| 191 | 
         
            +
                width: 600px;
         
     | 
| 192 | 
         
            +
                height: auto;
         
     | 
| 193 | 
         
            +
                max-width: 90%;
         
     | 
| 194 | 
         
            +
            }
         
     | 
| 195 | 
         
            +
             
     | 
| 196 | 
         
            +
             
     | 
| 197 | 
         
            +
            /* 标题区域 */
         
     | 
| 198 | 
         
            +
            .hero-title {
         
     | 
| 199 | 
         
            +
                text-align: center;
         
     | 
| 200 | 
         
            +
                margin-top: -300px;
         
     | 
| 201 | 
         
            +
                z-index: 3;
         
     | 
| 202 | 
         
            +
                position: relative;
         
     | 
| 203 | 
         
            +
            }
         
     | 
| 204 | 
         
            +
             
     | 
| 205 | 
         
            +
            .main-title {
         
     | 
| 206 | 
         
            +
                font-size: 4.5rem;
         
     | 
| 207 | 
         
            +
                margin-bottom: 15px;
         
     | 
| 208 | 
         
            +
                background: linear-gradient(to right, #c299fc, #7f9bff);
         
     | 
| 209 | 
         
            +
                -webkit-background-clip: text;
         
     | 
| 210 | 
         
            +
                background-clip: text;
         
     | 
| 211 | 
         
            +
                color: transparent;
         
     | 
| 212 | 
         
            +
            }
         
     | 
| 213 | 
         
            +
             
     | 
| 214 | 
         
            +
            .subtitle {
         
     | 
| 215 | 
         
            +
                font-size: 8rem;
         
     | 
| 216 | 
         
            +
                font-weight: bold;
         
     | 
| 217 | 
         
            +
                color: rgba(255, 255, 255, 0.1);
         
     | 
| 218 | 
         
            +
                letter-spacing: 4px;
         
     | 
| 219 | 
         
            +
                margin-bottom: 25px;
         
     | 
| 220 | 
         
            +
                margin-top: -100px;
         
     | 
| 221 | 
         
            +
            }
         
     | 
| 222 | 
         
            +
             
     | 
| 223 | 
         
            +
            .description {
         
     | 
| 224 | 
         
            +
                max-width: 800px;
         
     | 
| 225 | 
         
            +
                font-weight: lighter;
         
     | 
| 226 | 
         
            +
                margin: 0 auto 40px;
         
     | 
| 227 | 
         
            +
                color: rgba(255, 255, 255, 0.8);
         
     | 
| 228 | 
         
            +
                line-height: 1.8;
         
     | 
| 229 | 
         
            +
                font-size: 1.1rem;
         
     | 
| 230 | 
         
            +
            }
         
     | 
| 231 | 
         
            +
             
     | 
| 232 | 
         
            +
            /* 通用按钮样式 */
         
     | 
| 233 | 
         
            +
            .cta-button, .resolve-button, .generate-button {
         
     | 
| 234 | 
         
            +
                display: inline-block;
         
     | 
| 235 | 
         
            +
                background: linear-gradient(to right, #5E33F1, #BA9EF7);
         
     | 
| 236 | 
         
            +
                color: #fff;
         
     | 
| 237 | 
         
            +
                padding: 15px 70px;
         
     | 
| 238 | 
         
            +
                border-radius: 20px;
         
     | 
| 239 | 
         
            +
                font-size: 1.1rem;
         
     | 
| 240 | 
         
            +
                font-weight: bold;
         
     | 
| 241 | 
         
            +
                border: none;
         
     | 
| 242 | 
         
            +
                cursor: pointer;
         
     | 
| 243 | 
         
            +
                transition: transform 0.3s, box-shadow 0.3s;
         
     | 
| 244 | 
         
            +
            }
         
     | 
| 245 | 
         
            +
             
     | 
| 246 | 
         
            +
            .cta-button:hover, .resolve-button:hover, .generate-button:hover {
         
     | 
| 247 | 
         
            +
                transform: translateY(-6px);
         
     | 
| 248 | 
         
            +
                box-shadow: 0 10px 30px rgba(128, 49, 255, 0.5);
         
     | 
| 249 | 
         
            +
            }
         
     | 
| 250 | 
         
            +
             
     | 
| 251 | 
         
            +
            /* 设备展示区域 */
         
     | 
| 252 | 
         
            +
            .showcase-section {
         
     | 
| 253 | 
         
            +
                width: 100%;
         
     | 
| 254 | 
         
            +
                height: 550px;
         
     | 
| 255 | 
         
            +
                position: relative;
         
     | 
| 256 | 
         
            +
                margin: 300px 0 100px;
         
     | 
| 257 | 
         
            +
                display: flex;
         
     | 
| 258 | 
         
            +
                justify-content: center;
         
     | 
| 259 | 
         
            +
            }
         
     | 
| 260 | 
         
            +
             
     | 
| 261 | 
         
            +
            .device-wrapper {
         
     | 
| 262 | 
         
            +
                position: relative;
         
     | 
| 263 | 
         
            +
                width: 1100px;
         
     | 
| 264 | 
         
            +
                height: 100%;
         
     | 
| 265 | 
         
            +
                transform-style: preserve-3d;
         
     | 
| 266 | 
         
            +
            }
         
     | 
| 267 | 
         
            +
             
     | 
| 268 | 
         
            +
            .showcase-device {
         
     | 
| 269 | 
         
            +
                position: absolute;
         
     | 
| 270 | 
         
            +
                border-radius: 80px;
         
     | 
| 271 | 
         
            +
                overflow: hidden;
         
     | 
| 272 | 
         
            +
                box-shadow: 0 0 100px rgba(0, 0, 0, 0.5);
         
     | 
| 273 | 
         
            +
                transition: transform 0.4s ease-out;
         
     | 
| 274 | 
         
            +
            }
         
     | 
| 275 | 
         
            +
             
     | 
| 276 | 
         
            +
            .showcase-device img {
         
     | 
| 277 | 
         
            +
                width: 100%;
         
     | 
| 278 | 
         
            +
                height: 100%;
         
     | 
| 279 | 
         
            +
                object-fit: cover;
         
     | 
| 280 | 
         
            +
                display: block;
         
     | 
| 281 | 
         
            +
            }
         
     | 
| 282 | 
         
            +
             
     | 
| 283 | 
         
            +
            .device1 {
         
     | 
| 284 | 
         
            +
                width: 350px;
         
     | 
| 285 | 
         
            +
                height: 400px;
         
     | 
| 286 | 
         
            +
                left: -40px;
         
     | 
| 287 | 
         
            +
                top: -200px;
         
     | 
| 288 | 
         
            +
                z-index: 2;
         
     | 
| 289 | 
         
            +
                
         
     | 
| 290 | 
         
            +
            }
         
     | 
| 291 | 
         
            +
             
     | 
| 292 | 
         
            +
            .device2 {
         
     | 
| 293 | 
         
            +
                width: 740px;
         
     | 
| 294 | 
         
            +
                height: 540px;
         
     | 
| 295 | 
         
            +
                left: 160px;
         
     | 
| 296 | 
         
            +
                top: 0;
         
     | 
| 297 | 
         
            +
                z-index: 3;
         
     | 
| 298 | 
         
            +
                
         
     | 
| 299 | 
         
            +
            }
         
     | 
| 300 | 
         
            +
             
     | 
| 301 | 
         
            +
            .device3 {
         
     | 
| 302 | 
         
            +
                width: 320px;
         
     | 
| 303 | 
         
            +
                height: 300px;
         
     | 
| 304 | 
         
            +
                right:-20px;
         
     | 
| 305 | 
         
            +
                top: -120px;
         
     | 
| 306 | 
         
            +
                z-index: 4;
         
     | 
| 307 | 
         
            +
               
         
     | 
| 308 | 
         
            +
            }
         
     | 
| 309 | 
         
            +
             
     | 
| 310 | 
         
            +
            .device4 {
         
     | 
| 311 | 
         
            +
                width: 220px;
         
     | 
| 312 | 
         
            +
                height: 220px;
         
     | 
| 313 | 
         
            +
                left: 100px;
         
     | 
| 314 | 
         
            +
                bottom: -60px;
         
     | 
| 315 | 
         
            +
                z-index: 5;
         
     | 
| 316 | 
         
            +
             
     | 
| 317 | 
         
            +
            }
         
     | 
| 318 | 
         
            +
             
     | 
| 319 | 
         
            +
            .device1:hover, .device2:hover, .device3:hover, .device4:hover {
         
     | 
| 320 | 
         
            +
                transform: translateY(-10px);
         
     | 
| 321 | 
         
            +
                box-shadow: 0 0 100px rgba(77, 0, 209, 0.5);
         
     | 
| 322 | 
         
            +
            }
         
     | 
| 323 | 
         
            +
             
     | 
| 324 | 
         
            +
            /* 底部区域 */
         
     | 
| 325 | 
         
            +
            .bottom-section {
         
     | 
| 326 | 
         
            +
                text-align: center;
         
     | 
| 327 | 
         
            +
                margin-top: -20px;
         
     | 
| 328 | 
         
            +
                padding: 0px 20px;
         
     | 
| 329 | 
         
            +
                position: relative;
         
     | 
| 330 | 
         
            +
                z-index: 5;
         
     | 
| 331 | 
         
            +
            }
         
     | 
| 332 | 
         
            +
             
     | 
| 333 | 
         
            +
            .subtitle-text {
         
     | 
| 334 | 
         
            +
                color: #999;
         
     | 
| 335 | 
         
            +
                margin-bottom: 15px;
         
     | 
| 336 | 
         
            +
                font-size: 1.1rem;
         
     | 
| 337 | 
         
            +
            }
         
     | 
| 338 | 
         
            +
             
     | 
| 339 | 
         
            +
            .secondary-title {
         
     | 
| 340 | 
         
            +
                font-size: 3rem;
         
     | 
| 341 | 
         
            +
                margin-bottom: 25px;
         
     | 
| 342 | 
         
            +
                background: linear-gradient(to right, #c299fc, #7f9bff);
         
     | 
| 343 | 
         
            +
                -webkit-background-clip: text;
         
     | 
| 344 | 
         
            +
                background-clip: text;
         
     | 
| 345 | 
         
            +
                color: transparent;
         
     | 
| 346 | 
         
            +
            }
         
     | 
| 347 | 
         
            +
             
     | 
| 348 | 
         
            +
            .description-secondary {
         
     | 
| 349 | 
         
            +
                max-width: 800px;
         
     | 
| 350 | 
         
            +
                font-weight: lighter;
         
     | 
| 351 | 
         
            +
                margin: 0 auto 40px;
         
     | 
| 352 | 
         
            +
                color: rgba(255, 255, 255, 0.8);
         
     | 
| 353 | 
         
            +
                line-height: 1.8;
         
     | 
| 354 | 
         
            +
                font-size: 1.1rem;
         
     | 
| 355 | 
         
            +
                margin-top: 20px;
         
     | 
| 356 | 
         
            +
            }
         
     | 
| 357 | 
         
            +
             
     | 
| 358 | 
         
            +
            .secondary-button {
         
     | 
| 359 | 
         
            +
                margin-top: 40px;
         
     | 
| 360 | 
         
            +
                margin-bottom:200px
         
     | 
| 361 | 
         
            +
            }
         
     | 
| 362 | 
         
            +
             
     | 
| 363 | 
         
            +
            /* 深色主题容器 */
         
     | 
| 364 | 
         
            +
            .dark-container {
         
     | 
| 365 | 
         
            +
                min-height: 100vh;
         
     | 
| 366 | 
         
            +
                width: 100%;
         
     | 
| 367 | 
         
            +
                position: relative;
         
     | 
| 368 | 
         
            +
                overflow: hidden;
         
     | 
| 369 | 
         
            +
                background:  url(./assets/beijing.png),
         
     | 
| 370 | 
         
            +
                url(./assets/beijing2.png),
         
     | 
| 371 | 
         
            +
                url(./assets/beijing3.png),
         
     | 
| 372 | 
         
            +
                linear-gradient(to bottom right, #080618, #080618);
         
     | 
| 373 | 
         
            +
                background-size: 50% 50%,80% 80%,80% 80%,100% 100%;
         
     | 
| 374 | 
         
            +
                background-position: 0 0,90% 10%,-120% 260%, 0 0;
         
     | 
| 375 | 
         
            +
                background-repeat: no-repeat,no-repeat,no-repeat;
         
     | 
| 376 | 
         
            +
                padding: 20px;
         
     | 
| 377 | 
         
            +
            }
         
     | 
| 378 | 
         
            +
             
     | 
| 379 | 
         
            +
            /* 上传页面样式 - 新版本 */
         
     | 
| 380 | 
         
            +
            .upload-page {
         
     | 
| 381 | 
         
            +
                display: flex;
         
     | 
| 382 | 
         
            +
                flex-direction: column;
         
     | 
| 383 | 
         
            +
                align-items: center;
         
     | 
| 384 | 
         
            +
                justify-content: center;
         
     | 
| 385 | 
         
            +
                height: calc(100vh - 80px);
         
     | 
| 386 | 
         
            +
                max-width: 900px;
         
     | 
| 387 | 
         
            +
                margin: 0 auto;
         
     | 
| 388 | 
         
            +
                padding: 20px;
         
     | 
| 389 | 
         
            +
                gap: 30px;
         
     | 
| 390 | 
         
            +
            }
         
     | 
| 391 | 
         
            +
             
     | 
| 392 | 
         
            +
            .upload-box {
         
     | 
| 393 | 
         
            +
                width: 100%;
         
     | 
| 394 | 
         
            +
                height: 45vh;
         
     | 
| 395 | 
         
            +
                background: rgba(255, 255, 255, 0.05);
         
     | 
| 396 | 
         
            +
                border-radius: 20px;
         
     | 
| 397 | 
         
            +
                display: flex;
         
     | 
| 398 | 
         
            +
                align-items: center;
         
     | 
| 399 | 
         
            +
                justify-content: center;
         
     | 
| 400 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 401 | 
         
            +
                overflow: hidden;
         
     | 
| 402 | 
         
            +
            }
         
     | 
| 403 | 
         
            +
             
     | 
| 404 | 
         
            +
            .upload-area {
         
     | 
| 405 | 
         
            +
                width: 100%;
         
     | 
| 406 | 
         
            +
                height: 100%;
         
     | 
| 407 | 
         
            +
                display: flex;
         
     | 
| 408 | 
         
            +
                align-items: center;
         
     | 
| 409 | 
         
            +
                justify-content: center;
         
     | 
| 410 | 
         
            +
                cursor: pointer;
         
     | 
| 411 | 
         
            +
                transition: all 0.3s;
         
     | 
| 412 | 
         
            +
            }
         
     | 
| 413 | 
         
            +
             
     | 
| 414 | 
         
            +
            .upload-button {
         
     | 
| 415 | 
         
            +
                background: #5d4bb7;
         
     | 
| 416 | 
         
            +
                color: white;
         
     | 
| 417 | 
         
            +
                padding: 12px 30px;
         
     | 
| 418 | 
         
            +
                border-radius: 50px;
         
     | 
| 419 | 
         
            +
                font-weight: 500;
         
     | 
| 420 | 
         
            +
                transition: all 0.3s;
         
     | 
| 421 | 
         
            +
            }
         
     | 
| 422 | 
         
            +
             
     | 
| 423 | 
         
            +
            .upload-area:hover .upload-button {
         
     | 
| 424 | 
         
            +
                background: #6b5ed8;
         
     | 
| 425 | 
         
            +
                transform: translateY(-2px);
         
     | 
| 426 | 
         
            +
                box-shadow: 0 5px 15px rgba(107, 94, 216, 0.3);
         
     | 
| 427 | 
         
            +
            }
         
     | 
| 428 | 
         
            +
             
     | 
| 429 | 
         
            +
            .text-input-box {
         
     | 
| 430 | 
         
            +
                width: 100%;
         
     | 
| 431 | 
         
            +
                height: 25vh;
         
     | 
| 432 | 
         
            +
                background: rgba(255, 255, 255, 0.05);
         
     | 
| 433 | 
         
            +
                border-radius: 20px;
         
     | 
| 434 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 435 | 
         
            +
                overflow: hidden;
         
     | 
| 436 | 
         
            +
            }
         
     | 
| 437 | 
         
            +
             
     | 
| 438 | 
         
            +
            textarea {
         
     | 
| 439 | 
         
            +
                width: 100%;
         
     | 
| 440 | 
         
            +
                height: 100%;
         
     | 
| 441 | 
         
            +
                background: transparent;
         
     | 
| 442 | 
         
            +
                border: none;
         
     | 
| 443 | 
         
            +
                padding: 20px;
         
     | 
| 444 | 
         
            +
                color: #ccc;
         
     | 
| 445 | 
         
            +
                font-size: 16px;
         
     | 
| 446 | 
         
            +
                resize: none;
         
     | 
| 447 | 
         
            +
                outline: none;
         
     | 
| 448 | 
         
            +
            }
         
     | 
| 449 | 
         
            +
             
     | 
| 450 | 
         
            +
            .button-container {
         
     | 
| 451 | 
         
            +
                width: 100%;
         
     | 
| 452 | 
         
            +
                display: flex;
         
     | 
| 453 | 
         
            +
                justify-content: center;
         
     | 
| 454 | 
         
            +
                margin-top: 30px;
         
     | 
| 455 | 
         
            +
            }
         
     | 
| 456 | 
         
            +
             
     | 
| 457 | 
         
            +
            /* 图片预览 */
         
     | 
| 458 | 
         
            +
            .upload-area.with-image {
         
     | 
| 459 | 
         
            +
                padding: 0;
         
     | 
| 460 | 
         
            +
            }
         
     | 
| 461 | 
         
            +
             
     | 
| 462 | 
         
            +
            .upload-area img {
         
     | 
| 463 | 
         
            +
                width: 100%;
         
     | 
| 464 | 
         
            +
                height: 100%;
         
     | 
| 465 | 
         
            +
                object-fit: contain;
         
     | 
| 466 | 
         
            +
            }
         
     | 
| 467 | 
         
            +
             
     | 
| 468 | 
         
            +
            /* 新版反馈页面样式 */
         
     | 
| 469 | 
         
            +
            .feedback-page {
         
     | 
| 470 | 
         
            +
                max-width: 900px;
         
     | 
| 471 | 
         
            +
                margin: 0 auto;
         
     | 
| 472 | 
         
            +
                padding: 20px;
         
     | 
| 473 | 
         
            +
                display: flex;
         
     | 
| 474 | 
         
            +
                flex-direction: column;
         
     | 
| 475 | 
         
            +
                gap: 80px;
         
     | 
| 476 | 
         
            +
            }
         
     | 
| 477 | 
         
            +
             
     | 
| 478 | 
         
            +
            .feedback-section {
         
     | 
| 479 | 
         
            +
                width: 100%;
         
     | 
| 480 | 
         
            +
            }
         
     | 
| 481 | 
         
            +
             
     | 
| 482 | 
         
            +
            .section-title {
         
     | 
| 483 | 
         
            +
                font-size: 24px;
         
     | 
| 484 | 
         
            +
                font-weight: 600;
         
     | 
| 485 | 
         
            +
                margin-bottom: 20px;
         
     | 
| 486 | 
         
            +
                color: #fff;
         
     | 
| 487 | 
         
            +
            }
         
     | 
| 488 | 
         
            +
             
     | 
| 489 | 
         
            +
            /* 情绪值卡片 */
         
     | 
| 490 | 
         
            +
            .emotion-card {
         
     | 
| 491 | 
         
            +
                width: 100%;
         
     | 
| 492 | 
         
            +
                background: rgba(255, 255, 255, 0.05);
         
     | 
| 493 | 
         
            +
                border-radius: 20px;
         
     | 
| 494 | 
         
            +
                padding: 25px;
         
     | 
| 495 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 496 | 
         
            +
                display: flex;
         
     | 
| 497 | 
         
            +
                flex-direction: column;
         
     | 
| 498 | 
         
            +
                align-items: center;
         
     | 
| 499 | 
         
            +
            }
         
     | 
| 500 | 
         
            +
             
     | 
| 501 | 
         
            +
            .emotion-icons {
         
     | 
| 502 | 
         
            +
                display: flex;
         
     | 
| 503 | 
         
            +
                gap: 16px;
         
     | 
| 504 | 
         
            +
                margin-bottom: 15px;
         
     | 
| 505 | 
         
            +
            }
         
     | 
| 506 | 
         
            +
             
     | 
| 507 | 
         
            +
            .emoji {
         
     | 
| 508 | 
         
            +
                font-size: 50px;
         
     | 
| 509 | 
         
            +
            }
         
     | 
| 510 | 
         
            +
             
     | 
| 511 | 
         
            +
            .emotion-text {
         
     | 
| 512 | 
         
            +
                color: #afafaf;
         
     | 
| 513 | 
         
            +
                font-size: 16px;
         
     | 
| 514 | 
         
            +
                text-align: center;
         
     | 
| 515 | 
         
            +
                margin-top: 10px;
         
     | 
| 516 | 
         
            +
            }
         
     | 
| 517 | 
         
            +
             
     | 
| 518 | 
         
            +
            /* 修改建议卡片 */
         
     | 
| 519 | 
         
            +
            .suggestions-container {
         
     | 
| 520 | 
         
            +
                display: grid;
         
     | 
| 521 | 
         
            +
                grid-template-columns: repeat(3, 1fr);
         
     | 
| 522 | 
         
            +
                gap: 20px;
         
     | 
| 523 | 
         
            +
                position: relative; /* 确保容器有定位上下文 */
         
     | 
| 524 | 
         
            +
            }
         
     | 
| 525 | 
         
            +
             
     | 
| 526 | 
         
            +
            .suggestion-card {
         
     | 
| 527 | 
         
            +
                background: rgba(255, 255, 255, 0.1);
         
     | 
| 528 | 
         
            +
                border-radius: 20px;
         
     | 
| 529 | 
         
            +
                overflow: visible; /* 允许横条超出卡片 */
         
     | 
| 530 | 
         
            +
                height: 300px;
         
     | 
| 531 | 
         
            +
                display: flex;
         
     | 
| 532 | 
         
            +
                flex-direction: column;
         
     | 
| 533 | 
         
            +
                backdrop-filter: blur(10px);
         
     | 
| 534 | 
         
            +
                position: relative;
         
     | 
| 535 | 
         
            +
                box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
         
     | 
| 536 | 
         
            +
                border: 1px solid rgba(255, 255, 255, 0.2);
         
     | 
| 537 | 
         
            +
                z-index: 1;
         
     | 
| 538 | 
         
            +
            }
         
     | 
| 539 | 
         
            +
             
     | 
| 540 | 
         
            +
            .suggestion-card::after {
         
     | 
| 541 | 
         
            +
                content: '';
         
     | 
| 542 | 
         
            +
                position: absolute;
         
     | 
| 543 | 
         
            +
                top: -6px; /* 向上露出10px */
         
     | 
| 544 | 
         
            +
                left: 50%;
         
     | 
| 545 | 
         
            +
                transform: translateX(-50%);
         
     | 
| 546 | 
         
            +
                width: 100px; /* 略微减小宽度 */
         
     | 
| 547 | 
         
            +
                height: 10px; /* 略微减小高度 */
         
     | 
| 548 | 
         
            +
                border-radius: 8px;
         
     | 
| 549 | 
         
            +
                z-index: -1;
         
     | 
| 550 | 
         
            +
                
         
     | 
| 551 | 
         
            +
            }
         
     | 
| 552 | 
         
            +
             
     | 
| 553 | 
         
            +
            .yellow-top::after {
         
     | 
| 554 | 
         
            +
                background: linear-gradient(to right, #deb045, #ffd166);
         
     | 
| 555 | 
         
            +
               /* 负值确保在卡片下方 */
         
     | 
| 556 | 
         
            +
             
     | 
| 557 | 
         
            +
            }
         
     | 
| 558 | 
         
            +
             
     | 
| 559 | 
         
            +
            .cyan-top::after {
         
     | 
| 560 | 
         
            +
                background: linear-gradient(to right, #25b1c1, #3ec1cf);
         
     | 
| 561 | 
         
            +
               
         
     | 
| 562 | 
         
            +
            }
         
     | 
| 563 | 
         
            +
             
     | 
| 564 | 
         
            +
            .purple-top::after {
         
     | 
| 565 | 
         
            +
                background: linear-gradient(to right, #9747FF, #b26bff);
         
     | 
| 566 | 
         
            +
                
         
     | 
| 567 | 
         
            +
            }
         
     | 
| 568 | 
         
            +
             
     | 
| 569 | 
         
            +
            .suggestion-title {
         
     | 
| 570 | 
         
            +
                font-size: 18px;
         
     | 
| 571 | 
         
            +
                font-weight: 600;
         
     | 
| 572 | 
         
            +
                margin: 40px;
         
     | 
| 573 | 
         
            +
                text-align: center;
         
     | 
| 574 | 
         
            +
            }
         
     | 
| 575 | 
         
            +
             
     | 
| 576 | 
         
            +
            .suggestion-text {
         
     | 
| 577 | 
         
            +
                padding: 0 24px 24px;
         
     | 
| 578 | 
         
            +
                color: #afafaf;
         
     | 
| 579 | 
         
            +
                font-size: 13px;
         
     | 
| 580 | 
         
            +
                line-height: 2;
         
     | 
| 581 | 
         
            +
            }
         
     | 
| 582 | 
         
            +
             
     | 
| 583 | 
         
            +
            /* 参考案例卡片 */
         
     | 
| 584 | 
         
            +
            .examples-container {
         
     | 
| 585 | 
         
            +
                display: grid;
         
     | 
| 586 | 
         
            +
                grid-template-columns: repeat(2, 1fr);
         
     | 
| 587 | 
         
            +
                gap: 30px;
         
     | 
| 588 | 
         
            +
            }
         
     | 
| 589 | 
         
            +
             
     | 
| 590 | 
         
            +
            .example-card {
         
     | 
| 591 | 
         
            +
                position: relative;
         
     | 
| 592 | 
         
            +
                height: 320px;
         
     | 
| 593 | 
         
            +
                border-radius: 12px;
         
     | 
| 594 | 
         
            +
                overflow: hidden;
         
     | 
| 595 | 
         
            +
                display: flex;
         
     | 
| 596 | 
         
            +
                flex-direction: column;
         
     | 
| 597 | 
         
            +
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
         
     | 
| 598 | 
         
            +
                transition: transform 0.3s ease, box-shadow 0.3s ease;
         
     | 
| 599 | 
         
            +
                background-color: rgba(255, 255, 255, 0.05);
         
     | 
| 600 | 
         
            +
                backdrop-filter: blur(10px);
         
     | 
| 601 | 
         
            +
                border: 1px solid rgba(255, 255, 255, 0.1);
         
     | 
| 602 | 
         
            +
            }
         
     | 
| 603 | 
         
            +
             
     | 
| 604 | 
         
            +
            .example-card:hover {
         
     | 
| 605 | 
         
            +
                transform: translateY(-5px);
         
     | 
| 606 | 
         
            +
                box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
         
     | 
| 607 | 
         
            +
            }
         
     | 
| 608 | 
         
            +
             
     | 
| 609 | 
         
            +
            .example-image {
         
     | 
| 610 | 
         
            +
                width: 100%;
         
     | 
| 611 | 
         
            +
                height: 180px;
         
     | 
| 612 | 
         
            +
                object-fit: cover;
         
     | 
| 613 | 
         
            +
                border-top-left-radius: 12px;
         
     | 
| 614 | 
         
            +
                border-top-right-radius: 12px;
         
     | 
| 615 | 
         
            +
            }
         
     | 
| 616 | 
         
            +
             
     | 
| 617 | 
         
            +
            .example-content {
         
     | 
| 618 | 
         
            +
                padding: 15px;
         
     | 
| 619 | 
         
            +
                flex-grow: 1;
         
     | 
| 620 | 
         
            +
                display: flex;
         
     | 
| 621 | 
         
            +
                flex-direction: column;
         
     | 
| 622 | 
         
            +
                max-height: 140px;
         
     | 
| 623 | 
         
            +
                overflow: hidden;
         
     | 
| 624 | 
         
            +
            }
         
     | 
| 625 | 
         
            +
             
     | 
| 626 | 
         
            +
            .example-desc {
         
     | 
| 627 | 
         
            +
                color: #e0e0e0;
         
     | 
| 628 | 
         
            +
                margin: 0 0 10px 0;
         
     | 
| 629 | 
         
            +
                font-size: 14px;
         
     | 
| 630 | 
         
            +
                line-height: 1.5;
         
     | 
| 631 | 
         
            +
                flex-grow: 1;
         
     | 
| 632 | 
         
            +
                overflow-y: auto;
         
     | 
| 633 | 
         
            +
                max-height: 100px;
         
     | 
| 634 | 
         
            +
                padding-right: 5px;
         
     | 
| 635 | 
         
            +
                scrollbar-width: thin;
         
     | 
| 636 | 
         
            +
                scrollbar-color: #9747FF rgba(255, 255, 255, 0.1);
         
     | 
| 637 | 
         
            +
            }
         
     | 
| 638 | 
         
            +
             
     | 
| 639 | 
         
            +
            .example-desc::-webkit-scrollbar {
         
     | 
| 640 | 
         
            +
                width: 4px;
         
     | 
| 641 | 
         
            +
            }
         
     | 
| 642 | 
         
            +
             
     | 
| 643 | 
         
            +
            .example-desc::-webkit-scrollbar-track {
         
     | 
| 644 | 
         
            +
                background: rgba(255, 255, 255, 0.1);
         
     | 
| 645 | 
         
            +
                border-radius: 4px;
         
     | 
| 646 | 
         
            +
            }
         
     | 
| 647 | 
         
            +
             
     | 
| 648 | 
         
            +
            .example-desc::-webkit-scrollbar-thumb {
         
     | 
| 649 | 
         
            +
                background-color: #9747FF;
         
     | 
| 650 | 
         
            +
                border-radius: 4px;
         
     | 
| 651 | 
         
            +
            }
         
     | 
| 652 | 
         
            +
             
     | 
| 653 | 
         
            +
            .example-source {
         
     | 
| 654 | 
         
            +
                font-size: 12px;
         
     | 
| 655 | 
         
            +
                color: #888;
         
     | 
| 656 | 
         
            +
                margin-top: auto;
         
     | 
| 657 | 
         
            +
                text-decoration: none;
         
     | 
| 658 | 
         
            +
            }
         
     | 
| 659 | 
         
            +
             
     | 
| 660 | 
         
            +
            .example-source a {
         
     | 
| 661 | 
         
            +
                color: #9747FF;
         
     | 
| 662 | 
         
            +
                text-decoration: none;
         
     | 
| 663 | 
         
            +
            }
         
     | 
| 664 | 
         
            +
             
     | 
| 665 | 
         
            +
            .example-source a:hover {
         
     | 
| 666 | 
         
            +
                text-decoration: underline;
         
     | 
| 667 | 
         
            +
            }
         
     | 
| 668 | 
         
            +
             
     | 
| 669 | 
         
            +
            .loading-examples {
         
     | 
| 670 | 
         
            +
                width: 100%;
         
     | 
| 671 | 
         
            +
                padding: 20px;
         
     | 
| 672 | 
         
            +
                text-align: center;
         
     | 
| 673 | 
         
            +
                color: #888;
         
     | 
| 674 | 
         
            +
                font-size: 16px;
         
     | 
| 675 | 
         
            +
                grid-column: span 2;
         
     | 
| 676 | 
         
            +
            }
         
     | 
| 677 | 
         
            +
             
     | 
| 678 | 
         
            +
            .loading-error {
         
     | 
| 679 | 
         
            +
                width: 100%;
         
     | 
| 680 | 
         
            +
                padding: 20px;
         
     | 
| 681 | 
         
            +
                text-align: center;
         
     | 
| 682 | 
         
            +
                color: #ff6b6b;
         
     | 
| 683 | 
         
            +
                font-size: 16px;
         
     | 
| 684 | 
         
            +
                grid-column: span 2;
         
     | 
| 685 | 
         
            +
            }
         
     | 
| 686 | 
         
            +
             
     | 
| 687 | 
         
            +
            /* 润色卡片 */
         
     | 
| 688 | 
         
            +
            .polished-card {
         
     | 
| 689 | 
         
            +
                width: 100%;
         
     | 
| 690 | 
         
            +
                background: rgba(255, 255, 255, 0.05);
         
     | 
| 691 | 
         
            +
                border-radius: 20px;
         
     | 
| 692 | 
         
            +
                overflow: hidden;
         
     | 
| 693 | 
         
            +
                height: 150px;
         
     | 
| 694 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 695 | 
         
            +
                margin-bottom: 20px;
         
     | 
| 696 | 
         
            +
            }
         
     | 
| 697 | 
         
            +
             
     | 
| 698 | 
         
            +
            /* 结果文案卡片 */
         
     | 
| 699 | 
         
            +
            .result-card {
         
     | 
| 700 | 
         
            +
                width: 100%;
         
     | 
| 701 | 
         
            +
                background: rgba(255, 255, 255, 0.07);
         
     | 
| 702 | 
         
            +
                border-radius: 20px;
         
     | 
| 703 | 
         
            +
                overflow: hidden;
         
     | 
| 704 | 
         
            +
                margin-top: 20px;
         
     | 
| 705 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 706 | 
         
            +
                border: 1px solid rgba(138, 43, 226, 0.2);
         
     | 
| 707 | 
         
            +
            }
         
     | 
| 708 | 
         
            +
             
     | 
| 709 | 
         
            +
            .result-title {
         
     | 
| 710 | 
         
            +
                padding: 15px 20px;
         
     | 
| 711 | 
         
            +
                font-size: 16px;
         
     | 
| 712 | 
         
            +
                font-weight: 500;
         
     | 
| 713 | 
         
            +
                color: #fff;
         
     | 
| 714 | 
         
            +
                border-bottom: 1px solid rgba(255, 255, 255, 0.05);
         
     | 
| 715 | 
         
            +
                background: rgba(138, 43, 226, 0.1);
         
     | 
| 716 | 
         
            +
            }
         
     | 
| 717 | 
         
            +
             
     | 
| 718 | 
         
            +
            .result-content {
         
     | 
| 719 | 
         
            +
                padding: 20px;
         
     | 
| 720 | 
         
            +
                color: #ccc;
         
     | 
| 721 | 
         
            +
                font-size: 16px;
         
     | 
| 722 | 
         
            +
                line-height: 1.6;
         
     | 
| 723 | 
         
            +
                min-height: 100px;
         
     | 
| 724 | 
         
            +
            }
         
     | 
| 725 | 
         
            +
             
     | 
| 726 | 
         
            +
            footer {
         
     | 
| 727 | 
         
            +
                text-align: center;
         
     | 
| 728 | 
         
            +
                margin-top: 50px;
         
     | 
| 729 | 
         
            +
                padding: 20px 0;
         
     | 
| 730 | 
         
            +
                color: #777;
         
     | 
| 731 | 
         
            +
                border-top: 1px solid rgba(255, 255, 255, 0.05);
         
     | 
| 732 | 
         
            +
            }
         
     | 
| 733 | 
         
            +
             
     | 
| 734 | 
         
            +
            /* 响应式设计 */
         
     | 
| 735 | 
         
            +
            @media (max-width: 768px) {
         
     | 
| 736 | 
         
            +
                .landing-content {
         
     | 
| 737 | 
         
            +
                    padding: 10px;
         
     | 
| 738 | 
         
            +
                }
         
     | 
| 739 | 
         
            +
                
         
     | 
| 740 | 
         
            +
                .floating-avatar, .floating-feature {
         
     | 
| 741 | 
         
            +
                    position: static;
         
     | 
| 742 | 
         
            +
                    margin: 10px auto;
         
     | 
| 743 | 
         
            +
                }
         
     | 
| 744 | 
         
            +
                
         
     | 
| 745 | 
         
            +
                .flower-img {
         
     | 
| 746 | 
         
            +
                    max-width: 80%;
         
     | 
| 747 | 
         
            +
                }
         
     | 
| 748 | 
         
            +
                
         
     | 
| 749 | 
         
            +
                .main-title {
         
     | 
| 750 | 
         
            +
                    font-size: 2.5rem;
         
     | 
| 751 | 
         
            +
                }
         
     | 
| 752 | 
         
            +
                
         
     | 
| 753 | 
         
            +
                .subtitle {
         
     | 
| 754 | 
         
            +
                    font-size: 2rem;
         
     | 
| 755 | 
         
            +
                }
         
     | 
| 756 | 
         
            +
                
         
     | 
| 757 | 
         
            +
                .secondary-title {
         
     | 
| 758 | 
         
            +
                    font-size: 1.8rem;
         
     | 
| 759 | 
         
            +
                }
         
     | 
| 760 | 
         
            +
                
         
     | 
| 761 | 
         
            +
                .upload-page {
         
     | 
| 762 | 
         
            +
                    padding: 10px;
         
     | 
| 763 | 
         
            +
                }
         
     | 
| 764 | 
         
            +
                
         
     | 
| 765 | 
         
            +
                .upload-box {
         
     | 
| 766 | 
         
            +
                    height: 35vh;
         
     | 
| 767 | 
         
            +
                }
         
     | 
| 768 | 
         
            +
                
         
     | 
| 769 | 
         
            +
                .text-input-box {
         
     | 
| 770 | 
         
            +
                    height: 25vh;
         
     | 
| 771 | 
         
            +
                }
         
     | 
| 772 | 
         
            +
                
         
     | 
| 773 | 
         
            +
                .suggestions-container,
         
     | 
| 774 | 
         
            +
                .examples-container {
         
     | 
| 775 | 
         
            +
                    grid-template-columns: 1fr;
         
     | 
| 776 | 
         
            +
                }
         
     | 
| 777 | 
         
            +
                
         
     | 
| 778 | 
         
            +
                .button-container {
         
     | 
| 779 | 
         
            +
                    flex-direction: column;
         
     | 
| 780 | 
         
            +
                    gap: 15px;
         
     | 
| 781 | 
         
            +
                }
         
     | 
| 782 | 
         
            +
                
         
     | 
| 783 | 
         
            +
                .back-button, .submit-button, .save-button {
         
     | 
| 784 | 
         
            +
                    width: 100%;
         
     | 
| 785 | 
         
            +
                }
         
     | 
| 786 | 
         
            +
            }
         
     | 
| 787 | 
         
            +
             
     | 
| 788 | 
         
            +
            /* Toast提示 */
         
     | 
| 789 | 
         
            +
            .toast {
         
     | 
| 790 | 
         
            +
                position: fixed;
         
     | 
| 791 | 
         
            +
                top: 50%;
         
     | 
| 792 | 
         
            +
                left: 50%;
         
     | 
| 793 | 
         
            +
                transform: translate(-50%, -50%);
         
     | 
| 794 | 
         
            +
                background: rgba(0, 0, 0, 0.8);
         
     | 
| 795 | 
         
            +
                color: white;
         
     | 
| 796 | 
         
            +
                padding: 15px 30px;
         
     | 
| 797 | 
         
            +
                border-radius: 50px;
         
     | 
| 798 | 
         
            +
                z-index: 9999;
         
     | 
| 799 | 
         
            +
                font-size: 16px;
         
     | 
| 800 | 
         
            +
                display: none;
         
     | 
| 801 | 
         
            +
                animation: fadeIn 0.3s;
         
     | 
| 802 | 
         
            +
            }
         
     | 
| 803 | 
         
            +
             
     | 
| 804 | 
         
            +
            @keyframes fadeIn {
         
     | 
| 805 | 
         
            +
                from { opacity: 0; }
         
     | 
| 806 | 
         
            +
                to { opacity: 1; }
         
     | 
| 807 | 
         
            +
            }
         
     | 
| 808 | 
         
            +
             
     | 
| 809 | 
         
            +
            /* 优化方案卡片 */
         
     | 
| 810 | 
         
            +
            .optimization-container {
         
     | 
| 811 | 
         
            +
                display: grid;
         
     | 
| 812 | 
         
            +
                grid-template-columns: repeat(2, 1fr);
         
     | 
| 813 | 
         
            +
                gap: 20px;
         
     | 
| 814 | 
         
            +
            }
         
     | 
| 815 | 
         
            +
             
     | 
| 816 | 
         
            +
            .optimization-card {
         
     | 
| 817 | 
         
            +
                background: rgba(255, 255, 255, 0.05);
         
     | 
| 818 | 
         
            +
                border-radius: 20px;
         
     | 
| 819 | 
         
            +
                overflow: hidden;
         
     | 
| 820 | 
         
            +
                backdrop-filter: blur(5px);
         
     | 
| 821 | 
         
            +
                display: flex;
         
     | 
| 822 | 
         
            +
                flex-direction: column;
         
     | 
| 823 | 
         
            +
                min-height: 320px;
         
     | 
| 824 | 
         
            +
                border: 1px solid rgba(255, 255, 255, 0.1);
         
     | 
| 825 | 
         
            +
            }
         
     | 
| 826 | 
         
            +
             
     | 
| 827 | 
         
            +
            .optimization-header {
         
     | 
| 828 | 
         
            +
                display: flex;
         
     | 
| 829 | 
         
            +
                justify-content: space-between;
         
     | 
| 830 | 
         
            +
                align-items: center;
         
     | 
| 831 | 
         
            +
                padding: 16px 20px;
         
     | 
| 832 | 
         
            +
                border-bottom: 1px solid rgba(255, 255, 255, 0.1);
         
     | 
| 833 | 
         
            +
                background: rgba(0, 0, 0, 0.2);
         
     | 
| 834 | 
         
            +
            }
         
     | 
| 835 | 
         
            +
             
     | 
| 836 | 
         
            +
            .optimization-title {
         
     | 
| 837 | 
         
            +
                font-size: 18px;
         
     | 
| 838 | 
         
            +
                font-weight: 500;
         
     | 
| 839 | 
         
            +
                margin: 0;
         
     | 
| 840 | 
         
            +
            }
         
     | 
| 841 | 
         
            +
             
     | 
| 842 | 
         
            +
            .generate-btn {
         
     | 
| 843 | 
         
            +
                background: linear-gradient(to right, #5E33F1, #BA9EF7);
         
     | 
| 844 | 
         
            +
                color: white;
         
     | 
| 845 | 
         
            +
                border: none;
         
     | 
| 846 | 
         
            +
                padding: 8px 16px;
         
     | 
| 847 | 
         
            +
                border-radius: 20px;
         
     | 
| 848 | 
         
            +
                font-size: 14px;
         
     | 
| 849 | 
         
            +
                cursor: pointer;
         
     | 
| 850 | 
         
            +
                transition: all 0.3s ease;
         
     | 
| 851 | 
         
            +
            }
         
     | 
| 852 | 
         
            +
             
     | 
| 853 | 
         
            +
            .generate-btn:hover {
         
     | 
| 854 | 
         
            +
                transform: translateY(-2px);
         
     | 
| 855 | 
         
            +
                box-shadow: 0 5px 15px rgba(94, 51, 241, 0.3);
         
     | 
| 856 | 
         
            +
            }
         
     | 
| 857 | 
         
            +
             
     | 
| 858 | 
         
            +
            .generate-btn:disabled {
         
     | 
| 859 | 
         
            +
                background: #666;
         
     | 
| 860 | 
         
            +
                cursor: not-allowed;
         
     | 
| 861 | 
         
            +
                transform: none;
         
     | 
| 862 | 
         
            +
                box-shadow: none;
         
     | 
| 863 | 
         
            +
            }
         
     | 
| 864 | 
         
            +
             
     | 
| 865 | 
         
            +
            .optimization-content {
         
     | 
| 866 | 
         
            +
                padding: 20px;
         
     | 
| 867 | 
         
            +
                flex-grow: 1;
         
     | 
| 868 | 
         
            +
                display: flex;
         
     | 
| 869 | 
         
            +
                align-items: center;
         
     | 
| 870 | 
         
            +
                justify-content: center;
         
     | 
| 871 | 
         
            +
                position: relative;
         
     | 
| 872 | 
         
            +
                min-height: 260px;
         
     | 
| 873 | 
         
            +
            }
         
     | 
| 874 | 
         
            +
             
     | 
| 875 | 
         
            +
            .optimization-result {
         
     | 
| 876 | 
         
            +
                width: 100%;
         
     | 
| 877 | 
         
            +
                height: 100%;
         
     | 
| 878 | 
         
            +
                display: flex;
         
     | 
| 879 | 
         
            +
                align-items: center;
         
     | 
| 880 | 
         
            +
                justify-content: center;
         
     | 
| 881 | 
         
            +
            }
         
     | 
| 882 | 
         
            +
             
     | 
| 883 | 
         
            +
            .optimization-result img {
         
     | 
| 884 | 
         
            +
                max-width: 100%;
         
     | 
| 885 | 
         
            +
                max-height: 250px;
         
     | 
| 886 | 
         
            +
                border-radius: 8px;
         
     | 
| 887 | 
         
            +
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
         
     | 
| 888 | 
         
            +
            }
         
     | 
| 889 | 
         
            +
             
     | 
| 890 | 
         
            +
            .optimization-placeholder {
         
     | 
| 891 | 
         
            +
                color: #888;
         
     | 
| 892 | 
         
            +
                text-align: center;
         
     | 
| 893 | 
         
            +
                padding: 20px;
         
     | 
| 894 | 
         
            +
            }
         
     | 
| 895 | 
         
            +
             
     | 
| 896 | 
         
            +
            .optimization-loading {
         
     | 
| 897 | 
         
            +
                position: absolute;
         
     | 
| 898 | 
         
            +
                top: 0;
         
     | 
| 899 | 
         
            +
                left: 0;
         
     | 
| 900 | 
         
            +
                width: 100%;
         
     | 
| 901 | 
         
            +
                height: 100%;
         
     | 
| 902 | 
         
            +
                background: rgba(0, 0, 0, 0.7);
         
     | 
| 903 | 
         
            +
                display: flex;
         
     | 
| 904 | 
         
            +
                flex-direction: column;
         
     | 
| 905 | 
         
            +
                align-items: center;
         
     | 
| 906 | 
         
            +
                justify-content: center;
         
     | 
| 907 | 
         
            +
                z-index: 2;
         
     | 
| 908 | 
         
            +
            }
         
     | 
| 909 | 
         
            +
             
     | 
| 910 | 
         
            +
            .loading-spinner {
         
     | 
| 911 | 
         
            +
                width: 40px;
         
     | 
| 912 | 
         
            +
                height: 40px;
         
     | 
| 913 | 
         
            +
                border: 4px solid rgba(255, 255, 255, 0.1);
         
     | 
| 914 | 
         
            +
                border-left-color: #5E33F1;
         
     | 
| 915 | 
         
            +
                border-radius: 50%;
         
     | 
| 916 | 
         
            +
                animation: spin 1s linear infinite;
         
     | 
| 917 | 
         
            +
                margin-bottom: 15px;
         
     | 
| 918 | 
         
            +
            }
         
     | 
| 919 | 
         
            +
             
     | 
| 920 | 
         
            +
            .loading-text {
         
     | 
| 921 | 
         
            +
                color: #ccc;
         
     | 
| 922 | 
         
            +
                font-size: 14px;
         
     | 
| 923 | 
         
            +
            }
         
     | 
| 924 | 
         
            +
             
     | 
| 925 | 
         
            +
            @keyframes spin {
         
     | 
| 926 | 
         
            +
                to { transform: rotate(360deg); }
         
     | 
| 927 | 
         
            +
            } 
         
     | 
    	
        static/upload.html
    ADDED
    
    | 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            <!DOCTYPE html>
         
     | 
| 2 | 
         
            +
            <html lang="zh-CN">
         
     | 
| 3 | 
         
            +
            <head>
         
     | 
| 4 | 
         
            +
                <meta charset="UTF-8">
         
     | 
| 5 | 
         
            +
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
         
     | 
| 6 | 
         
            +
                <title>内容上传 - 解语花</title>
         
     | 
| 7 | 
         
            +
                <link rel="stylesheet" href="/static/styles.css">
         
     | 
| 8 | 
         
            +
            </head>
         
     | 
| 9 | 
         
            +
            <body>
         
     | 
| 10 | 
         
            +
                <div class="dark-container">
         
     | 
| 11 | 
         
            +
                    <header>
         
     | 
| 12 | 
         
            +
                        <div class="logo"><a href="/static/index.html">解语花</a></div>
         
     | 
| 13 | 
         
            +
                    </header>
         
     | 
| 14 | 
         
            +
                    
         
     | 
| 15 | 
         
            +
                    <main class="upload-page">
         
     | 
| 16 | 
         
            +
                        <div class="upload-box">
         
     | 
| 17 | 
         
            +
                            <div class="upload-area" id="image-upload">
         
     | 
| 18 | 
         
            +
                                <div class="upload-button">点击/拖拽设计稿</div>
         
     | 
| 19 | 
         
            +
                            </div>
         
     | 
| 20 | 
         
            +
                            <input type="file" id="image-input" accept="image/*" hidden>
         
     | 
| 21 | 
         
            +
                        </div>
         
     | 
| 22 | 
         
            +
                        
         
     | 
| 23 | 
         
            +
                        <div class="text-input-box">
         
     | 
| 24 | 
         
            +
                            <textarea id="text-input" placeholder="请输入设计类型和内容描述,以及老板反馈"></textarea>
         
     | 
| 25 | 
         
            +
                        </div>
         
     | 
| 26 | 
         
            +
                        
         
     | 
| 27 | 
         
            +
                        <div class="button-container">
         
     | 
| 28 | 
         
            +
                            <button type="button" class="resolve-button" id="resolve-button">一键解读</button>
         
     | 
| 29 | 
         
            +
                        </div>
         
     | 
| 30 | 
         
            +
                    </main>
         
     | 
| 31 | 
         
            +
                </div>
         
     | 
| 32 | 
         
            +
                
         
     | 
| 33 | 
         
            +
                <script src="/static/script.js"></script>
         
     | 
| 34 | 
         
            +
            </body>
         
     | 
| 35 | 
         
            +
            </html> 
         
     |