1
This commit is contained in:
11
docker-compose.yaml
Normal file → Executable file
11
docker-compose.yaml
Normal file → Executable file
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
trellis:
|
trellis:
|
||||||
image: zhouchengrong/fida-trellis:latest # 你 commit 的镜像
|
image: zhouchengrong/fida-trellis-a6000:latest # 你 commit 的镜像
|
||||||
container_name: trellis-dev
|
container_name: FiDA_3D_Trellis
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- NVIDIA_VISIBLE_DEVICES=all
|
- NVIDIA_VISIBLE_DEVICES=all
|
||||||
@@ -24,8 +24,5 @@ services:
|
|||||||
capabilities: [ gpu, compute, utility ] # 移除 video(非必需,减少兼容问题)
|
capabilities: [ gpu, compute, utility ] # 移除 video(非必需,减少兼容问题)
|
||||||
command: >
|
command: >
|
||||||
bash -c "
|
bash -c "
|
||||||
/opt/conda/envs/trellis/bin/python -c 'import torch; print(torch.__version__, torch.cuda.is_available())' &&
|
conda run --no-capture-output -n trellis python server.py
|
||||||
/opt/conda/envs/trellis/bin/python server.py
|
"
|
||||||
"
|
|
||||||
# /opt/conda/envs/trellis/bin/python server.py
|
|
||||||
# tail -f /dev/null
|
|
||||||
144
server.py
Normal file → Executable file
144
server.py
Normal file → Executable file
@@ -144,11 +144,12 @@ class TrellisAPI(ls.LitAPI):
|
|||||||
|
|
||||||
def decode_request(self, request):
|
def decode_request(self, request):
|
||||||
image_paths = request["image_paths"]
|
image_paths = request["image_paths"]
|
||||||
|
bucket_name = request["bucket_name"]
|
||||||
|
user_id = request["user_id"]
|
||||||
|
|
||||||
images = []
|
images = []
|
||||||
for path in image_paths:
|
for path in image_paths:
|
||||||
bucket = path.split('/')[0]
|
bucket, object_name = path.split('/', 1)
|
||||||
object_name = path[path.find('/') + 1:]
|
|
||||||
|
|
||||||
image = minio_get_image(minio_client, bucket, object_name)
|
image = minio_get_image(minio_client, bucket, object_name)
|
||||||
images.append(image)
|
images.append(image)
|
||||||
|
|
||||||
@@ -163,6 +164,8 @@ class TrellisAPI(ls.LitAPI):
|
|||||||
"simplify": request.get("simplify", 0.95),
|
"simplify": request.get("simplify", 0.95),
|
||||||
"texture_size": request.get("texture_size", 1024),
|
"texture_size": request.get("texture_size", 1024),
|
||||||
"fps": request.get("fps", 30),
|
"fps": request.get("fps", 30),
|
||||||
|
"bucket_name": bucket_name,
|
||||||
|
"user_id": user_id
|
||||||
}
|
}
|
||||||
|
|
||||||
return images, params
|
return images, params
|
||||||
@@ -202,8 +205,7 @@ class TrellisAPI(ls.LitAPI):
|
|||||||
|
|
||||||
glb_info = analyze_mesh(local_glb_path)
|
glb_info = analyze_mesh(local_glb_path)
|
||||||
|
|
||||||
local_static_model_image_path = os.path.join("glb_output", generate_unique_name("static_model_image.png"))
|
static_model_image = self.get_static_model_image(model_path=local_glb_path, params=params)
|
||||||
static_model_image = self.get_static_model_image(model_path=local_glb_path, output_path=local_static_model_image_path)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"glb_path": minio_glb_path,
|
"glb_path": minio_glb_path,
|
||||||
@@ -214,49 +216,49 @@ class TrellisAPI(ls.LitAPI):
|
|||||||
def encode_response(self, output):
|
def encode_response(self, output):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def upload_video(self, outputs, params):
|
# def upload_video(self, outputs, params):
|
||||||
gaussian_name = f"3d_result/video/{params['file_name']}-gaussian.mp4"
|
# gaussian_name = f"3d_result/video/{params['file_name']}-gaussian.mp4"
|
||||||
radiance_field_name = f"3d_result/video/{params['file_name']}-radiance_field.mp4"
|
# radiance_field_name = f"3d_result/video/{params['file_name']}-radiance_field.mp4"
|
||||||
mesh_name = f"3d_result/video/{params['file_name']}-mesh.mp4"
|
# mesh_name = f"3d_result/video/{params['file_name']}-mesh.mp4"
|
||||||
|
#
|
||||||
# gaussian video
|
# # gaussian video
|
||||||
video = render_utils.render_video(outputs["gaussian"][0])["color"]
|
# video = render_utils.render_video(outputs["gaussian"][0])["color"]
|
||||||
buffer = BytesIO()
|
# buffer = BytesIO()
|
||||||
imageio.mimsave(buffer, video, format="mp4", fps=params['fps'])
|
# imageio.mimsave(buffer, video, format="mp4", fps=params['fps'])
|
||||||
gaussian_video_path = upload_bytes(
|
# gaussian_video_path = upload_bytes(
|
||||||
buffer.getvalue(),
|
# buffer.getvalue(),
|
||||||
gaussian_name,
|
# gaussian_name,
|
||||||
"video/mp4",
|
# "video/mp4",
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# radiance field video
|
# # radiance field video
|
||||||
video = render_utils.render_video(outputs["radiance_field"][0])["color"]
|
# video = render_utils.render_video(outputs["radiance_field"][0])["color"]
|
||||||
buffer = BytesIO()
|
# buffer = BytesIO()
|
||||||
imageio.mimsave(buffer, video, format="mp4", fps=params['fps'])
|
# imageio.mimsave(buffer, video, format="mp4", fps=params['fps'])
|
||||||
radiance_field_video_path = upload_bytes(
|
# radiance_field_video_path = upload_bytes(
|
||||||
buffer.getvalue(),
|
# buffer.getvalue(),
|
||||||
radiance_field_name,
|
# radiance_field_name,
|
||||||
"video/mp4",
|
# "video/mp4",
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# mesh video
|
# # mesh video
|
||||||
video = render_utils.render_video(outputs["mesh"][0])["normal"]
|
# video = render_utils.render_video(outputs["mesh"][0])["normal"]
|
||||||
buffer = BytesIO()
|
# buffer = BytesIO()
|
||||||
imageio.mimsave(buffer, video, format="mp4", fps=params['fps'])
|
# imageio.mimsave(buffer, video, format="mp4", fps=params['fps'])
|
||||||
mesh_path = upload_bytes(
|
# mesh_path = upload_bytes(
|
||||||
buffer.getvalue(),
|
# buffer.getvalue(),
|
||||||
mesh_name,
|
# mesh_name,
|
||||||
"video/mp4",
|
# "video/mp4",
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
return {
|
# return {
|
||||||
"gaussian": gaussian_video_path,
|
# "gaussian": gaussian_video_path,
|
||||||
"radiance_field": radiance_field_video_path,
|
# "radiance_field": radiance_field_video_path,
|
||||||
"mesh": mesh_path
|
# "mesh": mesh_path
|
||||||
}
|
# }
|
||||||
|
|
||||||
def upload_glb(self, outputs, params):
|
def upload_glb(self, outputs, params):
|
||||||
file_name = f"3d_result/glb/{params['file_name']}.glb"
|
minio_path = f"{params['bucket_name']}/{params['user_id']}/3d_result/{params['file_name']}.glb"
|
||||||
local_glb_path = os.path.join("glb_output", generate_unique_name("sample.glb"))
|
local_glb_path = os.path.join("glb_output", generate_unique_name("sample.glb"))
|
||||||
out_dir = os.path.dirname(local_glb_path)
|
out_dir = os.path.dirname(local_glb_path)
|
||||||
if out_dir:
|
if out_dir:
|
||||||
@@ -275,31 +277,28 @@ class TrellisAPI(ls.LitAPI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
glb_path = upload_local_file(
|
glb_path = upload_local_file(
|
||||||
local_glb_path,
|
file_path=local_glb_path,
|
||||||
file_name,
|
minio_path=minio_path,
|
||||||
"application/octet-stream",
|
content_type="application/octet-stream"
|
||||||
)
|
)
|
||||||
return glb_path, local_glb_path
|
return glb_path, local_glb_path
|
||||||
|
|
||||||
def upload_ply(self, outputs, params):
|
# def upload_ply(self, outputs, params):
|
||||||
file_name = f"3d_result/ply/{params['file_name']}.ply"
|
# file_name = f"3d_result/ply/{params['file_name']}.ply"
|
||||||
|
#
|
||||||
|
# with tempfile.NamedTemporaryFile(suffix=".ply") as tmp:
|
||||||
|
# outputs["gaussian"][0].save_ply(tmp.name)
|
||||||
|
# tmp.seek(0)
|
||||||
|
#
|
||||||
|
# ply_path = upload_bytes(
|
||||||
|
# tmp.read(),
|
||||||
|
# file_name,
|
||||||
|
# "application/octet-stream",
|
||||||
|
# )
|
||||||
|
# return {"ply": ply_path}
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile(suffix=".ply") as tmp:
|
def get_static_model_image(self, model_path, params):
|
||||||
outputs["gaussian"][0].save_ply(tmp.name)
|
local_static_model_image_path = os.path.join("glb_output", generate_unique_name("static_model_image.png"))
|
||||||
tmp.seek(0)
|
|
||||||
|
|
||||||
ply_path = upload_bytes(
|
|
||||||
tmp.read(),
|
|
||||||
file_name,
|
|
||||||
"application/octet-stream",
|
|
||||||
)
|
|
||||||
return {"ply": ply_path}
|
|
||||||
|
|
||||||
def get_static_model_image(self, model_path, output_path):
|
|
||||||
local_static_model_image_path = os.path.join(
|
|
||||||
"glb_output",
|
|
||||||
generate_unique_name("static_model_image.png")
|
|
||||||
)
|
|
||||||
|
|
||||||
print(f"model_path : {model_path}")
|
print(f"model_path : {model_path}")
|
||||||
print(f"local_static_model_image_path :{local_static_model_image_path}")
|
print(f"local_static_model_image_path :{local_static_model_image_path}")
|
||||||
@@ -307,17 +306,18 @@ class TrellisAPI(ls.LitAPI):
|
|||||||
|
|
||||||
static_model_image = self.upload_local_file(
|
static_model_image = self.upload_local_file(
|
||||||
output_path,
|
output_path,
|
||||||
"png"
|
params['bucket_name'],
|
||||||
|
params['user_id'],
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"Saved to {static_model_image}")
|
print(f"Saved to {static_model_image}")
|
||||||
return static_model_image
|
return static_model_image
|
||||||
|
|
||||||
def upload_local_file(self, local_path, type):
|
def upload_local_file(self, local_path, bucket_name, user_id):
|
||||||
"""
|
"""
|
||||||
通用上传函数:支持 SVG, PNG, OBJ 等
|
通用上传函数:支持 SVG, PNG, OBJ 等
|
||||||
"""
|
"""
|
||||||
object_name = f"3d_result/{type}/{uuid.uuid4().hex}.{type}"
|
object_name = f"{user_id}/3d_result/{uuid.uuid4().hex}.png"
|
||||||
if not os.path.exists(local_path):
|
if not os.path.exists(local_path):
|
||||||
print(f"错误: 文件 {local_path} 不存在")
|
print(f"错误: 文件 {local_path} 不存在")
|
||||||
return None
|
return None
|
||||||
@@ -330,13 +330,13 @@ class TrellisAPI(ls.LitAPI):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
minio_client.fput_object(
|
minio_client.fput_object(
|
||||||
bucket_name=MINIO_BUCKET,
|
bucket_name=bucket_name,
|
||||||
object_name=object_name,
|
object_name=object_name,
|
||||||
file_path=local_path,
|
file_path=local_path,
|
||||||
content_type=content_type
|
content_type=content_type
|
||||||
)
|
)
|
||||||
print(f"成功上传 [{content_type}]: {object_name}")
|
print(f"成功上传 [{content_type}]: {object_name}")
|
||||||
return f"{MINIO_BUCKET}/{object_name}"
|
return f"{bucket_name}/{object_name}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"上传失败: {e}")
|
print(f"上传失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|||||||
9
utils/new_oss_client.py
Normal file → Executable file
9
utils/new_oss_client.py
Normal file → Executable file
@@ -76,7 +76,7 @@ def upload_bytes(data_bytes, object_name, content_type):
|
|||||||
return f"{MINIO_BUCKET}/{object_name}"
|
return f"{MINIO_BUCKET}/{object_name}"
|
||||||
|
|
||||||
|
|
||||||
def upload_local_file(file_path, object_name, content_type="application/octet-stream"):
|
def upload_local_file(file_path, minio_path, content_type="application/octet-stream"):
|
||||||
"""
|
"""
|
||||||
将本地磁盘上的文件上传到 MinIO
|
将本地磁盘上的文件上传到 MinIO
|
||||||
:param file_path: 本地文件路径 (如: 'output/sample.obj')
|
:param file_path: 本地文件路径 (如: 'output/sample.obj')
|
||||||
@@ -88,14 +88,15 @@ def upload_local_file(file_path, object_name, content_type="application/octet-st
|
|||||||
raise FileNotFoundError(f"本地文件未找到: {file_path}")
|
raise FileNotFoundError(f"本地文件未找到: {file_path}")
|
||||||
|
|
||||||
# 使用 fput_object 直接从磁盘流式上传,不占用过多内存
|
# 使用 fput_object 直接从磁盘流式上传,不占用过多内存
|
||||||
|
bucket, object_name = minio_path.split('/', 1)
|
||||||
|
|
||||||
minio_client.fput_object(
|
minio_client.fput_object(
|
||||||
bucket_name=MINIO_BUCKET,
|
bucket_name=bucket,
|
||||||
object_name=object_name,
|
object_name=object_name,
|
||||||
file_path=file_path,
|
file_path=file_path,
|
||||||
content_type=content_type
|
content_type=content_type
|
||||||
)
|
)
|
||||||
|
return f"{bucket}/{object_name}"
|
||||||
return f"{MINIO_BUCKET}/{object_name}"
|
|
||||||
|
|
||||||
|
|
||||||
def download_from_minio(object_path, local_path):
|
def download_from_minio(object_path, local_path):
|
||||||
|
|||||||
Reference in New Issue
Block a user