feat: add homepage background removal tool and fix whitelist multipart support
- Add HomePage.vue with background removal functionality - Fix whitelist service to support multipart/form-data file uploads - Remove unused imports
This commit is contained in:
parent
1d20385e96
commit
6292b8b510
@ -18,6 +18,12 @@ const router = createRouter({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
name: 'HomePage',
|
||||||
|
component: () => import('../../views/HomePage.vue'),
|
||||||
|
meta: { requiresAuth: false }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/app',
|
||||||
name: 'AppLayout',
|
name: 'AppLayout',
|
||||||
component: () => import('../layouts/AppLayout.vue'),
|
component: () => import('../layouts/AppLayout.vue'),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
"Pending Review": "待审核",
|
"Pending Review": "待审核",
|
||||||
"Dashboard": "仪表板",
|
"Dashboard": "仪表板",
|
||||||
"Agents": "AI智能体",
|
"Agents": "AI智能体",
|
||||||
"Settings": "设置",
|
"Settings": "系统设置",
|
||||||
"Agent Detail": "智能体详情",
|
"Agent Detail": "智能体详情",
|
||||||
"Flow Builder": "流程编排",
|
"Flow Builder": "流程编排",
|
||||||
"Profile": "个人资料",
|
"Profile": "个人资料",
|
||||||
|
|||||||
1602
apps/jingrow/frontend/src/views/HomePage.vue
Normal file
1602
apps/jingrow/frontend/src/views/HomePage.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -60,15 +60,6 @@ async def authenticate_request(request: Request, allow_guest: bool) -> bool:
|
|||||||
async def _process_whitelist_call(request: Request, full_module_path: str):
|
async def _process_whitelist_call(request: Request, full_module_path: str):
|
||||||
"""通用处理:接收完整点分路径 '<package.module.function>' 并执行调用"""
|
"""通用处理:接收完整点分路径 '<package.module.function>' 并执行调用"""
|
||||||
try:
|
try:
|
||||||
async def _get_request_data(req: Request) -> Dict[str, Any]:
|
|
||||||
"""GET 使用查询参数,其他方法使用 JSON body"""
|
|
||||||
if req.method == 'GET':
|
|
||||||
return dict(req.query_params)
|
|
||||||
try:
|
|
||||||
return await req.json()
|
|
||||||
except Exception:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
# 确保 apps 目录在 sys.path 中(支持跨 app 导入)
|
# 确保 apps 目录在 sys.path 中(支持跨 app 导入)
|
||||||
ensure_apps_on_sys_path()
|
ensure_apps_on_sys_path()
|
||||||
|
|
||||||
@ -96,8 +87,28 @@ async def _process_whitelist_call(request: Request, full_module_path: str):
|
|||||||
if not await authenticate_request(request, whitelist_info['allow_guest']):
|
if not await authenticate_request(request, whitelist_info['allow_guest']):
|
||||||
raise HTTPException(status_code=401, detail="Authentication required")
|
raise HTTPException(status_code=401, detail="Authentication required")
|
||||||
|
|
||||||
|
# 根据请求类型获取数据
|
||||||
|
if request.method == 'GET':
|
||||||
|
request_data = dict(request.query_params)
|
||||||
|
else:
|
||||||
|
# 检查 Content-Type 是否为 multipart/form-data
|
||||||
|
content_type = request.headers.get('content-type', '')
|
||||||
|
is_multipart = 'multipart/form-data' in content_type
|
||||||
|
|
||||||
|
if is_multipart:
|
||||||
|
# 处理文件上传
|
||||||
|
form = await request.form()
|
||||||
|
request_data = {}
|
||||||
|
for key, value in form.items():
|
||||||
|
request_data[key] = value
|
||||||
|
else:
|
||||||
|
# 处理 JSON body
|
||||||
|
try:
|
||||||
|
request_data = await request.json()
|
||||||
|
except Exception:
|
||||||
|
request_data = {}
|
||||||
|
|
||||||
# 调用函数(只有通过白名单验证的函数才能执行到这里)
|
# 调用函数(只有通过白名单验证的函数才能执行到这里)
|
||||||
request_data = await _get_request_data(request)
|
|
||||||
result = func(**request_data)
|
result = func(**request_data)
|
||||||
|
|
||||||
return JSONResponse(content={"success": True, "data": result})
|
return JSONResponse(content={"success": True, "data": result})
|
||||||
|
|||||||
@ -15,6 +15,127 @@ from jingrow.utils.auth import get_jingrow_cloud_api_headers, get_jingrow_cloud_
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@jingrow.whitelist(allow_guest=True)
|
||||||
|
def remove_background_from_file_free(file) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
免费图片去背景工具(无需认证)
|
||||||
|
参考 remove_background_from_file 实现,调用 Jingrow Cloud API 实现图片背景移除
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file: 上传的文件对象
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 处理结果,格式与 remove_background_from_file 一致
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 获取认证头(使用系统配置的 API Key)
|
||||||
|
headers = get_jingrow_cloud_api_headers()
|
||||||
|
|
||||||
|
if not headers or not headers.get('Authorization'):
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "API密钥未设置,请联系管理员配置"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 读取文件内容
|
||||||
|
# whitelist 服务传递的 file 是 FastAPI 的 UploadFile 对象
|
||||||
|
# UploadFile.file 是底层的 SpooledTemporaryFile,可以同步读取
|
||||||
|
# 需要先重置文件指针到开头(因为可能已经被读取过)
|
||||||
|
file.file.seek(0)
|
||||||
|
file_content = file.file.read()
|
||||||
|
|
||||||
|
if not file_content or len(file_content) == 0:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": "文件内容为空"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 获取文件扩展名和内容类型
|
||||||
|
filename = getattr(file, 'filename', None) or 'image.png'
|
||||||
|
ext = filename.split('.')[-1].lower() if '.' in filename else 'png'
|
||||||
|
if ext == 'jpg':
|
||||||
|
ext = 'jpg'
|
||||||
|
content_type = 'image/jpeg'
|
||||||
|
elif ext == 'jpeg':
|
||||||
|
ext = 'jpg'
|
||||||
|
content_type = 'image/jpeg'
|
||||||
|
elif ext == 'png':
|
||||||
|
ext = 'png'
|
||||||
|
content_type = 'image/png'
|
||||||
|
elif ext == 'webp':
|
||||||
|
ext = 'webp'
|
||||||
|
content_type = 'image/webp'
|
||||||
|
else:
|
||||||
|
ext = 'png'
|
||||||
|
content_type = 'image/png'
|
||||||
|
|
||||||
|
# 处理EXIF orientation(参考 remove_background_from_file)
|
||||||
|
image = Image.open(io.BytesIO(file_content))
|
||||||
|
image = ImageOps.exif_transpose(image)
|
||||||
|
output = io.BytesIO()
|
||||||
|
save_format = image.format or content_type.split('/')[-1].upper()
|
||||||
|
image.save(output, format=save_format)
|
||||||
|
image_bytes = output.getvalue()
|
||||||
|
|
||||||
|
# 调用文件上传端点(与 remove_background_from_file 使用相同的接口)
|
||||||
|
api_url = f"{get_jingrow_cloud_api_url()}/rmbg/file/free"
|
||||||
|
|
||||||
|
# 移除 Content-Type,让 requests 自动设置 multipart/form-data
|
||||||
|
upload_headers = {k: v for k, v in headers.items() if k.lower() != 'content-type'}
|
||||||
|
files = {
|
||||||
|
'file': (f'image.{ext}', image_bytes, content_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
# 转发请求
|
||||||
|
response = requests.post(
|
||||||
|
api_url,
|
||||||
|
files=files,
|
||||||
|
headers=upload_headers,
|
||||||
|
timeout=180
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
result_data = response.json()
|
||||||
|
|
||||||
|
# 使用 image_url 字段,返回格式与 remove_background_from_file 一致
|
||||||
|
if 'image_url' in result_data:
|
||||||
|
image_url = result_data.get('image_url', '')
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"data": [{
|
||||||
|
"success": True,
|
||||||
|
"image_url": image_url,
|
||||||
|
"index": 1,
|
||||||
|
"total": 1
|
||||||
|
}],
|
||||||
|
"total_processed": 1,
|
||||||
|
"total_success": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": result_data.get('error', '未找到图片URL')
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
error_data = response.json()
|
||||||
|
error_message = error_data.get("message") or error_data.get("error") or f"API请求失败 (HTTP {response.status_code})"
|
||||||
|
except:
|
||||||
|
error_message = f"API请求失败 (HTTP {response.status_code})"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": error_message
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"调用图片去背景API异常:{str(e)}", exc_info=True)
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": f"调用图片去背景API异常:{str(e)}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@jingrow.whitelist()
|
@jingrow.whitelist()
|
||||||
def remove_background_from_file(image_data: Union[str, list]) -> Dict[str, Any]:
|
def remove_background_from_file(image_data: Union[str, list]) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user