'commit'
This commit is contained in:
0
dsLightRag/QWenImage/__init__.py
Normal file
0
dsLightRag/QWenImage/__init__.py
Normal file
BIN
dsLightRag/QWenImage/__pycache__/QwenImageKit.cpython-310.pyc
Normal file
BIN
dsLightRag/QWenImage/__pycache__/QwenImageKit.cpython-310.pyc
Normal file
Binary file not shown.
BIN
dsLightRag/QWenImage/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
dsLightRag/QWenImage/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
147
dsLightRag/Routes/QWenImageRoute.py
Normal file
147
dsLightRag/Routes/QWenImageRoute.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import atexit
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile # 新增导入
|
||||||
|
import uuid
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from Config.Config import OBS_PREFIX, OBS_BUCKET, OBS_SERVER
|
||||||
|
# 导入QwenImageGenerator类
|
||||||
|
from QWenImage.QwenImageKit import QwenImageGenerator
|
||||||
|
from Util.ObsUtil import ObsUploader
|
||||||
|
|
||||||
|
# 创建路由路由器
|
||||||
|
router = APIRouter(prefix="/api/qwenImage", tags=["千问生图"])
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# 初始化图片生成器
|
||||||
|
image_generator = QwenImageGenerator()
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateImageRequest(BaseModel):
|
||||||
|
"""生成图片请求模型"""
|
||||||
|
prompt: str = Field(..., description="图片描述提示词")
|
||||||
|
n: int = Field(default=1, ge=1, le=4, description="生成图片数量,范围1-4")
|
||||||
|
size: str = Field(default="1328*1328", description="图片尺寸")
|
||||||
|
api_key: Optional[str] = Field(default=None, description="自定义API密钥")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/generate")
|
||||||
|
async def generate_image(request: GenerateImageRequest):
|
||||||
|
"""生成图片API接口
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: 包含生成图片参数的请求对象
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 包含生成结果的字典
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
logger.info(f"接收到图片生成请求: prompt={request.prompt[:50]}..., n={request.n}, size={request.size}")
|
||||||
|
|
||||||
|
# 如果提供了自定义API密钥,创建新的生成器实例
|
||||||
|
generator = QwenImageGenerator(api_key=request.api_key) if request.api_key else image_generator
|
||||||
|
|
||||||
|
# 仅生成图片,不保存本地
|
||||||
|
result = generator.generate_image(
|
||||||
|
prompt=request.prompt,
|
||||||
|
n=request.n,
|
||||||
|
size=request.size
|
||||||
|
)
|
||||||
|
|
||||||
|
# 处理结果
|
||||||
|
if result['success']:
|
||||||
|
logger.info(f"图片生成成功,返回{len(result['images'])}张图片")
|
||||||
|
|
||||||
|
# 构造返回响应
|
||||||
|
response = {
|
||||||
|
"code": 200,
|
||||||
|
"message": "图片生成成功",
|
||||||
|
"data": {
|
||||||
|
"images": result['images']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# 新增:无条件执行OBS上传(直接处理图片URL)
|
||||||
|
obs_urls = []
|
||||||
|
uploader = ObsUploader()
|
||||||
|
for image_url in result['images']:
|
||||||
|
try:
|
||||||
|
# 直接从URL下载图片二进制数据
|
||||||
|
import requests
|
||||||
|
response_img = requests.get(image_url, timeout=10)
|
||||||
|
response_img.raise_for_status()
|
||||||
|
bytes_data = response_img.content
|
||||||
|
|
||||||
|
# 生成UUID文件名并上传
|
||||||
|
jpg_file_name = f"{str(uuid.uuid4())}.jpg"
|
||||||
|
object_key = f"{OBS_PREFIX}/QWen3Image/{jpg_file_name}"
|
||||||
|
success, upload_result = uploader.upload_base64_image(object_key, bytes_data)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
obs_url = f"https://{OBS_BUCKET}.{OBS_SERVER}/{object_key}"
|
||||||
|
obs_urls.append(obs_url)
|
||||||
|
logger.info(f"图片上传OBS成功: {obs_url}")
|
||||||
|
else:
|
||||||
|
logger.error(f"图片上传OBS失败: {upload_result}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"处理图片URL {image_url} 时出错: {str(e)}")
|
||||||
|
|
||||||
|
response["data"]["obs_files"] = obs_urls
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
logger.error(f"图片生成失败: {result['error_msg']}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail={
|
||||||
|
"code": 500,
|
||||||
|
"message": "图片生成失败",
|
||||||
|
"error_detail": result['error_msg']
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"处理图片生成请求时发生异常: {str(e)}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail={
|
||||||
|
"code": 500,
|
||||||
|
"message": "处理请求时发生异常",
|
||||||
|
"error_detail": str(e)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/config")
|
||||||
|
async def get_image_config():
|
||||||
|
"""获取图片生成配置信息
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 包含配置信息的字典
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"code": 200,
|
||||||
|
"message": "获取配置成功",
|
||||||
|
"data": {
|
||||||
|
"supported_sizes": ["1328*1328", "1024*1024", "768*1024", "1024*768"],
|
||||||
|
"max_images_per_request": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 注册程序退出时的清理函数
|
||||||
|
@atexit.register
|
||||||
|
def clean_temp_files():
|
||||||
|
temp_root = os.path.join(tempfile.gettempdir(), "qwen_images")
|
||||||
|
if os.path.exists(temp_root):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(temp_root)
|
||||||
|
logger.info(f"临时图片目录已清理: {temp_root}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"清理临时文件失败: {str(e)}")
|
||||||
|
|
BIN
dsLightRag/Routes/__pycache__/QWenImageRoute.cpython-310.pyc
Normal file
BIN
dsLightRag/Routes/__pycache__/QWenImageRoute.cpython-310.pyc
Normal file
Binary file not shown.
@@ -23,6 +23,7 @@ from Routes.JiMengRoute import router as jimeng_router
|
|||||||
from Routes.SunoRoute import router as suno_router
|
from Routes.SunoRoute import router as suno_router
|
||||||
from Routes.XueBanRoute import router as xueban_router
|
from Routes.XueBanRoute import router as xueban_router
|
||||||
from Routes.MjRoute import router as mj_router
|
from Routes.MjRoute import router as mj_router
|
||||||
|
from Routes.QWenImageRoute import router as qwen_image_router
|
||||||
from Util.LightRagUtil import *
|
from Util.LightRagUtil import *
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
@@ -36,8 +37,8 @@ logger.addHandler(handler)
|
|||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(_: FastAPI):
|
async def lifespan(_: FastAPI):
|
||||||
#pool = await init_postgres_pool()
|
pool = await init_postgres_pool()
|
||||||
#app.state.pool = pool
|
app.state.pool = pool
|
||||||
|
|
||||||
asyncio.create_task(train_document_task())
|
asyncio.create_task(train_document_task())
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ async def lifespan(_: FastAPI):
|
|||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
# 应用关闭时销毁连接池
|
# 应用关闭时销毁连接池
|
||||||
#await close_postgres_pool(pool)
|
await close_postgres_pool(pool)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -66,6 +67,8 @@ app.include_router(jimeng_router) # 即梦路由
|
|||||||
app.include_router(suno_router) # Suno路由
|
app.include_router(suno_router) # Suno路由
|
||||||
app.include_router(xueban_router) # 学伴路由
|
app.include_router(xueban_router) # 学伴路由
|
||||||
app.include_router(mj_router) # Midjourney路由
|
app.include_router(mj_router) # Midjourney路由
|
||||||
|
app.include_router(qwen_image_router) # Qwen Image 路由
|
||||||
|
|
||||||
|
|
||||||
# Teaching Model 相关路由
|
# Teaching Model 相关路由
|
||||||
# 登录相关(不用登录)
|
# 登录相关(不用登录)
|
||||||
@@ -84,4 +87,4 @@ app.include_router(teaching_model_router, prefix="/api/teaching/model", tags=["t
|
|||||||
app.include_router(teaching_model_router, prefix="/api/teaching/model", tags=["teacher_model"])
|
app.include_router(teaching_model_router, prefix="/api/teaching/model", tags=["teacher_model"])
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
uvicorn.run(app, host="0.0.0.0", port=8100)
|
uvicorn.run(app, host="0.0.0.0", port=8200)
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.9 MiB |
Binary file not shown.
Before Width: | Height: | Size: 1.9 MiB |
140
dsLightRag/Test/TestQWen3Image.py
Normal file
140
dsLightRag/Test/TestQWen3Image.py
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger("TestQWenImage")
|
||||||
|
|
||||||
|
# API基础URL
|
||||||
|
base_url = "http://localhost:8200/api/qwenImage"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_config():
|
||||||
|
"""测试获取配置接口"""
|
||||||
|
try:
|
||||||
|
url = f"{base_url}/config"
|
||||||
|
logger.info(f"调用获取配置接口: {url}")
|
||||||
|
response = requests.get(url)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
result = response.json()
|
||||||
|
logger.info(f"获取配置成功: {json.dumps(result, ensure_ascii=False, indent=2)}")
|
||||||
|
return True, result
|
||||||
|
else:
|
||||||
|
logger.error(f"获取配置失败: HTTP状态码={response.status_code}, 响应内容={response.text}")
|
||||||
|
return False, None
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"获取配置时发生异常: {str(e)}")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_image(prompt, n=1, size='1328*1328', save_local=True):
|
||||||
|
"""测试生成图片接口
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prompt: 图片描述提示词
|
||||||
|
n: 生成图片数量
|
||||||
|
size: 图片尺寸
|
||||||
|
save_local: 是否保存到本地
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (是否成功, 结果数据)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
url = f"{base_url}/generate"
|
||||||
|
headers = {"Content-Type": "application/json"}
|
||||||
|
data = {
|
||||||
|
"prompt": prompt,
|
||||||
|
"n": n,
|
||||||
|
"size": size,
|
||||||
|
"save_local": save_local
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(f"调用生成图片接口: {url}")
|
||||||
|
logger.info(f"请求参数: prompt={prompt[:50]}..., n={n}, size={size}, save_local={save_local}")
|
||||||
|
|
||||||
|
# 记录开始时间
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
# 发送请求
|
||||||
|
response = requests.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False))
|
||||||
|
|
||||||
|
# 计算耗时
|
||||||
|
elapsed_time = time.time() - start_time
|
||||||
|
logger.info(f"请求耗时: {elapsed_time:.2f}秒")
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
result = response.json()
|
||||||
|
logger.info(f"生成图片成功: {json.dumps(result, ensure_ascii=False, indent=2)}")
|
||||||
|
|
||||||
|
# 检查返回的数据
|
||||||
|
if result.get("code") == 200 and "data" in result:
|
||||||
|
images = result["data"].get("images", [])
|
||||||
|
logger.info(f"成功生成{len(images)}张图片")
|
||||||
|
|
||||||
|
# 如果保存了本地文件,检查文件是否存在
|
||||||
|
if save_local and "local_file_paths" in result["data"]:
|
||||||
|
for file_path in result["data"]["local_file_paths"]:
|
||||||
|
full_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), file_path.lstrip('.'))
|
||||||
|
if os.path.exists(full_path):
|
||||||
|
logger.info(f"本地文件已保存: {full_path}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"本地文件不存在: {full_path}")
|
||||||
|
|
||||||
|
return True, result
|
||||||
|
else:
|
||||||
|
logger.error(f"生成图片失败: HTTP状态码={response.status_code}, 响应内容={response.text}")
|
||||||
|
return False, None
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"生成图片时发生异常: {str(e)}")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数,运行单元测试"""
|
||||||
|
logger.info("===== 开始测试QWenImage接口 ====")
|
||||||
|
|
||||||
|
# 1. 测试获取配置接口
|
||||||
|
logger.info("\n1. 测试获取配置接口")
|
||||||
|
config_success, config_data = test_get_config()
|
||||||
|
|
||||||
|
# 2. 测试生成图片接口 - 基本测试
|
||||||
|
logger.info("\n2. 测试生成图片接口 - 基本测试")
|
||||||
|
basic_prompt = "一只可爱的小猫在草地上玩耍,阳光明媚,高清细节"
|
||||||
|
generate_success, generate_data = test_generate_image(
|
||||||
|
prompt=basic_prompt,
|
||||||
|
n=1,
|
||||||
|
size="1328*1328",
|
||||||
|
save_local=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 测试生成图片接口 - 不同参数
|
||||||
|
if config_success:
|
||||||
|
supported_sizes = config_data["data"].get("supported_sizes", ["1328*1328"])
|
||||||
|
max_images = min(2, config_data["data"].get("max_images_per_request", 1)) # 为了测试效率,最多请求2张
|
||||||
|
|
||||||
|
logger.info(f"\n3. 测试生成图片接口 - 不同参数(size={supported_sizes[0]}, n={max_images})")
|
||||||
|
different_prompt = "美丽的山水风景画,中国水墨画风格"
|
||||||
|
test_generate_image(
|
||||||
|
prompt=different_prompt,
|
||||||
|
n=max_images,
|
||||||
|
size=supported_sizes[0],
|
||||||
|
save_local=True
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info("\n===== QWenImage接口测试完成 =====")
|
||||||
|
|
||||||
|
# 输出测试结果摘要
|
||||||
|
success_count = sum([config_success, generate_success])
|
||||||
|
total_count = 2 # 基本测试的接口数量
|
||||||
|
logger.info(f"测试结果: {success_count}/{total_count} 接口测试成功")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Binary file not shown.
After Width: | Height: | Size: 1.7 MiB |
Reference in New Issue
Block a user