6 Commits

Author SHA1 Message Date
zcr
ea1b017f75 Merge branch 'master' into develop 2026-06-04 11:42:46 +08:00
zcr
de349a6d20 代码结构化 优化 2026-06-04 11:35:59 +08:00
zcr
893f5e87b4 3D 打板部署
All checks were successful
git commit AiDA python develop 分支构建部署 / scheduled_deploy (push) Has been skipped
2026-04-28 17:17:29 +08:00
zcr
c73bfa7e2a 3D 打板部署
All checks were successful
git commit AiDA python develop 分支构建部署 / scheduled_deploy (push) Has been skipped
2026-04-28 17:03:04 +08:00
zcr
ad4db736de 新增nacos 配置 测试
All checks were successful
git commit AiDA python develop 分支构建部署 / scheduled_deploy (push) Has been skipped
2026-04-24 10:17:42 +08:00
zcr
cfbd9e47ac 新增nacos 配置 测试
All checks were successful
git commit AiDA python develop 分支构建部署 / scheduled_deploy (push) Has been skipped
2026-04-23 17:10:22 +08:00
14 changed files with 2484 additions and 2234 deletions

3
.gitignore vendored
View File

@@ -150,4 +150,5 @@ app/logs/*
*.avi
*.json
*.env*
config.backup.py
config.backup.py
*.pckl

View File

@@ -11,6 +11,7 @@ from app.api import api_precompute
from app.api import api_prompt_generation
from app.api import api_recommendation
from app.api import api_test
from app.api import api_sketch_to_garment
router = APIRouter()
@@ -26,6 +27,7 @@ router.include_router(api_precompute.router, tags=['api_precompute'], prefix="/a
router.include_router(api_mannequins_edit.router, tags=['api_mannequins_edit'], prefix="/api")
router.include_router(api_pose_transform.router, tags=['api_pose_transform'], prefix="/api")
router.include_router(api_clothing_seg.router, tags=['api_clothing_seg'], prefix="/api")
router.include_router(api_sketch_to_garment.router, tags=['sketch_to_garment'], prefix="/api")
"""停用"""
# from app.api import api_chat_robot

View File

@@ -0,0 +1,104 @@
import json
import logging
from fastapi import APIRouter, HTTPException
from app.schemas.response_template import ResponseModel
from app.schemas.sketch_to_garment_schemas import SketchToGarmentModel
from app.service.sketch2garment.server import submit_sketch_to_garment_task
logger = logging.getLogger()
router = APIRouter()
@router.post("/sketch_to_garment")
def sketch_to_garment_api(request_item: SketchToGarmentModel):
"""
### 接口说明:
将图片转换为3D模型异步处理。接口接收请求后立即返回任务ID后台通过 Celery 处理,处理完成后结果会通过 RabbitMQ 发送。
### 参数说明:
- **input_image_path**: 输入图片路径
- **bucket_name**: bucket name
- **user_id**: 用户id
- **callback_url**: 回调url
- **task_id**: 任务id
- **model**: 转换模式 文本和图片 ,默认只有图片
### 请求体示例:
**单张图片模式:**
```json
{
"input_image_path": "test/53d38bd5-f77b-4034-ada2-45f1e2ebe00c.png",
"bucket_name": "test",
"user_id": "string-456",
"callback_url": "http://18.167.251.121:10015/api/image/webhook/img-to-3d",
"task_id": "string12",
"model": "picture"
}
```
### 输出示例:
```json
{
"code": 200,
"msg": "OK!",
"data": {
"state": "success",
"task_id": "string12",
"message": "任务已成功提交,正在后台处理..."
}
}
```
### 错误输出
参考文档: https://platform.tripo3d.ai/docs/error-handling
```json
{
"code": 500,
"message": "You dont have enough credit to create this task",
"data": {
"status": "fail",
"task_id": "123",
"message": "You dont have enough credit to create this task",
"error": str(e)
}
}
```
回调请求参数例子:
```json
{
"task_id": "string12",
"status": "success",
"result": {
"pattern": "test/string-456/pattern_making/now_string-456_pattern.png",
"texture": "test/string-456/pattern_making/now_string-456_texture.png",
"glb": "test/string-456/pattern_making/now_string-456_sim.glb",
"texture_fabric": "test/string-456/pattern_making/now_string-456_texture_fabric.png"
}
}
```
"""
try:
logger.info(f"sketch_to_garment request item is : @@@@@@:{json.dumps(request_item.model_dump(), indent=4)}")
result = submit_sketch_to_garment_task(
task_id=request_item.task_id,
callback_url=request_item.callback_url,
bucket_name=request_item.bucket_name,
input_image_path=request_item.input_image_path,
user_id=request_item.user_id,
model=request_item.model
)
result = {
"state": "success",
"task_id": request_item.task_id,
"message": "任务已成功提交,正在后台处理...",
}
state_code = 200
return ResponseModel(data=result, code=state_code)
except Exception as e:
logger.warning(f"super_resolution Run Exception @@@@@@:{e}")
raise HTTPException(status_code=404, detail=str(e))

View File

@@ -1,75 +1,91 @@
import logging
from typing import Dict, Any
import yaml
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
from v2.nacos import ClientConfigBuilder, GRPCConfig, NacosConfigService, ConfigParam, NacosNamingService, RegisterInstanceParam, DeregisterInstanceParam
logger = logging.getLogger(__name__)
# ====================== Nacos 配置 ======================
NACOS_SERVER_ADDRESSES = "18.167.251.121:28848"
NACOS_NAMESPACE = "zcr"
NACOS_USERNAME = "nacos"
NACOS_PASSWORD = "Aidlab123123!"
NACOS_GROUP = "LOCAL"
NACOS_DATA_ID = "aida.python"
SERVICE_NAME = "fastapi-service" # ←←← 必须修改!建议格式:项目名-环境,例如 ai-image-service-dev
class Settings(BaseSettings):
"""
应用配置类。Pydantic Settings 会自动从环境变量和 .env 文件中加载这些值。
"""
model_config = SettingsConfigDict(
env_file='.env',
env_file_encoding='utf-8',
# extra='ignore' # 忽略环境变量中多余的键
)
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore") # 忽略环境变量中多余的键
# --- 服务端口配置信息 ---
PORT: int = Field(default=8001, description="")
# --- 服务环境 配置信息 ---
SERVE_ENV: str = Field(default='', description="")
SERVE_ENV: str = Field(default="", description="")
# --- 开发状态 配置信息 ---
DEBUG: bool = Field(default=False, description="")
# --- 千问api 配置信息 ---
QWEN_API_KEY: str = Field(default="", description="")
# --- ComfyUI 配置信息 ---
COMFYUI_SERVER_ADDRESS: str = Field(default='', description="")
COMFYUI_SERVER_ADDRESS: str = Field(default="", description="")
# --- minio 配置信息 ---
MINIO_URL: str = Field(default='', description="")
MINIO_ACCESS: str = Field(default='', description="")
MINIO_SECRET: str = Field(default='', description="")
MINIO_URL: str = Field(default="", description="")
MINIO_ACCESS: str = Field(default="", description="")
MINIO_SECRET: str = Field(default="", description="")
MINIO_SECURE: bool = Field(default=True, description="")
# --- redis 配置信息 ---
REDIS_HOST: str = Field(default='', description="")
REDIS_PORT: str = Field(default='', description="")
REDIS_HOST: str = Field(default="", description="")
REDIS_PORT: str = Field(default="", description="")
REDIS_DB: int = Field(default=0, description="")
# --- mysql 配置信息 ---
MYSQL_HOST: str = Field(default='', description="")
MYSQL_HOST: str = Field(default="", description="")
MYSQL_PORT: int = Field(default=3306, description="")
MYSQL_USER: str = Field(default='', description="")
MYSQL_PASSWORD: str = Field(default='', description="")
MYSQL_DB: str = Field(default='', description="")
MYSQL_CHARSET: str = Field(default='utf8mb4', description="")
MYSQL_USER: str = Field(default="", description="")
MYSQL_PASSWORD: str = Field(default="", description="")
MYSQL_DB: str = Field(default="", description="")
MYSQL_CHARSET: str = Field(default="utf8mb4", description="")
# --- rabbit-mq 配置信息 ---
MQ_HOST: str = Field(default='', description="")
MQ_PORT: str = Field(default='', description="")
MQ_USERNAME: str = Field(default='', description="")
MQ_PASSWORD: str = Field(default='', description="")
MQ_VIRTUAL_HOST: str = Field(default='/', description="")
MQ_ENV: str = Field(default='', description="")
MQ_HOST: str = Field(default="", description="")
MQ_PORT: str = Field(default="", description="")
MQ_USERNAME: str = Field(default="", description="")
MQ_PASSWORD: str = Field(default="", description="")
MQ_VIRTUAL_HOST: str = Field(default="/", description="")
MQ_ENV: str = Field(default="", description="")
# --- milvus 配置信息 ---
MILVUS_URL: str = Field(default='', description="")
MILVUS_TOKEN: str = Field(default='', description="")
MILVUS_ALIAS: str = Field(default='', description="")
MILVUS_URL: str = Field(default="", description="")
MILVUS_TOKEN: str = Field(default="", description="")
MILVUS_ALIAS: str = Field(default="", description="")
# --- ollama 配置信息 ---
CHROMADB_PATH: str = Field(default='', description="")
CHROMADB_PATH: str = Field(default="", description="")
# --- ollama 配置信息 ---
OLLAMA_URL: str = Field(default='', description="")
OLLAMA_URL: str = Field(default="", description="")
# --- Design Callback Java 接口 ---
JAVA_STREAM_API_URL: str = Field(default='', description="")
JAVA_STREAM_API_URL: str = Field(default="", description="")
# --- flux2 klein model url ---
FLUX2_GEN_IMG_MODEL_URL: str = Field(default='', description="")
FLUX2_GEN_IMG_MODEL_URL: str = Field(default="", description="")
# --- 服务器IP ---
A6000_SERVICE_HOST: str = Field(default='', description="")
B_4_X_4090_SERVICE_HOST: str = Field(default='', description="")
A6000_SERVICE_HOST: str = Field(default="", description="")
B_4_X_4090_SERVICE_HOST: str = Field(default="", description="")
# --- sketch to garment 模型url ---
SKETCH_TO_GARMENT_URL: str = Field(default='', description="")
# --- 其他配置信息 以下均为Docker容器内配置---
LOGS_PATH: str = Field(default="/logs/", description="")
@@ -77,6 +93,7 @@ class Settings(BaseSettings):
SEG_CACHE_PATH: str = Field(default="/seg_cache/", description="")
RECOMMEND_PATH_PREFIX: str = Field(default="/app/service/recommend/", description="")
SERVE_PORT: int = Field(default=2010, description="")
sketch_to_garment_url: str = Field(default="", description="")
settings = Settings()
@@ -91,36 +108,49 @@ TABLE_CATEGORIES = {
"female_blouse": "female/blouse",
"male_tops": "male/tops",
"male_bottoms": "male/bottoms",
"male_outwear": "male/outwear"
"male_outwear": "male/outwear",
}
# Design前后排优先级
PRIORITY_DICT = {
'earring_front': 99,
'bag_front': 98,
'hairstyle_front': 97,
'outwear_front': 20,
'tops_front': 19,
'dress_front': 18,
'blouse_front': 17,
'skirt_front': 16,
'trousers_front': 15,
'bottoms_front': 14,
'shoes_right': 1,
'shoes_left': 1,
'body': 0,
'bottoms_back': -14,
'trousers_back': -15,
'skirt_back': -16,
'blouse_back': -17,
'dress_back': -18,
'tops_back': -19,
'outwear_back': -20,
'hairstyle_back': -97,
'bag_back': -98,
'earring_back': -99,
"earring_front": 99,
"bag_front": 98,
"hairstyle_front": 97,
"outwear_front": 20,
"tops_front": 19,
"dress_front": 18,
"blouse_front": 17,
"skirt_front": 16,
"trousers_front": 15,
"bottoms_front": 14,
"shoes_right": 1,
"shoes_left": 1,
"body": 0,
"bottoms_back": -14,
"trousers_back": -15,
"skirt_back": -16,
"blouse_back": -17,
"dress_back": -18,
"tops_back": -19,
"outwear_back": -20,
"hairstyle_back": -97,
"bag_back": -98,
"earring_back": -99,
}
# Design 关键点字段
KEYPOINT_RESULT_TABLE_FIELD_SET = ('neckline_left', 'neckline_right', 'shoulder_left', 'shoulder_right', 'armpit_left', 'armpit_right', 'cuff_left_in', 'cuff_left_out', 'cuff_right_in', 'cuff_right_out', 'waistband_left', 'waistband_right')
KEYPOINT_RESULT_TABLE_FIELD_SET = (
"neckline_left",
"neckline_right",
"shoulder_left",
"shoulder_right",
"armpit_left",
"armpit_right",
"cuff_left_in",
"cuff_left_out",
"cuff_right_in",
"cuff_right_out",
"waistband_left",
"waistband_right",
)
# milvus配置信息
MILVUS_TABLE_KEYPOINT = "keypoint_cache_2"
@@ -129,37 +159,37 @@ OLLAMA_URL = f"http://{settings.A6000_SERVICE_HOST}:11434/api/embeddings"
"""Triton Server Config"""
# Design
DESIGN_MODEL_URL = f'{settings.A6000_SERVICE_HOST}:10000'
DESIGN_MODEL_NAME = 'seg_knet'
DESIGN_MODEL_URL = f"{settings.A6000_SERVICE_HOST}:10000"
DESIGN_MODEL_NAME = "seg_knet"
# Seg Product
SEG_PRODUCT_MODEL_URL = f'{settings.B_4_X_4090_SERVICE_HOST}:30000'
SEG_PRODUCT_MODEL_URL = f"{settings.B_4_X_4090_SERVICE_HOST}:30000"
# Generate Image
GI_MODEL_URL = f'{settings.A6000_SERVICE_HOST}:10061'
GI_MODEL_NAME = 'flux'
GI_MODEL_URL = f"{settings.A6000_SERVICE_HOST}:10061"
GI_MODEL_NAME = "flux"
# Generate Single Logo
GSL_MODEL_URL = f'{settings.B_4_X_4090_SERVICE_HOST}:10041'
GSL_MODEL_NAME = 'stable_diffusion_xl_transparent'
GSL_MODEL_URL = f"{settings.B_4_X_4090_SERVICE_HOST}:10041"
GSL_MODEL_NAME = "stable_diffusion_xl_transparent"
# Generate Product (整套和单品)
GPI_MODEL_URL = f'{settings.B_4_X_4090_SERVICE_HOST}:10051'
GPI_MODEL_NAME_OVERALL = 'diffusion_ensemble_all'
GPI_MODEL_NAME_SINGLE = 'stable_diffusion_1_5_cnet'
GPI_MODEL_URL = f"{settings.B_4_X_4090_SERVICE_HOST}:10051"
GPI_MODEL_NAME_OVERALL = "diffusion_ensemble_all"
GPI_MODEL_NAME_SINGLE = "stable_diffusion_1_5_cnet"
# 以下停用中...*************
# 多视角生成
GMV_MODEL_URL = f'{settings.B_4_X_4090_SERVICE_HOST}:10081'
GMV_MODEL_NAME = 'multi_view'
GMV_MODEL_URL = f"{settings.B_4_X_4090_SERVICE_HOST}:10081"
GMV_MODEL_NAME = "multi_view"
# 超分
SR_MODEL_NAME = "super_resolution"
SR_TRITON_URL = f"{settings.A6000_SERVICE_HOST}:10031"
# 打光
GRI_MODEL_URL = f'{settings.A6000_SERVICE_HOST}:10051'
GRI_MODEL_NAME_OVERALL = 'diffusion_relight_ensemble'
GRI_MODEL_NAME_SINGLE = 'stable_diffusion_1_5_relight'
GRI_MODEL_URL = f"{settings.A6000_SERVICE_HOST}:10051"
GRI_MODEL_NAME_OVERALL = "diffusion_relight_ensemble"
GRI_MODEL_NAME_SINGLE = "stable_diffusion_1_5_relight"
# agent 图片生成
FAST_GI_MODEL_URL = f'{settings.B_4_X_4090_SERVICE_HOST}:10011'
FAST_GI_MODEL_NAME = 'stable_diffusion_xl'
FAST_GI_MODEL_URL = f"{settings.B_4_X_4090_SERVICE_HOST}:10011"
FAST_GI_MODEL_NAME = "stable_diffusion_xl"
# 图转视频 triton版
PT_MODEL_URL = f'{settings.B_4_X_4090_SERVICE_HOST}:10061'
PT_MODEL_URL = f"{settings.B_4_X_4090_SERVICE_HOST}:10061"
# *************

View File

@@ -1,5 +1,8 @@
# 1. 这里的顺序至关重要!必须在最顶端
import sys
from contextlib import asynccontextmanager
# from app.core.nacos_config import load_nacos_config, register_server, deregister_server
try:
import asyncore
@@ -30,8 +33,21 @@ logger = logging.getLogger(__name__)
load_dotenv()
# @asynccontextmanager
# async def lifespan(app: FastAPI):
# try:
# load_nacos_config()
# register_server()
#
# yield
# finally:
# deregister_server()
# logger.info("lifespan down")
def get_application() -> FastAPI:
application = FastAPI(
# lifespan=lifespan,
docs_url="/docs",
redoc_url='/re-docs',
openapi_url=f"/openapi.json",
@@ -64,5 +80,11 @@ async def http_exception_handler(exc: HTTPException):
)
@app.get("/health", operation_id="health")
async def health():
logger.info("health check")
return {"ok": True, "env": settings.APP_ENV}
if __name__ == '__main__':
uvicorn.run(app, host="0.0.0.0", port=settings.PORT)

View File

@@ -0,0 +1,12 @@
from typing import List
from pydantic import BaseModel, Field
class SketchToGarmentModel(BaseModel):
input_image_path: str = Field(..., description="输入图片路径列表")
bucket_name: str = Field(..., description="输入图片路径列表")
user_id: str = Field(..., description="用户id")
callback_url: str # 必填,客户端提供的回调地址
task_id: str = Field()
model: str = Field(default="single", description="模型类型: single 或 multi")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
import logging
import httpx
logger = logging.getLogger("app")
async def notify_callback(callback_url: str, task_id: str, status: str, result: dict, ):
"""
调用客户端提供的回调接口
"""
try:
payload = {
"task_id": task_id,
"status": status,
"result": result
}
logger.info(payload)
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.post(
str(callback_url),
json=payload,
headers={"Content-Type": "application/json"}
)
if 200 <= resp.status_code < 300:
logger.info(f"回调成功 | task_id: {task_id} | status: {status} | url: {callback_url}")
return True
else:
logger.warning(f"回调返回非2xx状态码 | task_id: {task_id} | status: {resp.status_code} | url: {callback_url}")
return False
except Exception as e:
logger.error(f"回调失败 | task_id: {task_id} | url: {callback_url} | error: {e}", exc_info=True)
return False

View File

@@ -0,0 +1,46 @@
from celery import Celery
from kombu import Queue, Exchange
from app.core.config import settings
celery_app = Celery(
"sketch_to_garment",
broker=f"redis://{settings.REDIS_HOST}:{settings.REDIS_PORT}/2",
backend=f"redis://{settings.REDIS_HOST}:{settings.REDIS_PORT}/{settings.REDIS_DB}",
include=["app.service.sketch2garment.tasks"]
)
print(f"redis://{settings.REDIS_HOST}:{settings.REDIS_PORT}/3")
print(f"celery_app: {celery_app}")
celery_app.conf.update(
task_serializer="json",
accept_content=["json"],
result_serializer="json",
timezone="Asia/Hong_Kong",
enable_utc=True,
task_track_started=True,
task_time_limit=300, # 单个任务最长 5 分钟
task_soft_time_limit=280,
# 定义队列
task_queues=(
Queue("sketch_to_garment_queue",
exchange=Exchange("sketch_to_garment_exchange", type="direct"),
durable=True),
),
task_routes={
'app.service.sketch2garment.tasks.sketch_to_garment':
{
'queue': 'sketch_to_garment_queue',
'exchange': 'sketch_to_garment_exchange', # ← 修改这里
},
},
task_default_queue="sketch_to_garment_queue",
worker_concurrency=1,
worker_prefetch_multiplier=1,
worker_max_tasks_per_child=1,
task_acks_late=True,
task_reject_on_worker_lost=True,
)

View File

@@ -0,0 +1,44 @@
import logging
from app.service.sketch2garment.tasks import sketch_to_garment
logger = logging.getLogger(__name__)
def submit_sketch_to_garment_task(model: str = "single", task_id: str = "", callback_url: str = "", bucket_name: str = "test", user_id: str = "123", input_image_path: str = ""):
"""提交 img_to_3D 任务(带队列长度限制)"""
queue_name = "img_to_3d_queue"
max_queue_length = 10
try:
# current_length = get_queue_length(queue_name)
# if current_length >= max_queue_length:
# return {
# "state": "queue_full",
# "message": "当前 3D 生成请求较多,请稍后重试。",
# "queue_length": current_length,
# "max_length": max_queue_length
# }
# 提交任务
task = sketch_to_garment.apply_async(
args=(task_id, callback_url, bucket_name, input_image_path, user_id, model),
task_id=task_id,
queue="sketch_to_garment_queue")
# logger.info(f"img_to_3d_task 已提交 | task_id: {task_id} | 当前队列长度: {current_length}")
return {
"state": "success",
"task_id": task_id,
"message": "任务已成功提交,正在后台处理...",
}
except Exception as e:
logger.error(f"提交 img_to_3d_task 失败: {e}", exc_info=True)
return {
"state": "fail",
"message": "提交失败,请稍后重试。",
"error": str(e)
}

View File

@@ -0,0 +1,57 @@
import asyncio
import logging
from app.core.config import settings
from app.service.sketch2garment.callback import notify_callback
import httpx
from app.service.sketch2garment.celery_app import celery_app
logger = logging.getLogger(__name__)
@celery_app.task(bind=True, queue="sketch_to_garment_queue", max_retries=3, name='app.service.sketch2garment.tasks.sketch_to_garment')
def sketch_to_garment(self, task_id: str, callback_url: str, bucket_name: str, input_image_path: str, user_id: str, category: str = None):
payload = {
"bucket_name": bucket_name,
"category": category or settings.DEFAULT_CATEGORY,
"input_image_path": input_image_path,
"user_id": user_id
}
logger.info(f"payload: {payload}")
try:
with httpx.Client(timeout=300.0) as client: # 注意这里用 AsyncClient 配合 Celery
# 如果你的 LitServe 是同步 endpoint也可以用 httpx.Client()
response = client.post(settings.SKETCH_TO_GARMENT_URL, json=payload)
if response.status_code == 200:
result = response.json()
result_json = {
"pattern": result[1],
"texture": result[2],
"glb": result[3],
"texture_fabric": result[4]
}
asyncio.run(
notify_callback(callback_url=callback_url, task_id=task_id, result=result_json, status="success")
)
else:
asyncio.run(
notify_callback(
callback_url=callback_url,
task_id=task_id,
result={
"status": "fail",
"task_id": task_id,
"message": "fail",
"error": "fail"
},
status="fail")
)
except Exception as e:
return {
"status": "failed",
"task_id": task_id,
"input": payload,
"error": str(e)
}

View File

@@ -11,7 +11,12 @@ from minio import Minio
from app.core.config import settings
from app.service.utils.decorator import RunTime
minio_client = Minio(settings.MINIO_URL, access_key=settings.MINIO_ACCESS, secret_key=settings.MINIO_SECRET, secure=settings.MINIO_SECURE)
minio_client = Minio(
settings.MINIO_URL,
access_key=settings.MINIO_ACCESS,
secret_key=settings.MINIO_SECRET,
secure=settings.MINIO_SECURE,
)
# 自定义 Retry 类
@@ -30,7 +35,7 @@ http_client = urllib3.PoolManager(
num_pools=10, # 设置连接池大小
maxsize=10,
timeout=timeout,
cert_reqs='CERT_REQUIRED', # 需要证书验证
cert_reqs="CERT_REQUIRED", # 需要证书验证
retries=CustomRetry(
total=5,
backoff_factor=0.2,
@@ -51,7 +56,7 @@ def oss_get_image(oss_client, bucket, object_name, data_type):
image_array = np.frombuffer(image_bytes, np.uint8) # 转成8位无符号整型
image_object = cv2.imdecode(image_array, cv2.IMREAD_UNCHANGED)
if image_object.dtype == np.uint16:
image_object = (image_object / 256).astype('uint8')
image_object = (image_object / 256).astype("uint8")
else:
data_bytes = BytesIO(image_data.read())
image_object = Image.open(data_bytes)
@@ -63,13 +68,19 @@ def oss_get_image(oss_client, bucket, object_name, data_type):
def oss_upload_image(oss_client, bucket, object_name, image_bytes):
req = None
try:
req = oss_client.put_object(bucket_name=bucket, object_name=object_name, data=io.BytesIO(image_bytes), length=len(image_bytes), content_type='image/png')
req = oss_client.put_object(
bucket_name=bucket,
object_name=object_name,
data=io.BytesIO(image_bytes),
length=len(image_bytes),
content_type="image/png",
)
except Exception as e:
logger.warning(f" | 上传图片出现异常 ######: {e}")
return req
if __name__ == '__main__':
if __name__ == "__main__":
# url = "aida-results/result_0002186a-e631-11ee-86a6-b48351119060.png"
# url = "aida-collection-element/11523/Moodboard/f60af0d2-94c2-48f9-90ff-74b8e8a481b5.jpg"
# url = "aida-sys-image/images/female/outwear/0628000054.jpg"
@@ -81,16 +92,26 @@ if __name__ == '__main__':
# url = "aida-users/89/sketchboard/female/Dress/e6724ab7-8d3f-4677-abe0-c3e42ab7af85.jpeg"
# url = "aida-users/87/print/956614a2-7e75-4fbe-9ed0-c1831e37a2c9-4-87.png"
# url = "aida-users/89/single_logo/123-89.png"
url = "aida-results/result_a7adcbd8-ef8d-11f0-8c92-0966ede33ab5.png"
url = "aida-collection-element/26293/Sketchboard/b503d482-3334-46e7-9dee-44e380fb4294.png"
# url = "aida-collection-element/12148/Sketchboard/95ea577b-305b-4a62-b30a-39c0dd3ddb3f.png"
read_type = "2"
if read_type == "cv2":
img = oss_get_image(oss_client=minio_client, bucket=url.split('/')[0], object_name=url[url.find('/') + 1:], data_type=read_type)
img = oss_get_image(
oss_client=minio_client,
bucket=url.split("/")[0],
object_name=url[url.find("/") + 1 :],
data_type=read_type,
)
cv2.imshow("", img)
cv2.waitKey(0)
else:
img = oss_get_image(oss_client=minio_client, bucket=url.split('/')[0], object_name=url[url.find('/') + 1:], data_type=read_type)
img = oss_get_image(
oss_client=minio_client,
bucket=url.split("/")[0],
object_name=url[url.find("/") + 1 :],
data_type=read_type,
)
draw = ImageDraw.Draw(img)
# 获取图片尺寸
width, height = img.size
@@ -103,7 +124,7 @@ if __name__ == '__main__':
draw.line(
[(center_x, 0), (center_x, height)], # 从顶部到底部的垂直线
fill=(255, 0, 0), # 红色 (R, G, B)
width=2 # 线宽
width=2, # 线宽
)
img.show()

View File

@@ -13,17 +13,22 @@ dependencies = [
"celery-types>=0.23.0",
"chromadb>=1.3.7",
"dashscope>=1.25.5",
"deepagents>=0.6.7",
"dominate>=2.9.1",
"dotenv>=0.9.9",
"fastapi[standard]>=0.125.0",
"image>=1.5.33",
"langchain>=1.2.0",
"langchain-community>=0.4.1",
"langchain-qwq>=0.3.5",
"langgraph>=1.0.5",
"langgraph-cli[inmem,redis]<=0.4.26",
"load>=1.0.14",
"load-dotenv>=0.1.0",
"loguru>=0.7.3",
"minio>=7.2.20",
"moviepy==1.0.3",
"nacos-sdk-python==2.0.1",
"np>=1.0.2",
"numpy<2",
"ollama>=0.6.1",
@@ -49,6 +54,6 @@ dependencies = [
"tool>=0.8.0",
"torch>=2.9.1",
"torchvision>=0.24.1",
"tritonclient[all]>=2.63.0",
"tritonclient[all]>=2.69.0",
"uvicorn>=0.38.0",
]

2610
uv.lock generated

File diff suppressed because it is too large Load Diff