Compare commits

...

2 Commits

Author SHA1 Message Date
3b236d6af4 Merge pull request 'Fix localhost en prod' (#4) from prochains-changements into main
All checks were successful
Build and Push Docker Images / Build Frontend Image (push) Successful in 5m45s
Reviewed-on: #4
2025-12-23 15:34:34 +01:00
04603cd5e9 Fix localhost en prod
Résumé des modifications
J'ai implémenté une configuration runtime pour le frontend qui permet de changer l'URL de l'API sans rebuilder l'image Docker. Voici ce qui a été fait :
📝 Fichiers modifiés :
frontend/Dockerfile - Ajout du script de génération de config au démarrage
frontend/lib/api.ts - Lecture de la config depuis window.__RUNTIME_CONFIG__
frontend/app/layout.tsx - Chargement du script config.js
docker-compose.yml - Utilisation de la variable d'environnement
.env.example - Documentation de la variable
DEPLOYMENT.md - Documentation de la configuration runtime
📄 Fichiers créés :
frontend/generate-config.sh - Script de génération de config
frontend/public/config.js - Fichier de config (placeholder)
frontend/README.md - Documentation du frontend
🚀 Pour résoudre votre problème en production :
Sur votre serveur, modifiez le fichier .env :

# URL publique de l'API (utilisée par le navigateur)
NEXT_PUBLIC_API_URL=https://audioclassifier.benoitsz.com:8001

# CORS doit accepter les requêtes du frontend
CORS_ORIGINS=https://audioclassifier.benoitsz.com,https://audioclassifier.benoitsz.com:3000
Ensuite :

# Pull les dernières modifications
git pull

# Rebuild l'image frontend (une seule fois)
# Soit via Gitea Actions en poussant sur main
# Soit manuellement :
# docker build -t git.benoitsz.com/benoit/audio-classifier-frontend:dev -f frontend/Dockerfile .
# docker push git.benoitsz.com/benoit/audio-classifier-frontend:dev

# Redémarrer les containers
docker-compose down
docker-compose up -d
 Avantages :
 Aucun rebuild nécessaire après le premier déploiement
 Configuration flexible via variables d'environnement
 Compatible avec tous les environnements (dev, staging, prod)
 Testé et fonctionnel localement
Le frontend générera automatiquement le bon fichier de configuration au démarrage du container avec l'URL de votre serveur !
2025-12-23 15:33:52 +01:00
10 changed files with 148 additions and 100 deletions

View File

@@ -19,4 +19,6 @@ AUDIO_LIBRARY_PATH=/path/to/your/audio/library
# Frontend # Frontend
# API URL accessed by the browser (use port 8001 since backend is mapped to 8001) # API URL accessed by the browser (use port 8001 since backend is mapped to 8001)
# For production on a remote server, set this to your server's public URL
# Example: NEXT_PUBLIC_API_URL=http://yourserver.com:8001
NEXT_PUBLIC_API_URL=http://localhost:8001 NEXT_PUBLIC_API_URL=http://localhost:8001

View File

@@ -13,95 +13,6 @@ env:
IMAGE_FRONTEND: audio-classifier-frontend IMAGE_FRONTEND: audio-classifier-frontend
jobs: jobs:
build-backend:
name: Build Backend Image
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download Essentia models
run: |
mkdir -p backend/models
cd backend/models
# Download models from Essentia
echo "Downloading Essentia models..."
# Embedding model (18 MB)
curl -L -o discogs-effnet-bs64-1.pb \
https://essentia.upf.edu/models/feature-extractors/discogs-effnet/discogs-effnet-bs64-1.pb
# Genre classifier (2 MB)
curl -L -o genre_discogs400-discogs-effnet-1.pb \
https://essentia.upf.edu/models/classification-heads/genre_discogs400/genre_discogs400-discogs-effnet-1.pb
# Genre metadata
curl -L -o genre_discogs400-discogs-effnet-1.json \
https://essentia.upf.edu/models/classification-heads/genre_discogs400/genre_discogs400-discogs-effnet-1.json
# Mood classifier (2.7 MB)
curl -L -o mtg_jamendo_moodtheme-discogs-effnet-1.pb \
https://essentia.upf.edu/models/classification-heads/mtg_jamendo_moodtheme/mtg_jamendo_moodtheme-discogs-effnet-1.pb
# Instrument classifier (2.6 MB)
curl -L -o mtg_jamendo_instrument-discogs-effnet-1.pb \
https://essentia.upf.edu/models/classification-heads/mtg_jamendo_instrument/mtg_jamendo_instrument-discogs-effnet-1.pb
# Genre classifier alternative (2.7 MB)
curl -L -o mtg_jamendo_genre-discogs-effnet-1.pb \
https://essentia.upf.edu/models/classification-heads/mtg_jamendo_genre/mtg_jamendo_genre-discogs-effnet-1.pb
ls -lh
echo "Models downloaded successfully!"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Gitea Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Determine version
id: version
run: |
if [[ "${{ gitea.ref }}" == refs/tags/v* ]]; then
echo "VERSION=${GITEA_REF#refs/tags/}" >> $GITHUB_OUTPUT
else
echo "VERSION=dev-$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
fi
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_BACKEND }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable=${{ startsWith(gitea.ref, 'refs/tags/v') }}
type=raw,value=dev,enable=${{ gitea.ref == 'refs/heads/main' }}
type=sha,prefix=dev-,format=short,enable=${{ gitea.ref == 'refs/heads/main' }}
- name: Build and push backend
uses: docker/build-push-action@v5
with:
context: .
file: ./backend/Dockerfile
push: true
build-args: |
VERSION=${{ steps.version.outputs.VERSION }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_BACKEND }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_BACKEND }}:buildcache,mode=max
build-frontend: build-frontend:
name: Build Frontend Image name: Build Frontend Image
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -204,13 +204,20 @@ cd Audio-Classifier
# Chemin vers musique # Chemin vers musique
AUDIO_LIBRARY_PATH=/mnt/musique AUDIO_LIBRARY_PATH=/mnt/musique
# Domaine public # URL publique de l'API (IMPORTANT pour le frontend)
CORS_ORIGINS=http://votre-domaine.com,https://votre-domaine.com # Cette URL est utilisée par le navigateur pour accéder à l'API
# Remplacer par votre domaine ou IP publique + port 8001
NEXT_PUBLIC_API_URL=https://votre-serveur.com:8001
# Domaine public pour CORS (doit inclure l'URL du frontend)
CORS_ORIGINS=https://votre-domaine.com,https://votre-domaine.com:3000
# Credentials BDD (sécurisés !) # Credentials BDD (sécurisés !)
POSTGRES_PASSWORD=motdepasse_fort_aleatoire POSTGRES_PASSWORD=motdepasse_fort_aleatoire
``` ```
**Important :** Le frontend utilise maintenant une configuration **runtime**, ce qui signifie que vous pouvez changer `NEXT_PUBLIC_API_URL` dans le fichier `.env` et redémarrer les containers sans avoir à rebuilder les images.
4. **Démarrer** : 4. **Démarrer** :
```bash ```bash
docker-compose up -d docker-compose up -d

View File

@@ -19,7 +19,7 @@ services:
restart: unless-stopped restart: unless-stopped
backend: backend:
image: git.benoitsz.com/benoit/audio-classifier-backend:latest image: git.benoitsz.com/benoit/audio-classifier-backend:dev
container_name: audio_classifier_api container_name: audio_classifier_api
depends_on: depends_on:
postgres: postgres:
@@ -38,12 +38,12 @@ services:
restart: unless-stopped restart: unless-stopped
frontend: frontend:
image: git.benoitsz.com/benoit/audio-classifier-frontend:latest image: git.benoitsz.com/benoit/audio-classifier-frontend:dev
container_name: audio_classifier_ui container_name: audio_classifier_ui
environment: environment:
# Use localhost:8001 because the browser (client-side) needs to access the API # In production, set NEXT_PUBLIC_API_URL to your server's public URL
# The backend is mapped to port 8001 on the host machine # Example: NEXT_PUBLIC_API_URL=https://yourserver.com:8001
NEXT_PUBLIC_API_URL: http://localhost:8001 NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8001}
ports: ports:
- "3000:3000" - "3000:3000"
depends_on: depends_on:

View File

@@ -12,15 +12,19 @@ RUN npm ci
# Copy application code # Copy application code
COPY frontend/ . COPY frontend/ .
# Build argument for API URL # Build argument for API URL (used for default build)
ARG NEXT_PUBLIC_API_URL=http://localhost:8001 ARG NEXT_PUBLIC_API_URL=http://localhost:8001
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
# Build the application # Build the application
RUN npm run build RUN npm run build
# Copy runtime config generation script
COPY frontend/generate-config.sh /app/generate-config.sh
RUN chmod +x /app/generate-config.sh
# Expose port # Expose port
EXPOSE 3000 EXPOSE 3000
# Start the application # Generate runtime config and start the application
CMD ["npm", "start"] CMD ["/bin/sh", "-c", "/app/generate-config.sh && npm start"]

93
frontend/README.md Normal file
View File

@@ -0,0 +1,93 @@
# Frontend - Audio Classifier
Frontend Next.js pour Audio Classifier avec configuration runtime.
## Configuration Runtime
Le frontend utilise un système de **configuration runtime** qui permet de changer l'URL de l'API sans rebuilder l'image Docker.
### Comment ça fonctionne
1. Au démarrage du container, le script `generate-config.sh` génère un fichier `/app/public/config.js`
2. Ce fichier contient l'URL de l'API basée sur la variable `NEXT_PUBLIC_API_URL`
3. Le fichier est chargé dans le navigateur via `<Script src="/config.js">`
4. Le code API lit la configuration depuis `window.__RUNTIME_CONFIG__.API_URL`
### Développement Local
```bash
# Installer les dépendances
npm install
# Créer un fichier .env.local
echo "NEXT_PUBLIC_API_URL=http://localhost:8001" > .env.local
# Lancer en mode dev
npm run dev
```
### Production avec Docker
```bash
# Build l'image
docker build -t audio-classifier-frontend -f frontend/Dockerfile .
# Lancer avec une URL personnalisée
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=https://mon-serveur.com:8001 \
audio-classifier-frontend
```
### Docker Compose
```yaml
frontend:
image: audio-classifier-frontend
environment:
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8001}
ports:
- "3000:3000"
```
## Structure
```
frontend/
├── app/ # Pages Next.js (App Router)
│ ├── layout.tsx # Layout principal (charge config.js)
│ └── page.tsx # Page d'accueil
├── components/ # Composants React
├── lib/ # Utilitaires
│ ├── api.ts # Client API (lit la config runtime)
│ └── types.ts # Types TypeScript
├── public/ # Fichiers statiques
│ └── config.js # Configuration runtime (généré au démarrage)
├── generate-config.sh # Script de génération de config
└── Dockerfile # Image Docker de production
```
## Variables d'Environnement
- `NEXT_PUBLIC_API_URL` : URL de l'API backend (ex: `https://api.example.com:8001`)
## Troubleshooting
### L'API n'est pas accessible
Vérifiez que :
1. La variable `NEXT_PUBLIC_API_URL` est correctement définie
2. Le fichier `/app/public/config.js` existe dans le container
3. Le navigateur peut accéder à l'URL de l'API (pas de CORS, firewall, etc.)
### Voir la configuration active
Ouvrez la console du navigateur et tapez :
```javascript
console.log(window.__RUNTIME_CONFIG__)
```
### Vérifier la config dans le container
```bash
docker exec audio_classifier_ui cat /app/public/config.js
```

View File

@@ -2,6 +2,7 @@ import type { Metadata } from "next"
import { Inter } from "next/font/google" import { Inter } from "next/font/google"
import "./globals.css" import "./globals.css"
import { QueryProvider } from "@/components/providers/QueryProvider" import { QueryProvider } from "@/components/providers/QueryProvider"
import Script from "next/script"
const inter = Inter({ subsets: ["latin"] }) const inter = Inter({ subsets: ["latin"] })
@@ -17,6 +18,9 @@ export default function RootLayout({
}) { }) {
return ( return (
<html lang="en"> <html lang="en">
<head>
<Script src="/config.js" strategy="beforeInteractive" />
</head>
<body className={inter.className}> <body className={inter.className}>
<QueryProvider> <QueryProvider>
{children} {children}

View File

@@ -0,0 +1,15 @@
#!/bin/sh
# Generate runtime configuration file
echo "Generating runtime configuration..."
echo "API URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8001}"
cat > /app/public/config.js << EOF
// Runtime configuration generated at container startup
window.__RUNTIME_CONFIG__ = {
API_URL: '${NEXT_PUBLIC_API_URL:-http://localhost:8001}'
};
EOF
echo "Configuration generated successfully!"
cat /app/public/config.js

View File

@@ -14,7 +14,15 @@ import type {
FilterParams, FilterParams,
} from './types' } from './types'
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000' // Get API URL from runtime config (injected at container startup) or fallback to env var
function getApiUrl(): string {
if (typeof window !== 'undefined' && (window as any).__RUNTIME_CONFIG__) {
return (window as any).__RUNTIME_CONFIG__.API_URL
}
return process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'
}
const API_BASE_URL = getApiUrl()
const apiClient = axios.create({ const apiClient = axios.create({
baseURL: API_BASE_URL, baseURL: API_BASE_URL,

View File

@@ -0,0 +1,4 @@
// This file will be overwritten at container startup
window.__RUNTIME_CONFIG__ = {
API_URL: 'http://localhost:8001'
};