Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
build/
runtime/
venv/

dist/
*.spec
Expand Down
7 changes: 5 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ ENV DEBIAN_FRONTEND=noninteractive \
# Install required packages with official Wine PPA
RUN apt-get update && \
apt-get install -y \
xvfb \
x11-utils -y \
xauth \
wget \
software-properties-common \
gnupg2 \
Expand All @@ -24,9 +27,9 @@ RUN apt-get update && \
mkdir -pm755 /etc/apt/keyrings && \
wget -O - https://dl.winehq.org/wine-builds/winehq.key | gpg --dearmor -o /etc/apt/keyrings/winehq-archive.key - && \
wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/noble/winehq-noble.sources;

RUN apt update;
RUN apt install -y --install-recommends winehq-stable && \
apt install -y winetricks;

CMD ["/bin/bash"]

CMD ["/bin/bash"]
6 changes: 3 additions & 3 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ services:
dockerfile: docker/Dockerfile
volumes:
- ../docker:/app/docker:ro
- ../project:/app/project:ro
- ../project:/app/project:rwo
- ../build:/app/build:rwo
- ../runtime:/app/runtime:rwo
- /tmp/.X11-unix:/tmp/.X11-unix:rw
- ~/.Xauthority:/root/.Xauthority:rw
- installation_state:/app/state
- wine:/root/.wine
network_mode: host
working_dir: /app
entrypoint: ["/app/docker/entrypoint.sh"]
command: []
stdin_open: true
tty: true
ports:
- 127.0.0.1:8000:8000

volumes:
installation_state:
wine:

61 changes: 46 additions & 15 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
#!/bin/bash

export DISPLAY=:99
export WINEDLLOVERRIDES="mscoree,mshtml,winemenubuilder="
export WINEDEBUG=-all

Xvfb $DISPLAY -screen 0 720x720x24 2>/dev/null &
XVFB_PID=$!
echo "Started Xvfb on $DISPLAY with PID $XVFB_PID"

sleep 3

mkdir -p /app/state
read -r PYTHON_VERSION < /app/project/__version__.txt
echo "PYTHON VERSION: $PYTHON_VERSION"
echo "Mode: $MODE"
echo "Arguments for main.exe: $MAINARGS"
echo "Arguments for pyinstaller: $PYINSTALLERARGS"


echo "Uvicorn command: $UVICORN_CMD"

# Check installation state
installed_version=$(wine python --version)
Expand All @@ -21,18 +30,38 @@ if [[ $installed_version != $required_version ]]; then
fi
echo -e "\n\nUninstalling Python...\nChoose and uninstall previous version of python"
wine uninstaller

sleep 5
done

winetricks --force vcrun2019
echo "Downloading and silently installing VC_redist"
VCRUNTIME_URL="https://aka.ms/vs/16/release/vc_redist.x86.exe"
VCRUNTIME_CACHE_PATH="/root/.cache/winetricks/vcrun2019"
VCRUNTIME_EXE="$VCRUNTIME_CACHE_PATH/vc_redist.x86.exe"

mkdir -p "$VSCRUNTIME_CACHE_PATH"
wget -O "$VCRUNTIME_EXE" "$VCRUNTIME_URL"

wine "$VCRUNTIME_EXE" /install /passive /norestart

if [[ $? -ne 0 ]]; then
echo "Error: VC_redist silent install failed"
fi

winetricks -q win10

wine python --version
wget "https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-amd64.exe"
wine ./python-${PYTHON_VERSION}-amd64.exe
PYTHON_EXE="python-${PYTHON_VERSION}-amd64.exe"
wine python --version
echo "Installing Python silently..."
wine ./"$PYTHON_EXE" /quiet InstallAllUsers=1 PrependPath=1
if [ $? -ne 0 ]; then
echo "Warning: Python silent install returned a non-zero code"
fi
wine pip install -r /app/docker/requirements.txt
if [ $? -ne 0 ]; then
echo "Error: pip install failed"
echo "Error: pip install failed1"
exit 1
fi

Expand All @@ -45,15 +74,13 @@ else
fi



echo "Starting main script"
wine python --version
wine --version
winetricks -q win10
wine pip freeze



export OMP_NUM_THREADS=1
export OMP_WAIT_POLICY=PASSIVE
export KMP_BLOCKTIME=0
Expand All @@ -79,15 +106,18 @@ case "$MODE" in
cd /app/build
wine pyinstaller --noconfirm $PYINSTALLERARGS "Z:\\app\\project\\main.py"
;;
"run-onefile")
echo "Running previously compiled main.exe..."
cd /app/runtime
wine /app/build/dist/main.exe $MAINARGS
;;
"run-onedir")
"run-onefile"|"run-onedir")
echo "Running previously compiled main.exe..."
cd /app/runtime
wine /app/build/dist/main/main.exe $MAINARGS
cd /app/project

echo "Current directory: $(pwd)"
echo "Starting main.exe which will launch FastAPI server..."

if [[ "$MODE" == "run-onefile" ]]; then
wine /app/build/dist/main.exe
else
wine /app/build/dist/main/main.exe
fi
;;
*)
echo "Error: Unknown mode '$MODE'"
Expand All @@ -101,3 +131,4 @@ if [[ $MODE == "compile"* ]] && [[ $PYINSTALLERARGS == *"--onedir"* ]]; then
zip -r -q -T --symlinks main.zip main/
fi

kill $XVFB_PID
2 changes: 0 additions & 2 deletions project/.gitignore

This file was deleted.

2 changes: 1 addition & 1 deletion project/__version__.txt
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
3.12.10
3.10.6

125 changes: 79 additions & 46 deletions project/main.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,61 +1,94 @@
import sys
import os
import torch
from fastapi import FastAPI, HTTPException, File, UploadFile
from fastapi.responses import FileResponse

from typing import Annotated, Optional

from pathlib import Path
import shutil
import os
import tempfile
import asyncio

from schemas import UniqueIdGenerator

def main():
print("Windows PyTorch Test Application v4.1")
print("=" * 40)
import os
import uvicorn

# Простая проверка аргументов
if len(sys.argv) < 3:
print("Usage: stl_processor.exe path_to_stl=... target_folder=...")
return 1

# Проверяем что PyTorch работает
try:
print("Testing PyTorch...")
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
result = torch.matmul(a, b)
print(f"PyTorch test passed! Result:\n{result}")
except Exception as e:
print(f"PyTorch test failed: {e}")
return 1
app = FastAPI()

# Простая имитация работы с файлами
try:
path_to_stl = sys.argv[1].split('=')[1]
target_folder = sys.argv[2].split('=')[1]
FILE_EXTENSIONS = (".step", ".stl", ".obj")
BASE_DIR = Path("result_files")
BASE_DIR.mkdir(exist_ok=True)

print(f"Input STL: {path_to_stl}")
print(f"Output folder: {target_folder}")
generator = UniqueIdGenerator()

# Создаем простые файлы
stl_path = Path(path_to_stl)
obj_file = stl_path.stem + ".obj"
txt_file = stl_path.stem + ".txt"

# Записываем тестовые файлы
with open(obj_file, 'w') as f:
f.write("# Test OBJ file\n")
f.write(f"# Generated from {path_to_stl}\n")
async def wait_for_file(old_file_name: str, new_extension: str = ".color", check_interval: float = 2.0) -> tuple:
new_file = old_file_name + new_extension

with open(txt_file, 'w') as f:
f.write(f"Source: {path_to_stl}\n")
f.write(f"Output: {obj_file}\n")
f.write("Status: Success\n")
file_path = BASE_DIR / new_file

print(f"Created: {obj_file}")
print(f"Created: {txt_file}")
while not file_path.exists():
await asyncio.sleep(check_interval)

return 0
return (str(file_path), new_file)

except Exception as e:
print(f"Error: {e}")
return 1

if __name__ == "__main__":
sys.exit(main())
@app.get("/color")
async def get_file(filename: str, path_to_temp: Optional[str] = None) -> FileResponse:
if not (filename.lower().endswith(FILE_EXTENSIONS)):
raise HTTPException(status_code=404, detail="The file has an incorrect extension.")

if path_to_temp != None:
path_to_file = Path(path_to_temp)
else:
path_to_file = Path(filename)

extension = os.path.splitext(filename)[1]

new_file_base = generator.generate_uuid()
full_file_name = new_file_base + extension

target_path = BASE_DIR / full_file_name
shutil.move(path_to_file, target_path)

new_extension_file_path, new_file_name = await wait_for_file(new_file_base)

return FileResponse(path=new_extension_file_path, filename=new_file_name)


@app.post("/color_file")
async def upload_file(
file: Annotated[UploadFile,
File(description="File of obj, step, stl extensions")]
) -> FileResponse:

with tempfile.TemporaryDirectory() as tmpdir:
file_path = os.path.join(tmpdir, file.filename)
content = await file.read()
with open(file_path, 'wb') as f:
f.write(content)

result = await get_file(file.filename, file_path)

return result


if __name__ == "__main__":
print("Starting FastAPI Server from main.exe")
print("=" * 50)

try:
uvicorn.run(
app=app,
host="0.0.0.0",
port=8000,
reload=False,
log_level="info"
)
except KeyboardInterrupt:
print("\n Server stopped by user")
except Exception as e:
print(f" Error starting server: {e}")
input("Press Enter to exit...")
7 changes: 3 additions & 4 deletions project/requirements.txt
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
-i https://download.pytorch.org/whl/cpu
numpy==2.1.2
torch==2.8.0

fastapi
uvicorn
python-multipart
15 changes: 15 additions & 0 deletions project/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import uuid

class UniqueIdGenerator():
def __init__(self):
self.generated = set()

def generate_uuid(self):
while True:
code = str(uuid.uuid4()).replace('-', '')[:8]
if code not in self.generated:
self.generated.add(code)
return code



4 changes: 3 additions & 1 deletion run.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/bin/bash

xhost +local:
xhost +local:docker

export "$@"

chmod +x docker/entrypoint.sh

docker compose -f docker/docker-compose.yml up --build