python+vue实现gemini-2.5-flash-image nano-banana对话生成修改图片助手代码

代码语言:python

所属分类:其他

代码描述:python+vue实现gemini-2.5-flash-image nano-banana对话生成修改图片助手代码,说说话就能编辑修改生成图片,丢掉ps吧,需要google的ai studio的apikey。

代码标签: python vue gemini-2.5-flash-image nano-banana 对话

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

#!/usr/local/python3/bin/python3
# -*- coding: utf-8 -*
import os
import asyncio
import base64
from io import BytesIO
from PIL import Image

import google.generativeai as genai
from google.generativeai import types
from fastapi import FastAPI, Request, Form, UploadFile, File
from fastapi.responses import HTMLResponse, StreamingResponse
import uvicorn
import json
from typing import List, Optional # 1. 导入 Optional

# ===============================================================================
#  1. 初始化 FastAPI 应用和 Google AI 客户端
# ===============================================================================
app = FastAPI()

# 从环境变量中安全地获取 API 密钥
api_key =""
if not api_key:
    raise ValueError("错误:未找到 GOOGLE_API_KEY 环境变量。请设置该变量。")

# 配置 Google AI 客户端
genai.configure(api_key=api_key)

# ===============================================================================
#  2. 后端核心逻辑:与 Google AI 模型交互
# ===============================================================================
async def generate_ai_responses(contents: list):
    """
    一个异步生成器函数,用于与 AI 模型交互并流式返回结果。
    """
    try:
        # gemini-pro-vision 模型同时支持纯文本和图文输入
        model = genai.GenerativeModel("gemini-2.5-flash-image-preview")
        
        # 使用 stream=True 进行流式生成
        response_stream = await model.generate_content_async(contents, stream=True)

        async for chunk in response_stream:
            if not chunk.parts:
                continue

            for part in chunk.parts:
                if part.text:
                    response_data = {"type": "text", "data": part.text}
                    yield f"data: {json.dumps(response_data)}\n\n"
                
            await asyncio.sleep(0.01)

    except Exception as e:
        error_message = f"AI 调用失败: {str(e)}"
        print(error_message)
        response_data = {"type": "error", "data": error_message}
        yield f"data: {json.dumps(response_data)}\n\n"


@app.post("/chat")
# 2. 将 files 标记为可选
async def chat_endpoint(prompt: str = Form(""), files: Optional[List[UploadFile]] = File(None)):
    """
    处理聊天请求的 API 端点,接收文本和可选的图片。
    """
    contents = []

    # 3. 增加判断,仅在 files 存在时处理图片
    if files:
        for file in files:
            if file.filename:
                image_bytes = await file.read()
                try:
                    img = Image.open(BytesIO(image_bytes))
                    contents.append(img)
                except Exception as e:
                    print(f"无法处理上传的文件 {file.filename}: {e}")
                    continue
    
    if prompt:
        contents.append(prompt)

    if not contents:
        async def error_stream():
            response_data = {"type": "error", "data": "请输入文字或上传图片。"}
            yield f"data: {json.dumps(response_data)}\n\n"
        return StreamingResponse(error_stream(), media_type="text/event-stream")

    return StreamingResponse(generate_ai_responses(contents), media_type="text/event-stream")


# ===============================================================================
#  3. 前端界面 (HTML, CSS, Vue.js in a single string)
# ===============================================================================
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>gemini AI 聊天对话ps图片助手</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/marked@4.2.12/marked.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.min.css">
    <style>
        :root {
            --bg-color: #f0f2f5;
            --primary-color: #5b5fc7;
            --primary-hover: #4b4fb7;
            --user-msg-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            --ai-msg-bg: #ffffff;
            --text-color-light: #ffffff;
            --text-color-dark: #1a1a1a;
            --text-color-secondary: #6b7280;
            --border-color: #e5e7eb;
            --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
            --border-radius: 20px;
            --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
            --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.1);
            --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12);
        }

        * {
            box-sizing: border-box;
        }

        html, body {
            height: 100%;
            margin: 0;
            font-family: var(--font-family);
            background-color: var(--bg-color);
            overflow: hidden;
            color: var(--text-color-dark);
        }

        #app {
            display: flex;
            flex-direction: column;
            height: 100%;
            max-width: 900px;
            margin: 0 auto;
            background-color: #ffffff;
            box-shadow: var(--shadow-lg);
            position: relative;
            overflow: hidden;
        }

        /* Header */
        .header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 1.25rem 1.5rem;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 10.........完整代码请登录后点击上方下载按钮下载查看

网友评论0