zxd
This commit is contained in:
@@ -19,6 +19,7 @@ import time
|
||||
import json
|
||||
import traceback
|
||||
import re
|
||||
import asyncio
|
||||
from typing import Optional, List, Dict, Any
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
@@ -100,6 +101,49 @@ async def verify_api_key(api_key: Optional[str] = Depends(api_key_header)):
|
||||
# 4. Lifespan Management (生命周期管理)
|
||||
# ==========================================
|
||||
|
||||
async def cleanup_old_files(directory: str, lifetime_seconds: int, interval_seconds: int):
|
||||
"""
|
||||
后台任务:定期清理过期的图片文件
|
||||
"""
|
||||
print(f"🧹 自动清理任务已启动 | 目录: {directory} | 生命周期: {lifetime_seconds}s | 检查间隔: {interval_seconds}s")
|
||||
while True:
|
||||
try:
|
||||
await asyncio.sleep(interval_seconds)
|
||||
current_time = time.time()
|
||||
count = 0
|
||||
# 遍历所有文件(包括子目录)
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
# 获取文件修改时间
|
||||
try:
|
||||
file_mtime = os.path.getmtime(file_path)
|
||||
if current_time - file_mtime > lifetime_seconds:
|
||||
os.remove(file_path)
|
||||
count += 1
|
||||
except OSError:
|
||||
pass # 文件可能已被删除
|
||||
|
||||
# 尝试清理空目录 (可选,仅清理二级目录)
|
||||
for root, dirs, files in os.walk(directory, topdown=False):
|
||||
for dir in dirs:
|
||||
dir_path = os.path.join(root, dir)
|
||||
try:
|
||||
if not os.listdir(dir_path): # 如果目录为空
|
||||
os.rmdir(dir_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if count > 0:
|
||||
print(f"🧹 已清理 {count} 个过期文件")
|
||||
|
||||
except asyncio.CancelledError:
|
||||
print("🛑 清理任务已停止")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"⚠️ 清理任务出错: {e}")
|
||||
await asyncio.sleep(60) # 出错后等待一分钟再试
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""
|
||||
@@ -132,9 +176,33 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
print(f"模型加载完成,设备: {device}")
|
||||
|
||||
# --- 启动后台清理任务 ---
|
||||
cleanup_task_handle = None
|
||||
# 优先读取环境变量,否则使用默认值
|
||||
if os.getenv("AUTO_CLEANUP_ENABLED", "False").lower() == "true":
|
||||
try:
|
||||
lifetime = int(os.getenv("FILE_LIFETIME_SECONDS", "3600"))
|
||||
interval = int(os.getenv("CLEANUP_INTERVAL_SECONDS", "600"))
|
||||
cleanup_task_handle = asyncio.create_task(
|
||||
cleanup_old_files(RESULT_IMAGE_DIR, lifetime, interval)
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"启动清理任务失败: {e}")
|
||||
# -----------------------
|
||||
|
||||
yield
|
||||
|
||||
print("正在清理资源...")
|
||||
|
||||
# --- 停止后台任务 ---
|
||||
if cleanup_task_handle:
|
||||
cleanup_task_handle.cancel()
|
||||
try:
|
||||
await cleanup_task_handle
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
# ------------------
|
||||
|
||||
# 这里可以添加释放显存的逻辑,如果需要
|
||||
|
||||
# ==========================================
|
||||
@@ -537,14 +605,18 @@ async def segment(
|
||||
image_url: Optional[str] = Form(None, description="URL of the image"),
|
||||
save_segment_images: bool = Form(False, description="Whether to save and return individual segmented objects"),
|
||||
cutout: bool = Form(False, description="If True, returns transparent background PNGs; otherwise returns original crops"),
|
||||
highlight: bool = Form(False, description="If True, darkens the background to highlight the subject (周边变黑放大)."),
|
||||
confidence: float = Form(0.7, description="Confidence threshold (0.0-1.0). Default is 0.7.")
|
||||
|
||||
):
|
||||
"""
|
||||
**通用图像分割接口**
|
||||
|
||||
- 支持上传图片或提供图片 URL
|
||||
- 支持自动将中文 Prompt 翻译为英文
|
||||
- 支持周边变黑放大效果 (Highlight Mode)
|
||||
- 支持手动设置置信度 (Confidence Threshold)
|
||||
|
||||
"""
|
||||
if not file and not image_url:
|
||||
raise HTTPException(status_code=400, detail="必须提供 file (图片文件) 或 image_url (图片链接)")
|
||||
@@ -601,6 +673,12 @@ async def segment(
|
||||
|
||||
# 4. 结果可视化与保存
|
||||
try:
|
||||
if highlight:
|
||||
filename = f"seg_highlight_{uuid.uuid4().hex}.jpg"
|
||||
save_path = os.path.join(RESULT_IMAGE_DIR, filename)
|
||||
# 使用 human_analysis_service 中的可视化函数 (周边变黑)
|
||||
human_analysis_service.create_highlighted_visualization(image, masks, save_path)
|
||||
else:
|
||||
filename = generate_and_save_result(image, inference_state)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"绘图保存错误: {str(e)}")
|
||||
@@ -924,6 +1002,21 @@ async def segment_face(
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
# ==========================================
|
||||
# 自动清理图片配置 (Auto Cleanup Config)
|
||||
# ==========================================
|
||||
# 设置是否开启自动清理 (True/False)
|
||||
os.environ["AUTO_CLEANUP_ENABLED"] = "True"
|
||||
|
||||
# 设置图片生命周期 (秒),超过此时间的图片将被删除
|
||||
# 例如: 3600 = 1小时, 86400 = 1天
|
||||
os.environ["FILE_LIFETIME_SECONDS"] = "3600"
|
||||
|
||||
# 设置检查间隔 (秒),每隔多久检查一次
|
||||
os.environ["CLEANUP_INTERVAL_SECONDS"] = "600"
|
||||
# ==========================================
|
||||
|
||||
# 启动服务器
|
||||
uvicorn.run(
|
||||
"fastAPI_tarot:app",
|
||||
|
||||
BIN
static/results/1771167659_ef9e57ff/face_0.jpg
Normal file
BIN
static/results/1771167659_ef9e57ff/face_0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
static/results/seg_9745a70b2b5c4cc6b0d1b69857704aed.jpg
Normal file
BIN
static/results/seg_9745a70b2b5c4cc6b0d1b69857704aed.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Reference in New Issue
Block a user