diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..0fc27ce4b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +# syntax=docker/dockerfile:1 +FROM node:20-alpine AS frontend-builder + +WORKDIR /app/react + +# Copy package files +COPY react/package*.json ./ +RUN npm install --force + +# Copy frontend source and build +COPY react/ ./ +RUN npx vite build + +# Python runtime stage +FROM python:3.12-slim AS runtime + +WORKDIR /app + +# Install system dependencies including curl for healthcheck +RUN apt-get update && apt-get install -y \ + gcc \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Copy Python requirements and install dependencies +COPY server/requirements.txt ./server/ +RUN pip install --no-cache-dir -r server/requirements.txt + +# Copy server code +COPY server/ ./server/ + +# Copy built frontend from builder stage +COPY --from=frontend-builder /app/react/dist ./react/dist + +# Set environment variables +ENV UI_DIST_DIR=/app/react/dist +ENV HOST=0.0.0.0 + +# Run the application +WORKDIR /app/server +CMD ["python", "main.py", "--host", "0.0.0.0", "--port", "8088"] diff --git a/README_zh.md b/README_zh.md index b7332620c..a3515dd93 100644 --- a/README_zh.md +++ b/README_zh.md @@ -114,3 +114,9 @@ VSCode/Cursor Install Extensions: `python main.py` + + +## 使用docker安装 + +`git clone https://github.com/11cafe/localart` +`docker compose up -d` \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..958cc140f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +version: '3.8' + +services: + jaaz-app: + build: + context: . + dockerfile: Dockerfile + ports: + - "8088:8088" + environment: + - UI_DIST_DIR=/app/react/dist + volumes: + # Optional: mount for persistent data + - ./data:/app/data + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8088/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s \ No newline at end of file diff --git a/electron/comfyUIInstaller.js b/electron/comfyUIInstaller.js index 214e7e620..da70c64aa 100644 --- a/electron/comfyUIInstaller.js +++ b/electron/comfyUIInstaller.js @@ -109,8 +109,7 @@ async function getLatestComfyUIRelease() { if (res.statusCode !== 200) { reject( new Error( - `GitHub API error: ${res.statusCode} - ${ - release.message || 'Unknown error' + `GitHub API error: ${res.statusCode} - ${release.message || 'Unknown error' }` ) ) @@ -618,7 +617,7 @@ async function updateConfigWithComfyUI() { try { // Call backend API to update configuration const response = await fetch( - 'http://127.0.0.1:57988/api/comfyui/update_config', + 'http://127.0.0.1:8088/api/comfyui/update_config', { method: 'POST', headers: { diff --git a/electron/main.js b/electron/main.js index 3f82804ed..d24f6b67e 100644 --- a/electron/main.js +++ b/electron/main.js @@ -165,7 +165,7 @@ const appRoot = app.getAppPath() const startPythonApi = async () => { // Find an available port - pyPort = await findAvailablePort(57988) + pyPort = await findAvailablePort(8088) console.log('available pyPort:', pyPort) // 在某些开发情况,我们希望 python server 独立运行,那么就不通过 electron 启动 @@ -216,12 +216,12 @@ const startPythonApi = async () => { const isWindows = process.platform === 'win32' const pythonExecutable = app.isPackaged ? path.join( - process.resourcesPath, - 'server', - 'dist', - 'main', - isWindows ? 'main.exe' : 'main' - ) + process.resourcesPath, + 'server', + 'dist', + 'main', + isWindows ? 'main.exe' : 'main' + ) : 'python' console.log('Resolved Python executable:', pythonExecutable) diff --git a/react/src/contexts/socket.tsx b/react/src/contexts/socket.tsx index 2b473742f..a0e26e738 100644 --- a/react/src/contexts/socket.tsx +++ b/react/src/contexts/socket.tsx @@ -42,7 +42,7 @@ export const SocketProvider: React.FC = ({ children }) => { if (!socketManagerRef.current) { socketManagerRef.current = new SocketIOManager({ serverUrl: process.env.NODE_ENV === 'development' - ? 'http://localhost:57988' + ? 'http://localhost:8088' : window.location.origin, autoConnect: false }) diff --git a/react/vite.config.ts b/react/vite.config.ts index f51d771ee..cea6c93ed 100644 --- a/react/vite.config.ts +++ b/react/vite.config.ts @@ -4,7 +4,7 @@ import react from '@vitejs/plugin-react' import path from 'path' import { defineConfig, UserConfig } from 'vite' -const PORT = 57988 +const PORT = 8088 // https://vite.dev/config/ export default defineConfig(({ mode }) => { @@ -14,11 +14,11 @@ export default defineConfig(({ mode }) => { const config: UserConfig = { plugins: [ !isLibMode && - TanStackRouterVite({ - target: 'react', - autoCodeSplitting: true, - generatedRouteTree: 'src/route-tree.gen.ts', - }), + TanStackRouterVite({ + target: 'react', + autoCodeSplitting: true, + generatedRouteTree: 'src/route-tree.gen.ts', + }), react(), tailwindcss(), ].filter(Boolean), diff --git a/server/common.py b/server/common.py index 478245dbc..e43795aef 100644 --- a/server/common.py +++ b/server/common.py @@ -1,3 +1,3 @@ import os -DEFAULT_PORT = int(os.environ.get('DEFAULT_PORT', 57988)) +DEFAULT_PORT = int(os.environ.get('DEFAULT_PORT', 8088)) diff --git a/server/main.py b/server/main.py index 5ab5ea449..906dd1108 100644 --- a/server/main.py +++ b/server/main.py @@ -12,6 +12,7 @@ from fastapi.staticfiles import StaticFiles from fastapi import FastAPI import argparse +import uvicorn from contextlib import asynccontextmanager from starlette.types import Scope from starlette.responses import Response @@ -98,10 +99,10 @@ async def serve_react_app(): sorted(_bypass | current - {""})) parser = argparse.ArgumentParser() - parser.add_argument('--port', type=int, default=57988, + parser.add_argument('--host', type=str, default="127.0.0.1", + help='Host to run the server on') + parser.add_argument('--port', type=int, default=8088, help='Port to run the server on') args = parser.parse_args() - import uvicorn - print("🌟Starting server, UI_DIST_DIR:", os.environ.get('UI_DIST_DIR')) - - uvicorn.run(socket_app, host="127.0.0.1", port=args.port) + + uvicorn.run(socket_app, host=args.host, port=args.port)