У меня возникла проблема. Мне нужно загружать tfjs и fld по мере необходимости. Я создал простую функцию для этого и загружаю их из публичных CDN, таких как jsdelivr или unpkg. Однако при этом возникает ошибка <b> TypeError: s.loadGraphModel is not a function</b>. Если я загружаю их стандартным способом через тег script в HTML, все работает нормально. Может быть, кто-то подскажет, в чем может быть причина этой проблемы?
Ошибка `TypeError: s.loadGraphModel is not a function` скорее всего возникает из-за того, что вы загружаете библиотеки TensorFlow.js и FLD (Face Landmarks Detection) не в правильном порядке или не правильно импортируете их. Когда вы загружаете библиотеки через CDN динамически, нужно убедиться, что они загружаются полностью перед тем, как вы попытаетесь их использовать. Вот простой пример, как можно реализовать ленивую загрузку библиотек и гарантировать их доступность перед использованием. ```html <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ленивая загрузка TensorFlow.js</title> </head> <body> <button id="loadModels">Загрузить модели</button> <script> async function loadScript(src) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = () => resolve(); script.onerror = () => reject(new Error(`Ошибка загрузки скрипта ${src}`)); document.head.appendChild(script); }); } async function loadModels() { try { // Загружаем TensorFlow.js await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs'); // Загружаем FLD для определения ключевых точек await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow-models/face-landmarks-detection'); // Используем модели после их загрузки const model = await faceLandmarksDetection.load( faceLandmarksDetection.SupportedPackages.mediapipeFacemesh); console.log('Модель загружена:', model); // Тут может быть ваш код для работы с моделью } catch (error) { console.error('Ошибка при загрузке моделей:', error); } } document.getElementById('loadModels').addEventListener('click', loadModels); </script> </body> </html> ``` ### Объяснение кода: 1. **loadScript:** Это функция, которая динамически создает тег `<script>` для загрузки указанного скрипта. Она возвращает промис, который завершается, когда скрипт загружен. 2. **loadModels:** Это асинхронная функция, которая использует `loadScript` для загрузки TensorFlow.js и модели FLD. После успешной загрузки, она загружает именно нужную модель для определения ключевых точек. 3. **Обработка ошибок:** Добавлено обработка ошибок с помощью `try-catch`, чтобы вы могли видеть, если что-то пошло не так в процессе загрузки. ### Замечания: - Убедитесь, что ваши ссылки на скрипты актуальны. Иногда версии могут измениться, и вам нужно будет использовать актуальные ссылки. - Важно дождаться полной загрузки каждой библиотеки, прежде чем использовать их функциональность. Используйте `async/await` для упрощения работы с асинхронным кодом.
Ваша конкретная ошибка состоит в том, что вы не подключаете все необходимые зависимости или загружаете их в неправильном порядке.
Более вероятно второе: не забывайте, что динамически добавляемые скрипты по-умолчанию являются асинхронными (то есть первым выполнится тот скрипт, который загрузится раньше других). В данном случае это некорректное поведение, которое нужно исправить:
script.async = false;
Также разумно использовать промисы вместо коллбэков, чтобы не росла вложенность кода. Полный пример:
// Functions const loadedScripts = new Set(); async function loadScript(url) { if (loadedScripts.has(url)) return; const script = document.createElement('script'); script.src = url; script.async = false; document.head.append(script); return new Promise((resolve, reject) => { script.addEventListener('load', () => { loadedScripts.add(url); resolve(); }); script.addEventListener('error', () => reject( new Error(`Error loading script: ${url}`) )); }); } async function loadImage(url) { const image = new Image(); image.src = url; image.crossOrigin = 'anonymous'; return new Promise((resolve, reject) => { image.addEventListener('load', () => { resolve(image); }); image.addEventListener('error', () => reject( new Error(`Error loading image: ${url}`) )); }); } // Example const image = loadImage('https://habrastorage.org/r/w1560/getpro/habr/upload_files/799/62f/375/79962f375d90db7f7d926ff40d623456.png'); await Promise.all([ loadScript('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core'), loadScript('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter'), loadScript('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-webgl'), loadScript('https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]/dist/face-landmarks-detection.min.js') ]); const model = faceLandmarksDetection.SupportedModels.MediaPipeFaceMesh; const detectorConfig = { runtime: 'tfjs', solutionPath: 'https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh' }; const detector = await faceLandmarksDetection.createDetector(model, detectorConfig); const faces = await detector.estimateFaces(await image); console.log(faces);