chore(android): propagate CMake fix to native subprojects
The withCmakeFix plugin now also modifies the root android/build.gradle
via withProjectBuildGradle, iterating over subprojects with
plugins.withId('com.android.library') / plugins.withId('com.android.application').
Using plugins.withId (vs subprojects { afterEvaluate {} }) avoids the
"Cannot run Project.afterEvaluate when the project is already evaluated"
error caused by gradle-plugins (kotlin, expo-gradle-plugin, ...) being
evaluated before the closure runs.
This unblocks the native CMake build of react-native-fast-tflite,
react-native-nitro-modules, react-native-screens, expo-modules-core, etc.
on Windows where the path-too-long issue affected subproject .o files.
Build verified: BUILD SUCCESSFUL in 15m 17s, 842 tasks, 0 errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a25295e186
commit
f247748adc
|
|
@ -37,7 +37,7 @@ Public cible : amateurs de vin, viticulteurs, jardiniers.
|
||||||
| Base de donnees | AsyncStorage (local) | PostgreSQL via Prisma 7.6 | — |
|
| Base de donnees | AsyncStorage (local) | PostgreSQL via Prisma 7.6 | — |
|
||||||
| Auth | — (local only) | Better Auth (JWT + sessions) | — |
|
| Auth | — (local only) | Better Auth (JWT + sessions) | — |
|
||||||
| Forms | — | Zod validation | — |
|
| Forms | — | Zod validation | — |
|
||||||
| IA | TFLite (mock actuel) | — | CNN 4 blocs conv, 3.8M params |
|
| IA | Mock JS (intégration TFLite native échouée — build CMake Windows) | — | CNN MobileNetV2, 256×256 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ Public cible : amateurs de vin, viticulteurs, jardiniers.
|
||||||
| i18n (FR + EN) | Done | Toutes les cles traduites (maladies enrichies + guides sections + tips) |
|
| i18n (FR + EN) | Done | Toutes les cles traduites (maladies enrichies + guides sections + tips) |
|
||||||
| Notifications | Partiel | UI uniquement, pas de push notifs |
|
| Notifications | Partiel | UI uniquement, pas de push notifs |
|
||||||
| Carte/Map | Partiel | Placeholder, geoloc non implementee |
|
| Carte/Map | Partiel | Placeholder, geoloc non implementee |
|
||||||
| Inference IA reelle | A faire | Mock actuellement (weighted random) |
|
| Inference IA reelle | Bloque | Code mobile pret + libs installees, mais build CMake echoue sur Windows (path-too-long sur node_modules/react-native-fast-tflite). Voir Points critiques. |
|
||||||
|
|
||||||
### Dashboard admin — 95% complete
|
### Dashboard admin — 95% complete
|
||||||
|
|
||||||
|
|
@ -96,23 +96,34 @@ Public cible : amateurs de vin, viticulteurs, jardiniers.
|
||||||
| Dataset | Done | 9 027 images, 4 classes (Black Rot, ESCA, Healthy, Leaf Blight) |
|
| Dataset | Done | 9 027 images, 4 classes (Black Rot, ESCA, Healthy, Leaf Blight) |
|
||||||
| Entrainement | Done | 100 epochs, Adam lr=0.001, augmentation |
|
| Entrainement | Done | 100 epochs, Adam lr=0.001, augmentation |
|
||||||
| Precision modele | A ameliorer | ~30% (surapprentissage probable vers ESCA) |
|
| Precision modele | A ameliorer | ~30% (surapprentissage probable vers ESCA) |
|
||||||
| Export TFLite | A faire | Conversion pour inference mobile |
|
| Export TFLite | Done | grapevine_v1.tflite (9 MB) embarque dans assets mobile |
|
||||||
| Integration mobile | A faire | Remplacer le mock dans `services/tflite/model.ts` |
|
| Integration mobile | Bloque | Code mobile pret + libs installees, mais build CMake natif echoue (Windows path-too-long sur le sous-projet react-native-fast-tflite) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Points critiques
|
## Points critiques
|
||||||
|
|
||||||
### 1. Inference IA — BLOQUANT
|
### 1. Inference IA — Modele branche, qualite a ameliorer
|
||||||
|
|
||||||
Le coeur du projet (la detection de maladie) est actuellement **mocke**. Le fichier `VinEye/src/services/tflite/model.ts` retourne des resultats aleatoires ponderes (70% vigne, 20% incertain, 10% non-vigne).
|
**Status** : modele branche et fonctionnel via `react-native-fast-tflite`. MAIS le
|
||||||
|
modele actuel a ~25% de validation accuracy (overfitting massif diagnostique).
|
||||||
|
Les predictions sont donc souvent erronees en conditions reelles.
|
||||||
|
|
||||||
**Actions requises :**
|
**Stack mobile** :
|
||||||
- Ameliorer la precision du modele (actuellement ~30%)
|
- `react-native-fast-tflite ^3.0.1` + `react-native-nitro-modules ^0.35.6`
|
||||||
- Exporter le modele en TFLite
|
- Modele : `VinEye/src/assets/models/grapevine_v1.tflite` (9 MB, MobileNetV2 256x256, 4 classes)
|
||||||
- Integrer les poids reels dans l'app mobile
|
- Plugin Expo `withCmakeFix` pour les flags CMake (response files + ninja path)
|
||||||
- Tester la performance sur device (latence, memoire)
|
qui evitent le bug "path too long" sur Windows lors du build C++ Nitro
|
||||||
- Eventuellement : quantization / pruning pour optimiser
|
- Fallback gracieux : si chargement modele echoue, le service tombe sur
|
||||||
|
`mockDetection()` (random pondere) + log error console
|
||||||
|
|
||||||
|
**Prochaines actions** :
|
||||||
|
- Retrainer le modele (data augmentation, regularization, fix data leakage,
|
||||||
|
fine-tuning progressif de MobileNetV2)
|
||||||
|
- Voir `docs/audit_report.md` (a produire) pour le diagnostic complet
|
||||||
|
- Quand un nouveau .tflite sera pret, juste remplacer le fichier dans
|
||||||
|
`assets/models/grapevine_v1.tflite` (interface du service inchangee)
|
||||||
|
- Eventuellement : quantization int8 post-training pour passer de 9 MB a ~2.5 MB
|
||||||
|
|
||||||
### 2. Stockage images — PARTIELLEMENT RESOLU
|
### 2. Stockage images — PARTIELLEMENT RESOLU
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ Cible des amateurs de vin/jardinage. Scan par camera, identification de maladies
|
||||||
| Styling | **NativeWind v4** (Tailwind) prioritaire, StyleSheet pour ombres/gradients |
|
| Styling | **NativeWind v4** (Tailwind) prioritaire, StyleSheet pour ombres/gradients |
|
||||||
| Icones | **lucide-react-native** (bottom bar) + **Ionicons** (reste de l'app) |
|
| Icones | **lucide-react-native** (bottom bar) + **Ionicons** (reste de l'app) |
|
||||||
| Animations | React Native Reanimated v4 |
|
| Animations | React Native Reanimated v4 |
|
||||||
| IA | Mock JS pondéré (random 4 classes) — `react-native-fast-tflite` désinstallé temporairement, voir `services/tflite/model.ts` pour la procédure de réintégration |
|
| IA | `react-native-fast-tflite` (inférence on-device) avec fallback mock JS si module absent — voir `services/tflite/model.ts` |
|
||||||
| Persistance | AsyncStorage |
|
| Persistance | AsyncStorage |
|
||||||
| i18n | i18next + react-i18next (FR + EN) |
|
| i18n | i18next + react-i18next (FR + EN) |
|
||||||
| Camera | expo-camera |
|
| Camera | expo-camera |
|
||||||
|
|
@ -193,11 +193,12 @@ pnpm ios # Build iOS
|
||||||
|
|
||||||
## ML / inference on-device
|
## ML / inference on-device
|
||||||
|
|
||||||
> ⚠️ **2026-04-30** : `react-native-fast-tflite` et `react-native-nitro-modules` ont été **désinstallés temporairement**. Le service `services/tflite/model.ts` retourne actuellement un **mock JS pondéré** (random sur les 4 classes). Raisons : modèle pas encore exporté en `.tflite` final + builds Android C++ instables sur Windows (CMake/Nitro headers). Procédure de réintégration documentée en tête de `services/tflite/model.ts`.
|
> ✅ **2026-05-01** : `react-native-fast-tflite` + `react-native-nitro-modules` **réintégrés et build natif Android validé** (15m 17s, 0 erreur). Le `withCmakeFix` plugin propage maintenant les flags CMake (response files + ninja path) aux sous-projets natifs via `subprojects { plugins.withId('com.android.library') { ... } }` dans `android/build.gradle`. Voir `plugins/withCmakeFix.js`.
|
||||||
|
|
||||||
Le modele MobileNetV2 (val_accuracy 99.93% — voir `docs/paper.md`) est destiné
|
Le modele MobileNetV2 256×256 (4 classes — voir `docs/paper.md`) est embarqué
|
||||||
à être embarqué dans le bundle et exécuté en local via `react-native-fast-tflite`
|
dans `src/assets/models/grapevine_v1.tflite` et exécuté on-device via
|
||||||
une fois la lib réintégrée.
|
`react-native-fast-tflite`. Si le module natif est absent (Expo Go par ex.),
|
||||||
|
fallback automatique sur un mock JS pondéré pour ne pas casser l'UX.
|
||||||
|
|
||||||
### Pipeline
|
### Pipeline
|
||||||
|
|
||||||
|
|
@ -273,8 +274,8 @@ le dev sans device natif.
|
||||||
|
|
||||||
Détail complet : [`.claude/notes/android-build/README.md`](.claude/notes/android-build/README.md)
|
Détail complet : [`.claude/notes/android-build/README.md`](.claude/notes/android-build/README.md)
|
||||||
|
|
||||||
- ✅ **CMake/Ninja path too long** — résolu via plugin Expo config `plugins/withCmakeFix.js` (référencé dans `app.json`) qui injecte response files + ninja 1.12.1 + `CMAKE_OBJECT_PATH_MAX=1024` à chaque prebuild
|
- ✅ **CMake/Ninja path too long sur `:app`** — résolu via plugin `plugins/withCmakeFix.js` qui injecte les flags response files + ninja 1.12.1 + `CMAKE_OBJECT_PATH_MAX=1024` dans `android/app/build.gradle.defaultConfig.externalNativeBuild`
|
||||||
- ✅ **`react-native-nitro-modules` headers manquants** — contourné en désinstallant `react-native-fast-tflite` (qui dépendait de Nitro). Mock JS en place. À réintégrer quand le `.tflite` sera prêt et idéalement via EAS Build pour éviter les soucis Windows.
|
- ✅ **CMake/Ninja path too long sur les sous-projets natifs** (`react-native-fast-tflite`, `react-native-nitro-modules`, etc.) — résolu en étendant `withCmakeFix` pour modifier aussi `android/build.gradle` racine via `withProjectBuildGradle`. Le bloc injecté itère sur `subprojects` avec `plugins.withId('com.android.library')` qui n'agit que sur les modules Android (les gradle-plugins déjà évalués sont naturellement ignorés, évitant `Cannot run Project.afterEvaluate(Closure) when the project is already evaluated`).
|
||||||
|
|
||||||
### Setup dev Windows recommandé
|
### Setup dev Windows recommandé
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,56 @@
|
||||||
const { withAppBuildGradle } = require("expo/config-plugins");
|
const {
|
||||||
|
withAppBuildGradle,
|
||||||
|
withProjectBuildGradle,
|
||||||
|
} = require("expo/config-plugins");
|
||||||
|
|
||||||
const NINJA_PATH =
|
const NINJA_PATH =
|
||||||
"C:\\\\Users\\\\Client\\\\AppData\\\\Local\\\\Android\\\\Sdk\\\\cmake\\\\4.1.2\\\\bin\\\\ninja.exe";
|
"C:\\\\Users\\\\Client\\\\AppData\\\\Local\\\\Android\\\\Sdk\\\\cmake\\\\4.1.2\\\\bin\\\\ninja.exe";
|
||||||
|
|
||||||
|
const CMAKE_ARGS = [
|
||||||
|
`"-DCMAKE_MAKE_PROGRAM=${NINJA_PATH}"`,
|
||||||
|
`"-DCMAKE_OBJECT_PATH_MAX=1024"`,
|
||||||
|
`"-DCMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS=1"`,
|
||||||
|
`"-DCMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES=1"`,
|
||||||
|
`"-DCMAKE_CXX_RESPONSE_FILE_LINK_FLAG=@"`,
|
||||||
|
`"-DCMAKE_NINJA_FORCE_RESPONSE_FILE=1"`,
|
||||||
|
];
|
||||||
|
|
||||||
const CMAKE_BLOCK = `
|
const CMAKE_BLOCK = `
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
arguments "-DCMAKE_MAKE_PROGRAM=${NINJA_PATH}",
|
arguments ${CMAKE_ARGS.join(",\n ")}
|
||||||
"-DCMAKE_OBJECT_PATH_MAX=1024",
|
|
||||||
"-DCMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS=1",
|
|
||||||
"-DCMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES=1",
|
|
||||||
"-DCMAKE_CXX_RESPONSE_FILE_LINK_FLAG=@",
|
|
||||||
"-DCMAKE_NINJA_FORCE_RESPONSE_FILE=1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MARKER = "// CMAKE_FIX_INJECTED";
|
const APP_MARKER = "// CMAKE_FIX_INJECTED";
|
||||||
|
const ROOT_MARKER = "// CMAKE_FIX_SUBPROJECTS_INJECTED";
|
||||||
|
|
||||||
function injectCmakeFix(buildGradle) {
|
const SUBPROJECTS_BLOCK = `
|
||||||
if (buildGradle.includes(MARKER)) return buildGradle;
|
${ROOT_MARKER}
|
||||||
|
subprojects { subproject ->
|
||||||
|
def applyCmakeFix = {
|
||||||
|
try {
|
||||||
|
subproject.android {
|
||||||
|
defaultConfig {
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
arguments ${CMAKE_ARGS.join(",\n ")}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
println "[CMAKE_FIX] Skipping " + subproject.name + ": " + e.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subproject.plugins.withId('com.android.library', applyCmakeFix)
|
||||||
|
subproject.plugins.withId('com.android.application', applyCmakeFix)
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
function injectAppCmakeFix(buildGradle) {
|
||||||
|
if (buildGradle.includes(APP_MARKER)) return buildGradle;
|
||||||
|
|
||||||
const defaultConfigRegex = /(defaultConfig\s*\{)([\s\S]*?)(\n\s*\})/m;
|
const defaultConfigRegex = /(defaultConfig\s*\{)([\s\S]*?)(\n\s*\})/m;
|
||||||
const match = buildGradle.match(defaultConfigRegex);
|
const match = buildGradle.match(defaultConfigRegex);
|
||||||
|
|
@ -30,13 +61,27 @@ function injectCmakeFix(buildGradle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, openTag, body, closeTag] = match;
|
const [, openTag, body, closeTag] = match;
|
||||||
const newBlock = `${openTag}${body}\n ${MARKER}${CMAKE_BLOCK}${closeTag}`;
|
const newBlock = `${openTag}${body}\n ${APP_MARKER}${CMAKE_BLOCK}${closeTag}`;
|
||||||
return buildGradle.replace(defaultConfigRegex, newBlock);
|
return buildGradle.replace(defaultConfigRegex, newBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function injectRootSubprojectsFix(buildGradle) {
|
||||||
|
if (buildGradle.includes(ROOT_MARKER)) return buildGradle;
|
||||||
|
return `${buildGradle.trimEnd()}\n${SUBPROJECTS_BLOCK}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function withCmakeFix(config) {
|
module.exports = function withCmakeFix(config) {
|
||||||
return withAppBuildGradle(config, (config) => {
|
config = withAppBuildGradle(config, (config) => {
|
||||||
config.modResults.contents = injectCmakeFix(config.modResults.contents);
|
config.modResults.contents = injectAppCmakeFix(config.modResults.contents);
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
config = withProjectBuildGradle(config, (config) => {
|
||||||
|
config.modResults.contents = injectRootSubprojectsFix(
|
||||||
|
config.modResults.contents
|
||||||
|
);
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
return config;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue