diff --git a/Demos/PaliGemma2-on-Web/README.md b/Demos/PaliGemma2-on-Web/README.md
new file mode 100644
index 0000000..40019f2
--- /dev/null
+++ b/Demos/PaliGemma2-on-Web/README.md
@@ -0,0 +1,41 @@
+### Developed by [Nitin Tiwari](https://linkedin.com/in/tiwari-nitin).
+
+# Inference PaliGemma 2 on the browser with ONNX & Transformers.js
+This project is an implementation of inferencing the paligemma2-3b-mix-224 model on the browser using its converted ONNX weights and Hugging Face Transformers.js.
+
+## PaliGemma 2 to ONNX Conversion:
+
+
+
+## Steps to run:
+
+1. Clone the repository on your local machine.
+2. Navigate to `gemma-cookbook/Demos/PaliGemma2-on-Web` directory.
+3. Run `npm install` to install the Node.js packages.
+4. Run `node server.js` to start the server.
+5. Open `localhost:3000` on your web browser and start inferencing with PaliGemma 2.
+
+> [!NOTE]
+> For the first time, it will take around 10-15 minutes to load the model weights.
+
+## Results:
+
+
+
+## Resources & References
+
+1. [Google DeepMind PaliGemma 2](https://developers.googleblog.com/en/introducing-paligemma-2-mix/)
+2. Colab Notebooks:
+
+
+ Convert and quantize PaliGemma 2 to ONNX
+
+
+
+ Inference PaliGemma 2 with Transformers.js
+
+
+
+
+3. [**Medium Blog**](https://medium.com/@tiwarinitin1999/inference-paligemma-2-with-transformers-js-5545986ac14a) for step-by-step implementation.
+4. [ONNX Community](https://huggingface.co/onnx-community)
diff --git a/Demos/PaliGemma2-on-Web/assets/paligemma2-onnx-output.gif b/Demos/PaliGemma2-on-Web/assets/paligemma2-onnx-output.gif
new file mode 100644
index 0000000..086ac7f
Binary files /dev/null and b/Demos/PaliGemma2-on-Web/assets/paligemma2-onnx-output.gif differ
diff --git a/Demos/PaliGemma2-on-Web/assets/paligemma2-onnx-pipeline.png b/Demos/PaliGemma2-on-Web/assets/paligemma2-onnx-pipeline.png
new file mode 100644
index 0000000..d06ebe3
Binary files /dev/null and b/Demos/PaliGemma2-on-Web/assets/paligemma2-onnx-pipeline.png differ
diff --git a/Demos/PaliGemma2-on-Web/package.json b/Demos/PaliGemma2-on-Web/package.json
new file mode 100644
index 0000000..d413577
--- /dev/null
+++ b/Demos/PaliGemma2-on-Web/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "paligemma2-onnx-transformers.js",
+ "version": "1.0.0",
+ "main": "server.js",
+ "type": "module",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node server.js"
+ },
+ "keywords": [],
+ "author": "Nitin Tiwari",
+ "license": "MIT",
+ "description": "Inference PaliGemma 2 on the browser using ONNX weights, and Transformers.js.",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/NSTiwari/PaliGemma2-ONNX-Transformers.js.git"
+ },
+ "bugs": {
+ "url": "https://github.com/NSTiwari/PaliGemma2-ONNX-Transformers.js/issues"
+ },
+ "homepage": "https://github.com/NSTiwari/PaliGemma2-ONNX-Transformers.js#readme",
+ "dependencies": {
+ "@huggingface/transformers": "^3.3.3",
+ "canvas": "^3.1.0",
+ "express": "^4.21.2",
+ "server.js": "^1.0.0"
+ }
+}
diff --git a/Demos/PaliGemma2-on-Web/public/index.html b/Demos/PaliGemma2-on-Web/public/index.html
new file mode 100644
index 0000000..bc5fa73
--- /dev/null
+++ b/Demos/PaliGemma2-on-Web/public/index.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ Inference PaliGemma 2 with 🤗 Transformers.js
+
+
+
+
+
+
+ Inference PaliGemma 2 with 🤗 Transformers.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Demos/PaliGemma2-on-Web/public/script.js b/Demos/PaliGemma2-on-Web/public/script.js
new file mode 100644
index 0000000..fc60e43
--- /dev/null
+++ b/Demos/PaliGemma2-on-Web/public/script.js
@@ -0,0 +1,186 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const imageUpload = document.getElementById('imageUpload');
+ const processButton = document.getElementById('processButton');
+ const originalImage = document.getElementById('originalImage');
+ const processedCanvas = document.getElementById('processedCanvas');
+ const promptInput = document.getElementById('promptInput');
+ const responseTextDiv = document.getElementById('responseText');
+ const ctx = processedCanvas.getContext('2d');
+
+ let imageBase64 = '';
+ let originalImageURL = '';
+ let originalImageObj;
+
+ // Initially hide the original image
+ originalImage.style.display = 'none';
+
+ // Handle image upload
+ imageUpload.addEventListener('change', (event) => {
+ const file = event.target.files[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ imageBase64 = e.target.result.split(',')[1];
+ originalImageURL = e.target.result;
+ originalImage.src = originalImageURL;
+
+ originalImageObj = new Image();
+ originalImageObj.onload = () => {
+ // Keep aspect ratio while scaling
+ const originalWidth = originalImageObj.width;
+ const originalHeight = originalImageObj.height;
+
+ // Maximum dimensions for the display area
+ const maxWidth = 600;
+ const maxHeight = 400;
+
+ // Calculate aspect ratio
+ const aspectRatio = originalWidth / originalHeight;
+
+ let displayWidth = maxWidth;
+ let displayHeight = maxWidth / aspectRatio;
+
+ if (displayHeight > maxHeight) {
+ displayHeight = maxHeight;
+ displayWidth = maxHeight * aspectRatio;
+ }
+
+ processedCanvas.width = displayWidth;
+ processedCanvas.height = displayHeight;
+ ctx.clearRect(0, 0, processedCanvas.width, processedCanvas.height);
+ ctx.drawImage(originalImageObj, 0, 0, displayWidth, displayHeight); // Draw the original image on the canvas
+
+ // Show the original image after it's loaded for preview
+ originalImage.style.display = 'block';
+ };
+ originalImageObj.src = originalImageURL;
+
+ // Enable the process button
+ processButton.disabled = false;
+ responseTextDiv.style.display = 'none';
+ responseTextDiv.innerHTML = '';
+ promptInput.value = '';
+ };
+ reader.readAsDataURL(file);
+ }
+ });
+
+ // Handle process button click
+ processButton.addEventListener('click', async () => {
+ if (!imageBase64) {
+ alert("Please upload an image first.");
+ return;
+ }
+
+ // Clear off previous results.
+ ctx.clearRect(0, 0, processedCanvas.width, processedCanvas.height);
+ responseTextDiv.innerHTML = 'Analyzing...';
+ responseTextDiv.style.display = 'block';
+
+
+ let prompt = promptInput.value || "";
+ if (prompt.toLowerCase().includes("detect")) {
+ const labelMatch = prompt.match(/detect\s+(.*)/i);
+ const label = labelMatch ? labelMatch[1] : 'Unknown';
+ prompt = `detect ${label}`;
+ } else {
+ prompt = `${prompt}`;
+ }
+
+ try {
+ const response = await fetch('/process-image', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ image: imageBase64, prompt: prompt, targetWidth: processedCanvas.width, targetHeight: processedCanvas.height, originalWidth: originalImageObj.width, originalHeight: originalImageObj.height }),
+ });
+
+ if (response.ok) {
+ const data = await response.json();
+
+ if (data.success) {
+ if (prompt.includes("detect")) {
+ const { boundingBox } = data;
+ drawBoundingBox(boundingBox, ctx)
+
+ responseTextDiv.style.display = 'block';
+ responseTextDiv.innerHTML = "Response: " + escapeHtml(data.message);
+ }
+ else {
+ processedCanvas.width = 0;
+ processedCanvas.height = 0;
+ ctx.clearRect(0, 0, processedCanvas.width, processedCanvas.height);
+ responseTextDiv.style.display = 'block';
+ responseTextDiv.innerHTML = data.message;
+ }
+ }
+ else {
+ processedCanvas.width = 0;
+ processedCanvas.height = 0;
+ ctx.clearRect(0, 0, processedCanvas.width, processedCanvas.height);
+ responseTextDiv.style.display = 'block';
+ responseTextDiv.innerHTML = "Response: " + data.message;
+ }
+ }
+ else {
+ alert('Error processing image.');
+ }
+
+ } catch (error) {
+ console.error('Error:', error);
+ alert('Error processing image.');
+ } finally {
+
+ }
+ });
+
+
+ // Function to draw the bounding box on canvas
+ function drawBoundingBox(boundingBox, ctx) {
+
+ const { x1, y1, x2, y2, label } = boundingBox;
+
+ // Generate random color for the bounding box and label background
+ const randomColor = getRandomColor();
+
+ // Set styles for the bounding box (random color stroke)
+ ctx.strokeStyle = randomColor;
+ ctx.lineWidth = 5;
+ ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
+
+ // Adjust label background height to fit the text properly
+ const labelPadding = 10;
+ const textWidth = ctx.measureText(label.charAt(0).toUpperCase() + label.slice(1)).width;
+ const labelWidth = textWidth * 3;
+ const labelHeight = 30;
+ const labelY = y1 - labelHeight;
+
+ // Draw background for the label (same random color as bounding box)
+ ctx.fillStyle = randomColor;
+ ctx.fillRect(x1, labelY, labelWidth, labelHeight);
+
+ // Set the text color to white
+ ctx.fillStyle = "white";
+ ctx.font = "bold 20px Arial";
+ ctx.fillText(label.charAt(0).toUpperCase() + label.slice(1), x1 + labelPadding, labelY + labelHeight - labelPadding);
+ }
+
+ // Function to generate a random RGB color
+ function getRandomColor() {
+ const r = Math.floor(Math.random() * 256);
+ const g = Math.floor(Math.random() * 256);
+ const b = Math.floor(Math.random() * 256);
+ return `rgb(${r},${g},${b})`;
+ }
+
+ function escapeHtml(unsafe) {
+ return unsafe
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+ }
+
+});
diff --git a/Demos/PaliGemma2-on-Web/public/style.css b/Demos/PaliGemma2-on-Web/public/style.css
new file mode 100644
index 0000000..bf916ff
--- /dev/null
+++ b/Demos/PaliGemma2-on-Web/public/style.css
@@ -0,0 +1,165 @@
+/* General Reset and Body Styling */
+body,
+h1,
+h2,
+h3,
+p,
+ul,
+li,
+button,
+input {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ background-color: #f7f7f7;
+ color: #333;
+ line-height: 1.6;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 100vh;
+ padding: 20px;
+}
+
+/* Container Styling */
+.container {
+ width: 100%;
+ max-width: 800px;
+ background-color: #fff;
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+}
+
+/* Header Styling */
+header {
+ background-color: #1A237E; /* Updated to the new background color */
+ color: #fff;
+ text-align: center;
+ font-size: 24px;
+ padding: 15px;
+ border-bottom: 2px solid #120C55; /* Slightly darker border for contrast */
+}
+
+/* Image Section Styling */
+.image-section {
+ padding: 20px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 300px;
+ position: relative; /* Ensure it can hold both the image and canvas */
+}
+
+.image-container {
+ width: 100%;
+ max-width: 600px;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+}
+
+.image-container img {
+ max-width: 100%;
+ max-height: 400px;
+ object-fit: contain;
+ display: block;
+ margin: 0 auto;
+}
+
+#processedCanvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+ pointer-events: none; /* Prevent the canvas from interfering with image interactions */
+ width: 100%; /* Ensure canvas scales with the image */
+ height: 100%; /* Match the image size */
+ object-fit: contain;
+}
+
+/* Input Section Styling */
+.input-section {
+ padding: 20px;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-bottom: -20px;
+}
+
+.file-upload {
+ display: inline-block;
+ border: 1px solid #ccc;
+ background-color: #f2f2f2;
+ padding: 10px 15px;
+ border-radius: 6px;
+ cursor: pointer;
+ position: relative;
+ width: 100%;
+ margin-right: 10px;
+ box-sizing: border-box;
+}
+
+.file-upload input[type=file] {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%; /* Take up the full width */
+ height: 100%; /* Take up the full height */
+ opacity: 0; /* Make it invisible */
+ cursor: pointer;
+}
+
+/* Text Input Styling */
+.input-section input[type="text"] {
+ padding: 10px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ font-size: 19px;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+/* Detect Button Styling */
+.input-section button {
+ background-color: #2979FF; /* Default button color */
+ border: none;
+ color: white;
+ font-size: 20px;
+ padding: 10px 15px;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ cursor: pointer;
+ border-radius: 6px;
+ transition: background-color 0.3s ease;
+}
+
+/* Hover effect for the buttons */
+.input-section button:hover {
+ background-color: #2196F3; /* Darker blue on hover */
+}
+
+/* Status Section Styling */
+.status-section {
+ text-align: center;
+ padding: 12px;
+}
+
+
+#responseText {
+ font-size: 18px;
+ color: #263238;
+ font-weight: bold;
+ margin-top: 5px;
+}
diff --git a/Demos/PaliGemma2-on-Web/server.js b/Demos/PaliGemma2-on-Web/server.js
new file mode 100644
index 0000000..ef60b9a
--- /dev/null
+++ b/Demos/PaliGemma2-on-Web/server.js
@@ -0,0 +1,144 @@
+import express from 'express';
+import { AutoProcessor, PaliGemmaForConditionalGeneration, load_image } from "@huggingface/transformers";
+import { createCanvas, loadImage } from "canvas"; // Import canvas for drawing
+import fs from "fs";
+import { createRequire } from 'module';
+const require = createRequire(import.meta.url);
+const path = require('path');
+
+import { Buffer } from 'node:buffer';
+global.Buffer = Buffer;
+
+// Function to generate a random RGB color
+function getRandomColor() {
+ const r = Math.floor(Math.random() * 256);
+ const g = Math.floor(Math.random() * 256);
+ const b = Math.floor(Math.random() * 256);
+ return `rgb(${r},${g},${b})`;
+}
+
+// Load processor and model
+const model_id = "NSTiwari/paligemma2-3b-mix-224-onnx"; // Change this to use a different PaliGemma model
+const processor = await AutoProcessor.from_pretrained(model_id);
+const model = await PaliGemmaForConditionalGeneration.from_pretrained(
+ model_id,
+ {
+ dtype: {
+ embed_tokens: "fp16", // or 'fp16'
+ vision_encoder: "fp16", // or 'q4', 'fp16'
+ decoder_model_merged: "q4", // or 'q4f16'
+ },
+ }
+);
+console.log("Model and processor loaded successfully.");
+
+const app = express();
+const port = 3000;
+
+// Serve static files from the 'public' directory
+app.use(express.static('public'));
+app.use(express.json({ limit: '10mb' })); // Increase limit if needed for large images
+
+// API endpoint for image processing
+app.post('/process-image', async (req, res) => {
+ try {
+ const base64Image = req.body.image;
+ const prompt = req.body.prompt || "caption en"; // Default prompt if not sent
+ const targetWidth = req.body.targetWidth; //Added targetWidth from body to get the targetWidth
+ const targetHeight = req.body.targetHeight; //Added targetHeight from body to get the targetHeight
+ const originalWidth = req.body.originalWidth; //Add the originalWidth
+ const originalHeight = req.body.originalHeight; //Add the originalHeight
+
+ // Create a buffer from the base64 image data
+ const buffer = Buffer.from(base64Image, 'base64');
+
+ // Save the buffer to disk as a JPEG file
+ const tempImagePath = path.join(process.cwd(), 'temp_image.jpg'); // Use a unique filename for each image
+ fs.writeFileSync(tempImagePath, buffer);
+
+ // Load the image
+ const raw_image = await loadImage(tempImagePath);
+
+ // Resize the image using canvas
+ const canvas = createCanvas(targetWidth, targetHeight);
+ const ctx = canvas.getContext('2d');
+ ctx.drawImage(raw_image, 0, 0, targetWidth, targetHeight);
+
+ // Convert canvas to a data URL
+ const resizedImageDataURL = canvas.toDataURL('image/jpeg');
+
+ // Extract base64 from resized image
+ const resizedBase64Image = resizedImageDataURL.split(',')[1];
+ const resizedBuffer = Buffer.from(resizedBase64Image, 'base64');
+ const resizedTempImagePath = path.join(process.cwd(), 'resized_temp_image.jpg');
+ fs.writeFileSync(resizedTempImagePath, resizedBuffer);
+
+ // Load the resized image with huggingface
+ const resizedImage = await load_image(resizedTempImagePath);
+
+ const inputs = await processor(resizedImage, prompt);
+
+ // Generate a response from the model
+ const response = await model.generate({
+ ...inputs,
+ max_new_tokens: 100,
+ });
+
+ // Extract the generated IDs from the response
+ const generatedIds = response.slice(null, [inputs.input_ids.dims[1], null]);
+
+ // Decode the generated IDs to get the answer
+ const decodedAnswer = processor.batch_decode(generatedIds, {
+ skip_special_tokens: true,
+ });
+
+ console.log("Prompt: ", prompt);
+ console.log("Response: ", decodedAnswer[0]);
+
+ if (prompt.includes("detect")) {
+ // Parse the response to extract bounding box coordinates
+ const boundingBoxes = decodedAnswer[0].match(//g);
+
+ if (boundingBoxes && boundingBoxes.length === 4) {
+ // Extract numbers from tags and cast to integers
+ const coordinates = boundingBoxes.map(tag => parseInt(tag.replace("", "")));
+ const [y1, x1, y2, x2] = coordinates.map(coord => Math.floor(coord));
+
+ // Normalize the bounding box coordinates to the RESIZED image dimensions
+ const normX1 = Math.round((x1 / 1024) * targetWidth);
+ const normY1 = Math.round((y1 / 1024) * targetHeight);
+ const normX2 = Math.round((x2 / 1024) * targetWidth);
+ const normY2 = Math.round((y2 / 1024) * targetHeight);
+
+ // Extract the label from the prompt
+ const labelMatch = prompt.match(/detect (.*)/);
+ const label = labelMatch ? labelMatch[1] : "Unknown";
+
+ // Remove the temp image file
+ fs.unlinkSync(tempImagePath);
+ fs.unlinkSync(resizedTempImagePath);
+ res.json({ success: true, boundingBox: { x1: normX1, y1: normY1, x2: normX2, y2: normY2, label: label}, message: decodedAnswer[0] });
+ }
+ else {
+ // Remove the temp image file if the bounding box coordinates were not found
+ fs.unlinkSync(tempImagePath);
+ fs.unlinkSync(resizedTempImagePath);
+ res.json({ success: false, message: decodedAnswer[0] });
+ }
+ }
+ else {
+ // Remove the temp image file if the bounding box coordinates were not found
+ fs.unlinkSync(tempImagePath);
+ fs.unlinkSync(resizedTempImagePath);
+ res.json({ success: false, message: decodedAnswer[0] });
+ }
+
+ } catch (error) {
+ console.error("Error processing image:", error);
+ res.status(500).json({ success: false, message: 'Error processing image' });
+ }
+});
+
+app.listen(port, () => {
+ console.log(`Server listening at http://localhost:${port}`);
+});
diff --git a/Demos/README.md b/Demos/README.md
index e876216..e168b3c 100644
--- a/Demos/README.md
+++ b/Demos/README.md
@@ -14,3 +14,8 @@ This folder houses the companion notebooks for the "Build with AI" video series,
| ----------------------------------------------------------- | ----------- |
| [Gemma on Android](Gemma-on-Android/) | Android app to deploy fine-tuned Gemma-2B-it model using MediaPipe LLM Inference API. |
| [PaliGemma on Android](PaliGemma-on-Android/) | Inference PaliGemma on Android using Hugging Face and Gradio Client API for tasks like zero-shot object detection, image captioning, and visual question-answering. |
+
+## Web App Demo
+| Folder | Description |
+| ----------------------------------------------------------- | ----------- |
+| [PaliGemma 2 on Web](PaliGemma2-on-Web/) | Inference PaliGemma 2 on the web using its ONNX weights and Transformers.js for tasks like object detection, image captioning, OCR, and visual Q&A. |
diff --git a/Demos/personal-code-assistant/pipet-code-agent-2/package-lock.json b/Demos/personal-code-assistant/pipet-code-agent-2/package-lock.json
index 0b213cc..9fb30fb 100644
--- a/Demos/personal-code-assistant/pipet-code-agent-2/package-lock.json
+++ b/Demos/personal-code-assistant/pipet-code-agent-2/package-lock.json
@@ -21,7 +21,7 @@
"@vscode/test-electron": "^2.3.2",
"eslint": "^8.41.0",
"glob": "^8.1.0",
- "mocha": "^10.2.0",
+ "mocha": "^10.8.2",
"typescript": "^5.1.3"
},
"engines": {
@@ -468,10 +468,11 @@
}
},
"node_modules/ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -703,12 +704,13 @@
}
},
"node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -738,10 +740,11 @@
"dev": true
},
"node_modules/diff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
- "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
+ "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
"dev": true,
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
@@ -1578,32 +1581,32 @@
}
},
"node_modules/mocha": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
- "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "4.1.1",
- "browser-stdout": "1.3.1",
- "chokidar": "3.5.3",
- "debug": "4.3.4",
- "diff": "5.0.0",
- "escape-string-regexp": "4.0.0",
- "find-up": "5.0.0",
- "glob": "7.2.0",
- "he": "1.2.0",
- "js-yaml": "4.1.0",
- "log-symbols": "4.1.0",
- "minimatch": "5.0.1",
- "ms": "2.1.3",
- "nanoid": "3.3.3",
- "serialize-javascript": "6.0.0",
- "strip-json-comments": "3.1.1",
- "supports-color": "8.1.1",
- "workerpool": "6.2.1",
- "yargs": "16.2.0",
- "yargs-parser": "20.2.4",
- "yargs-unparser": "2.0.0"
+ "version": "10.8.2",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz",
+ "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-colors": "^4.1.3",
+ "browser-stdout": "^1.3.1",
+ "chokidar": "^3.5.3",
+ "debug": "^4.3.5",
+ "diff": "^5.2.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-up": "^5.0.0",
+ "glob": "^8.1.0",
+ "he": "^1.2.0",
+ "js-yaml": "^4.1.0",
+ "log-symbols": "^4.1.0",
+ "minimatch": "^5.1.6",
+ "ms": "^2.1.3",
+ "serialize-javascript": "^6.0.2",
+ "strip-json-comments": "^3.1.1",
+ "supports-color": "^8.1.1",
+ "workerpool": "^6.5.1",
+ "yargs": "^16.2.0",
+ "yargs-parser": "^20.2.9",
+ "yargs-unparser": "^2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
@@ -1611,49 +1614,24 @@
},
"engines": {
"node": ">= 14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mochajs"
- }
- },
- "node_modules/mocha/node_modules/glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "node_modules/mocha/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
+ "balanced-match": "^1.0.0"
}
},
"node_modules/mocha/node_modules/minimatch": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
- "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -1661,21 +1639,6 @@
"node": ">=10"
}
},
- "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/mocha/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
"node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -1692,22 +1655,11 @@
}
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/nanoid": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
- "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
+ "license": "MIT"
},
"node_modules/natural-compare": {
"version": "1.4.0",
@@ -1901,6 +1853,7 @@
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"safe-buffer": "^5.1.0"
}
@@ -2040,10 +1993,11 @@
}
},
"node_modules/serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"randombytes": "^2.1.0"
}
@@ -2259,10 +2213,11 @@
}
},
"node_modules/workerpool": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
- "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
- "dev": true
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
+ "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
+ "dev": true,
+ "license": "Apache-2.0"
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
@@ -2321,10 +2276,11 @@
}
},
"node_modules/yargs-parser": {
- "version": "20.2.4",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
- "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
+ "license": "ISC",
"engines": {
"node": ">=10"
}
diff --git a/Demos/personal-code-assistant/pipet-code-agent-2/package.json b/Demos/personal-code-assistant/pipet-code-agent-2/package.json
index 53e5dc2..c98b9eb 100644
--- a/Demos/personal-code-assistant/pipet-code-agent-2/package.json
+++ b/Demos/personal-code-assistant/pipet-code-agent-2/package.json
@@ -76,7 +76,7 @@
"@vscode/test-electron": "^2.3.2",
"eslint": "^8.41.0",
"glob": "^8.1.0",
- "mocha": "^10.2.0",
+ "mocha": "^10.8.2",
"typescript": "^5.1.3"
},
"dependencies": {