From 18b2015499596d131f5193d8d736f5af220026d5 Mon Sep 17 00:00:00 2001 From: Matt Williams Date: Fri, 5 Jan 2024 09:21:38 -0800 Subject: [PATCH] add example that applies llava to image management Signed-off-by: Matt Williams --- .../1084-536x354-grayscale.jpg | Bin 0 -> 27997 bytes examples/typescript-airenamer/package.json | 18 ++++++++ examples/typescript-airenamer/readme.md | 29 ++++++++++++ examples/typescript-airenamer/renamer.ts | 42 ++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 examples/typescript-airenamer/1084-536x354-grayscale.jpg create mode 100644 examples/typescript-airenamer/package.json create mode 100644 examples/typescript-airenamer/readme.md create mode 100644 examples/typescript-airenamer/renamer.ts diff --git a/examples/typescript-airenamer/1084-536x354-grayscale.jpg b/examples/typescript-airenamer/1084-536x354-grayscale.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d9e90ce988adeac4ec2600b63db1260506acc622 GIT binary patch literal 27997 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 I?(Tp8*^s;aSpWb4 literal 0 HcmV?d00001 diff --git a/examples/typescript-airenamer/package.json b/examples/typescript-airenamer/package.json new file mode 100644 index 00000000..4d6b3ae9 --- /dev/null +++ b/examples/typescript-airenamer/package.json @@ -0,0 +1,18 @@ +{ + "name": "typescript-airenamer", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "tsx renamer.ts", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "tsx": "^4.7.0" + }, + "devDependencies": { + "@types/node": "^20.10.6" + } +} diff --git a/examples/typescript-airenamer/readme.md b/examples/typescript-airenamer/readme.md new file mode 100644 index 00000000..13367673 --- /dev/null +++ b/examples/typescript-airenamer/readme.md @@ -0,0 +1,29 @@ +# Renaming Files with AI + +![airenamer 2024-01-05 09_09_08](https://github.com/jmorganca/ollama/assets/633681/b98df1c8-61a7-4dff-aeb7-b04e034dced0) + +This example applies the benefits of the llava models to managing images. It will find any images in your current directory, generate keywords for the image, and then copy the file to a new name based on the keywords. + +## Running the example + +1. Clone this repo and navigate to the `examples/typescript-airenamer` directory. +2. Install the dependencies with `npm install`. +3. Run `npm run start`. + +## Review the Code + +The main part of the code is in the `getkeywords` function. It calls the `/api/generate` endpoint passing in the body: + +```json +{ + "model": "llava:13b-v1.5-q5_K_M", + "prompt": `Describe the image as a collection of keywords. Output in JSON format. Use the following schema: { filename: string, keywords: string[] }`, + "format": "json", + "images": [image], + "stream": false + } +``` + +This demonstrates how to use images as well as `format: json` to allow calling another function. The images key takes an array of base64 encoded images. And `format: json` tells the model to output JSON instead of regular text. When using `format: json`, it's important to also say that you expect the output to be JSON in the prompt. Adding the expected schema to the prompt also helps the model understand what you're looking for. + +The `main` function calls getkeywords passing it the base64 encoded image. Then it parses the JSON output, formats the keywords into a string, and copies the file to the new name. diff --git a/examples/typescript-airenamer/renamer.ts b/examples/typescript-airenamer/renamer.ts new file mode 100644 index 00000000..97c0fd38 --- /dev/null +++ b/examples/typescript-airenamer/renamer.ts @@ -0,0 +1,42 @@ +import fs from 'fs'; + +export async function getkeywords(image: string): Promise { + const body = { + "model": "llava:13b-v1.5-q5_K_M", + "prompt": `Describe the image as a collection of keywords. Output in JSON format. Use the following schema: { filename: string, keywords: string[] }`, + "format": "json", + "images": [image], + "stream": false + }; + + const response = await fetch("http://localhost:11434/api/generate", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + const json = await response.json(); + const keywords = JSON.parse(json.response); + + return keywords?.keywords || []; +} + +async function main() { + for (const file of fs.readdirSync(".")) { + if (file.endsWith(".jpg") || file.endsWith(".png")) { + const currentpath = __dirname; + const b64 = fs.readFileSync(`${currentpath}/${file}`, { encoding: 'base64' }); + const keywords = await getkeywords(b64.toString()); + const fileparts = keywords.map(k => k.replace(/ /g, "_")); + const fileext = file.split(".").pop(); + const newfilename = fileparts.join("-") + "." + fileext; + fs.copyFileSync(`${currentpath}/${file}`, `${currentpath}/${newfilename}`); + console.log(`Copied ${file} to ${newfilename}`); + } + } + +} + +main(); \ No newline at end of file