ai_service/API_文档.md

14 KiB
Raw Blame History

AI海报生成系统 API 文档

🎯 API概览

AI海报生成系统提供统一的REST API接口一键生成Vue组件代码和PSD文件。

基础URL: http://localhost:8000

主要特性:

  • 🚀 一键生成Vue代码和PSD文件
  • 🎨 集成多个AI模型DeepSeek + Kimi + ComfyUI
  • 📁 会话管理和文件下载
  • 🔄 自动图片生成和合成

📋 API端点总览

端点 方法 描述 状态
/ GET 获取API信息
/health GET 健康检查
/api/generate-poster POST 主要接口 - 生成海报
/api/download/{file_type} GET 下载文件
/api/status/{session_id} GET 获取会话状态

🔧 主要接口详情

1. 生成海报(核心接口)

POST /api/generate-poster

这是唯一需要的主要接口,一次调用完成所有生成任务。

请求示例:

{
  "user_input": "端午节海报,传统风格,包含荷花和龙舟",
  "session_id": "可选 - 用于跟踪会话"
}

完整响应示例:

{
  "status": "success",
  "message": "海报生成完成",
  "data": {
    "vue_code": "完整的Vue 3组件代码",
    "suggestions": {
      "layer5_logo_content": {
        "text": "主办方",
        "color": "#000000"
      },
      "layer6_title_content": {
        "content": "端午节安康",
        "font_name": "SimHei",
        "color": "#7E0C6E"
      },
      "layer7_subtitle_content": {
        "content": "粽叶飘香,龙舟竞渡,共庆端午佳节",
        "font_name": "Microsoft YaHei",
        "color": "#000000"
      }
    },
    "analysis_result": {
      "analyzed_prompt": "端午节海报,传统风格",
      "main_theme": "端午节祝福",
      "style_preference": "传统",
      "width": 1080,
      "height": 1920,
      "keywords": ["端午节", "传统", "荷花", "龙舟"]
    },
    "psd_file_path": "/path/to/session_xxx/final_poster.psd",
    "file_size_mb": 5.93,
    "generated_images": 2,
    "files": {
      "vue_file": "/path/to/generated_code.vue",
      "psd_file": "/path/to/final_poster.psd"
    }
  },
  "session_id": "uuid-generated-session-id"
}

2. 文件下载

GET /api/download/{file_type}?session_id={session_id}

参数:

  • file_type: 文件类型
    • vue - Vue组件文件
    • psd - PSD文件
    • json - 文案建议JSON文件
  • session_id: 会话ID必需

响应: 直接返回文件流,浏览器会自动下载

3. 健康检查

GET /health

响应:

{
  "status": "healthy",
  "timestamp": "2025-01-02T20:30:00.123456"
}

4. 会话状态查询

GET /api/status/{session_id}

响应:

{
  "status": "success",
  "message": "状态获取成功",
  "data": {
    "user_input": "端午节海报,传统风格",
    "analysis_result": "...",
    "suggestions": "...",
    "vue_path": "/path/to/vue/file",
    "psd_path": "/path/to/psd/file",
    "created_at": "2025-01-02T20:30:00"
  },
  "session_id": "session-id"
}

🛠️ 前端集成指南

JavaScript ES6+ 示例

class PosterGenerator {
  constructor(baseUrl = 'http://localhost:8000') {
    this.baseUrl = baseUrl;
  }

  // 主要方法:生成海报
  async generatePoster(userInput) {
    try {
      const response = await fetch(`${this.baseUrl}/api/generate-poster`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          user_input: userInput
        })
      });

      const result = await response.json();
      
      if (result.status === 'success') {
        console.log('✅ 海报生成成功');
        console.log('Vue代码长度:', result.data.vue_code.length);
        console.log('PSD文件大小:', result.data.file_size_mb, 'MB');
        console.log('生成的图片数量:', result.data.generated_images);
        
        return result;
      } else {
        throw new Error(result.message || '生成失败');
      }
    } catch (error) {
      console.error('❌ 海报生成失败:', error);
      throw error;
    }
  }

  // 下载文件
  downloadFile(sessionId, fileType) {
    const url = `${this.baseUrl}/api/download/${fileType}?session_id=${sessionId}`;
    const a = document.createElement('a');
    a.href = url;
    a.download = '';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  }

  // 获取会话状态
  async getSessionStatus(sessionId) {
    const response = await fetch(`${this.baseUrl}/api/status/${sessionId}`);
    return await response.json();
  }
}

// 使用示例
const generator = new PosterGenerator();

async function createPoster() {
  try {
    // 生成海报
    const result = await generator.generatePoster("春节海报,红色背景,现代风格");
    
    // 显示Vue代码
    document.getElementById('vue-code').textContent = result.data.vue_code;
    
    // 显示文案建议
    document.getElementById('suggestions').textContent = 
      JSON.stringify(result.data.suggestions, null, 2);
    
    // 设置下载按钮
    document.getElementById('download-vue').onclick = () => 
      generator.downloadFile(result.session_id, 'vue');
    document.getElementById('download-psd').onclick = () => 
      generator.downloadFile(result.session_id, 'psd');
      
  } catch (error) {
    alert('生成失败: ' + error.message);
  }
}

Vue.js 组件示例

<template>
  <div class="poster-generator">
    <div class="input-section">
      <h2>AI海报生成器</h2>
      <div class="form-group">
        <label>海报需求描述</label>
        <textarea 
          v-model="userInput" 
          placeholder="请描述您的海报需求,例如:端午节海报,传统风格,包含荷花和龙舟"
          rows="4"
        ></textarea>
      </div>
      <button 
        @click="generatePoster" 
        :disabled="loading || !userInput.trim()"
        :class="{ loading: loading }"
      >
        {{ loading ? '生成中...' : '生成海报' }}
      </button>
    </div>
    
    <div v-if="result" class="result-section">
      <div class="tabs">
        <button 
          @click="activeTab = 'vue'" 
          :class="{ active: activeTab === 'vue' }"
        >
          Vue代码
        </button>
        <button 
          @click="activeTab = 'suggestions'" 
          :class="{ active: activeTab === 'suggestions' }"
        >
          文案建议
        </button>
        <button 
          @click="activeTab = 'info'" 
          :class="{ active: activeTab === 'info' }"
        >
          生成信息
        </button>
      </div>
      
      <div class="tab-content">
        <div v-if="activeTab === 'vue'" class="vue-code">
          <h3>Vue组件代码</h3>
          <pre><code>{{ result.data.vue_code }}</code></pre>
        </div>
        
        <div v-if="activeTab === 'suggestions'" class="suggestions">
          <h3>文案建议</h3>
          <div class="suggestion-item" v-for="(item, key) in result.data.suggestions" :key="key">
            <h4>{{ getSuggestionTitle(key) }}</h4>
            <p><strong>内容:</strong> {{ item.content || item.text }}</p>
            <p><strong>字体:</strong> {{ item.font_name || '未指定' }}</p>
            <p><strong>颜色:</strong> <span :style="{ color: item.color }">{{ item.color }}</span></p>
          </div>
        </div>
        
        <div v-if="activeTab === 'info'" class="info">
          <h3>生成信息</h3>
          <p><strong>主题:</strong> {{ result.data.analysis_result.main_theme }}</p>
          <p><strong>风格:</strong> {{ result.data.analysis_result.style_preference }}</p>
          <p><strong>PSD文件大小:</strong> {{ result.data.file_size_mb }} MB</p>
          <p><strong>生成图片数量:</strong> {{ result.data.generated_images }}</p>
        </div>
      </div>
      
      <div class="download-section">
        <h3>下载文件</h3>
        <button @click="downloadFile('vue')" class="download-btn">
          📄 下载Vue文件
        </button>
        <button @click="downloadFile('psd')" class="download-btn">
          🎨 下载PSD文件
        </button>
        <button @click="downloadFile('json')" class="download-btn">
          📋 下载文案JSON
        </button>
      </div>
    </div>
    
    <div v-if="error" class="error">
      <h3>错误信息</h3>
      <p>{{ error }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const userInput = ref('')
const loading = ref(false)
const result = ref(null)
const error = ref('')
const activeTab = ref('vue')

const generatePoster = async () => {
  loading.value = true
  error.value = ''
  
  try {
    const response = await fetch('http://localhost:8000/api/generate-poster', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        user_input: userInput.value
      })
    })
    
    const data = await response.json()
    
    if (data.status === 'success') {
      result.value = data
    } else {
      error.value = data.message || '生成失败'
    }
  } catch (err) {
    error.value = '网络错误: ' + err.message
  } finally {
    loading.value = false
  }
}

const downloadFile = (fileType) => {
  if (!result.value) return
  
  const url = `http://localhost:8000/api/download/${fileType}?session_id=${result.value.session_id}`
  const a = document.createElement('a')
  a.href = url
  a.download = ''
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}

const getSuggestionTitle = (key) => {
  const titles = {
    layer5_logo_content: 'Logo文字',
    layer6_title_content: '主标题',
    layer7_subtitle_content: '副标题'
  }
  return titles[key] || key
}
</script>

<style scoped>
.poster-generator {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.input-section {
  background: #f5f5f5;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
}

.form-group {
  margin-bottom: 15px;
}

.form-group label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

.form-group textarea {
  width: 100%;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

button {
  background: #007bff;
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
}

button:disabled {
  background: #ccc;
  cursor: not-allowed;
}

button.loading {
  background: #ffc107;
}

.result-section {
  background: white;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.tabs {
  display: flex;
  background: #f8f9fa;
  border-bottom: 1px solid #ddd;
}

.tabs button {
  flex: 1;
  padding: 15px;
  background: transparent;
  color: #666;
  border: none;
  border-radius: 0;
}

.tabs button.active {
  background: white;
  color: #007bff;
  border-bottom: 2px solid #007bff;
}

.tab-content {
  padding: 20px;
  min-height: 400px;
}

.vue-code pre {
  background: #f8f9fa;
  padding: 15px;
  border-radius: 4px;
  overflow-x: auto;
  white-space: pre-wrap;
}

.suggestion-item {
  background: #f8f9fa;
  padding: 15px;
  margin-bottom: 10px;
  border-radius: 4px;
}

.download-section {
  padding: 20px;
  background: #f8f9fa;
  border-top: 1px solid #ddd;
}

.download-btn {
  margin-right: 10px;
  margin-bottom: 10px;
}

.error {
  background: #f8d7da;
  color: #721c24;
  padding: 15px;
  border-radius: 4px;
  margin-top: 20px;
}
</style>

快速开始

1. 启动服务器

cd E:\砚\ai_service\scripts
python run_pipeline.py
# 选择: 2 (API服务器模式)

2. 测试API

# 健康检查
curl http://localhost:8000/health

# 生成海报
curl -X POST http://localhost:8000/api/generate-poster \
  -H "Content-Type: application/json" \
  -d '{"user_input": "春节海报,红色背景,现代风格"}'

3. 前端调用

// 最简单的调用方式
fetch('http://localhost:8000/api/generate-poster', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ user_input: '端午节海报,传统风格' })
})
.then(response => response.json())
.then(data => {
  if (data.status === 'success') {
    console.log('Vue代码:', data.data.vue_code);
    // 下载PSD文件
    window.open(`http://localhost:8000/api/download/psd?session_id=${data.session_id}`);
  }
});

🔧 错误处理

错误响应格式

{
  "detail": "具体错误信息"
}

常见错误

  • 400 Bad Request: 请求参数错误
  • 404 Not Found: 会话不存在或文件不存在
  • 500 Internal Server Error: 服务器内部错误

错误处理示例

try {
  const response = await fetch('/api/generate-poster', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ user_input: 'test' })
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.detail || '请求失败');
  }
  
  const result = await response.json();
  // 处理成功结果
} catch (error) {
  console.error('API调用失败:', error.message);
  // 显示错误给用户
}

🚀 部署配置

开发环境

# 启动开发服务器
python run_pipeline.py
# 访问: http://localhost:8000

生产环境

# 使用uvicorn直接运行
uvicorn run_pipeline:app --host 0.0.0.0 --port 8000

# 或使用PM2管理
pm2 start "uvicorn run_pipeline:app --host 0.0.0.0 --port 8000" --name poster-api

Docker部署

FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 8000
CMD ["uvicorn", "scripts.run_pipeline:app", "--host", "0.0.0.0", "--port", "8000"]

📝 更新日志

v1.0.0 (2025-01-02)

  • 统一API接口设计
  • 集成DeepSeek + Kimi + ComfyUI
  • 支持Vue组件和PSD文件生成
  • 会话管理和文件下载
  • 完整的错误处理和文档