ChatGPT has helped me write a page of HTML to use Google Facemesh to measure rotation of the participant’s head. Over many hours of trial and trial we arrived at a solution that worked pretty well. However, I wasn’t 100% sure that I had applied all edits correctly and asked it to give me the whole script again. Alas, this script omitted many fixes that took us hours to do. That is NOT the ChatGPT bug i’m reported.
Since I don’t have a copy of the earlier working version, I asked ChatGPT to read our past interactions and fix the bugs. It agreed to do that but produced a version that still has those bugs. So I asked it to fix them, and it keeps giving me exactly the same reply, about 3 or 4 times. I alerted it that it was repeating itself, and it seems to acknowledge, but then gave me the same reply again.
ChatGPT repeating itself, unable to move on, seems a serious bug.
The HTML bug is that the program isn’t saving the meshes. With much trial and error it fixed this 5 hours ago. Now it’s incapable of fixing the same bug.
I wanted to share the conversation, but it gives an error: Please try again. APIError 404. I tried many times.
I’m attaching the current HTML file. THis is a one-page web app. Just open it in any browser.
- it asks for permission to use the camera.
- it shows a live camera feed.
- press “Left mesh”. This should save facemesh data for you looking at the left edge of screen. The Console acknowledges the button press, and then reports that the attempt to save data failed.
I keep telling ChatGPT that the program fails with this error, and it keeps suggesting the same changes to the code, forgetting that it already told me to do this several times, and I have in fact done them.
[my email]
I can’t attach, so I’m pasting my HTML file below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>FaceMesh Head Rotation</title>
<style>
video { transform: scaleX(-1); width: 640px; height: 480px; }
#container { display: flex; flex-direction: column; align-items: center; margin-top: 20px; }
#results { margin-top: 20px; padding: 10px; border: 1px solid #ccc; width: 80%; text-align: left; font-family: monospace; white-space: pre-wrap; min-height: 100px; }
</style>
</head>
<body>
<div id="container">
<video id="video" autoplay playsinline></video>
<br/>
<button id="captureLeft">Capture Left Mesh</button>
<button id="captureRight">Capture Right Mesh</button>
<button id="computeTransform">Compute Transform</button>
<div id="results">Results will appear here...</div>
</div>
<!-- ✅ Load ml-matrix Correctly -->
<script type="module">
import * as mlMatrix from "https://cdn.jsdelivr.net/npm/ml-matrix@6.8.0/+esm";
window.Matrix = mlMatrix.Matrix;
window.SVD = mlMatrix.SVD;
console.log("✅ ml-matrix loaded successfully.");
</script>
<!-- Load MediaPipe FaceMesh -->
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/face_mesh.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"></script>
<script>
let cameraStarted = false;
let lastLogTime = 0;
let currentFaceLandmarks = null;
let leftMesh = null;
let rightMesh = null;
document.addEventListener("DOMContentLoaded", function () {
console.log("✅ Document Loaded, Starting Script...");
if (!window.Matrix || !window.SVD) {
console.error("❌ ml-matrix failed to load.");
return;
}
const videoEl = document.getElementById('video');
const resultsEl = document.getElementById('results');
const faceMesh = new FaceMesh({
locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}`
});
faceMesh.setOptions({
maxNumFaces: 1,
refineLandmarks: true,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5
});
faceMesh.onResults((results) => {
if (results.multiFaceLandmarks && results.multiFaceLandmarks.length > 0) {
currentFaceLandmarks = results.multiFaceLandmarks[0];
const now = Date.now();
if (now - lastLogTime > 1000) {
console.log(`✅ FaceMesh detected a face with ${currentFaceLandmarks.length} landmarks.`);
lastLogTime = now;
}
}
});
async function captureMesh(type) {
console.log(`🟡 Capture ${type} Mesh button pressed.`);
await new Promise(resolve => setTimeout(resolve, 200)); // ✅ Small delay to ensure FaceMesh updates
if (!currentFaceLandmarks || currentFaceLandmarks.length === 0) {
resultsEl.textContent = `⚠️ No face detected for ${type} mesh. Try again.`;
console.warn(`⚠️ No face detected when capturing ${type} mesh.`);
return;
}
const meshData = JSON.parse(JSON.stringify(currentFaceLandmarks.map(lm => ({ x: lm.x, y: lm.y, z: lm.z }))));
if (type === "Left") {
leftMesh = meshData;
resultsEl.textContent = `✅ Left mesh captured (${leftMesh.length} landmarks).`;
console.log("✅ Left mesh successfully captured.");
} else {
rightMesh = meshData;
resultsEl.textContent = `✅ Right mesh captured (${rightMesh.length} landmarks).`;
console.log("✅ Right mesh successfully captured.");
}
}
document.getElementById('captureLeft').addEventListener('click', () => captureMesh("Left"));
document.getElementById('captureRight').addEventListener('click', () => captureMesh("Right"));
document.getElementById('computeTransform').addEventListener('click', () => {
if (!leftMesh || !rightMesh) {
resultsEl.textContent = '❌ Capture both left and right meshes first.';
return;
}
console.log("✅ Computing transform...");
resultsEl.textContent = "⏳ Computing transform...";
const transform = computeRigidTransform(leftMesh, rightMesh);
const euler = rotationMatrixToEuler(transform.rotationMatrix);
console.log("✅ Euler Angles Computed:", euler);
resultsEl.textContent =
`✅ Transformation computed!\n\n` +
`=== Rotation (Euler Angles) ===\n` +
`Pitch (Up/Down): ${-euler[0].toFixed(2)}°\n` +
`Roll (Tilt): ${-euler[1].toFixed(2)}°\n` +
`Yaw (Left/Right): ${euler[2].toFixed(2)}°\n\n` +
`=== Translation (Shift in Position) ===\n` +
`X: ${-transform.translationVector[0].toFixed(4)}\n` +
`Y: ${-transform.translationVector[1].toFixed(4)}\n` +
`Z: ${transform.translationVector[2].toFixed(4)}\n`;
});
startCamera();
});
async function startCamera() {
if (cameraStarted) return;
cameraStarted = true;
console.log("📷 Requesting camera permission...");
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const videoEl = document.getElementById('video');
videoEl.srcObject = stream;
await videoEl.play();
console.log("✅ Camera started.");
}
function computeRigidTransform(leftPoints, rightPoints) {
const leftMatrix = new Matrix(leftPoints.map(p => [p.x, p.y, p.z]));
const rightMatrix = new Matrix(rightPoints.map(p => [p.x, p.y, p.z]));
const centroidLeft = new Matrix([leftMatrix.mean('column')]).transpose();
const centroidRight = new Matrix([rightMatrix.mean('column')]).transpose();
const H = leftMatrix.subRowVector(centroidLeft).transpose()
.mmul(rightMatrix.subRowVector(centroidRight));
const svd = new SVD(H);
let rotationMatrix = new Matrix(svd.rightSingularVectors).mmul(new Matrix(svd.leftSingularVectors).transpose());
rotationMatrix = new Matrix(rotationMatrix.to2DArray());
const translationVector = centroidRight.sub(rotationMatrix.mmul(centroidLeft));
return { rotationMatrix: rotationMatrix.to2DArray(), translationVector: translationVector.to1DArray() };
}
function rotationMatrixToEuler(rot) {
const sy = Math.sqrt(rot[2][1] * rot[2][1] + rot[2][2] * rot[2][2]);
let pitch, roll, yaw;
if (sy > 1e-6) {
pitch = Math.atan2(rot[2][1], rot[2][2]);
yaw = Math.atan2(-rot[2][0], sy);
roll = Math.atan2(rot[1][0], rot[0][0]);
} else {
pitch = Math.atan2(-rot[1][2], rot[1][1]);
yaw = Math.atan2(-rot[2][0], sy);
roll = 0;
}
return [-pitch * (180 / Math.PI), -roll * (180 / Math.PI), yaw * (180 / Math.PI)];
}
</script>
</body>
</html>