From 49c4c554a696be0b93f0593f5cdd36b716bc9279 Mon Sep 17 00:00:00 2001 From: qnderkk Date: Thu, 23 Oct 2025 22:23:00 +0300 Subject: [PATCH] can start server --- .gitignore | 1 + docker/Dockerfile | 7 ++- docker/docker-compose.yml | 6 +- docker/entrypoint.sh | 61 ++++++++++++++----- project/.gitignore | 2 - project/__version__.txt | 2 +- project/main.py | 125 ++++++++++++++++++++++++-------------- project/requirements.txt | 7 +-- project/schemas.py | 15 +++++ run.sh | 4 +- 10 files changed, 156 insertions(+), 74 deletions(-) delete mode 100644 project/.gitignore mode change 100644 => 100755 project/__version__.txt mode change 100644 => 100755 project/main.py mode change 100644 => 100755 project/requirements.txt create mode 100755 project/schemas.py diff --git a/.gitignore b/.gitignore index eaf2f93..28d6db5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ build/ runtime/ +venv/ dist/ *.spec diff --git a/docker/Dockerfile b/docker/Dockerfile index f7ba58f..01bc288 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -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 \ @@ -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"] \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 8dbf763..f9d15fc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -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: - diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 0055fc4..bf3ecf5 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -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) @@ -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 @@ -45,7 +74,6 @@ else fi - echo "Starting main script" wine python --version wine --version @@ -53,7 +81,6 @@ winetricks -q win10 wine pip freeze - export OMP_NUM_THREADS=1 export OMP_WAIT_POLICY=PASSIVE export KMP_BLOCKTIME=0 @@ -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'" @@ -101,3 +131,4 @@ if [[ $MODE == "compile"* ]] && [[ $PYINSTALLERARGS == *"--onedir"* ]]; then zip -r -q -T --symlinks main.zip main/ fi +kill $XVFB_PID diff --git a/project/.gitignore b/project/.gitignore deleted file mode 100644 index e91862f..0000000 --- a/project/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -**/__pycache__/ - diff --git a/project/__version__.txt b/project/__version__.txt old mode 100644 new mode 100755 index d41d28a..927cc60 --- a/project/__version__.txt +++ b/project/__version__.txt @@ -1,2 +1,2 @@ -3.12.10 +3.10.6 diff --git a/project/main.py b/project/main.py old mode 100644 new mode 100755 index f61fda5..d8e101d --- a/project/main.py +++ b/project/main.py @@ -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...") \ No newline at end of file diff --git a/project/requirements.txt b/project/requirements.txt old mode 100644 new mode 100755 index b472b6f..6d7503c --- a/project/requirements.txt +++ b/project/requirements.txt @@ -1,4 +1,3 @@ --i https://download.pytorch.org/whl/cpu -numpy==2.1.2 -torch==2.8.0 - +fastapi +uvicorn +python-multipart \ No newline at end of file diff --git a/project/schemas.py b/project/schemas.py new file mode 100755 index 0000000..357ddd5 --- /dev/null +++ b/project/schemas.py @@ -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 + + + diff --git a/run.sh b/run.sh index dc7a96e..717cf84 100755 --- a/run.sh +++ b/run.sh @@ -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