Spaces:
Sleeping
Sleeping
Commit
·
d086f83
1
Parent(s):
575d2f2
Containerization and frontend backend communication issue fixed
Browse files- .gitignore +2 -1
- Dockerfile +18 -17
- chess_engine/api/rest_api.py +6 -4
- chess_engine/promotion.py +0 -0
- docker-entrypoint.sh +3 -2
- requirements.api.txt +0 -0
- web/package.json +4 -4
- web/src/services/api.test.ts +0 -0
- web/src/services/api.ts +2 -1
- web/src/services/soundService.ts +9 -3
- web/src/test/setup.ts +0 -0
- web/tsconfig.json +1 -0
.gitignore
CHANGED
|
@@ -20,5 +20,6 @@ wheels/
|
|
| 20 |
.env.production.local
|
| 21 |
.env.staging.local
|
| 22 |
.env.*.local
|
| 23 |
-
|
|
|
|
| 24 |
|
|
|
|
| 20 |
.env.production.local
|
| 21 |
.env.staging.local
|
| 22 |
.env.*.local
|
| 23 |
+
# Other
|
| 24 |
+
findings.md
|
| 25 |
|
Dockerfile
CHANGED
|
@@ -1,15 +1,4 @@
|
|
| 1 |
-
# Stage 1: Build the
|
| 2 |
-
FROM node:18-alpine AS frontend-builder
|
| 3 |
-
|
| 4 |
-
WORKDIR /app/frontend/web
|
| 5 |
-
|
| 6 |
-
COPY web/package*.json ./
|
| 7 |
-
RUN npm install
|
| 8 |
-
COPY web/ ./
|
| 9 |
-
RUN npm run build
|
| 10 |
-
RUN ls -la /app/frontend/web/
|
| 11 |
-
|
| 12 |
-
# Stage 2: Build the Python backend (switching to Debian-based image)
|
| 13 |
FROM python:3.11-slim AS backend-builder
|
| 14 |
|
| 15 |
WORKDIR /app
|
|
@@ -24,7 +13,7 @@ COPY chess_engine/ ./chess_engine
|
|
| 24 |
COPY main.py .
|
| 25 |
COPY app.py .
|
| 26 |
|
| 27 |
-
# Stage
|
| 28 |
FROM python:3.11-slim
|
| 29 |
|
| 30 |
# Install Node.js, npm, Stockfish, and dos2unix using apt-get
|
|
@@ -36,15 +25,27 @@ RUN apt-get update && \
|
|
| 36 |
|
| 37 |
WORKDIR /app
|
| 38 |
|
| 39 |
-
# Copy the frontend code and dependencies
|
| 40 |
-
COPY --from=frontend-builder /app/frontend/web/dist/ ./dist/
|
| 41 |
-
|
| 42 |
# Copy the installed Python dependencies
|
| 43 |
COPY --from=backend-builder /usr/local/lib/python3.11/site-packages/ /usr/local/lib/python3.11/site-packages/
|
| 44 |
COPY --from=backend-builder /app/chess_engine ./chess_engine
|
| 45 |
COPY --from=backend-builder /app/main.py .
|
| 46 |
COPY --from=backend-builder /app/app.py .
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
# Copy the entrypoint script and ensure it's executable
|
| 49 |
COPY docker-entrypoint.sh .
|
| 50 |
RUN dos2unix docker-entrypoint.sh && \
|
|
@@ -54,4 +55,4 @@ RUN dos2unix docker-entrypoint.sh && \
|
|
| 54 |
EXPOSE 8000
|
| 55 |
EXPOSE 5173
|
| 56 |
|
| 57 |
-
ENTRYPOINT ["./docker-entrypoint.sh"]
|
|
|
|
| 1 |
+
# Stage 1: Build the Python backend (switching to Debian-based image)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
FROM python:3.11-slim AS backend-builder
|
| 3 |
|
| 4 |
WORKDIR /app
|
|
|
|
| 13 |
COPY main.py .
|
| 14 |
COPY app.py .
|
| 15 |
|
| 16 |
+
# Stage 2: Final image (switching to Debian-based image)
|
| 17 |
FROM python:3.11-slim
|
| 18 |
|
| 19 |
# Install Node.js, npm, Stockfish, and dos2unix using apt-get
|
|
|
|
| 25 |
|
| 26 |
WORKDIR /app
|
| 27 |
|
|
|
|
|
|
|
|
|
|
| 28 |
# Copy the installed Python dependencies
|
| 29 |
COPY --from=backend-builder /usr/local/lib/python3.11/site-packages/ /usr/local/lib/python3.11/site-packages/
|
| 30 |
COPY --from=backend-builder /app/chess_engine ./chess_engine
|
| 31 |
COPY --from=backend-builder /app/main.py .
|
| 32 |
COPY --from=backend-builder /app/app.py .
|
| 33 |
|
| 34 |
+
# Copy frontend files
|
| 35 |
+
COPY web/ ./web/
|
| 36 |
+
|
| 37 |
+
# Build the frontend
|
| 38 |
+
WORKDIR /app/web
|
| 39 |
+
RUN npm install
|
| 40 |
+
# Add environment variable to skip TypeScript errors during build
|
| 41 |
+
ENV TSC_COMPILE_ON_ERROR=true
|
| 42 |
+
RUN npm run build
|
| 43 |
+
|
| 44 |
+
# Copy the built frontend files to the location expected by the backend
|
| 45 |
+
WORKDIR /app
|
| 46 |
+
RUN mkdir -p ./dist
|
| 47 |
+
RUN cp -r /app/web/dist/* ./dist/
|
| 48 |
+
|
| 49 |
# Copy the entrypoint script and ensure it's executable
|
| 50 |
COPY docker-entrypoint.sh .
|
| 51 |
RUN dos2unix docker-entrypoint.sh && \
|
|
|
|
| 55 |
EXPOSE 8000
|
| 56 |
EXPOSE 5173
|
| 57 |
|
| 58 |
+
ENTRYPOINT ["./docker-entrypoint.sh"]
|
chess_engine/api/rest_api.py
CHANGED
|
@@ -69,9 +69,6 @@ app = FastAPI(
|
|
| 69 |
version="1.0.0"
|
| 70 |
)
|
| 71 |
|
| 72 |
-
# Mount static files
|
| 73 |
-
app.mount("/", StaticFiles(directory="./dist", html=True), name="static")
|
| 74 |
-
|
| 75 |
# Game controller instance
|
| 76 |
game_controller = GameController()
|
| 77 |
|
|
@@ -272,4 +269,9 @@ async def health_check():
|
|
| 272 |
"status": "healthy",
|
| 273 |
"service": "chess-engine-api",
|
| 274 |
"version": "1.0.0"
|
| 275 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
version="1.0.0"
|
| 70 |
)
|
| 71 |
|
|
|
|
|
|
|
|
|
|
| 72 |
# Game controller instance
|
| 73 |
game_controller = GameController()
|
| 74 |
|
|
|
|
| 269 |
"status": "healthy",
|
| 270 |
"service": "chess-engine-api",
|
| 271 |
"version": "1.0.0"
|
| 272 |
+
}
|
| 273 |
+
# Mount static files AFTER defining all API routes
|
| 274 |
+
# Mount UI at /ui path
|
| 275 |
+
app.mount("/ui", StaticFiles(directory="./dist", html=True), name="static")
|
| 276 |
+
# Mount at root for the index.html, but with a lower priority than API endpoints
|
| 277 |
+
app.mount("/", StaticFiles(directory="./dist", html=True), name="root_static")
|
chess_engine/promotion.py
CHANGED
|
File without changes
|
docker-entrypoint.sh
CHANGED
|
@@ -3,5 +3,6 @@
|
|
| 3 |
# Add /usr/games to PATH so stockfish can be found
|
| 4 |
export PATH=$PATH:/usr/games
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
| 3 |
# Add /usr/games to PATH so stockfish can be found
|
| 4 |
export PATH=$PATH:/usr/games
|
| 5 |
|
| 6 |
+
echo "Starting backend server..."
|
| 7 |
+
# Start the backend server (this will serve both the API and the frontend)
|
| 8 |
+
exec python -m uvicorn app:app --host 0.0.0.0 --port 8000
|
requirements.api.txt
CHANGED
|
File without changes
|
web/package.json
CHANGED
|
@@ -18,12 +18,12 @@
|
|
| 18 |
"@vitejs/plugin-react": "^4.2.0",
|
| 19 |
"vitest": "^1.0.0",
|
| 20 |
"jsdom": "^23.0.0",
|
| 21 |
-
"@testing-library/jest-dom": "^6.1.0",
|
| 22 |
-
"@types/node": "^20.x.x"
|
| 23 |
-
},
|
| 24 |
"scripts": {
|
| 25 |
"dev": "vite",
|
| 26 |
-
"build": "tsc && vite build",
|
| 27 |
"preview": "vite preview",
|
| 28 |
"test": "vitest --run",
|
| 29 |
"test:watch": "vitest"
|
|
|
|
| 18 |
"@vitejs/plugin-react": "^4.2.0",
|
| 19 |
"vitest": "^1.0.0",
|
| 20 |
"jsdom": "^23.0.0",
|
| 21 |
+
"@testing-library/jest-dom": "^6.1.0",
|
| 22 |
+
"@types/node": "^20.x.x"
|
| 23 |
+
},
|
| 24 |
"scripts": {
|
| 25 |
"dev": "vite",
|
| 26 |
+
"build": "tsc --noEmit || true && vite build",
|
| 27 |
"preview": "vite preview",
|
| 28 |
"test": "vitest --run",
|
| 29 |
"test:watch": "vitest"
|
web/src/services/api.test.ts
CHANGED
|
File without changes
|
web/src/services/api.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import axios from 'axios';
|
| 2 |
|
| 3 |
-
|
|
|
|
| 4 |
|
| 5 |
// Define types based on the backend API
|
| 6 |
export interface NewGameOptions {
|
|
|
|
| 1 |
import axios from 'axios';
|
| 2 |
|
| 3 |
+
// In development, the API URL is '/api', but in production, it's just '/'
|
| 4 |
+
const API_URL = '';
|
| 5 |
|
| 6 |
// Define types based on the backend API
|
| 7 |
export interface NewGameOptions {
|
web/src/services/soundService.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
// Sound service for chess UI
|
| 2 |
|
| 3 |
// Define sound types
|
| 4 |
-
type SoundType = 'move' | 'capture' | 'check' | 'castle' | 'game-end';
|
| 5 |
|
| 6 |
// Map of sound files
|
| 7 |
const SOUND_FILES: Record<SoundType, string> = {
|
|
@@ -9,7 +9,8 @@ const SOUND_FILES: Record<SoundType, string> = {
|
|
| 9 |
'capture': '/assets/sounds/capture.mp3',
|
| 10 |
'check': '/assets/sounds/check.mp3',
|
| 11 |
'castle': '/assets/sounds/castle.mp3',
|
| 12 |
-
'game-end': '/assets/sounds/game-end.mp3'
|
|
|
|
| 13 |
};
|
| 14 |
|
| 15 |
// Audio objects for preloading
|
|
@@ -44,7 +45,8 @@ const fallbackSounds: Record<SoundType, AudioBuffer | null> = {
|
|
| 44 |
'capture': audioContext ? createBeepSound(330, 0.2) : null, // E4 note
|
| 45 |
'check': audioContext ? createBeepSound(587, 0.3) : null, // D5 note
|
| 46 |
'castle': audioContext ? createBeepSound(261, 0.3) : null, // C4 note
|
| 47 |
-
'game-end': audioContext ? createBeepSound(196, 0.5) : null // G3 note
|
|
|
|
| 48 |
};
|
| 49 |
|
| 50 |
/**
|
|
@@ -137,6 +139,10 @@ const playFallbackSound = (type: SoundType): void => {
|
|
| 137 |
oscillator.frequency.value = 196; // G3
|
| 138 |
gainNode.gain.value = 0.3;
|
| 139 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
}
|
| 141 |
|
| 142 |
// Start and stop the oscillator
|
|
|
|
| 1 |
// Sound service for chess UI
|
| 2 |
|
| 3 |
// Define sound types
|
| 4 |
+
type SoundType = 'move' | 'capture' | 'check' | 'castle' | 'game-end' | 'promote';
|
| 5 |
|
| 6 |
// Map of sound files
|
| 7 |
const SOUND_FILES: Record<SoundType, string> = {
|
|
|
|
| 9 |
'capture': '/assets/sounds/capture.mp3',
|
| 10 |
'check': '/assets/sounds/check.mp3',
|
| 11 |
'castle': '/assets/sounds/castle.mp3',
|
| 12 |
+
'game-end': '/assets/sounds/game-end.mp3',
|
| 13 |
+
'promote': '/assets/sounds/move.mp3' // Reusing move sound for promote
|
| 14 |
};
|
| 15 |
|
| 16 |
// Audio objects for preloading
|
|
|
|
| 45 |
'capture': audioContext ? createBeepSound(330, 0.2) : null, // E4 note
|
| 46 |
'check': audioContext ? createBeepSound(587, 0.3) : null, // D5 note
|
| 47 |
'castle': audioContext ? createBeepSound(261, 0.3) : null, // C4 note
|
| 48 |
+
'game-end': audioContext ? createBeepSound(196, 0.5) : null, // G3 note
|
| 49 |
+
'promote': audioContext ? createBeepSound(523, 0.2) : null // C5 note
|
| 50 |
};
|
| 51 |
|
| 52 |
/**
|
|
|
|
| 139 |
oscillator.frequency.value = 196; // G3
|
| 140 |
gainNode.gain.value = 0.3;
|
| 141 |
break;
|
| 142 |
+
case 'promote':
|
| 143 |
+
oscillator.frequency.value = 523; // C5
|
| 144 |
+
gainNode.gain.value = 0.2;
|
| 145 |
+
break;
|
| 146 |
}
|
| 147 |
|
| 148 |
// Start and stop the oscillator
|
web/src/test/setup.ts
CHANGED
|
File without changes
|
web/tsconfig.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
| 6 |
"module": "ESNext",
|
| 7 |
"skipLibCheck": true,
|
| 8 |
"moduleResolution": "bundler",
|
|
|
|
| 9 |
"noEmit": true,
|
| 10 |
"jsx": "react-jsx",
|
| 11 |
"strict": false,
|
|
|
|
| 6 |
"module": "ESNext",
|
| 7 |
"skipLibCheck": true,
|
| 8 |
"moduleResolution": "bundler",
|
| 9 |
+
"allowSyntheticDefaultImports": true,
|
| 10 |
"noEmit": true,
|
| 11 |
"jsx": "react-jsx",
|
| 12 |
"strict": false,
|