FastAPI開發AI應用教程:新增文生圖、圖生圖功能
本文將深入講解如何在 FastAPI AI 聊天應用中實現文生圖和圖生圖功能,重點介紹豆包 Seedream 4.0 圖像生成模型的強大能力。通過本教程,你將學會如何構建完整的 AI 圖像生成系統,包括文生圖、圖生圖等圖像輸出核心技術。
?? 項目地址:https://github.com/wayn111/fastapi-ai-chat-demo
溫馨提示:本文全文約八千字,看完約需 15 分鐘。
項目概述
想象一下,當你向 AI 描述一個場景時,AI 能夠立即為你生成對應的高質量圖像;當你上傳一張圖片時,AI 能夠基于你的描述對圖片進行創意改造——這就是我們要實現的文生圖和圖生圖功能!用戶可以通過文字描述生成全新的圖像,也可以上傳參考圖片進行風格轉換、內容編輯和創意重構。

核心功能
- 文本生成圖像(Text-to-Image):基于自然語言描述生成高質量圖像
- 圖像生成圖像(Image-to-Image):基于參考圖片和文字描述進行圖像轉換
- 多模態輸入處理:支持文本、圖像的組合輸入和融合創作
- 4K 高清輸出:支持最高 4K 分辨率的圖像生成
- 秒級生成體驗:借助先進推理加速技術實現快速圖像生成
技術棧
- 后端框架:FastAPI(高性能異步 Web 框架)
- 圖像生成模型:豆包 Seedream 4.0(支持 4K 多模態生圖)
- 圖片處理:Pillow(Python 圖像處理庫)
- 數據編碼:Base64(圖片數據傳輸編碼)
- 前端交互:HTML5 File API + JavaScript(圖片上傳和預覽)
- 數據存儲:Redis(消息持久化)
豆包 Seedream 4.0 模型介紹
豆包·圖像創作模型 Seedream 4.0 是字節跳動正式發布的新一代圖像生成模型,是集生成與編輯于一體的一站式圖像創作解決方案。值得一提的是,9月11日晚,Seedream 4.0 在 Artificial Analysis「文生圖」和「圖像編輯」兩大榜單榮登榜首,充分證明了其在業界的領先地位。
能力特性
業界首款 4K 多模態生圖:Seedream 4.0 是業界首款支持 4K 分辨率的多模態圖像生成模型,能夠靈活處理文本、圖像的組合輸入,實現多圖融合創作、參考生圖、組合生圖、圖像編輯等核心功能。主體一致性相比前代版本顯著提升,生成的圖像質量和細節表現力大幅增強。
極致推理性能:借助先進的推理加速技術,Seedream 4.0 的推理速度較 Seedream 3.0 版本提升超過 10 倍,最快可在秒級時間內生成 2K 高清圖片,為用戶提供近乎實時的圖像生成體驗。
突破性文字渲染:在文字處理方面突破了以往生成模型的瓶頸,不僅能正確渲染出清晰的文字內容,還能一定程度上處理公式、表格、化學結構、統計圖等復雜排版,為專業應用場景提供強有力支持。
應用場景
Seedream 4.0 可廣泛應用于多個領域,為企業提供穩定、優質且風格統一的視覺輸出解決方案,顯著提升工作效率:
- 電商營銷:產品展示圖、廣告創意圖、營銷海報生成
- 商業設計:品牌視覺、包裝設計、UI/UX 原型圖
- 專業海報:活動宣傳、展覽海報、信息圖表
- 內容創作:社交媒體配圖、博客插圖、創意素材
核心架構設計
系統架構圖
圖片
數據模型設計
圖像生成請求模型
class ImageGenerationAPIRequest(BaseModel):
"""圖片生成API請求模型"""
prompt: str = Field(..., descriptinotallow="圖片生成提示詞")
size: Optional[str] = Field("1024x1024", descriptinotallow="圖片尺寸")
image_data: Optional[str] = Field(None, descriptinotallow="參考圖片數據 (base64編碼,圖片生成圖片模式)")
provider: Optional[str] = Field("doubao", descriptinotallow="AI提供商")
image_type: Optional[str] = Field(None, descriptinotallow="圖片類型")這個模型定義了圖像生成請求的完整數據結構,支持純文本生成圖像和基于參考圖片的圖像轉換兩種模式。
圖像生成響應模型
class ImageGenerationAPIResponse(BaseModel):
"""圖片生成API響應模型"""
success: bool = Field(..., descriptinotallow="是否成功")
message: str = Field(..., descriptinotallow="響應消息")
data: Optional[dict] = Field(None, descriptinotallow="圖片數據")
provider: str = Field(..., descriptinotallow="使用的AI提供商")
timestamp: float = Field(..., descriptinotallow="時間戳")AI提供商基礎模型
@dataclass
class ImageGenerationRequest:
"""圖片生成請求數據類"""
prompt: str
size: str = "1024x1024"
image_data: Optional[str] = None
image_type: Optional[str] = None
@dataclass
class ImageGenerationResponse:
"""圖片生成響應數據類"""
url: Optional[str] = None
b64_json: Optional[str] = None
revised_prompt: Optional[str] = None核心功能實現
后端圖像生成接口實現
主要API接口
@app.post("/generate/image", response_model=ImageGenerationAPIResponse)
asyncdef generate_image(request: ImageGenerationAPIRequest):
"""圖片生成API接口
支持兩種模式:
1. 純文本生成圖片:僅提供prompt參數
2. 圖片生成圖片:提供prompt和image_data參數
"""
logger.info(f"接收圖片生成請求 - 提示詞: {request.prompt[:50]}..., 提供商: {request.provider}")
try:
# 獲取AI提供商
provider_obj = ai_manager.get_provider(request.provider)
ifnot provider_obj:
raise HTTPException(status_code=400, detail=f"不支持的AI提供商: {request.provider}")
# 檢查提供商是否支持圖片生成
ifnot hasattr(provider_obj, 'generate_image'):
raise HTTPException(status_code=400, detail=f"提供商 {request.provider} 不支持圖片生成功能")
# 構建圖片生成請求
generation_request = ImageGenerationRequest(
prompt=request.prompt,
size=request.size,
quality=request.quality,
image_data=request.image_data,
image_type=request.image_type
)
logger.info(f"開始生成圖片 - 提供商: {request.provider}, 模式: {'圖片生成圖片' if request.image_data else '文本生成圖片'}")
generation_response = await provider_obj.generate_image(generation_request)
logger.info(f"圖片生成成功 - 提供商: {request.provider}, URL: {generation_response.url[:50] if generation_response.url else 'N/A'}...")
# 構建響應數據
response_data = {
"image_url": generation_response.url,
"image_b64": generation_response.b64_json,
"revised_prompt": generation_response.revised_prompt,
"size": request.size,
"quality": request.quality,
}
return ImageGenerationAPIResponse(
success=True,
message="圖片生成成功",
data=response_data,
provider=request.provider,
timestamp=time.time()
)
except Exception as e:
logger.error(f"圖片生成失敗: {e}")
return ImageGenerationAPIResponse(
success=False,
message=f"圖片生成失敗: {str(e)}",
data=None,
provider=request.provider,
timestamp=time.time()
)豆包提供商圖像生成實現
class DoubaoProvider(OpenAICompatibleProvider):
"""豆包AI提供商實現類"""
def __init__(self):
super().__init__()
self.IMAGE_GENERATION_MODEL = "doubao-seed-1.6"# Seedream 4.0模型
asyncdef generate_image(self, request: ImageGenerationRequest) -> ImageGenerationResponse:
"""
生成圖片功能實現
支持純文本生成圖片和圖片生成圖片兩種模式
Args:
request: 圖片生成請求對象
Returns:
ImageGenerationResponse: 圖片生成響應對象
"""
try:
ifnot self.client:
logger.error("Doubao客戶端未初始化,無法生成圖片")
return ImageGenerationResponse(
url=None,
b64_jsnotallow=None,
revised_prompt=None,
model=self.IMAGE_GENERATION_MODEL,
provider=self.PROVIDER_NAME
)
# 構建圖片生成請求參數
image_params = {
'model': self.IMAGE_GENERATION_MODEL,
'prompt': request.prompt,
'size': request.size or"2K", # 豆包支持的尺寸格式
'response_format': request.response_format or"url",
'extra_body': {
'watermark': request.watermark if request.watermark isnotNoneelseTrue
}
}
# 如果提供了輸入圖片URL,則為圖片生成圖片模式
if request.image_data:
image_params['extra_body']['image'] = f"data:image/{request.image_type};base64,{request.image_data}"
logger.info(f"Doubao圖片生成圖片模式 - 輸入圖片: {request.image_data}")
else:
logger.info("Doubao純文本生成圖片模式")
logger.info(f"調用Doubao圖片生成API - 模型: {self.IMAGE_GENERATION_MODEL}, 提示詞: {request.prompt[:50]}...")
# 調用豆包圖片生成API
response = self.client.images.generate(**image_params)
# 構建響應對象
if response.data and len(response.data) > 0:
image_data = response.data[0]
image_response = ImageGenerationResponse(
url=getattr(image_data, 'url', None),
b64_jsnotallow=getattr(image_data, 'b64_json', None),
revised_prompt=getattr(image_data, 'revised_prompt', request.prompt),
model=self.IMAGE_GENERATION_MODEL,
provider=self.PROVIDER_NAME
)
logger.info(f"Doubao圖片生成成功 - URL: {image_response.url is not None}")
return image_response
else:
logger.error("Doubao圖片生成響應為空")
return ImageGenerationResponse(
url=None,
b64_jsnotallow=None,
revised_prompt=request.prompt,
model=self.IMAGE_GENERATION_MODEL,
provider=self.PROVIDER_NAME
)
except Exception as e:
logger.error(f"Doubao圖片生成失敗: {e}")
return ImageGenerationResponse(
url=None,
b64_jsnotallow=None,
revised_prompt=request.prompt,
model=self.IMAGE_GENERATION_MODEL,
provider=self.PROVIDER_NAME
)前端圖像生成界面實現
圖像生成模態框HTML結構
<!-- 圖片生成模態框 -->
<div id="imageGenerateModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>AI 圖片生成</h3>
<span class="close" onclick="hideImageGenerateModal()">×</span>
</div>
<div class="modal-body">
<!-- 生成模式選擇 -->
<div class="generate-mode-selector">
<button id="textToImageBtn" class="mode-btn active" onclick="switchGenerateMode('text')">
?? 文生圖
</button>
<button id="imageToImageBtn" class="mode-btn" onclick="switchGenerateMode('image')">
??? 圖生圖
</button>
</div>
<!-- 基礎圖片上傳區域(圖生圖模式) -->
<div id="baseImageSection" class="base-image-section" style="display: none;">
<label for="baseImageUpload" class="upload-label">
<div class="upload-area">
<span class="upload-icon">??</span>
<span class="upload-text">點擊選擇基礎圖片</span>
<span class="upload-hint">支持 JPG、PNG、GIF 格式,最大 10MB</span>
</div>
</label>
<input type="file" id="baseImageUpload" accept="image/*" style="display: none;" onchange="handleBaseImageSelect(event)">
<div id="baseImagePreview" class="image-preview"></div>
</div>
<!-- 提示詞輸入 -->
<div class="prompt-section">
<label for="imagePrompt">描述你想要的圖片:</label>
<textarea id="imagePrompt" placeholder="請詳細描述你想要生成的圖片內容,例如:一只可愛的橘貓坐在窗臺上,陽光透過窗戶灑在它身上,背景是城市風景..." rows="4"></textarea>
</div>
<!-- 生成參數設置 -->
<div class="generation-settings">
<div class="setting-group">
<label for="imageSize">圖片尺寸:</label>
<select id="imageSize">
<option value="1024x1024">1024×1024 (正方形)</option>
<option value="1024x1792">1024×1792 (豎版)</option>
<option value="1792x1024">1792×1024 (橫版)</option>
</select>
</div>
<div class="setting-group">
<label for="imageQuality">圖片質量:</label>
<select id="imageQuality">
<option value="standard">標準</option>
<option value="hd">高清</option>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button id="generateImageBtn" class="generate-btn" onclick="generateImage()">
?? 生成圖片
</button>
</div>
</div>
</div>核心JavaScript實現
/**
* 切換圖片生成模式
* @param {string} mode - 生成模式:'text' 或 'image'
*/
function switchGenerateMode(mode) {
const textBtn = document.getElementById('textToImageBtn');
const imageBtn = document.getElementById('imageToImageBtn');
const baseImageSection = document.getElementById('baseImageSection');
if (mode === 'text') {
// 文生圖模式
textBtn.classList.add('active');
imageBtn.classList.remove('active');
baseImageSection.style.display = 'none';
currentGenerateMode = 'text';
} else {
// 圖生圖模式
imageBtn.classList.add('active');
textBtn.classList.remove('active');
baseImageSection.style.display = 'block';
currentGenerateMode = 'image';
}
}
/**
* 處理基礎圖片選擇
* @param {Event} event - 文件選擇事件
*/
asyncfunction handleBaseImageSelect(event) {
const file = event.target.files[0];
if (!file) return;
// 文件類型驗證
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
if (!allowedTypes.includes(file.type)) {
alert('請選擇有效的圖片文件(JPG、PNG、GIF、WebP)');
return;
}
// 文件大小驗證
const maxSize = 10 * 1024 * 1024; // 10MB
if (file.size > maxSize) {
alert('圖片文件大小不能超過 10MB');
return;
}
try {
// 調用upload/image接口上傳圖片并獲取格式信息
const formData = new FormData();
formData.append('file', file);
const uploadResponse = await fetch('/upload/image', {
method: 'POST',
body: formData
});
if (!uploadResponse.ok) {
thrownewError(`上傳失敗: ${uploadResponse.status}`);
}
const uploadResult = await uploadResponse.json();
if (uploadResult.success) {
// 保存上傳結果
baseImageFile = {
data: uploadResult.data.base64_data,
type: uploadResult.data.content_type.split('/')[1] // 從content_type提取格式
};
// 顯示圖片預覽
const preview = document.getElementById('baseImagePreview');
preview.innerHTML = `
<div class="preview-container">
<img src="data:${uploadResult.data.content_type};base64,${uploadResult.data.base64_data}" alt="基礎圖片預覽">
<button class="remove-btn" notallow="removeBaseImage()">×</button>
</div>
`;
} else {
thrownewError(uploadResult.message || '上傳失敗');
}
} catch (error) {
console.error('圖片上傳失敗:', error);
alert('圖片上傳失敗: ' + error.message);
}
}
/**
* 生成圖片主函數
*/
asyncfunction generateImage() {
const prompt = document.getElementById('imagePrompt').value.trim();
const size = document.getElementById('imageSize').value;
const quality = document.getElementById('imageQuality').value;
const mode = currentGenerateMode;
// 輸入驗證
if (!prompt) {
alert('請輸入圖片描述');
return;
}
if (mode === 'image' && !baseImageFile) {
alert('請選擇基礎圖片');
return;
}
const generateBtn = document.getElementById('generateImageBtn');
const originalText = generateBtn.textContent;
generateBtn.disabled = true;
generateBtn.textContent = '生成中...';
try {
// 構建請求數據
const requestData = {
prompt: prompt,
size: size,
provider: 'doubao'
};
// 如果是圖生圖模式,添加圖片數據
if (mode === 'image' && baseImageFile) {
requestData.image_data = baseImageFile.data;
requestData.image_type = baseImageFile.type;
} else {
// 文生圖模式,設置默認圖片類型
requestData.image_type = 'png';
}
console.log('發送圖片生成請求:', {
prompt: prompt.substring(0, 50) + '...',
size: size,
quality: quality,
mode: mode,
hasImage: !!requestData.image_data
});
// 發送生成請求
const response = await fetch('/generate/image', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
thrownewError(`請求失敗: ${response.status}`);
}
const result = await response.json();
if (result.success && result.data && result.data.image_b64) {
// 生成成功,顯示圖片
const imageData = result.data.image_b64;
const imageUrl = `data:image/png;base64,${imageData}`;
// 創建圖片消息并添加到聊天區域
const messageDiv = document.createElement('div');
messageDiv.className = 'message assistant-message';
messageDiv.innerHTML = `
<div class="message-avatar">
<img src="/static/images/assistant-avatar.png" alt="AI助手">
</div>
<div class="message-content">
<div class="generated-image">
<img src="${imageUrl}" alt="AI生成圖片" notallow="showImageModal('${imageUrl}')">
<div class="image-info">
<span class="image-size">${size}</span>
<span class="image-quality">${quality}</span>
<span class="generation-mode">${mode === 'text' ? '文生圖' : '圖生圖'}</span>
</div>
</div>
<div class="generation-prompt">
<strong>生成提示詞:</strong>${prompt}
</div>
</div>
`;
// 添加到聊天容器
const chatContainer = document.getElementById('chatContainer');
chatContainer.appendChild(messageDiv);
chatContainer.scrollTop = chatContainer.scrollHeight;
// 關閉模態框并重置
hideImageGenerateModal();
resetImageGenerateForm();
// 顯示成功消息
showNotification('圖片生成成功!', 'success');
} else {
thrownewError(result.message || '圖片生成失敗');
}
} catch (error) {
console.error('圖片生成失敗:', error);
alert('圖片生成失敗: ' + error.message);
} finally {
// 恢復按鈕狀態
generateBtn.disabled = false;
generateBtn.textContent = originalText;
}
}
/**
* 重置圖片生成表單
*/
function resetImageGenerateForm() {
document.getElementById('imagePrompt').value = '';
document.getElementById('imageSize').value = '1024x1024';
document.getElementById('imageQuality').value = 'standard';
document.getElementById('baseImagePreview').innerHTML = '';
baseImageFile = null;
switchGenerateMode('text');
}
/**
* 顯示通知消息
* @param {string} message - 通知內容
* @param {string} type - 通知類型:'success', 'error', 'info'
*/
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.textContent = message;
document.body.appendChild(notification);
// 3秒后自動移除
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 3000);
}圖生圖實測
圖像元素增刪改
輸入 | 輸出 |
|
|
|
|
風格遷移
輸入 | 輸出 |
|
|
|
|
主體特征保持
不同的創作形態下,均能高質量保持主體核心特征的一致性
輸入 | 輸出 |
|
|
|
|
|
|
文生圖實測
連續生成圖片
生成3張女孩和奶牛玩偶在游樂園開心地坐過山車的圖片,涵蓋早晨、中午、晚上 |
|
|
|
生成3張動漫 穿鞋得魚 |
|
|
|
最后
本文項目代碼已經全部上傳只Github,大家想要直接體驗豆包 Seedream 4.0 模型的話,推薦在方舟AI體驗中心,就可以輕量體驗了,登陸狀態可以免費體驗200次
體驗地址:https://event1.cn/5LGO92,
個人、企業接入的話,接入火山方舟發模型平臺即可




















































