Compare commits
8 Commits
560c07d5c3
...
v0.18.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 5bc038acd8 | |||
| f347dcd357 | |||
| 46fea8d53c | |||
| e05b26563f | |||
| dc66199177 | |||
| b133d0f16d | |||
| 024d37dea6 | |||
| 997aadf5b5 |
80
.github/workflows/desktop-release.yml
vendored
80
.github/workflows/desktop-release.yml
vendored
@@ -1,12 +1,12 @@
|
|||||||
name: Desktop installers
|
name: Desktop installers
|
||||||
|
|
||||||
# Produit les installeurs de BUREAU (.msi Windows pour l'instant) et les publie
|
# Produit les installeurs de BUREAU (.msi Windows + AppImage Linux) et les publie
|
||||||
# en tant qu'assets d'une GitHub Release, sur tag `v*`.
|
# en tant qu'assets d'une GitHub Release, sur tag `v*`.
|
||||||
#
|
#
|
||||||
# Complementaire au pipeline Gitea Actions (.gitea/workflows/release.yml) qui,
|
# Complementaire au pipeline Gitea Actions (.gitea/workflows/release.yml) qui,
|
||||||
# lui, build et pousse les IMAGES Docker. Ici on est sur GitHub car jpackage et
|
# lui, build et pousse les IMAGES Docker. Ici on est sur GitHub car jpackage ne
|
||||||
# PyInstaller ne savent PAS cross-compiler : le .msi DOIT etre construit sur un
|
# sait PAS cross-compiler : le .msi DOIT etre construit sur un runner Windows et
|
||||||
# runner Windows, et GitHub en fournit gratuitement (windows-latest).
|
# l'AppImage sur un runner Linux — GitHub fournit les deux gratuitement.
|
||||||
#
|
#
|
||||||
# Prerequis : le depot Gitea doit etre mirrore vers GitHub (push mirror, tags
|
# Prerequis : le depot Gitea doit etre mirrore vers GitHub (push mirror, tags
|
||||||
# inclus) pour que le tag declenche ce workflow.
|
# inclus) pour que le tag declenche ce workflow.
|
||||||
@@ -191,6 +191,72 @@ jobs:
|
|||||||
path: core/target/dist-out/*.msi
|
path: core/target/dist-out/*.msi
|
||||||
retention-days: 90
|
retention-days: 90
|
||||||
|
|
||||||
# TODO (plus tard) : job `linux` sur ubuntu-latest produisant un AppImage
|
# LINUX : AppImage (1 fichier, toutes distros) attache a la MEME release.
|
||||||
# (jpackage --type app-image + appimagetool) + PyInstaller Linux du Brain,
|
# Tourne sur ubuntu-latest (jpackage ne cross-compile pas -> build natif Linux).
|
||||||
# attache a la MEME release. Reutilise la meme matrice / les memes etapes.
|
# Brain empaquete via python-build-standalone (pas de Python embeddable Linux
|
||||||
|
# officiel ; pas de PyInstaller -> pas de faux positif AV). Memes regles de
|
||||||
|
# publication que windows : stable -> release publique ; beta -> artefact prive.
|
||||||
|
linux:
|
||||||
|
needs: tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', inputs.version) || github.ref }}
|
||||||
|
|
||||||
|
# Apporte jpackage (empaquetage natif) dans le PATH.
|
||||||
|
- name: Set up JDK 21
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: '21'
|
||||||
|
|
||||||
|
- name: Set up Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
# Pas de setup-python : le Brain utilise SON python-build-standalone
|
||||||
|
# (telecharge par le script, avec son propre pip). Le host n'en a pas besoin.
|
||||||
|
|
||||||
|
# Version (numerique X.Y.Z) + tag + isbeta, comme le job windows.
|
||||||
|
- name: Derive version
|
||||||
|
id: ver
|
||||||
|
run: |
|
||||||
|
if [ '${{ github.event_name }}' = 'workflow_dispatch' ]; then
|
||||||
|
raw='${{ inputs.version }}'
|
||||||
|
else
|
||||||
|
raw='${{ github.ref_name }}'
|
||||||
|
fi
|
||||||
|
raw="${raw#v}" # 0.15.0 ou 0.15.0-beta
|
||||||
|
num="${raw%%-*}" # 0.15.0
|
||||||
|
case "$raw" in *-beta*) isbeta=true ;; *) isbeta=false ;; esac
|
||||||
|
echo "version=$num" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "tag=v$raw" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "isbeta=$isbeta" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Build Linux AppImage
|
||||||
|
env:
|
||||||
|
# Authentifie l'appel API GitHub (resolution python-build-standalone) :
|
||||||
|
# evite le rate limit 60/h anonyme des runners partages.
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
run: bash ./installers/desktop/build-linux.sh --version ${{ steps.ver.outputs.version }}
|
||||||
|
|
||||||
|
# STABLE uniquement : attache l'AppImage a la release publique (meme tag que
|
||||||
|
# le .msi -> les deux installeurs sur la meme release).
|
||||||
|
- name: Publish AppImage to GitHub Release (stable)
|
||||||
|
if: ${{ steps.ver.outputs.isbeta == 'false' }}
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: ${{ steps.ver.outputs.tag }}
|
||||||
|
files: core/target/dist-out/DM_Loremind*.AppImage
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
|
||||||
|
# BETA uniquement : artefact PRIVE (pas de release publique).
|
||||||
|
- name: Upload AppImage as private artifact (beta)
|
||||||
|
if: ${{ steps.ver.outputs.isbeta == 'true' }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: loremind-beta-${{ steps.ver.outputs.version }}-appimage
|
||||||
|
path: core/target/dist-out/DM_Loremind*.AppImage
|
||||||
|
retention-days: 90
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from app.infrastructure.ollama_model_installer import ensure_ollama_embedding_mo
|
|||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="LoreMind Brain",
|
title="LoreMind Brain",
|
||||||
description="Backend IA pour la génération de contenu narratif.",
|
description="Backend IA pour la génération de contenu narratif.",
|
||||||
version="0.17.0",
|
version="0.18.0",
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ sys.path.insert(0, _HERE)
|
|||||||
# AVANT que l'app n'importe le pdf_extractor (qui détecte la version au chargement).
|
# AVANT que l'app n'importe le pdf_extractor (qui détecte la version au chargement).
|
||||||
# tessdata (fra+eng) est embarqué dans tesseract/tessdata. Sans ce bloc, l'OCR
|
# tessdata (fra+eng) est embarqué dans tesseract/tessdata. Sans ce bloc, l'OCR
|
||||||
# reste désactivé en dégradation gracieuse (PDF born-digital OK, scans signalés).
|
# reste désactivé en dégradation gracieuse (PDF born-digital OK, scans signalés).
|
||||||
_TESS = os.path.join(_HERE, "tesseract", "tesseract.exe")
|
# Binaire selon l'OS : tesseract.exe (Windows embeddable) ou tesseract (Linux/Mac).
|
||||||
|
# Si aucun Tesseract n'est bundlé (cas Linux/AppImage par défaut), le bloc est
|
||||||
|
# sauté et pytesseract retombe sur le tesseract SYSTÈME du PATH (ex. apt install
|
||||||
|
# tesseract-ocr) — sinon OCR désactivé en dégradation gracieuse.
|
||||||
|
_TESS = os.path.join(_HERE, "tesseract", "tesseract.exe" if os.name == "nt" else "tesseract")
|
||||||
if os.path.exists(_TESS):
|
if os.path.exists(_TESS):
|
||||||
os.environ.setdefault("TESSDATA_PREFIX", os.path.join(_HERE, "tesseract"))
|
os.environ.setdefault("TESSDATA_PREFIX", os.path.join(_HERE, "tesseract"))
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<groupId>com.loremind</groupId>
|
<groupId>com.loremind</groupId>
|
||||||
<artifactId>loremind-core</artifactId>
|
<artifactId>loremind-core</artifactId>
|
||||||
<version>0.17.0</version>
|
<version>0.18.0</version>
|
||||||
<name>LoreMind Core</name>
|
<name>LoreMind Core</name>
|
||||||
<description>Backend Core - Architecture Hexagonale</description>
|
<description>Backend Core - Architecture Hexagonale</description>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.springframework.context.annotation.Profile;
|
|||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.awt.SplashScreen;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* En mode bureau (profil "local"), ouvre le navigateur par defaut sur
|
* En mode bureau (profil "local"), ouvre le navigateur par defaut sur
|
||||||
* l'application des que le serveur est pret. L'app n'ayant pas de fenetre
|
* l'application des que le serveur est pret. L'app n'ayant pas de fenetre
|
||||||
@@ -25,7 +27,26 @@ public class DesktopBrowserOpener {
|
|||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
public void onReady() {
|
public void onReady() {
|
||||||
|
// Ferme le splash natif (affiche par la JVM via -splash des le double-clic)
|
||||||
|
// juste avant d'ouvrir le navigateur : le relais visuel est assure.
|
||||||
|
closeSplash();
|
||||||
log.info("[Desktop] Application prete — ouverture du navigateur.");
|
log.info("[Desktop] Application prete — ouverture du navigateur.");
|
||||||
DesktopSingleInstance.openAppInBrowser();
|
DesktopSingleInstance.openAppInBrowser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ferme l'ecran de demarrage si l'app a ete lancee avec {@code -splash:...}
|
||||||
|
* (cas des installeurs jpackage). No-op silencieux sinon (lancement dev sans
|
||||||
|
* splash, ou environnement sans affichage).
|
||||||
|
*/
|
||||||
|
private void closeSplash() {
|
||||||
|
try {
|
||||||
|
SplashScreen splash = SplashScreen.getSplashScreen();
|
||||||
|
if (splash != null) {
|
||||||
|
splash.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("[Desktop] Pas de splash a fermer : {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
installers/desktop/app-icon.png
Normal file
BIN
installers/desktop/app-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
261
installers/desktop/build-linux.sh
Normal file
261
installers/desktop/build-linux.sh
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Construit l'application de BUREAU Linux de DM Loremind sous forme d'AppImage,
|
||||||
|
# sans Docker. Equivalent Linux de installers/desktop/build-windows.ps1.
|
||||||
|
#
|
||||||
|
# Pipeline complet "local-first" :
|
||||||
|
# 1. Build du front Angular (web/ -> web/dist/web)
|
||||||
|
# 2. Prep du Brain (Python standalone) (brain/ -> dist-embed-linux : python relocatable + deps + sources)
|
||||||
|
# 3. Build du Core en fat jar + front (core/ -> target/*.jar, profil Maven "desktop")
|
||||||
|
# 4. Assemblage de la charge utile (jar + brain) dans un dossier d'entree jpackage
|
||||||
|
# 5. jpackage --type app-image -> image applicative + JRE embarque
|
||||||
|
# 6. appimagetool -> DM_Loremind-x86_64.AppImage (1 fichier, toutes distros)
|
||||||
|
#
|
||||||
|
# L'app resultante se lance d'un double-clic (chmod +x puis ./*.AppImage) : le Core
|
||||||
|
# demarre en profil Spring "local" (H2 fichier + stockage filesystem) et lance lui-meme
|
||||||
|
# le Brain en sidecar. Aucune dependance externe (ni Docker, ni Java, ni Python).
|
||||||
|
#
|
||||||
|
# PREREQUIS (machine de BUILD Linux uniquement, PAS chez l'utilisateur final) :
|
||||||
|
# - JDK 21+ avec jpackage dans le PATH (Temurin OK).
|
||||||
|
# - Node.js + npm (build Angular) ; Maven via le wrapper du repo.
|
||||||
|
# - curl, tar, et FUSE *ou* (sur CI sans FUSE) on lance appimagetool en
|
||||||
|
# --appimage-extract-and-run (gere automatiquement ci-dessous).
|
||||||
|
# - Internet (telecharge python-build-standalone + appimagetool).
|
||||||
|
#
|
||||||
|
# IMPORTANT : jpackage NE cross-compile PAS. Ce script DOIT tourner sur Linux
|
||||||
|
# (machine, WSL, ou runner ubuntu-latest). Il ne produira rien d'utile sous Windows.
|
||||||
|
#
|
||||||
|
# Projet : DM Loremind — assistant pour Maitres de Jeu de JDR — Licence AGPL-3.0
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# --- Args ------------------------------------------------------------------
|
||||||
|
VERSION=""
|
||||||
|
SKIP_FRONT=0; SKIP_BRAIN=0; SKIP_JAR=0
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--version) VERSION="$2"; shift 2 ;;
|
||||||
|
--skip-front) SKIP_FRONT=1; shift ;;
|
||||||
|
--skip-brain) SKIP_BRAIN=1; shift ;;
|
||||||
|
--skip-jar) SKIP_JAR=1; shift ;;
|
||||||
|
*) echo "Option inconnue : $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
step() { printf '\033[36m==> %s\033[0m\n' "$1"; }
|
||||||
|
ok() { printf '\033[32m OK %s\033[0m\n' "$1"; }
|
||||||
|
err() { printf '\033[31m XX %s\033[0m\n' "$1" >&2; }
|
||||||
|
|
||||||
|
# --- Chemins ---------------------------------------------------------------
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
WEB_DIR="$REPO_ROOT/web"
|
||||||
|
BRAIN_DIR="$REPO_ROOT/brain"
|
||||||
|
CORE_DIR="$REPO_ROOT/core"
|
||||||
|
STAGE_DIR="$CORE_DIR/target/dist-input" # charge utile jpackage
|
||||||
|
OUT_DIR="$CORE_DIR/target/dist-out" # image applicative + AppImage produits
|
||||||
|
BRAIN_EMBED="$BRAIN_DIR/dist-embed-linux" # staging du brain empaquete (Linux)
|
||||||
|
ICON_PNG="$SCRIPT_DIR/app-icon.png" # icone de l'app (jpackage Linux exige un PNG)
|
||||||
|
APP_NAME="DM Loremind"
|
||||||
|
|
||||||
|
# python-build-standalone (Astral) : equivalent Linux du Python embeddable de
|
||||||
|
# python.org (qui n'existe que sous Windows). Build "install_only" = Python complet
|
||||||
|
# RELOCATABLE (pip inclus), donc on installe les deps directement dedans.
|
||||||
|
PY_MINOR="3.12" # doit matcher python:3.12 du Docker
|
||||||
|
|
||||||
|
# --- Version (numerique) ---------------------------------------------------
|
||||||
|
if [[ -z "$VERSION" ]]; then
|
||||||
|
# Viser la version DU PROJET (artifactId loremind-core), pas le <version> du parent.
|
||||||
|
VERSION="$(grep -oPz '<artifactId>loremind-core</artifactId>\s*<version>\K[0-9]+\.[0-9]+\.[0-9]+' \
|
||||||
|
"$CORE_DIR/pom.xml" | tr -d '\0' | head -1 || true)"
|
||||||
|
[[ -z "$VERSION" ]] && VERSION="0.0.0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
printf '\033[35m============================================================\033[0m\n'
|
||||||
|
printf '\033[35m DM Loremind - Build AppImage Linux (v%s)\033[0m\n' "$VERSION"
|
||||||
|
printf '\033[35m============================================================\033[0m\n'
|
||||||
|
|
||||||
|
# --- Verif outils ----------------------------------------------------------
|
||||||
|
command -v jpackage >/dev/null 2>&1 || { err "jpackage introuvable dans le PATH. Installez un JDK 21+ (Temurin)."; exit 1; }
|
||||||
|
|
||||||
|
# --- 1. Front Angular ------------------------------------------------------
|
||||||
|
if [[ $SKIP_FRONT -eq 0 ]]; then
|
||||||
|
step "Build du front Angular"
|
||||||
|
( cd "$WEB_DIR"
|
||||||
|
[[ -d node_modules ]] || npm ci
|
||||||
|
npm run build )
|
||||||
|
ok "Front construit (web/dist/web)"
|
||||||
|
else step "Front : saute (--skip-front)"; fi
|
||||||
|
|
||||||
|
# --- 2. Brain (Python standalone relocatable, PAS d'exe gele) --------------
|
||||||
|
if [[ $SKIP_BRAIN -eq 0 ]]; then
|
||||||
|
step "Preparation du Brain (python-build-standalone $PY_MINOR)"
|
||||||
|
rm -rf "$BRAIN_EMBED"; mkdir -p "$BRAIN_EMBED"
|
||||||
|
|
||||||
|
# a) Resoudre l'asset install_only linux-gnu pour $PY_MINOR dans la derniere
|
||||||
|
# release PBS (la date du tag change a chaque release -> on la decouvre).
|
||||||
|
step " Resolution de l'archive python-build-standalone"
|
||||||
|
# URL EPINGLEE de secours (pas d'API) : version figee comme le build Windows,
|
||||||
|
# utilisee si la resolution dynamique echoue (rate limit, API HS, regex sans match).
|
||||||
|
PY_PIN='3.12.8'
|
||||||
|
PBS_DATE='20241219'
|
||||||
|
pbs_fallback="https://github.com/astral-sh/python-build-standalone/releases/download/${PBS_DATE}/cpython-${PY_PIN}+${PBS_DATE}-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
|
||||||
|
# Appel API AUTHENTIFIE si un token est dispo (le runner partage est rate-limite
|
||||||
|
# a 60 req/h en anonyme -> 403 ; avec token : 1000/h). Tolerant : tout echec
|
||||||
|
# bascule sur l'URL epinglee (pas d'abort silencieux du a set -e).
|
||||||
|
auth=()
|
||||||
|
[[ -n "${GITHUB_TOKEN:-}" ]] && auth=(-H "Authorization: Bearer ${GITHUB_TOKEN}")
|
||||||
|
api_json="$(curl -fsSL "${auth[@]}" \
|
||||||
|
https://api.github.com/repos/astral-sh/python-build-standalone/releases/latest 2>/dev/null || true)"
|
||||||
|
# NB: dans browser_download_url, le '+' (version+date) est URL-encode en %2B
|
||||||
|
# -> on accepte les deux. On vise le x86_64 BASELINE (pas _v2/_v3/_v4, qui
|
||||||
|
# exigent un CPU plus recent) et install_only (pas _stripped).
|
||||||
|
asset_url="$(printf '%s' "$api_json" \
|
||||||
|
| grep -m1 -oE "https://[^\"]*cpython-${PY_MINOR//./\\.}\.[0-9]+(%2B|\+)[0-9]+-x86_64-unknown-linux-gnu-install_only\.tar\.gz" \
|
||||||
|
|| true)"
|
||||||
|
if [[ -z "$asset_url" ]]; then
|
||||||
|
echo " (resolution API indisponible -> URL epinglee de secours)"
|
||||||
|
asset_url="$pbs_fallback"
|
||||||
|
fi
|
||||||
|
echo " Telechargement $asset_url"
|
||||||
|
curl -fsSL "$asset_url" -o "$BRAIN_EMBED/python.tar.gz"
|
||||||
|
# L'archive install_only s'extrait en un dossier 'python/' (bin/python3, lib/...).
|
||||||
|
tar -xzf "$BRAIN_EMBED/python.tar.gz" -C "$BRAIN_EMBED"
|
||||||
|
rm -f "$BRAIN_EMBED/python.tar.gz"
|
||||||
|
PYBIN="$BRAIN_EMBED/python/bin/python3"
|
||||||
|
[[ -x "$PYBIN" ]] || { err "python3 introuvable apres extraction ($PYBIN)."; exit 1; }
|
||||||
|
|
||||||
|
# b) Installer les deps DANS le python standalone (site-packages interne).
|
||||||
|
# Python complet => pip fonctionne directement, pas de bricolage ._pth/--target.
|
||||||
|
"$PYBIN" -m pip install --upgrade pip >/dev/null
|
||||||
|
"$PYBIN" -m pip install -r "$BRAIN_DIR/requirements.txt"
|
||||||
|
|
||||||
|
# c) Copier les sources du Brain + le point d'entree.
|
||||||
|
cp -r "$BRAIN_DIR/app" "$BRAIN_EMBED/app"
|
||||||
|
cp "$BRAIN_DIR/run_local.py" "$BRAIN_EMBED/run_local.py"
|
||||||
|
|
||||||
|
# d) OCR (Tesseract) : pas bundle pour l'instant sous Linux (libs partagees
|
||||||
|
# lourdes a embarquer proprement). Degradation gracieuse : si l'utilisateur a
|
||||||
|
# 'tesseract-ocr' (apt/dnf), pytesseract le trouve sur le PATH et l'OCR des
|
||||||
|
# scans marche ; sinon PDF born-digital OK, scans signales. Cf. run_local.py.
|
||||||
|
ok "Brain prepare (brain/dist-embed-linux : python standalone + deps + sources)"
|
||||||
|
else step "Brain : saute (--skip-brain)"; fi
|
||||||
|
|
||||||
|
# --- 3. Core (fat jar avec front embarque) ---------------------------------
|
||||||
|
if [[ $SKIP_JAR -eq 0 ]]; then
|
||||||
|
step "Build du Core (fat jar, profil desktop)"
|
||||||
|
( cd "$CORE_DIR"
|
||||||
|
chmod +x ./mvnw
|
||||||
|
# -Pdesktop : copie web/dist/web dans le jar (classpath:/static).
|
||||||
|
./mvnw -q -Pdesktop -DskipTests clean package )
|
||||||
|
ok "Core construit (core/target)"
|
||||||
|
else step "Core : saute (--skip-jar)"; fi
|
||||||
|
|
||||||
|
# --- 4. Assemblage de la charge utile --------------------------------------
|
||||||
|
step "Assemblage de la charge utile jpackage"
|
||||||
|
rm -rf "$STAGE_DIR"; mkdir -p "$STAGE_DIR"
|
||||||
|
|
||||||
|
# Le jar repackage Spring Boot (executable) — on ignore le *.jar.original.
|
||||||
|
jar="$(find "$CORE_DIR/target" -maxdepth 1 -name 'loremind-core-*.jar' ! -name '*.original' | head -1)"
|
||||||
|
[[ -z "$jar" ]] && { err "Jar introuvable dans core/target. Relancez sans --skip-jar."; exit 1; }
|
||||||
|
cp "$jar" "$STAGE_DIR/loremind-core.jar"
|
||||||
|
|
||||||
|
# Le Brain (python standalone + deps + sources) -> stage/brain/
|
||||||
|
[[ -d "$BRAIN_EMBED/python" ]] || { err "Brain introuvable (brain/dist-embed-linux). Relancez sans --skip-brain."; exit 1; }
|
||||||
|
mkdir -p "$STAGE_DIR/brain"
|
||||||
|
cp -r "$BRAIN_EMBED/." "$STAGE_DIR/brain/"
|
||||||
|
|
||||||
|
# Splash : copie dans la charge utile -> atterrit dans $APPDIR/splash.png (cf. -splash plus bas).
|
||||||
|
[[ -f "$SCRIPT_DIR/splash.png" ]] && cp "$SCRIPT_DIR/splash.png" "$STAGE_DIR/splash.png"
|
||||||
|
ok "Charge utile prete ($STAGE_DIR)"
|
||||||
|
|
||||||
|
# --- 5. jpackage -> app-image ----------------------------------------------
|
||||||
|
step "Generation de l'image applicative (app-image) via jpackage"
|
||||||
|
[[ -f "$ICON_PNG" ]] || { err "Icone manquante : $ICON_PNG (PNG requis sous Linux)."; exit 1; }
|
||||||
|
rm -rf "$OUT_DIR"; mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
|
# $APPDIR : substitue par jpackage AU LANCEMENT par le dossier applicatif
|
||||||
|
# (lib/app), qui contient le jar ET le dossier brain copie depuis --input.
|
||||||
|
# Le Brain se lance via python3 + run_local.py. brain.sidecar.command est une
|
||||||
|
# LISTE : les deux chemins separes par une virgule (aucun chemin Linux n'en
|
||||||
|
# contient) sont bindes en List<String> par Spring. NB: $APPDIR doit rester
|
||||||
|
# LITTERAL ici (quote simple) — c'est jpackage, pas bash, qui le resout.
|
||||||
|
BRAIN_CMD='$APPDIR/brain/python/bin/python3,$APPDIR/brain/run_local.py'
|
||||||
|
|
||||||
|
jpackage \
|
||||||
|
--type app-image \
|
||||||
|
--name "$APP_NAME" \
|
||||||
|
--app-version "$VERSION" \
|
||||||
|
--vendor 'IGML Creation' \
|
||||||
|
--icon "$ICON_PNG" \
|
||||||
|
--input "$STAGE_DIR" \
|
||||||
|
--main-jar loremind-core.jar \
|
||||||
|
--main-class org.springframework.boot.loader.launch.JarLauncher \
|
||||||
|
--dest "$OUT_DIR" \
|
||||||
|
--java-options '-Dspring.profiles.active=local' \
|
||||||
|
--java-options "-Dbrain.sidecar.command=$BRAIN_CMD" \
|
||||||
|
--java-options '-splash:$APPDIR/splash.png'
|
||||||
|
|
||||||
|
APPIMG_SRC="$OUT_DIR/$APP_NAME" # dossier produit par jpackage (avec espace)
|
||||||
|
[[ -d "$APPIMG_SRC" ]] || { err "app-image jpackage introuvable ($APPIMG_SRC)."; exit 1; }
|
||||||
|
ok "Image applicative prete ($APPIMG_SRC)"
|
||||||
|
|
||||||
|
# --- 6. AppImage via appimagetool ------------------------------------------
|
||||||
|
step "Empaquetage AppImage (toutes distros)"
|
||||||
|
APPDIR="$OUT_DIR/AppDir"
|
||||||
|
rm -rf "$APPDIR"; mkdir -p "$APPDIR/usr"
|
||||||
|
|
||||||
|
# a) L'app-image jpackage va sous AppDir/usr/ (le lanceur bin/* resout lib/ en
|
||||||
|
# relatif via ../lib -> reste coherent).
|
||||||
|
cp -r "$APPIMG_SRC/." "$APPDIR/usr/"
|
||||||
|
|
||||||
|
# b) Icone a la racine de l'AppDir (nom = Icon= du .desktop, SANS extension).
|
||||||
|
cp "$ICON_PNG" "$APPDIR/dm-loremind.png"
|
||||||
|
mkdir -p "$APPDIR/usr/share/icons/hicolor/256x256/apps"
|
||||||
|
cp "$ICON_PNG" "$APPDIR/usr/share/icons/hicolor/256x256/apps/dm-loremind.png"
|
||||||
|
|
||||||
|
# c) Fichier .desktop (a la racine + copie standard).
|
||||||
|
cat > "$APPDIR/dm-loremind.desktop" <<EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=DM Loremind
|
||||||
|
Comment=Assistant pour Maitres de Jeu de JDR
|
||||||
|
Exec=DM Loremind
|
||||||
|
Icon=dm-loremind
|
||||||
|
Categories=Game;Utility;
|
||||||
|
Terminal=false
|
||||||
|
EOF
|
||||||
|
mkdir -p "$APPDIR/usr/share/applications"
|
||||||
|
cp "$APPDIR/dm-loremind.desktop" "$APPDIR/usr/share/applications/dm-loremind.desktop"
|
||||||
|
|
||||||
|
# d) AppRun : point d'entree de l'AppImage -> lance le binaire jpackage.
|
||||||
|
cat > "$APPDIR/AppRun" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
HERE="$(dirname "$(readlink -f "$0")")"
|
||||||
|
exec "$HERE/usr/bin/DM Loremind" "$@"
|
||||||
|
EOF
|
||||||
|
chmod +x "$APPDIR/AppRun"
|
||||||
|
|
||||||
|
# e) appimagetool (telecharge si absent). --appimage-extract-and-run : evite
|
||||||
|
# d'exiger FUSE (absent des runners CI).
|
||||||
|
# /!\ HORS de $OUT_DIR : sinon ce .AppImage (l'outil) serait pris pour un livrable
|
||||||
|
# et attache a la release a cote du vrai DM_Loremind-*.AppImage.
|
||||||
|
TOOL="$CORE_DIR/target/appimagetool-x86_64.AppImage"
|
||||||
|
if [[ ! -x "$TOOL" ]]; then
|
||||||
|
curl -fsSL -o "$TOOL" \
|
||||||
|
https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||||
|
chmod +x "$TOOL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# APPIMAGE_EXTRACT_AND_RUN : permet d'EXECUTER l'AppImage appimagetool SANS FUSE
|
||||||
|
# (absent des runners CI) — il se self-extrait au lieu de se monter via fuse.
|
||||||
|
OUT_FILE="$OUT_DIR/DM_Loremind-${VERSION}-x86_64.AppImage"
|
||||||
|
ARCH=x86_64 APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --appimage-extract-and-run "$APPDIR" "$OUT_FILE"
|
||||||
|
chmod +x "$OUT_FILE"
|
||||||
|
|
||||||
|
echo
|
||||||
|
printf '\033[32m============================================================\033[0m\n'
|
||||||
|
printf '\033[32m AppImage genere !\033[0m\n'
|
||||||
|
printf '\033[32m %s\033[0m\n' "$OUT_FILE"
|
||||||
|
printf '\033[32m============================================================\033[0m\n'
|
||||||
@@ -58,6 +58,8 @@ $CoreDir = Join-Path $RepoRoot 'core'
|
|||||||
$StageDir = Join-Path $CoreDir 'target\dist-input' # charge utile jpackage
|
$StageDir = Join-Path $CoreDir 'target\dist-input' # charge utile jpackage
|
||||||
$OutDir = Join-Path $CoreDir 'target\dist-out' # .msi produit
|
$OutDir = Join-Path $CoreDir 'target\dist-out' # .msi produit
|
||||||
$IconFile = Join-Path $PSScriptRoot 'app-icon.ico' # icone de l'app (.msi + raccourcis)
|
$IconFile = Join-Path $PSScriptRoot 'app-icon.ico' # icone de l'app (.msi + raccourcis)
|
||||||
|
$WixDir = Join-Path $PSScriptRoot 'wix' # main.wxs surcharge (case "Lancer" en fin d'install)
|
||||||
|
$SplashFile = Join-Path $PSScriptRoot 'splash.png' # ecran de demarrage (affiche par la JVM via -splash)
|
||||||
|
|
||||||
# --- Version (numerique pour MSI) ------------------------------------------
|
# --- Version (numerique pour MSI) ------------------------------------------
|
||||||
if (-not $Version) {
|
if (-not $Version) {
|
||||||
@@ -191,6 +193,9 @@ if (-not (Test-Path $BrainEmbed)) { Write-Err "Brain introuvable (brain/dist-emb
|
|||||||
$stageBrain = Join-Path $StageDir 'brain'
|
$stageBrain = Join-Path $StageDir 'brain'
|
||||||
New-Item -ItemType Directory -Force -Path $stageBrain | Out-Null
|
New-Item -ItemType Directory -Force -Path $stageBrain | Out-Null
|
||||||
Copy-Item (Join-Path $BrainEmbed '*') $stageBrain -Recurse
|
Copy-Item (Join-Path $BrainEmbed '*') $stageBrain -Recurse
|
||||||
|
|
||||||
|
# Splash : copie dans la charge utile -> atterrit dans $APPDIR\splash.png (cf. -splash plus bas).
|
||||||
|
if (Test-Path $SplashFile) { Copy-Item $SplashFile (Join-Path $StageDir 'splash.png') }
|
||||||
Write-Ok "Charge utile prete ($StageDir)"
|
Write-Ok "Charge utile prete ($StageDir)"
|
||||||
|
|
||||||
# --- 5. jpackage -> .msi ---------------------------------------------------
|
# --- 5. jpackage -> .msi ---------------------------------------------------
|
||||||
@@ -229,12 +234,14 @@ jpackage `
|
|||||||
--app-version $Version `
|
--app-version $Version `
|
||||||
--vendor 'IGML Creation' `
|
--vendor 'IGML Creation' `
|
||||||
--icon $IconFile `
|
--icon $IconFile `
|
||||||
|
--resource-dir $WixDir `
|
||||||
--input $StageDir `
|
--input $StageDir `
|
||||||
--main-jar loremind-core.jar `
|
--main-jar loremind-core.jar `
|
||||||
--main-class org.springframework.boot.loader.launch.JarLauncher `
|
--main-class org.springframework.boot.loader.launch.JarLauncher `
|
||||||
--dest $OutDir `
|
--dest $OutDir `
|
||||||
--java-options '-Dspring.profiles.active=local' `
|
--java-options '-Dspring.profiles.active=local' `
|
||||||
--java-options "-Dbrain.sidecar.command=$brainCmd" `
|
--java-options "-Dbrain.sidecar.command=$brainCmd" `
|
||||||
|
--java-options '-splash:$APPDIR\splash.png' `
|
||||||
--win-per-user-install `
|
--win-per-user-install `
|
||||||
--win-upgrade-uuid 'a7c4e1d2-9b3f-4e6a-8d05-1f2c3b4a5e6d' `
|
--win-upgrade-uuid 'a7c4e1d2-9b3f-4e6a-8d05-1f2c3b4a5e6d' `
|
||||||
--win-menu --win-menu-group 'DM Loremind' `
|
--win-menu --win-menu-group 'DM Loremind' `
|
||||||
|
|||||||
BIN
installers/desktop/splash.png
Normal file
BIN
installers/desktop/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
164
installers/desktop/wix/main.wxs
Normal file
164
installers/desktop/wix/main.wxs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
main.wxs SURCHARGE (option resource-dir de jpackage) : copie du template du
|
||||||
|
JDK 21, plus une case "Lancer DM Loremind" sur l'ecran de fin (ExitDialog).
|
||||||
|
|
||||||
|
A garder synchronise avec le template du JDK du build (JDK 21). Pour re-extraire
|
||||||
|
la base : jimage extract (include regex main.wxs) depuis $JAVA_HOME/lib/modules.
|
||||||
|
Les seuls ajouts maison sont marques [DM Loremind].
|
||||||
|
|
||||||
|
Lancement : installeur per-user, donc contexte utilisateur ; une custom action
|
||||||
|
Directory + ExeCommand suffit (pas besoin de WixUtilExtension).
|
||||||
|
-->
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||||
|
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||||
|
|
||||||
|
<?ifdef JpIsSystemWide ?>
|
||||||
|
<?define JpInstallScope="perMachine"?>
|
||||||
|
<?else?>
|
||||||
|
<?define JpInstallScope="perUser"?>
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<?define JpProductLanguage=1033 ?>
|
||||||
|
<?define JpInstallerVersion=200 ?>
|
||||||
|
<?define JpCompressedMsi=yes ?>
|
||||||
|
|
||||||
|
<?include $(var.JpConfigDir)/overrides.wxi ?>
|
||||||
|
|
||||||
|
<?ifdef JpAllowUpgrades ?>
|
||||||
|
<?define JpUpgradeVersionOnlyDetectUpgrade="no"?>
|
||||||
|
<?else?>
|
||||||
|
<?define JpUpgradeVersionOnlyDetectUpgrade="yes"?>
|
||||||
|
<?endif?>
|
||||||
|
<?ifdef JpAllowDowngrades ?>
|
||||||
|
<?define JpUpgradeVersionOnlyDetectDowngrade="no"?>
|
||||||
|
<?else?>
|
||||||
|
<?define JpUpgradeVersionOnlyDetectDowngrade="yes"?>
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<Product
|
||||||
|
Id="$(var.JpProductCode)"
|
||||||
|
Name="$(var.JpAppName)"
|
||||||
|
Language="$(var.JpProductLanguage)"
|
||||||
|
Version="$(var.JpAppVersion)"
|
||||||
|
Manufacturer="$(var.JpAppVendor)"
|
||||||
|
UpgradeCode="$(var.JpProductUpgradeCode)">
|
||||||
|
|
||||||
|
<Package
|
||||||
|
Description="$(var.JpAppDescription)"
|
||||||
|
Manufacturer="$(var.JpAppVendor)"
|
||||||
|
InstallerVersion="$(var.JpInstallerVersion)"
|
||||||
|
Compressed="$(var.JpCompressedMsi)"
|
||||||
|
InstallScope="$(var.JpInstallScope)" Platform="x64"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />
|
||||||
|
|
||||||
|
<Upgrade Id="$(var.JpProductUpgradeCode)">
|
||||||
|
<UpgradeVersion
|
||||||
|
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectUpgrade)"
|
||||||
|
Property="JP_UPGRADABLE_FOUND"
|
||||||
|
Maximum="$(var.JpAppVersion)"
|
||||||
|
MigrateFeatures="yes"
|
||||||
|
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
|
||||||
|
<UpgradeVersion
|
||||||
|
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
|
||||||
|
Property="JP_DOWNGRADABLE_FOUND"
|
||||||
|
Minimum="$(var.JpAppVersion)"
|
||||||
|
MigrateFeatures="yes"
|
||||||
|
IncludeMinimum="$(var.JpUpgradeVersionOnlyDetectDowngrade)" />
|
||||||
|
</Upgrade>
|
||||||
|
|
||||||
|
<?ifndef JpAllowUpgrades ?>
|
||||||
|
<CustomAction Id="JpDisallowUpgrade" Error="!(loc.DisallowUpgradeErrorMessage)" />
|
||||||
|
<?endif?>
|
||||||
|
<?ifndef JpAllowDowngrades ?>
|
||||||
|
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<Binary Id="JpCaDll" SourceFile="wixhelper.dll"/>
|
||||||
|
|
||||||
|
<CustomAction Id="JpFindRelatedProducts" BinaryKey="JpCaDll" DllEntry="FindRelatedProductsEx" />
|
||||||
|
|
||||||
|
<!-- Standard required root -->
|
||||||
|
<Directory Id="TARGETDIR" Name="SourceDir"/>
|
||||||
|
|
||||||
|
<Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
|
||||||
|
<ComponentGroupRef Id="Shortcuts"/>
|
||||||
|
<ComponentGroupRef Id="Files"/>
|
||||||
|
<ComponentGroupRef Id="FileAssociations"/>
|
||||||
|
</Feature>
|
||||||
|
|
||||||
|
<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
|
||||||
|
<CustomAction Id="JpSetARPCOMMENTS" Property="ARPCOMMENTS" Value="$(var.JpAppDescription)" />
|
||||||
|
<CustomAction Id="JpSetARPCONTACT" Property="ARPCONTACT" Value="$(var.JpAppVendor)" />
|
||||||
|
<CustomAction Id="JpSetARPSIZE" Property="ARPSIZE" Value="$(var.JpAppSizeKb)" />
|
||||||
|
|
||||||
|
<?ifdef JpHelpURL ?>
|
||||||
|
<CustomAction Id="JpSetARPHELPLINK" Property="ARPHELPLINK" Value="$(var.JpHelpURL)" />
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<?ifdef JpAboutURL ?>
|
||||||
|
<CustomAction Id="JpSetARPURLINFOABOUT" Property="ARPURLINFOABOUT" Value="$(var.JpAboutURL)" />
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<?ifdef JpUpdateURL ?>
|
||||||
|
<CustomAction Id="JpSetARPURLUPDATEINFO" Property="ARPURLUPDATEINFO" Value="$(var.JpUpdateURL)" />
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<?ifdef JpIcon ?>
|
||||||
|
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
|
||||||
|
<Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<UIRef Id="JpUI"/>
|
||||||
|
|
||||||
|
<!-- ===================== [DM Loremind] ===================== -->
|
||||||
|
<!-- Case « Lancer l'application » sur l'ExitDialog standard de WixUI.
|
||||||
|
WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT : libellé de la case (la rend visible).
|
||||||
|
WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 : cochée par défaut. -->
|
||||||
|
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Lancer $(var.JpAppName)" />
|
||||||
|
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1" />
|
||||||
|
<!-- Lance le launcher jpackage ([INSTALLDIR]<AppName>.exe). asyncNoWait : on
|
||||||
|
n'attend pas la fin de l'app. Contexte utilisateur (install per-user). -->
|
||||||
|
<CustomAction Id="JpLaunchApplication"
|
||||||
|
Directory="INSTALLDIR"
|
||||||
|
ExeCommand=""[INSTALLDIR]$(var.JpAppName).exe""
|
||||||
|
Return="asyncNoWait"
|
||||||
|
Impersonate="yes" />
|
||||||
|
<UI>
|
||||||
|
<Publish Dialog="ExitDialog" Control="Finish" Event="DoAction" Value="JpLaunchApplication" Order="1">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
|
||||||
|
</UI>
|
||||||
|
<!-- =================== fin [DM Loremind] =================== -->
|
||||||
|
|
||||||
|
<InstallExecuteSequence>
|
||||||
|
<Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize">Not Installed</Custom>
|
||||||
|
<Custom Action="JpSetARPCOMMENTS" After="CostFinalize">Not Installed</Custom>
|
||||||
|
<Custom Action="JpSetARPCONTACT" After="CostFinalize">Not Installed</Custom>
|
||||||
|
<Custom Action="JpSetARPSIZE" After="CostFinalize">Not Installed</Custom>
|
||||||
|
<?ifdef JpHelpURL ?>
|
||||||
|
<Custom Action="JpSetARPHELPLINK" After="CostFinalize">Not Installed</Custom>
|
||||||
|
<?endif?>
|
||||||
|
<?ifdef JpAboutURL ?>
|
||||||
|
<Custom Action="JpSetARPURLINFOABOUT" After="CostFinalize">Not Installed</Custom>
|
||||||
|
<?endif?>
|
||||||
|
<?ifdef JpUpdateURL ?>
|
||||||
|
<Custom Action="JpSetARPURLUPDATEINFO" After="CostFinalize">Not Installed</Custom>
|
||||||
|
<?endif?>
|
||||||
|
|
||||||
|
<?ifndef JpAllowUpgrades ?>
|
||||||
|
<Custom Action="JpDisallowUpgrade" After="JpFindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
|
||||||
|
<?endif?>
|
||||||
|
<?ifndef JpAllowDowngrades ?>
|
||||||
|
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
||||||
|
<?endif?>
|
||||||
|
<RemoveExistingProducts Before="CostInitialize"/>
|
||||||
|
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||||
|
</InstallExecuteSequence>
|
||||||
|
|
||||||
|
<InstallUISequence>
|
||||||
|
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||||
|
</InstallUISequence>
|
||||||
|
|
||||||
|
</Product>
|
||||||
|
</Wix>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#Requires -Version 5.1
|
#Requires -Version 5.1
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Installeur officiel de LoreMindMJ pour Windows 10/11.
|
Installeur officiel de DM Loremind pour Windows 10/11.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Script d'installation pas-a-pas qui :
|
Script d'installation pas-a-pas qui :
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
Le code source de ce script est public et auditable a l'adresse indiquee dans .LINK.
|
Le code source de ce script est public et auditable a l'adresse indiquee dans .LINK.
|
||||||
|
|
||||||
.PARAMETER InstallDir
|
.PARAMETER InstallDir
|
||||||
Dossier d'installation. Defaut : %LOCALAPPDATA%\LoreMind
|
Dossier d'installation. Defaut : %LOCALAPPDATA%\DM Loremind
|
||||||
|
|
||||||
.PARAMETER ComposeUrl
|
.PARAMETER ComposeUrl
|
||||||
URL du fichier docker-compose.yml a recuperer. Defaut : version officielle du depot.
|
URL du fichier docker-compose.yml a recuperer. Defaut : version officielle du depot.
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
.NOTES
|
.NOTES
|
||||||
Auteur : ietm64
|
Auteur : ietm64
|
||||||
Licence : AGPL-3.0
|
Licence : AGPL-3.0
|
||||||
Projet : LoreMindMJ - assistant pour Maitres de Jeu de JDR
|
Projet : DM Loremind - assistant pour Maitres de Jeu de JDR
|
||||||
Version : 0.8.3
|
Version : 0.8.3
|
||||||
|
|
||||||
.LINK
|
.LINK
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param(
|
param(
|
||||||
[string]$InstallDir = "$env:LOCALAPPDATA\LoreMind",
|
[string]$InstallDir = "$env:LOCALAPPDATA\DM Loremind",
|
||||||
[string]$ComposeUrl = "https://raw.githubusercontent.com/IGMLcreation/LoreMind/main/docker-compose.yml",
|
[string]$ComposeUrl = "https://raw.githubusercontent.com/IGMLcreation/LoreMind/main/docker-compose.yml",
|
||||||
[int]$WebPort = 8081,
|
[int]$WebPort = 8081,
|
||||||
[switch]$NonInteractive
|
[switch]$NonInteractive
|
||||||
@@ -142,7 +142,7 @@ if (-not (Test-Admin)) {
|
|||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "============================================================"
|
Write-Host "============================================================"
|
||||||
Write-Host " LoreMindMJ - Installeur Windows" -ForegroundColor Magenta
|
Write-Host " DM Loremind - Installeur Windows" -ForegroundColor Magenta
|
||||||
Write-Host "============================================================"
|
Write-Host "============================================================"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ if ($llmProvider -eq 'onemin' -and -not $NonInteractive) {
|
|||||||
# pare-feu pour que Docker puisse l'atteindre sans exposer le port.
|
# pare-feu pour que Docker puisse l'atteindre sans exposer le port.
|
||||||
# 2. Embarque : Ollama tourne dans un conteneur Docker dedie (profile local-ollama).
|
# 2. Embarque : Ollama tourne dans un conteneur Docker dedie (profile local-ollama).
|
||||||
# 3. Aucun : on n'installe rien tout de suite. L'utilisateur configurera
|
# 3. Aucun : on n'installe rien tout de suite. L'utilisateur configurera
|
||||||
# Ollama plus tard via la page Parametres de LoreMind.
|
# Ollama plus tard via la page Parametres de DM Loremind.
|
||||||
$ollamaMode = 'embedded' # valeurs : 'host' | 'embedded' | 'none'
|
$ollamaMode = 'embedded' # valeurs : 'host' | 'embedded' | 'none'
|
||||||
$ollamaBaseUrl = 'http://ollama:11434'
|
$ollamaBaseUrl = 'http://ollama:11434'
|
||||||
if ($llmProvider -eq 'ollama') {
|
if ($llmProvider -eq 'ollama') {
|
||||||
@@ -298,7 +298,7 @@ if ($llmProvider -eq 'ollama') {
|
|||||||
# sera installe plus tard sur l'hote. L'utilisateur peut aussi changer
|
# sera installe plus tard sur l'hote. L'utilisateur peut aussi changer
|
||||||
# l'URL via la page Parametres pour pointer vers un Ollama distant.
|
# l'URL via la page Parametres pour pointer vers un Ollama distant.
|
||||||
$ollamaBaseUrl = 'http://host.docker.internal:11434'
|
$ollamaBaseUrl = 'http://host.docker.internal:11434'
|
||||||
Write-Warn2 "Aucun Ollama ne sera installe pour le moment. Configurez-le plus tard via la page Parametres de LoreMind."
|
Write-Warn2 "Aucun Ollama ne sera installe pour le moment. Configurez-le plus tard via la page Parametres de DM Loremind."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +404,7 @@ if ($ollamaMode -eq 'embedded' -and $llmProvider -eq 'ollama') {
|
|||||||
$url = "http://localhost:$WebPort"
|
$url = "http://localhost:$WebPort"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "============================================================" -ForegroundColor Green
|
Write-Host "============================================================" -ForegroundColor Green
|
||||||
Write-Host " LoreMindMJ est lance !" -ForegroundColor Green
|
Write-Host " DM Loremind est lance !" -ForegroundColor Green
|
||||||
Write-Host "============================================================" -ForegroundColor Green
|
Write-Host "============================================================" -ForegroundColor Green
|
||||||
Write-Host " URL : $url"
|
Write-Host " URL : $url"
|
||||||
Write-Host " Identifiant : $adminUser"
|
Write-Host " Identifiant : $adminUser"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
# Installeur LoreMindMJ pour Linux (Debian/Ubuntu/Fedora/Arch)
|
# Installeur DM Loremind pour Linux (Debian/Ubuntu/Fedora/Arch)
|
||||||
# Usage :
|
# Usage :
|
||||||
# curl -fsSL https://raw.githubusercontent.com/IGMLcreation/LoreMind/main/installers/install.sh | bash
|
# curl -fsSL https://raw.githubusercontent.com/IGMLcreation/LoreMind/main/installers/install.sh | bash
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
@@ -71,7 +71,7 @@ install_docker() {
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
echo
|
echo
|
||||||
echo "============================================================"
|
echo "============================================================"
|
||||||
echo -e " ${c_cyan}LoreMindMJ - Installeur Linux${c_off}"
|
echo -e " ${c_cyan}DM Loremind - Installeur Linux${c_off}"
|
||||||
echo "============================================================"
|
echo "============================================================"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ if [ "$LLM_PROVIDER" = "ollama" ]; then
|
|||||||
# sera installe plus tard sur l'hote. L'utilisateur peut aussi
|
# sera installe plus tard sur l'hote. L'utilisateur peut aussi
|
||||||
# changer l'URL via la page Parametres pour un Ollama distant.
|
# changer l'URL via la page Parametres pour un Ollama distant.
|
||||||
OLLAMA_BASE_URL_VAL="http://host.docker.internal:11434"
|
OLLAMA_BASE_URL_VAL="http://host.docker.internal:11434"
|
||||||
warn "Aucun Ollama ne sera installe pour le moment. Configurez-le plus tard via la page Parametres de LoreMind."
|
warn "Aucun Ollama ne sera installe pour le moment. Configurez-le plus tard via la page Parametres de DM Loremind."
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
@@ -268,7 +268,7 @@ fi
|
|||||||
URL="http://localhost:${WEB_PORT}"
|
URL="http://localhost:${WEB_PORT}"
|
||||||
echo
|
echo
|
||||||
echo -e "${c_green}============================================================${c_off}"
|
echo -e "${c_green}============================================================${c_off}"
|
||||||
echo -e "${c_green} LoreMindMJ est lance !${c_off}"
|
echo -e "${c_green} DM Loremind est lance !${c_off}"
|
||||||
echo -e "${c_green}============================================================${c_off}"
|
echo -e "${c_green}============================================================${c_off}"
|
||||||
echo " URL : $URL"
|
echo " URL : $URL"
|
||||||
echo " Identifiant : $ADMIN_USERNAME"
|
echo " Identifiant : $ADMIN_USERNAME"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#Requires -Version 5.1
|
#Requires -Version 5.1
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Configuration securisee d'Ollama hote pour LoreMindMJ (Windows).
|
Configuration securisee d'Ollama hote pour DM Loremind (Windows).
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
But : permettre au conteneur Docker LoreMind d'atteindre l'Ollama installe
|
But : permettre au conteneur Docker DM Loremind d'atteindre l'Ollama installe
|
||||||
sur l'hote, SANS exposer Ollama sur le LAN ni Internet.
|
sur l'hote, SANS exposer Ollama sur le LAN ni Internet.
|
||||||
|
|
||||||
Strategie (specifique a Docker Desktop / WSL2 sur Windows) :
|
Strategie (specifique a Docker Desktop / WSL2 sur Windows) :
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# LoreMindMJ - Configuration securisee d'Ollama hote (Linux)
|
# DM Loremind - Configuration securisee d'Ollama hote (Linux)
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# But : permettre au conteneur Docker de LoreMind d'atteindre l'Ollama
|
# But : permettre au conteneur Docker de LoreMind d'atteindre l'Ollama
|
||||||
# installe sur l'hote, SANS l'exposer sur le LAN ni Internet.
|
# installe sur l'hote, SANS l'exposer sur le LAN ni Internet.
|
||||||
|
|||||||
4
web/package-lock.json
generated
4
web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "loremind-web",
|
"name": "loremind-web",
|
||||||
"version": "0.17.0",
|
"version": "0.18.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "loremind-web",
|
"name": "loremind-web",
|
||||||
"version": "0.17.0",
|
"version": "0.18.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^21.2.16",
|
"@angular/animations": "^21.2.16",
|
||||||
"@angular/common": "^21.2.16",
|
"@angular/common": "^21.2.16",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "loremind-web",
|
"name": "loremind-web",
|
||||||
"version": "0.17.0",
|
"version": "0.18.0",
|
||||||
"description": "LoreMind Frontend - Angular",
|
"description": "LoreMind Frontend - Angular",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
|
|||||||
@@ -77,15 +77,13 @@ export class LanguageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private resolveInitialLang(): string {
|
private resolveInitialLang(): string {
|
||||||
|
// 1) Choix mémorisé (sélecteur in-app) → prioritaire.
|
||||||
const stored = this.read();
|
const stored = this.read();
|
||||||
if (stored && this.languages.some((l) => l.code === stored)) {
|
if (stored && this.languages.some((l) => l.code === stored)) {
|
||||||
return stored;
|
return stored;
|
||||||
}
|
}
|
||||||
const browser = this.translate.getBrowserLang();
|
// 2) Sinon, détection du système : français → fr, toute autre langue → en.
|
||||||
if (browser && this.languages.some((l) => l.code === browser)) {
|
return this.translate.getBrowserLang() === 'fr' ? 'fr' : 'en';
|
||||||
return browser;
|
|
||||||
}
|
|
||||||
return this.defaultLang;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private read(): string | null {
|
private read(): string | null {
|
||||||
|
|||||||
Reference in New Issue
Block a user