mirror of
				https://github.com/amithkoujalgi/ollama4j.git
				synced 2025-10-30 08:00:42 +01:00 
			
		
		
		
	Compare commits
	
		
			38 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 2d3cf228cb | ||
|   | 5b3713c69e | ||
|   | e9486cbb8e | ||
|   | 057f0babeb | ||
|   | da146640ca | ||
|   | 82be761b86 | ||
|   | 9c3fc49df1 | ||
|   | 5f19eb17ac | ||
|   | ecb04d6d82 | ||
|   | 3fc7e9423c | ||
|   | 405a08b330 | ||
|   | 921f745435 | ||
|   | bedfec6bf9 | ||
|   | afa09e87a5 | ||
|   | baf2320ea6 | ||
|   | 948a7444fb | ||
|   | ec0eb8b469 | ||
|   | 8f33de7e59 | ||
|   | 8c59e6511b | ||
|   | b93fc7623a | ||
|   | bd1a57c7e0 | ||
|   | 7fabead249 | ||
|   | 268a973d5e | ||
|   | d949a3cb69 | ||
|   | e2443ed68a | ||
|   | 37193b1f5b | ||
|   | e33071ae38 | ||
|   | fffc8dc526 | ||
|   | def950cc9c | ||
|   | f4db7ca326 | ||
|   | 18760250ea | ||
|   | 233597efd1 | ||
|   | cec9f29eb7 | ||
|   | 20cb92a418 | ||
|   | b0dc38954b | ||
|   | 1479d0a494 | ||
|   | b328daee43 | ||
|   | b90c8bc622 | 
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @@ -11,9 +11,9 @@ doxygen: | ||||
| 	doxygen Doxyfile | ||||
|  | ||||
| list-releases: | ||||
| 	curl 'https://central.sonatype.com/api/internal/browse/component/versions?sortField=normalizedVersion&sortDirection=asc&page=0&size=12&filter=namespace%3Aio.github.amithkoujalgi%2Cname%3Aollama4j' \ | ||||
| 	curl 'https://central.sonatype.com/api/internal/browse/component/versions?sortField=normalizedVersion&sortDirection=desc&page=0&size=20&filter=namespace%3Aio.github.ollama4j%2Cname%3Aollama4j' \ | ||||
|       --compressed \ | ||||
|       --silent | jq '.components[].version' | ||||
|       --silent | jq -r '.components[].version' | ||||
|  | ||||
| build-docs: | ||||
| 	npm i --prefix docs && npm run build --prefix docs | ||||
|   | ||||
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							| @@ -4,12 +4,11 @@ | ||||
|   <img src='https://raw.githubusercontent.com/ollama4j/ollama4j/65a9d526150da8fcd98e2af6a164f055572bf722/ollama4j.jpeg' width='100' alt="ollama4j-icon"> | ||||
| </p> | ||||
|  | ||||
|  | ||||
| A Java library (wrapper/binding) for [Ollama](https://ollama.ai/) server. | ||||
| <div align="center"> | ||||
| A Java library (wrapper/binding) for Ollama server. | ||||
|  | ||||
| Find more details on the [website](https://ollama4j.github.io/ollama4j/). | ||||
|  | ||||
| <div align="center"> | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -155,7 +154,7 @@ In your Maven project, add this dependency: | ||||
| <dependency> | ||||
|     <groupId>io.github.ollama4j</groupId> | ||||
|     <artifactId>ollama4j</artifactId> | ||||
|     <version>1.0.79</version> | ||||
|     <version>1.0.87</version> | ||||
| </dependency> | ||||
| ``` | ||||
|  | ||||
| @@ -268,7 +267,10 @@ make integration-tests | ||||
|  | ||||
| Newer artifacts are published via GitHub Actions CI workflow when a new release is created from `main` branch. | ||||
|  | ||||
| #### Who's using Ollama4j? | ||||
| ## ⭐ Give us a Star! | ||||
| If you like or are using this project to build your own, please give us a star. It's a free way to show your support. | ||||
|  | ||||
| ## Who's using Ollama4j? | ||||
|  | ||||
| - `Datafaker`: a library to generate fake data | ||||
|     - https://github.com/datafaker-net/datafaker-experimental/tree/main/ollama-api | ||||
| @@ -277,18 +279,26 @@ Newer artifacts are published via GitHub Actions CI workflow when a new release | ||||
| - `ollama-translator`: Minecraft 1.20.6 spigot plugin allows to easily break language barriers by using ollama on the | ||||
|   server to translate all messages into a specfic target language. | ||||
|     - https://github.com/liebki/ollama-translator | ||||
| - `AI Player`: A minecraft mod which aims to add a "second player" into the game which will actually be intelligent. | ||||
|     - https://github.com/shasankp000/AI-Player | ||||
|     - https://www.reddit.com/r/fabricmc/comments/1e65x5s/comment/ldr2vcf/ | ||||
| - `Ollama4j Web UI`: A web UI for Ollama written in Java using Spring Boot and Vaadin framework and | ||||
|   Ollama4j. | ||||
|     - https://github.com/ollama4j/ollama4j-web-ui | ||||
| - `JnsCLI`: A command-line tool for Jenkins that manages jobs, builds, and configurations directly from the terminal while offering AI-powered error analysis for quick troubleshooting. | ||||
|     -  https://github.com/mirum8/jnscli | ||||
| - `Katie Backend`: An Open Source AI-based question-answering platform that helps companies and organizations make their private domain knowledge accessible and useful to their employees and customers. | ||||
|     - https://github.com/wyona/katie-backend | ||||
| - `TeleLlama3 Bot`: A Question-Answering Telegram Bot. | ||||
|     - https://git.hiast.edu.sy/mohamadbashar.disoki/telellama3-bot | ||||
| - `moqui-wechat`: A wechat plugin | ||||
|     - https://github.com/heguangyong/moqui-wechat | ||||
|  | ||||
| #### Traction | ||||
| ## Traction | ||||
|  | ||||
| [](https://star-history.com/#ollama4j/ollama4j&Date) | ||||
|  | ||||
| ### Get Involved | ||||
| ## Get Involved | ||||
|  | ||||
| <div align="center"> | ||||
|  | ||||
| @@ -316,6 +326,22 @@ Contributions are most welcome! Whether it's reporting a bug, proposing an enhan | ||||
| with code - any sort | ||||
| of contribution is much appreciated. | ||||
|  | ||||
| ## 🏷️ License and Citation | ||||
|  | ||||
| The code is available under [MIT License](./LICENSE). | ||||
|  | ||||
| If you find this project helpful in your research, please cite this work at | ||||
|  | ||||
| ``` | ||||
| @misc{ollama4j2024, | ||||
|     author       = {Amith Koujalgi}, | ||||
|     title        = {Ollama4j: A Java Library (Wrapper/Binding) for Ollama Server}, | ||||
|     year         = {2024}, | ||||
|     month        = {January}, | ||||
|     url          = {https://github.com/ollama4j/ollama4j} | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### References | ||||
|  | ||||
| - [Ollama REST APIs](https://github.com/jmorganca/ollama/blob/main/docs/api.md) | ||||
|   | ||||
							
								
								
									
										65
									
								
								docs/docs/apis-generate/custom-roles.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								docs/docs/apis-generate/custom-roles.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| --- | ||||
| sidebar_position: 8 | ||||
| --- | ||||
|  | ||||
| # Custom Roles | ||||
|  | ||||
| Allows to manage custom roles (apart from the base roles) for chat interactions with the models. | ||||
|  | ||||
| _Particularly helpful when you would need to use different roles that the newer models support other than the base | ||||
| roles._ | ||||
|  | ||||
| _Base roles are `SYSTEM`, `USER`, `ASSISTANT`, `TOOL`._ | ||||
|  | ||||
| ### Usage | ||||
|  | ||||
| #### Add new role | ||||
|  | ||||
| ```java | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.models.chat.OllamaChatMessageRole; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         String host = "http://localhost:11434/"; | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         OllamaChatMessageRole customRole = ollamaAPI.addCustomRole("custom-role"); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| #### List roles | ||||
|  | ||||
| ```java | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.models.chat.OllamaChatMessageRole; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         String host = "http://localhost:11434/"; | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         List<OllamaChatMessageRole> roles = ollamaAPI.listRoles(); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| #### Get role | ||||
|  | ||||
| ```java | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.models.chat.OllamaChatMessageRole; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         String host = "http://localhost:11434/"; | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         List<OllamaChatMessageRole> roles = ollamaAPI.getRole("custom-role"); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| @@ -8,12 +8,85 @@ Generate embeddings from a model. | ||||
|  | ||||
| Parameters: | ||||
|  | ||||
| - `model`: name of model to generate embeddings from | ||||
| - `input`: text/s to generate embeddings for | ||||
|  | ||||
| ```java | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.types.OllamaModelType; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedRequestModel; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|         String host = "http://localhost:11434/"; | ||||
|  | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         OllamaEmbedResponseModel embeddings = ollamaAPI.embed("all-minilm", Arrays.asList("Why is the sky blue?", "Why is the grass green?")); | ||||
|  | ||||
|         System.out.println(embeddings); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Or, using the `OllamaEmbedRequestModel`: | ||||
|  | ||||
| ```java | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.types.OllamaModelType; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedRequestModel; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel;import java.util.Arrays; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|         String host = "http://localhost:11434/"; | ||||
|  | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         OllamaEmbedResponseModel embeddings = ollamaAPI.embed(new OllamaEmbedRequestModel("all-minilm", Arrays.asList("Why is the sky blue?", "Why is the grass green?"))); | ||||
|  | ||||
|         System.out.println(embeddings); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| You will get a response similar to: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|     "model": "all-minilm", | ||||
|     "embeddings": [[-0.034674067, 0.030984823, 0.0067988685]], | ||||
|     "total_duration": 14173700, | ||||
|     "load_duration": 1198800, | ||||
|     "prompt_eval_count": 2 | ||||
| } | ||||
| ```` | ||||
|  | ||||
| :::note | ||||
|  | ||||
| This is a deprecated API | ||||
|  | ||||
| ::: | ||||
|  | ||||
| Parameters: | ||||
|  | ||||
| - `model`: name of model to generate embeddings from | ||||
| - `prompt`: text to generate embeddings for | ||||
|  | ||||
| ```java | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.types.OllamaModelType; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| public class Main { | ||||
| @@ -40,11 +113,6 @@ You will get a response similar to: | ||||
|     0.009260174818336964, | ||||
|     0.23178744316101074, | ||||
|     -0.2916173040866852, | ||||
|     -0.8924556970596313, | ||||
|     0.8785552978515625, | ||||
|     -0.34576427936553955, | ||||
|     0.5742510557174683, | ||||
|     -0.04222835972905159, | ||||
|     -0.137906014919281 | ||||
|     -0.8924556970596313 | ||||
| ] | ||||
| ``` | ||||
| @@ -1,5 +1,5 @@ | ||||
| --- | ||||
| sidebar_position: 4 | ||||
| sidebar_position: 5 | ||||
| --- | ||||
|  | ||||
| # Create Model | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| --- | ||||
| sidebar_position: 5 | ||||
| sidebar_position: 6 | ||||
| --- | ||||
|  | ||||
| # Delete Model | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| --- | ||||
| sidebar_position: 3 | ||||
| sidebar_position: 4 | ||||
| --- | ||||
|  | ||||
| # Get Model Details | ||||
|   | ||||
							
								
								
									
										133
									
								
								docs/docs/apis-model-management/list-library-models.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								docs/docs/apis-model-management/list-library-models.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| --- | ||||
| sidebar_position: 1 | ||||
| --- | ||||
|  | ||||
| # Models from Ollama Library | ||||
|  | ||||
| These API retrieves a list of models directly from the Ollama library. | ||||
|  | ||||
| ### List Models from Ollama Library | ||||
|  | ||||
| This API fetches available models from the Ollama library page, including details such as the model's name, pull count, | ||||
| popular tags, tag count, and the last update time. | ||||
|  | ||||
| ```java title="ListLibraryModels.java" | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.models.response.LibraryModel; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|         String host = "http://localhost:11434/"; | ||||
|  | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         List<LibraryModel> libraryModels = ollamaAPI.listModelsFromLibrary(); | ||||
|  | ||||
|         System.out.println(libraryModels); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The following is the sample output: | ||||
|  | ||||
| ``` | ||||
| [ | ||||
|     LibraryModel(name=llama3.2-vision, description=Llama 3.2 Vision is a collection of instruction-tuned image reasoning generative models in 11B and 90B sizes., pullCount=21.1K, totalTags=9, popularTags=[vision, 11b, 90b], lastUpdated=yesterday),  | ||||
|     LibraryModel(name=llama3.2, description=Meta's Llama 3.2 goes small with 1B and 3B models., pullCount=2.4M, totalTags=63, popularTags=[tools, 1b, 3b], lastUpdated=6 weeks ago) | ||||
| ] | ||||
| ``` | ||||
|  | ||||
| ### Get Tags of a Library Model | ||||
|  | ||||
| This API Fetches the tags associated with a specific model from Ollama library. | ||||
|  | ||||
| ```java title="GetLibraryModelTags.java" | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.models.response.LibraryModel; | ||||
| import io.github.ollama4j.models.response.LibraryModelDetail; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|         String host = "http://localhost:11434/"; | ||||
|  | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         List<LibraryModel> libraryModels = ollamaAPI.listModelsFromLibrary(); | ||||
|  | ||||
|         LibraryModelDetail libraryModelDetail = ollamaAPI.getLibraryModelDetails(libraryModels.get(0)); | ||||
|  | ||||
|         System.out.println(libraryModelDetail); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The following is the sample output: | ||||
|  | ||||
| ``` | ||||
| LibraryModelDetail( | ||||
|   model=LibraryModel(name=llama3.2-vision, description=Llama 3.2 Vision is a collection of instruction-tuned image reasoning generative models in 11B and 90B sizes., pullCount=21.1K, totalTags=9, popularTags=[vision, 11b, 90b], lastUpdated=yesterday),  | ||||
|   tags=[ | ||||
|         LibraryModelTag(name=llama3.2-vision, tag=latest, size=7.9GB, lastUpdated=yesterday),  | ||||
|         LibraryModelTag(name=llama3.2-vision, tag=11b, size=7.9GB, lastUpdated=yesterday),  | ||||
|         LibraryModelTag(name=llama3.2-vision, tag=90b, size=55GB, lastUpdated=yesterday) | ||||
|     ] | ||||
| ) | ||||
| ``` | ||||
|  | ||||
| ### Find a model from Ollama library | ||||
|  | ||||
| This API finds a specific model using model `name` and `tag` from Ollama library. | ||||
|  | ||||
| ```java title="FindLibraryModel.java" | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.models.response.LibraryModelTag; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|         String host = "http://localhost:11434/"; | ||||
|  | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         LibraryModelTag libraryModelTag = ollamaAPI.findModelTagFromLibrary("qwen2.5", "7b"); | ||||
|  | ||||
|         System.out.println(libraryModelTag); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The following is the sample output: | ||||
|  | ||||
| ``` | ||||
| LibraryModelTag(name=qwen2.5, tag=7b, size=4.7GB, lastUpdated=7 weeks ago) | ||||
| ``` | ||||
|  | ||||
| ### Pull model using `LibraryModelTag` | ||||
|  | ||||
| You can use `LibraryModelTag` to pull models into Ollama server. | ||||
|  | ||||
| ```java title="PullLibraryModelTags.java" | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.models.response.LibraryModelTag; | ||||
|  | ||||
| public class Main { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|         String host = "http://localhost:11434/"; | ||||
|  | ||||
|         OllamaAPI ollamaAPI = new OllamaAPI(host); | ||||
|  | ||||
|         LibraryModelTag libraryModelTag = ollamaAPI.findModelTagFromLibrary("qwen2.5", "7b"); | ||||
|  | ||||
|         ollamaAPI.pullModel(libraryModelTag); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| @@ -1,10 +1,10 @@ | ||||
| --- | ||||
| sidebar_position: 1 | ||||
| sidebar_position: 2 | ||||
| --- | ||||
|  | ||||
| # List Models | ||||
| # List Local Models | ||||
|  | ||||
| This API lets you list available models on the Ollama server. | ||||
| This API lets you list downloaded/available models on the Ollama server. | ||||
|  | ||||
| ```java title="ListModels.java" | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| --- | ||||
| sidebar_position: 2 | ||||
| sidebar_position: 3 | ||||
| --- | ||||
|  | ||||
| # Pull Model | ||||
| @@ -23,4 +23,12 @@ public class Main { | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Once downloaded, you can see them when you use [list models](./list-models) API. | ||||
| Once downloaded, you can see them when you use [list models](./list-models) API. | ||||
|  | ||||
| :::info | ||||
|  | ||||
| You can even pull models using Ollama model library APIs. This looks up the models directly on the Ollama model library page. Refer | ||||
| to [this](./list-library-models#pull-model-using-librarymodeltag). | ||||
|  | ||||
| ::: | ||||
|  | ||||
|   | ||||
							
								
								
									
										413
									
								
								docs/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										413
									
								
								docs/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -3383,24 +3383,6 @@ | ||||
|         "@types/ms": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/eslint": { | ||||
|       "version": "8.56.0", | ||||
|       "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.0.tgz", | ||||
|       "integrity": "sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==", | ||||
|       "dependencies": { | ||||
|         "@types/estree": "*", | ||||
|         "@types/json-schema": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/eslint-scope": { | ||||
|       "version": "3.7.7", | ||||
|       "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", | ||||
|       "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", | ||||
|       "dependencies": { | ||||
|         "@types/eslint": "*", | ||||
|         "@types/estree": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/estree": { | ||||
|       "version": "1.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", | ||||
| @@ -3691,9 +3673,10 @@ | ||||
|       "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/ast": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", | ||||
|       "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", | ||||
|       "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/helper-numbers": "1.11.6", | ||||
|         "@webassemblyjs/helper-wasm-bytecode": "1.11.6" | ||||
| @@ -3702,22 +3685,26 @@ | ||||
|     "node_modules/@webassemblyjs/floating-point-hex-parser": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", | ||||
|       "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" | ||||
|       "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/helper-api-error": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", | ||||
|       "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" | ||||
|       "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/helper-buffer": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", | ||||
|       "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", | ||||
|       "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/helper-numbers": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", | ||||
|       "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/floating-point-hex-parser": "1.11.6", | ||||
|         "@webassemblyjs/helper-api-error": "1.11.6", | ||||
| @@ -3727,23 +3714,26 @@ | ||||
|     "node_modules/@webassemblyjs/helper-wasm-bytecode": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", | ||||
|       "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" | ||||
|       "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/helper-wasm-section": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", | ||||
|       "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", | ||||
|       "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/ast": "1.11.6", | ||||
|         "@webassemblyjs/helper-buffer": "1.11.6", | ||||
|         "@webassemblyjs/ast": "1.12.1", | ||||
|         "@webassemblyjs/helper-buffer": "1.12.1", | ||||
|         "@webassemblyjs/helper-wasm-bytecode": "1.11.6", | ||||
|         "@webassemblyjs/wasm-gen": "1.11.6" | ||||
|         "@webassemblyjs/wasm-gen": "1.12.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/ieee754": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", | ||||
|       "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@xtuc/ieee754": "^1.2.0" | ||||
|       } | ||||
| @@ -3752,6 +3742,7 @@ | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", | ||||
|       "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", | ||||
|       "license": "Apache-2.0", | ||||
|       "dependencies": { | ||||
|         "@xtuc/long": "4.2.2" | ||||
|       } | ||||
| @@ -3759,29 +3750,32 @@ | ||||
|     "node_modules/@webassemblyjs/utf8": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", | ||||
|       "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" | ||||
|       "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/wasm-edit": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", | ||||
|       "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", | ||||
|       "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/ast": "1.11.6", | ||||
|         "@webassemblyjs/helper-buffer": "1.11.6", | ||||
|         "@webassemblyjs/ast": "1.12.1", | ||||
|         "@webassemblyjs/helper-buffer": "1.12.1", | ||||
|         "@webassemblyjs/helper-wasm-bytecode": "1.11.6", | ||||
|         "@webassemblyjs/helper-wasm-section": "1.11.6", | ||||
|         "@webassemblyjs/wasm-gen": "1.11.6", | ||||
|         "@webassemblyjs/wasm-opt": "1.11.6", | ||||
|         "@webassemblyjs/wasm-parser": "1.11.6", | ||||
|         "@webassemblyjs/wast-printer": "1.11.6" | ||||
|         "@webassemblyjs/helper-wasm-section": "1.12.1", | ||||
|         "@webassemblyjs/wasm-gen": "1.12.1", | ||||
|         "@webassemblyjs/wasm-opt": "1.12.1", | ||||
|         "@webassemblyjs/wasm-parser": "1.12.1", | ||||
|         "@webassemblyjs/wast-printer": "1.12.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/wasm-gen": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", | ||||
|       "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", | ||||
|       "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/ast": "1.11.6", | ||||
|         "@webassemblyjs/ast": "1.12.1", | ||||
|         "@webassemblyjs/helper-wasm-bytecode": "1.11.6", | ||||
|         "@webassemblyjs/ieee754": "1.11.6", | ||||
|         "@webassemblyjs/leb128": "1.11.6", | ||||
| @@ -3789,22 +3783,24 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/wasm-opt": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", | ||||
|       "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", | ||||
|       "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/ast": "1.11.6", | ||||
|         "@webassemblyjs/helper-buffer": "1.11.6", | ||||
|         "@webassemblyjs/wasm-gen": "1.11.6", | ||||
|         "@webassemblyjs/wasm-parser": "1.11.6" | ||||
|         "@webassemblyjs/ast": "1.12.1", | ||||
|         "@webassemblyjs/helper-buffer": "1.12.1", | ||||
|         "@webassemblyjs/wasm-gen": "1.12.1", | ||||
|         "@webassemblyjs/wasm-parser": "1.12.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/wasm-parser": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", | ||||
|       "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", | ||||
|       "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/ast": "1.11.6", | ||||
|         "@webassemblyjs/ast": "1.12.1", | ||||
|         "@webassemblyjs/helper-api-error": "1.11.6", | ||||
|         "@webassemblyjs/helper-wasm-bytecode": "1.11.6", | ||||
|         "@webassemblyjs/ieee754": "1.11.6", | ||||
| @@ -3813,23 +3809,26 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@webassemblyjs/wast-printer": { | ||||
|       "version": "1.11.6", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", | ||||
|       "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", | ||||
|       "version": "1.12.1", | ||||
|       "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", | ||||
|       "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@webassemblyjs/ast": "1.11.6", | ||||
|         "@webassemblyjs/ast": "1.12.1", | ||||
|         "@xtuc/long": "4.2.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@xtuc/ieee754": { | ||||
|       "version": "1.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", | ||||
|       "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" | ||||
|       "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", | ||||
|       "license": "BSD-3-Clause" | ||||
|     }, | ||||
|     "node_modules/@xtuc/long": { | ||||
|       "version": "4.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", | ||||
|       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" | ||||
|       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", | ||||
|       "license": "Apache-2.0" | ||||
|     }, | ||||
|     "node_modules/accepts": { | ||||
|       "version": "1.3.8", | ||||
| @@ -3873,10 +3872,11 @@ | ||||
|         "node": ">=0.4.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/acorn-import-assertions": { | ||||
|       "version": "1.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", | ||||
|       "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", | ||||
|     "node_modules/acorn-import-attributes": { | ||||
|       "version": "1.9.5", | ||||
|       "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", | ||||
|       "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", | ||||
|       "license": "MIT", | ||||
|       "peerDependencies": { | ||||
|         "acorn": "^8" | ||||
|       } | ||||
| @@ -4242,12 +4242,13 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/body-parser": { | ||||
|       "version": "1.20.1", | ||||
|       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", | ||||
|       "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", | ||||
|       "version": "1.20.2", | ||||
|       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", | ||||
|       "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "bytes": "3.1.2", | ||||
|         "content-type": "~1.0.4", | ||||
|         "content-type": "~1.0.5", | ||||
|         "debug": "2.6.9", | ||||
|         "depd": "2.0.0", | ||||
|         "destroy": "1.2.0", | ||||
| @@ -4255,7 +4256,7 @@ | ||||
|         "iconv-lite": "0.4.24", | ||||
|         "on-finished": "2.4.1", | ||||
|         "qs": "6.11.0", | ||||
|         "raw-body": "2.5.1", | ||||
|         "raw-body": "2.5.2", | ||||
|         "type-is": "~1.6.18", | ||||
|         "unpipe": "1.0.0" | ||||
|       }, | ||||
| @@ -4268,6 +4269,7 @@ | ||||
|       "version": "3.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", | ||||
|       "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.8" | ||||
|       } | ||||
| @@ -4276,6 +4278,7 @@ | ||||
|       "version": "2.6.9", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
|       "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "ms": "2.0.0" | ||||
|       } | ||||
| @@ -4283,7 +4286,8 @@ | ||||
|     "node_modules/body-parser/node_modules/ms": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||
|       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" | ||||
|       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/bonjour-service": { | ||||
|       "version": "1.1.1", | ||||
| @@ -4332,11 +4336,12 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/braces": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", | ||||
|       "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", | ||||
|       "version": "3.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", | ||||
|       "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "fill-range": "^7.0.1" | ||||
|         "fill-range": "^7.1.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
| @@ -4423,13 +4428,19 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/call-bind": { | ||||
|       "version": "1.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", | ||||
|       "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", | ||||
|       "version": "1.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", | ||||
|       "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "es-define-property": "^1.0.0", | ||||
|         "es-errors": "^1.3.0", | ||||
|         "function-bind": "^1.1.2", | ||||
|         "get-intrinsic": "^1.2.1", | ||||
|         "set-function-length": "^1.1.1" | ||||
|         "get-intrinsic": "^1.2.4", | ||||
|         "set-function-length": "^1.2.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
| @@ -4923,6 +4934,7 @@ | ||||
|       "version": "1.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", | ||||
|       "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.6" | ||||
|       } | ||||
| @@ -4933,9 +4945,10 @@ | ||||
|       "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" | ||||
|     }, | ||||
|     "node_modules/cookie": { | ||||
|       "version": "0.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", | ||||
|       "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", | ||||
|       "version": "0.6.0", | ||||
|       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", | ||||
|       "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.6" | ||||
|       } | ||||
| @@ -5962,16 +5975,20 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/define-data-property": { | ||||
|       "version": "1.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", | ||||
|       "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", | ||||
|       "version": "1.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", | ||||
|       "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "get-intrinsic": "^1.2.1", | ||||
|         "gopd": "^1.0.1", | ||||
|         "has-property-descriptors": "^1.0.0" | ||||
|         "es-define-property": "^1.0.0", | ||||
|         "es-errors": "^1.3.0", | ||||
|         "gopd": "^1.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/define-lazy-prop": { | ||||
| @@ -6302,9 +6319,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/enhanced-resolve": { | ||||
|       "version": "5.15.0", | ||||
|       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", | ||||
|       "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", | ||||
|       "version": "5.17.1", | ||||
|       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", | ||||
|       "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "graceful-fs": "^4.2.4", | ||||
|         "tapable": "^2.2.0" | ||||
| @@ -6332,6 +6350,27 @@ | ||||
|         "is-arrayish": "^0.2.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/es-define-property": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", | ||||
|       "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "get-intrinsic": "^1.2.4" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/es-errors": { | ||||
|       "version": "1.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", | ||||
|       "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/es-module-lexer": { | ||||
|       "version": "1.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", | ||||
| @@ -6580,16 +6619,17 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/express": { | ||||
|       "version": "4.18.2", | ||||
|       "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", | ||||
|       "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", | ||||
|       "version": "4.19.2", | ||||
|       "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", | ||||
|       "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "accepts": "~1.3.8", | ||||
|         "array-flatten": "1.1.1", | ||||
|         "body-parser": "1.20.1", | ||||
|         "body-parser": "1.20.2", | ||||
|         "content-disposition": "0.5.4", | ||||
|         "content-type": "~1.0.4", | ||||
|         "cookie": "0.5.0", | ||||
|         "cookie": "0.6.0", | ||||
|         "cookie-signature": "1.0.6", | ||||
|         "debug": "2.6.9", | ||||
|         "depd": "2.0.0", | ||||
| @@ -6826,9 +6866,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/fill-range": { | ||||
|       "version": "7.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", | ||||
|       "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", | ||||
|       "version": "7.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", | ||||
|       "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "to-regex-range": "^5.0.1" | ||||
|       }, | ||||
| @@ -6905,15 +6946,16 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/follow-redirects": { | ||||
|       "version": "1.15.3", | ||||
|       "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", | ||||
|       "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", | ||||
|       "version": "1.15.8", | ||||
|       "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.8.tgz", | ||||
|       "integrity": "sha512-xgrmBhBToVKay1q2Tao5LI26B83UhrB/vM1avwVSDzt8rx3rO6AizBAaF46EgksTVr+rFTQaqZZ9MVBfUe4nig==", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "individual", | ||||
|           "url": "https://github.com/sponsors/RubenVerborgh" | ||||
|         } | ||||
|       ], | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=4.0" | ||||
|       }, | ||||
| @@ -7140,15 +7182,20 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/get-intrinsic": { | ||||
|       "version": "1.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", | ||||
|       "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", | ||||
|       "version": "1.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", | ||||
|       "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "es-errors": "^1.3.0", | ||||
|         "function-bind": "^1.1.2", | ||||
|         "has-proto": "^1.0.1", | ||||
|         "has-symbols": "^1.0.3", | ||||
|         "hasown": "^2.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
| @@ -7207,7 +7254,8 @@ | ||||
|     "node_modules/glob-to-regexp": { | ||||
|       "version": "0.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", | ||||
|       "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" | ||||
|       "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", | ||||
|       "license": "BSD-2-Clause" | ||||
|     }, | ||||
|     "node_modules/global-dirs": { | ||||
|       "version": "3.0.1", | ||||
| @@ -7406,11 +7454,12 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/has-property-descriptors": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", | ||||
|       "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", | ||||
|       "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "get-intrinsic": "^1.2.2" | ||||
|         "es-define-property": "^1.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
| @@ -7950,6 +7999,7 @@ | ||||
|       "version": "0.4.24", | ||||
|       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", | ||||
|       "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "safer-buffer": ">= 2.1.2 < 3" | ||||
|       }, | ||||
| @@ -8259,6 +8309,7 @@ | ||||
|       "version": "7.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", | ||||
|       "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=0.12.0" | ||||
|       } | ||||
| @@ -9106,6 +9157,7 @@ | ||||
|       "version": "0.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", | ||||
|       "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.6" | ||||
|       } | ||||
| @@ -11286,11 +11338,12 @@ | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/micromatch": { | ||||
|       "version": "4.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", | ||||
|       "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", | ||||
|       "version": "4.0.8", | ||||
|       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", | ||||
|       "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "braces": "^3.0.2", | ||||
|         "braces": "^3.0.3", | ||||
|         "picomatch": "^2.3.1" | ||||
|       }, | ||||
|       "engines": { | ||||
| @@ -11544,9 +11597,13 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/object-inspect": { | ||||
|       "version": "1.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", | ||||
|       "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", | ||||
|       "version": "1.13.2", | ||||
|       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", | ||||
|       "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
| @@ -12685,6 +12742,7 @@ | ||||
|       "version": "6.11.0", | ||||
|       "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", | ||||
|       "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", | ||||
|       "license": "BSD-3-Clause", | ||||
|       "dependencies": { | ||||
|         "side-channel": "^1.0.4" | ||||
|       }, | ||||
| @@ -12750,9 +12808,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/raw-body": { | ||||
|       "version": "2.5.1", | ||||
|       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", | ||||
|       "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", | ||||
|       "version": "2.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", | ||||
|       "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "bytes": "3.1.2", | ||||
|         "http-errors": "2.0.0", | ||||
| @@ -12767,6 +12826,7 @@ | ||||
|       "version": "3.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", | ||||
|       "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.8" | ||||
|       } | ||||
| @@ -13887,14 +13947,17 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/set-function-length": { | ||||
|       "version": "1.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", | ||||
|       "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", | ||||
|       "version": "1.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", | ||||
|       "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "define-data-property": "^1.1.1", | ||||
|         "get-intrinsic": "^1.2.1", | ||||
|         "define-data-property": "^1.1.4", | ||||
|         "es-errors": "^1.3.0", | ||||
|         "function-bind": "^1.1.2", | ||||
|         "get-intrinsic": "^1.2.4", | ||||
|         "gopd": "^1.0.1", | ||||
|         "has-property-descriptors": "^1.0.0" | ||||
|         "has-property-descriptors": "^1.0.2" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
| @@ -13965,13 +14028,18 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/side-channel": { | ||||
|       "version": "1.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", | ||||
|       "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", | ||||
|       "version": "1.0.6", | ||||
|       "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", | ||||
|       "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "call-bind": "^1.0.0", | ||||
|         "get-intrinsic": "^1.0.2", | ||||
|         "object-inspect": "^1.9.0" | ||||
|         "call-bind": "^1.0.7", | ||||
|         "es-errors": "^1.3.0", | ||||
|         "get-intrinsic": "^1.2.4", | ||||
|         "object-inspect": "^1.13.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
| @@ -14394,15 +14462,16 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/terser-webpack-plugin": { | ||||
|       "version": "5.3.9", | ||||
|       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", | ||||
|       "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", | ||||
|       "version": "5.3.10", | ||||
|       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", | ||||
|       "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@jridgewell/trace-mapping": "^0.3.17", | ||||
|         "@jridgewell/trace-mapping": "^0.3.20", | ||||
|         "jest-worker": "^27.4.5", | ||||
|         "schema-utils": "^3.1.1", | ||||
|         "serialize-javascript": "^6.0.1", | ||||
|         "terser": "^5.16.8" | ||||
|         "terser": "^5.26.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 10.13.0" | ||||
| @@ -14535,6 +14604,7 @@ | ||||
|       "version": "5.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", | ||||
|       "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "is-number": "^7.0.0" | ||||
|       }, | ||||
| @@ -14604,6 +14674,7 @@ | ||||
|       "version": "1.6.18", | ||||
|       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", | ||||
|       "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "media-typer": "0.3.0", | ||||
|         "mime-types": "~2.1.24" | ||||
| @@ -14616,6 +14687,7 @@ | ||||
|       "version": "1.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", | ||||
|       "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.6" | ||||
|       } | ||||
| @@ -14624,6 +14696,7 @@ | ||||
|       "version": "2.1.35", | ||||
|       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | ||||
|       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "mime-db": "1.52.0" | ||||
|       }, | ||||
| @@ -15155,9 +15228,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/watchpack": { | ||||
|       "version": "2.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", | ||||
|       "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", | ||||
|       "version": "2.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", | ||||
|       "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "glob-to-regexp": "^0.4.1", | ||||
|         "graceful-fs": "^4.1.2" | ||||
| @@ -15189,33 +15263,33 @@ | ||||
|       "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" | ||||
|     }, | ||||
|     "node_modules/webpack": { | ||||
|       "version": "5.89.0", | ||||
|       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", | ||||
|       "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", | ||||
|       "version": "5.94.0", | ||||
|       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", | ||||
|       "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@types/eslint-scope": "^3.7.3", | ||||
|         "@types/estree": "^1.0.0", | ||||
|         "@webassemblyjs/ast": "^1.11.5", | ||||
|         "@webassemblyjs/wasm-edit": "^1.11.5", | ||||
|         "@webassemblyjs/wasm-parser": "^1.11.5", | ||||
|         "@types/estree": "^1.0.5", | ||||
|         "@webassemblyjs/ast": "^1.12.1", | ||||
|         "@webassemblyjs/wasm-edit": "^1.12.1", | ||||
|         "@webassemblyjs/wasm-parser": "^1.12.1", | ||||
|         "acorn": "^8.7.1", | ||||
|         "acorn-import-assertions": "^1.9.0", | ||||
|         "browserslist": "^4.14.5", | ||||
|         "acorn-import-attributes": "^1.9.5", | ||||
|         "browserslist": "^4.21.10", | ||||
|         "chrome-trace-event": "^1.0.2", | ||||
|         "enhanced-resolve": "^5.15.0", | ||||
|         "enhanced-resolve": "^5.17.1", | ||||
|         "es-module-lexer": "^1.2.1", | ||||
|         "eslint-scope": "5.1.1", | ||||
|         "events": "^3.2.0", | ||||
|         "glob-to-regexp": "^0.4.1", | ||||
|         "graceful-fs": "^4.2.9", | ||||
|         "graceful-fs": "^4.2.11", | ||||
|         "json-parse-even-better-errors": "^2.3.1", | ||||
|         "loader-runner": "^4.2.0", | ||||
|         "mime-types": "^2.1.27", | ||||
|         "neo-async": "^2.6.2", | ||||
|         "schema-utils": "^3.2.0", | ||||
|         "tapable": "^2.1.1", | ||||
|         "terser-webpack-plugin": "^5.3.7", | ||||
|         "watchpack": "^2.4.0", | ||||
|         "terser-webpack-plugin": "^5.3.10", | ||||
|         "watchpack": "^2.4.1", | ||||
|         "webpack-sources": "^3.2.3" | ||||
|       }, | ||||
|       "bin": { | ||||
| @@ -15269,9 +15343,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/webpack-dev-middleware": { | ||||
|       "version": "5.3.3", | ||||
|       "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", | ||||
|       "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", | ||||
|       "version": "5.3.4", | ||||
|       "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", | ||||
|       "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "colorette": "^2.0.10", | ||||
|         "memfs": "^3.4.3", | ||||
| @@ -15376,9 +15451,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/webpack-dev-server/node_modules/ws": { | ||||
|       "version": "8.15.1", | ||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", | ||||
|       "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", | ||||
|       "version": "8.18.0", | ||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", | ||||
|       "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=10.0.0" | ||||
|       }, | ||||
| @@ -15620,9 +15696,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ws": { | ||||
|       "version": "7.5.9", | ||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", | ||||
|       "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", | ||||
|       "version": "7.5.10", | ||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", | ||||
|       "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=8.3.0" | ||||
|       }, | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import HomepageFeatures from '@site/src/components/HomepageFeatures'; | ||||
| import BuyMeACoffee from '@site/src/components/BuyMeACoffee'; | ||||
| import Heading from '@theme/Heading'; | ||||
| import styles from './index.module.css'; | ||||
| import BrowserOnly from '@docusaurus/BrowserOnly'; | ||||
|  | ||||
| function HomepageHeader() { | ||||
|   const {siteConfig} = useDocusaurusContext(); | ||||
| @@ -36,7 +37,9 @@ export default function Home() { | ||||
|     <HomepageHeader/> | ||||
|     <main> | ||||
|       <HomepageFeatures/> | ||||
|       <BuyMeACoffee/> | ||||
|       <BrowserOnly> | ||||
|         {() => <BuyMeACoffee />} | ||||
|       </BrowserOnly> | ||||
|     </main> | ||||
|   </Layout>); | ||||
| } | ||||
							
								
								
									
										9
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -63,6 +63,10 @@ | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-javadoc-plugin</artifactId> | ||||
|                 <version>3.5.0</version> | ||||
|                 <configuration> | ||||
|                     <!-- to disable the "missing" warnings. Remove the doclint to enable warnings--> | ||||
|                     <doclint>all,-missing</doclint> | ||||
|                 </configuration> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <id>attach-javadocs</id> | ||||
| @@ -136,6 +140,11 @@ | ||||
|             <version>${lombok.version}</version> | ||||
|             <scope>provided</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.jsoup</groupId> | ||||
|             <artifactId>jsoup</artifactId> | ||||
|             <version>1.18.1</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>com.fasterxml.jackson.core</groupId> | ||||
|             <artifactId>jackson-databind</artifactId> | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| package io.github.ollama4j; | ||||
|  | ||||
| import io.github.ollama4j.exceptions.OllamaBaseException; | ||||
| import io.github.ollama4j.exceptions.RoleNotFoundException; | ||||
| import io.github.ollama4j.exceptions.ToolInvocationException; | ||||
| import io.github.ollama4j.exceptions.ToolNotFoundException; | ||||
| import io.github.ollama4j.models.chat.OllamaChatMessage; | ||||
| import io.github.ollama4j.models.chat.OllamaChatRequest; | ||||
| import io.github.ollama4j.models.chat.OllamaChatRequestBuilder; | ||||
| import io.github.ollama4j.models.chat.OllamaChatResult; | ||||
| import io.github.ollama4j.models.chat.*; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedRequestModel; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbeddingResponseModel; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestModel; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel; | ||||
| import io.github.ollama4j.models.generate.OllamaGenerateRequest; | ||||
| import io.github.ollama4j.models.generate.OllamaStreamHandler; | ||||
| import io.github.ollama4j.models.ps.ModelsProcessResponse; | ||||
| @@ -18,8 +18,6 @@ import io.github.ollama4j.tools.*; | ||||
| import io.github.ollama4j.utils.Options; | ||||
| import io.github.ollama4j.utils.Utils; | ||||
| import lombok.Setter; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import java.io.*; | ||||
| import java.net.URI; | ||||
| @@ -32,11 +30,19 @@ import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Files; | ||||
| import java.time.Duration; | ||||
| import java.util.*; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.jsoup.Jsoup; | ||||
| import org.jsoup.nodes.Document; | ||||
| import org.jsoup.nodes.Element; | ||||
| import org.jsoup.select.Elements; | ||||
|  | ||||
| /** | ||||
|  * The base Ollama API class. | ||||
|  */ | ||||
| @SuppressWarnings("DuplicatedCode") | ||||
| @SuppressWarnings({"DuplicatedCode", "resource"}) | ||||
| public class OllamaAPI { | ||||
|  | ||||
|     private static final Logger logger = LoggerFactory.getLogger(OllamaAPI.class); | ||||
| @@ -97,12 +103,7 @@ public class OllamaAPI { | ||||
|         HttpClient httpClient = HttpClient.newHttpClient(); | ||||
|         HttpRequest httpRequest = null; | ||||
|         try { | ||||
|             httpRequest = | ||||
|                     getRequestBuilderDefault(new URI(url)) | ||||
|                             .header("Accept", "application/json") | ||||
|                             .header("Content-type", "application/json") | ||||
|                             .GET() | ||||
|                             .build(); | ||||
|             httpRequest = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-type", "application/json").GET().build(); | ||||
|         } catch (URISyntaxException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
| @@ -121,19 +122,17 @@ public class OllamaAPI { | ||||
|     /** | ||||
|      * Provides a list of running models and details about each model currently loaded into memory. | ||||
|      * | ||||
|      * @return ModelsProcessResponse | ||||
|      * @return ModelsProcessResponse containing details about the running models | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      */ | ||||
|     public ModelsProcessResponse ps() throws IOException, InterruptedException, OllamaBaseException { | ||||
|         String url = this.host + "/api/ps"; | ||||
|         HttpClient httpClient = HttpClient.newHttpClient(); | ||||
|         HttpRequest httpRequest = null; | ||||
|         try { | ||||
|             httpRequest = | ||||
|                     getRequestBuilderDefault(new URI(url)) | ||||
|                             .header("Accept", "application/json") | ||||
|                             .header("Content-type", "application/json") | ||||
|                             .GET() | ||||
|                             .build(); | ||||
|             httpRequest = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-type", "application/json").GET().build(); | ||||
|         } catch (URISyntaxException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
| @@ -142,69 +141,182 @@ public class OllamaAPI { | ||||
|         int statusCode = response.statusCode(); | ||||
|         String responseString = response.body(); | ||||
|         if (statusCode == 200) { | ||||
|             return Utils.getObjectMapper() | ||||
|                     .readValue(responseString, ModelsProcessResponse.class); | ||||
|             return Utils.getObjectMapper().readValue(responseString, ModelsProcessResponse.class); | ||||
|         } else { | ||||
|             throw new OllamaBaseException(statusCode + " - " + responseString); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * List available models from Ollama server. | ||||
|      * Lists available models from the Ollama server. | ||||
|      * | ||||
|      * @return the list | ||||
|      * @return a list of models available on the server | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public List<Model> listModels() | ||||
|             throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|     public List<Model> listModels() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|         String url = this.host + "/api/tags"; | ||||
|         HttpClient httpClient = HttpClient.newHttpClient(); | ||||
|         HttpRequest httpRequest = | ||||
|                 getRequestBuilderDefault(new URI(url)) | ||||
|                         .header("Accept", "application/json") | ||||
|                         .header("Content-type", "application/json") | ||||
|                         .GET() | ||||
|                         .build(); | ||||
|         HttpResponse<String> response = | ||||
|                 httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); | ||||
|         HttpRequest httpRequest = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-type", "application/json").GET().build(); | ||||
|         HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
|         String responseString = response.body(); | ||||
|         if (statusCode == 200) { | ||||
|             return Utils.getObjectMapper() | ||||
|                     .readValue(responseString, ListModelsResponse.class) | ||||
|                     .getModels(); | ||||
|             return Utils.getObjectMapper().readValue(responseString, ListModelsResponse.class).getModels(); | ||||
|         } else { | ||||
|             throw new OllamaBaseException(statusCode + " - " + responseString); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Retrieves a list of models from the Ollama library. This method fetches the available models directly from Ollama | ||||
|      * library page, including model details such as the name, pull count, popular tags, tag count, and the time when model was updated. | ||||
|      * | ||||
|      * @return A list of {@link LibraryModel} objects representing the models available in the Ollama library. | ||||
|      * @throws OllamaBaseException  If the HTTP request fails or the response is not successful (non-200 status code). | ||||
|      * @throws IOException          If an I/O error occurs during the HTTP request or response processing. | ||||
|      * @throws InterruptedException If the thread executing the request is interrupted. | ||||
|      * @throws URISyntaxException   If there is an error creating the URI for the HTTP request. | ||||
|      */ | ||||
|     public List<LibraryModel> listModelsFromLibrary() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|         String url = "https://ollama.com/library"; | ||||
|         HttpClient httpClient = HttpClient.newHttpClient(); | ||||
|         HttpRequest httpRequest = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-type", "application/json").GET().build(); | ||||
|         HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
|         String responseString = response.body(); | ||||
|         List<LibraryModel> models = new ArrayList<>(); | ||||
|         if (statusCode == 200) { | ||||
|             Document doc = Jsoup.parse(responseString); | ||||
|             Elements modelSections = doc.selectXpath("//*[@id='repo']/ul/li/a"); | ||||
|             for (Element e : modelSections) { | ||||
|                 LibraryModel model = new LibraryModel(); | ||||
|                 Elements names = e.select("div > h2 > span"); | ||||
|                 Elements desc = e.select("div > p"); | ||||
|                 Elements pullCounts = e.select("div:nth-of-type(2) > p > span:first-of-type > span:first-of-type"); | ||||
|                 Elements popularTags = e.select("div > div > span"); | ||||
|                 Elements totalTags = e.select("div:nth-of-type(2) > p > span:nth-of-type(2) > span:first-of-type"); | ||||
|                 Elements lastUpdatedTime = e.select("div:nth-of-type(2) > p > span:nth-of-type(3) > span:nth-of-type(2)"); | ||||
|  | ||||
|                 if (names.first() == null || names.isEmpty()) { | ||||
|                     // if name cannot be extracted, skip. | ||||
|                     continue; | ||||
|                 } | ||||
|                 Optional.ofNullable(names.first()).map(Element::text).ifPresent(model::setName); | ||||
|                 model.setDescription(Optional.ofNullable(desc.first()).map(Element::text).orElse("")); | ||||
|                 model.setPopularTags(Optional.of(popularTags).map(tags -> tags.stream().map(Element::text).collect(Collectors.toList())).orElse(new ArrayList<>())); | ||||
|                 model.setPullCount(Optional.ofNullable(pullCounts.first()).map(Element::text).orElse("")); | ||||
|                 model.setTotalTags(Optional.ofNullable(totalTags.first()).map(Element::text).map(Integer::parseInt).orElse(0)); | ||||
|                 model.setLastUpdated(Optional.ofNullable(lastUpdatedTime.first()).map(Element::text).orElse("")); | ||||
|  | ||||
|                 models.add(model); | ||||
|             } | ||||
|             return models; | ||||
|         } else { | ||||
|             throw new OllamaBaseException(statusCode + " - " + responseString); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Fetches the tags associated with a specific model from Ollama library. | ||||
|      * This method fetches the available model tags directly from Ollama library model page, including model tag name, size and time when model was last updated | ||||
|      * into a list of {@link LibraryModelTag} objects. | ||||
|      * | ||||
|      * @param libraryModel the {@link LibraryModel} object which contains the name of the library model | ||||
|      *                     for which the tags need to be fetched. | ||||
|      * @return a list of {@link LibraryModelTag} objects containing the extracted tags and their associated metadata. | ||||
|      * @throws OllamaBaseException  if the HTTP response status code indicates an error (i.e., not 200 OK), | ||||
|      *                              or if there is any other issue during the request or response processing. | ||||
|      * @throws IOException          if an input/output exception occurs during the HTTP request or response handling. | ||||
|      * @throws InterruptedException if the thread is interrupted while waiting for the HTTP response. | ||||
|      * @throws URISyntaxException   if the URI format is incorrect or invalid. | ||||
|      */ | ||||
|     public LibraryModelDetail getLibraryModelDetails(LibraryModel libraryModel) throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|         String url = String.format("https://ollama.com/library/%s/tags", libraryModel.getName()); | ||||
|         HttpClient httpClient = HttpClient.newHttpClient(); | ||||
|         HttpRequest httpRequest = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-type", "application/json").GET().build(); | ||||
|         HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
|         String responseString = response.body(); | ||||
|  | ||||
|         List<LibraryModelTag> libraryModelTags = new ArrayList<>(); | ||||
|         if (statusCode == 200) { | ||||
|             Document doc = Jsoup.parse(responseString); | ||||
|             Elements tagSections = doc.select("html > body > main > div > section > div > div > div:nth-child(n+2) > div"); | ||||
|             for (Element e : tagSections) { | ||||
|                 Elements tags = e.select("div > a > div"); | ||||
|                 Elements tagsMetas = e.select("div > span"); | ||||
|  | ||||
|                 LibraryModelTag libraryModelTag = new LibraryModelTag(); | ||||
|  | ||||
|                 if (tags.first() == null || tags.isEmpty()) { | ||||
|                     // if tag cannot be extracted, skip. | ||||
|                     continue; | ||||
|                 } | ||||
|                 libraryModelTag.setName(libraryModel.getName()); | ||||
|                 Optional.ofNullable(tags.first()).map(Element::text).ifPresent(libraryModelTag::setTag); | ||||
|                 libraryModelTag.setSize(Optional.ofNullable(tagsMetas.first()).map(element -> element.text().split("•")).filter(parts -> parts.length > 1).map(parts -> parts[1].trim()).orElse("")); | ||||
|                 libraryModelTag.setLastUpdated(Optional.ofNullable(tagsMetas.first()).map(element -> element.text().split("•")).filter(parts -> parts.length > 1).map(parts -> parts[2].trim()).orElse("")); | ||||
|                 libraryModelTags.add(libraryModelTag); | ||||
|             } | ||||
|             LibraryModelDetail libraryModelDetail = new LibraryModelDetail(); | ||||
|             libraryModelDetail.setModel(libraryModel); | ||||
|             libraryModelDetail.setTags(libraryModelTags); | ||||
|             return libraryModelDetail; | ||||
|         } else { | ||||
|             throw new OllamaBaseException(statusCode + " - " + responseString); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Finds a specific model using model name and tag from Ollama library. | ||||
|      * <p> | ||||
|      * This method retrieves the model from the Ollama library by its name, then fetches its tags. | ||||
|      * It searches through the tags of the model to find one that matches the specified tag name. | ||||
|      * If the model or the tag is not found, it throws a {@link NoSuchElementException}. | ||||
|      * | ||||
|      * @param modelName The name of the model to search for in the library. | ||||
|      * @param tag       The tag name to search for within the specified model. | ||||
|      * @return The {@link LibraryModelTag} associated with the specified model and tag. | ||||
|      * @throws OllamaBaseException    If there is a problem with the Ollama library operations. | ||||
|      * @throws IOException            If an I/O error occurs during the operation. | ||||
|      * @throws URISyntaxException     If there is an error with the URI syntax. | ||||
|      * @throws InterruptedException   If the operation is interrupted. | ||||
|      * @throws NoSuchElementException If the model or the tag is not found. | ||||
|      */ | ||||
|     public LibraryModelTag findModelTagFromLibrary(String modelName, String tag) throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { | ||||
|         List<LibraryModel> libraryModels = this.listModelsFromLibrary(); | ||||
|         LibraryModel libraryModel = libraryModels.stream().filter(model -> model.getName().equals(modelName)).findFirst().orElseThrow(() -> new NoSuchElementException(String.format("Model by name '%s' not found", modelName))); | ||||
|         LibraryModelDetail libraryModelDetail = this.getLibraryModelDetails(libraryModel); | ||||
|         LibraryModelTag libraryModelTag = libraryModelDetail.getTags().stream().filter(tagName -> tagName.getTag().equals(tag)).findFirst().orElseThrow(() -> new NoSuchElementException(String.format("Tag '%s' for model '%s' not found", tag, modelName))); | ||||
|         return libraryModelTag; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Pull a model on the Ollama server from the list of <a | ||||
|      * href="https://ollama.ai/library">available models</a>. | ||||
|      * | ||||
|      * @param modelName the name of the model | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public void pullModel(String modelName) | ||||
|             throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { | ||||
|     public void pullModel(String modelName) throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { | ||||
|         String url = this.host + "/api/pull"; | ||||
|         String jsonData = new ModelRequest(modelName).toString(); | ||||
|         HttpRequest request = | ||||
|                 getRequestBuilderDefault(new URI(url)) | ||||
|                         .POST(HttpRequest.BodyPublishers.ofString(jsonData)) | ||||
|                         .header("Accept", "application/json") | ||||
|                         .header("Content-type", "application/json") | ||||
|                         .build(); | ||||
|         HttpRequest request = getRequestBuilderDefault(new URI(url)).POST(HttpRequest.BodyPublishers.ofString(jsonData)).header("Accept", "application/json").header("Content-type", "application/json").build(); | ||||
|         HttpClient client = HttpClient.newHttpClient(); | ||||
|         HttpResponse<InputStream> response = | ||||
|                 client.send(request, HttpResponse.BodyHandlers.ofInputStream()); | ||||
|         HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()); | ||||
|         int statusCode = response.statusCode(); | ||||
|         InputStream responseBodyStream = response.body(); | ||||
|         String responseString = ""; | ||||
|         try (BufferedReader reader = | ||||
|                      new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { | ||||
|         try (BufferedReader reader = new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { | ||||
|             String line; | ||||
|             while ((line = reader.readLine()) != null) { | ||||
|                 ModelPullResponse modelPullResponse = | ||||
|                         Utils.getObjectMapper().readValue(line, ModelPullResponse.class); | ||||
|                 ModelPullResponse modelPullResponse = Utils.getObjectMapper().readValue(line, ModelPullResponse.class); | ||||
|                 if (verbose) { | ||||
|                     logger.info(modelPullResponse.getStatus()); | ||||
|                 } | ||||
| @@ -215,22 +327,37 @@ public class OllamaAPI { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Pulls a model using the specified Ollama library model tag. | ||||
|      * The model is identified by a name and a tag, which are combined into a single identifier | ||||
|      * in the format "name:tag" to pull the corresponding model. | ||||
|      * | ||||
|      * @param libraryModelTag the {@link LibraryModelTag} object containing the name and tag | ||||
|      *                        of the model to be pulled. | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public void pullModel(LibraryModelTag libraryModelTag) throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { | ||||
|         String tagToPull = String.format("%s:%s", libraryModelTag.getName(), libraryModelTag.getTag()); | ||||
|         pullModel(tagToPull); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets model details from the Ollama server. | ||||
|      * | ||||
|      * @param modelName the model | ||||
|      * @return the model details | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public ModelDetail getModelDetails(String modelName) | ||||
|             throws IOException, OllamaBaseException, InterruptedException, URISyntaxException { | ||||
|     public ModelDetail getModelDetails(String modelName) throws IOException, OllamaBaseException, InterruptedException, URISyntaxException { | ||||
|         String url = this.host + "/api/show"; | ||||
|         String jsonData = new ModelRequest(modelName).toString(); | ||||
|         HttpRequest request = | ||||
|                 getRequestBuilderDefault(new URI(url)) | ||||
|                         .header("Accept", "application/json") | ||||
|                         .header("Content-type", "application/json") | ||||
|                         .POST(HttpRequest.BodyPublishers.ofString(jsonData)) | ||||
|                         .build(); | ||||
|         HttpRequest request = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-type", "application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData)).build(); | ||||
|         HttpClient client = HttpClient.newHttpClient(); | ||||
|         HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
| @@ -248,17 +375,15 @@ public class OllamaAPI { | ||||
|      * | ||||
|      * @param modelName     the name of the custom model to be created. | ||||
|      * @param modelFilePath the path to model file that exists on the Ollama server. | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public void createModelWithFilePath(String modelName, String modelFilePath) | ||||
|             throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { | ||||
|     public void createModelWithFilePath(String modelName, String modelFilePath) throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { | ||||
|         String url = this.host + "/api/create"; | ||||
|         String jsonData = new CustomModelFilePathRequest(modelName, modelFilePath).toString(); | ||||
|         HttpRequest request = | ||||
|                 getRequestBuilderDefault(new URI(url)) | ||||
|                         .header("Accept", "application/json") | ||||
|                         .header("Content-Type", "application/json") | ||||
|                         .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) | ||||
|                         .build(); | ||||
|         HttpRequest request = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build(); | ||||
|         HttpClient client = HttpClient.newHttpClient(); | ||||
|         HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
| @@ -282,17 +407,15 @@ public class OllamaAPI { | ||||
|      * | ||||
|      * @param modelName         the name of the custom model to be created. | ||||
|      * @param modelFileContents the path to model file that exists on the Ollama server. | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public void createModelWithModelFileContents(String modelName, String modelFileContents) | ||||
|             throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { | ||||
|     public void createModelWithModelFileContents(String modelName, String modelFileContents) throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { | ||||
|         String url = this.host + "/api/create"; | ||||
|         String jsonData = new CustomModelFileContentsRequest(modelName, modelFileContents).toString(); | ||||
|         HttpRequest request = | ||||
|                 getRequestBuilderDefault(new URI(url)) | ||||
|                         .header("Accept", "application/json") | ||||
|                         .header("Content-Type", "application/json") | ||||
|                         .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) | ||||
|                         .build(); | ||||
|         HttpRequest request = getRequestBuilderDefault(new URI(url)).header("Accept", "application/json").header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build(); | ||||
|         HttpClient client = HttpClient.newHttpClient(); | ||||
|         HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
| @@ -313,17 +436,15 @@ public class OllamaAPI { | ||||
|      * | ||||
|      * @param modelName          the name of the model to be deleted. | ||||
|      * @param ignoreIfNotPresent ignore errors if the specified model is not present on Ollama server. | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public void deleteModel(String modelName, boolean ignoreIfNotPresent) | ||||
|             throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { | ||||
|     public void deleteModel(String modelName, boolean ignoreIfNotPresent) throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { | ||||
|         String url = this.host + "/api/delete"; | ||||
|         String jsonData = new ModelRequest(modelName).toString(); | ||||
|         HttpRequest request = | ||||
|                 getRequestBuilderDefault(new URI(url)) | ||||
|                         .method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) | ||||
|                         .header("Accept", "application/json") | ||||
|                         .header("Content-type", "application/json") | ||||
|                         .build(); | ||||
|         HttpRequest request = getRequestBuilderDefault(new URI(url)).method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).header("Accept", "application/json").header("Content-type", "application/json").build(); | ||||
|         HttpClient client = HttpClient.newHttpClient(); | ||||
|         HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
| @@ -342,9 +463,13 @@ public class OllamaAPI { | ||||
|      * @param model  name of model to generate embeddings from | ||||
|      * @param prompt text to generate embeddings for | ||||
|      * @return embeddings | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @deprecated Use {@link #embed(String, List)} instead. | ||||
|      */ | ||||
|     public List<Double> generateEmbeddings(String model, String prompt) | ||||
|             throws IOException, InterruptedException, OllamaBaseException { | ||||
|     @Deprecated | ||||
|     public List<Double> generateEmbeddings(String model, String prompt) throws IOException, InterruptedException, OllamaBaseException { | ||||
|         return generateEmbeddings(new OllamaEmbeddingsRequestModel(model, prompt)); | ||||
|     } | ||||
|  | ||||
| @@ -353,28 +478,69 @@ public class OllamaAPI { | ||||
|      * | ||||
|      * @param modelRequest request for '/api/embeddings' endpoint | ||||
|      * @return embeddings | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @deprecated Use {@link #embed(OllamaEmbedRequestModel)} instead. | ||||
|      */ | ||||
|     @Deprecated | ||||
|     public List<Double> generateEmbeddings(OllamaEmbeddingsRequestModel modelRequest) throws IOException, InterruptedException, OllamaBaseException { | ||||
|         URI uri = URI.create(this.host + "/api/embeddings"); | ||||
|         String jsonData = modelRequest.toString(); | ||||
|         HttpClient httpClient = HttpClient.newHttpClient(); | ||||
|         HttpRequest.Builder requestBuilder = | ||||
|                 getRequestBuilderDefault(uri) | ||||
|                         .header("Accept", "application/json") | ||||
|                         .POST(HttpRequest.BodyPublishers.ofString(jsonData)); | ||||
|         HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri).header("Accept", "application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData)); | ||||
|         HttpRequest request = requestBuilder.build(); | ||||
|         HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
|         String responseBody = response.body(); | ||||
|         if (statusCode == 200) { | ||||
|             OllamaEmbeddingResponseModel embeddingResponse = | ||||
|                     Utils.getObjectMapper().readValue(responseBody, OllamaEmbeddingResponseModel.class); | ||||
|             OllamaEmbeddingResponseModel embeddingResponse = Utils.getObjectMapper().readValue(responseBody, OllamaEmbeddingResponseModel.class); | ||||
|             return embeddingResponse.getEmbedding(); | ||||
|         } else { | ||||
|             throw new OllamaBaseException(statusCode + " - " + responseBody); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Generate embeddings for a given text from a model | ||||
|      * | ||||
|      * @param model  name of model to generate embeddings from | ||||
|      * @param inputs text/s to generate embeddings for | ||||
|      * @return embeddings | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaEmbedResponseModel embed(String model, List<String> inputs) throws IOException, InterruptedException, OllamaBaseException { | ||||
|         return embed(new OllamaEmbedRequestModel(model, inputs)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Generate embeddings using a {@link OllamaEmbedRequestModel}. | ||||
|      * | ||||
|      * @param modelRequest request for '/api/embed' endpoint | ||||
|      * @return embeddings | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaEmbedResponseModel embed(OllamaEmbedRequestModel modelRequest) throws IOException, InterruptedException, OllamaBaseException { | ||||
|         URI uri = URI.create(this.host + "/api/embed"); | ||||
|         String jsonData = Utils.getObjectMapper().writeValueAsString(modelRequest); | ||||
|         HttpClient httpClient = HttpClient.newHttpClient(); | ||||
|  | ||||
|         HttpRequest request = HttpRequest.newBuilder(uri).header("Accept", "application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData)).build(); | ||||
|  | ||||
|         HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         int statusCode = response.statusCode(); | ||||
|         String responseBody = response.body(); | ||||
|  | ||||
|         if (statusCode == 200) { | ||||
|             return Utils.getObjectMapper().readValue(responseBody, OllamaEmbedResponseModel.class); | ||||
|         } else { | ||||
|             throw new OllamaBaseException(statusCode + " - " + responseBody); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Generate response for a question to a model running on Ollama server. This is a sync/blocking | ||||
| @@ -387,9 +553,11 @@ public class OllamaAPI { | ||||
|      *                      details on the options</a> | ||||
|      * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. | ||||
|      * @return OllamaResult that includes response text and time taken for response | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaResult generate(String model, String prompt, boolean raw, Options options, OllamaStreamHandler streamHandler) | ||||
|             throws OllamaBaseException, IOException, InterruptedException { | ||||
|     public OllamaResult generate(String model, String prompt, boolean raw, Options options, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt); | ||||
|         ollamaRequestModel.setRaw(raw); | ||||
|         ollamaRequestModel.setOptions(options.getOptionsMap()); | ||||
| @@ -406,13 +574,14 @@ public class OllamaAPI { | ||||
|      * @param raw     In some cases, you may wish to bypass the templating system and provide a full prompt. In this case, you can use the raw parameter to disable templating. Also note that raw mode will not return a context. | ||||
|      * @param options Additional options or configurations to use when generating the response. | ||||
|      * @return {@link OllamaResult} | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaResult generate(String model, String prompt, boolean raw, Options options) | ||||
|             throws OllamaBaseException, IOException, InterruptedException { | ||||
|     public OllamaResult generate(String model, String prompt, boolean raw, Options options) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         return generate(model, prompt, raw, options, null); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Generates response using the specified AI model and prompt (in blocking mode), and then invokes a set of tools | ||||
|      * on the generated response. | ||||
| @@ -421,13 +590,11 @@ public class OllamaAPI { | ||||
|      * @param prompt  The input text or prompt to provide to the AI model. | ||||
|      * @param options Additional options or configurations to use when generating the response. | ||||
|      * @return {@link OllamaToolsResult} An OllamaToolsResult object containing the response from the AI model and the results of invoking the tools on that output. | ||||
|      * @throws OllamaBaseException  If there is an error related to the Ollama API or service. | ||||
|      * @throws IOException          If there is an error related to input/output operations. | ||||
|      * @throws InterruptedException If the method is interrupted while waiting for the AI model | ||||
|      *                              to generate the response or for the tools to be invoked. | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaToolsResult generateWithTools(String model, String prompt, Options options) | ||||
|             throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException { | ||||
|     public OllamaToolsResult generateWithTools(String model, String prompt, Options options) throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException { | ||||
|         boolean raw = true; | ||||
|         OllamaToolsResult toolResult = new OllamaToolsResult(); | ||||
|         Map<ToolFunctionCallSpec, Object> toolResults = new HashMap<>(); | ||||
| @@ -448,7 +615,6 @@ public class OllamaAPI { | ||||
|         return toolResult; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Generate response for a question to a model running on Ollama server and get a callback handle | ||||
|      * that can be used to check for status and get the response from the model later. This would be | ||||
| @@ -462,9 +628,7 @@ public class OllamaAPI { | ||||
|         OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt); | ||||
|         ollamaRequestModel.setRaw(raw); | ||||
|         URI uri = URI.create(this.host + "/api/generate"); | ||||
|         OllamaAsyncResultStreamer ollamaAsyncResultStreamer = | ||||
|                 new OllamaAsyncResultStreamer( | ||||
|                         getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds); | ||||
|         OllamaAsyncResultStreamer ollamaAsyncResultStreamer = new OllamaAsyncResultStreamer(getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds); | ||||
|         ollamaAsyncResultStreamer.start(); | ||||
|         return ollamaAsyncResultStreamer; | ||||
|     } | ||||
| @@ -481,10 +645,11 @@ public class OllamaAPI { | ||||
|      *                      details on the options</a> | ||||
|      * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. | ||||
|      * @return OllamaResult that includes response text and time taken for response | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaResult generateWithImageFiles( | ||||
|             String model, String prompt, List<File> imageFiles, Options options, OllamaStreamHandler streamHandler) | ||||
|             throws OllamaBaseException, IOException, InterruptedException { | ||||
|     public OllamaResult generateWithImageFiles(String model, String prompt, List<File> imageFiles, Options options, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         List<String> images = new ArrayList<>(); | ||||
|         for (File imageFile : imageFiles) { | ||||
|             images.add(encodeFileToBase64(imageFile)); | ||||
| @@ -498,10 +663,12 @@ public class OllamaAPI { | ||||
|      * Convenience method to call Ollama API without streaming responses. | ||||
|      * <p> | ||||
|      * Uses {@link #generateWithImageFiles(String, String, List, Options, OllamaStreamHandler)} | ||||
|      * | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaResult generateWithImageFiles( | ||||
|             String model, String prompt, List<File> imageFiles, Options options) | ||||
|             throws OllamaBaseException, IOException, InterruptedException { | ||||
|     public OllamaResult generateWithImageFiles(String model, String prompt, List<File> imageFiles, Options options) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         return generateWithImageFiles(model, prompt, imageFiles, options, null); | ||||
|     } | ||||
|  | ||||
| @@ -517,10 +684,12 @@ public class OllamaAPI { | ||||
|      *                      details on the options</a> | ||||
|      * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. | ||||
|      * @return OllamaResult that includes response text and time taken for response | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public OllamaResult generateWithImageURLs( | ||||
|             String model, String prompt, List<String> imageURLs, Options options, OllamaStreamHandler streamHandler) | ||||
|             throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|     public OllamaResult generateWithImageURLs(String model, String prompt, List<String> imageURLs, Options options, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|         List<String> images = new ArrayList<>(); | ||||
|         for (String imageURL : imageURLs) { | ||||
|             images.add(encodeByteArrayToBase64(Utils.loadImageBytesFromUrl(imageURL))); | ||||
| @@ -534,14 +703,16 @@ public class OllamaAPI { | ||||
|      * Convenience method to call Ollama API without streaming responses. | ||||
|      * <p> | ||||
|      * Uses {@link #generateWithImageURLs(String, String, List, Options, OllamaStreamHandler)} | ||||
|      * | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      * @throws URISyntaxException   if the URI for the request is malformed | ||||
|      */ | ||||
|     public OllamaResult generateWithImageURLs(String model, String prompt, List<String> imageURLs, | ||||
|                                               Options options) | ||||
|             throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|     public OllamaResult generateWithImageURLs(String model, String prompt, List<String> imageURLs, Options options) throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { | ||||
|         return generateWithImageURLs(model, prompt, imageURLs, options, null); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Ask a question to a model based on a given message stack (i.e. a chat history). Creates a synchronous call to the api | ||||
|      * 'api/chat'. | ||||
| @@ -552,6 +723,9 @@ public class OllamaAPI { | ||||
|      * @throws OllamaBaseException  any response code than 200 has been returned | ||||
|      * @throws IOException          in case the responseStream can not be read | ||||
|      * @throws InterruptedException in case the server is not reachable or network issues happen | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaChatResult chat(String model, List<OllamaChatMessage> messages) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(model); | ||||
| @@ -568,6 +742,9 @@ public class OllamaAPI { | ||||
|      * @throws OllamaBaseException  any response code than 200 has been returned | ||||
|      * @throws IOException          in case the responseStream can not be read | ||||
|      * @throws InterruptedException in case the server is not reachable or network issues happen | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaChatResult chat(OllamaChatRequest request) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         return chat(request, null); | ||||
| @@ -584,6 +761,9 @@ public class OllamaAPI { | ||||
|      * @throws OllamaBaseException  any response code than 200 has been returned | ||||
|      * @throws IOException          in case the responseStream can not be read | ||||
|      * @throws InterruptedException in case the server is not reachable or network issues happen | ||||
|      * @throws OllamaBaseException  if the response indicates an error status | ||||
|      * @throws IOException          if an I/O error occurs during the HTTP request | ||||
|      * @throws InterruptedException if the operation is interrupted | ||||
|      */ | ||||
|     public OllamaChatResult chat(OllamaChatRequest request, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose); | ||||
| @@ -601,6 +781,37 @@ public class OllamaAPI { | ||||
|         toolRegistry.addFunction(toolSpecification.getFunctionName(), toolSpecification.getToolDefinition()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a custom role. | ||||
|      * | ||||
|      * @param roleName the name of the custom role to be added | ||||
|      * @return the newly created OllamaChatMessageRole | ||||
|      */ | ||||
|     public OllamaChatMessageRole addCustomRole(String roleName) { | ||||
|         return OllamaChatMessageRole.newCustomRole(roleName); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Lists all available roles. | ||||
|      * | ||||
|      * @return a list of available OllamaChatMessageRole objects | ||||
|      */ | ||||
|     public List<OllamaChatMessageRole> listRoles() { | ||||
|         return OllamaChatMessageRole.getRoles(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Retrieves a specific role by name. | ||||
|      * | ||||
|      * @param roleName the name of the role to retrieve | ||||
|      * @return the OllamaChatMessageRole associated with the given name | ||||
|      * @throws RoleNotFoundException if the role with the specified name does not exist | ||||
|      */ | ||||
|     public OllamaChatMessageRole getRole(String roleName) throws RoleNotFoundException { | ||||
|         return OllamaChatMessageRole.getRole(roleName); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // technical private methods // | ||||
|  | ||||
|     private static String encodeFileToBase64(File file) throws IOException { | ||||
| @@ -611,11 +822,8 @@ public class OllamaAPI { | ||||
|         return Base64.getEncoder().encodeToString(bytes); | ||||
|     } | ||||
|  | ||||
|     private OllamaResult generateSyncForOllamaRequestModel( | ||||
|             OllamaGenerateRequest ollamaRequestModel, OllamaStreamHandler streamHandler) | ||||
|             throws OllamaBaseException, IOException, InterruptedException { | ||||
|         OllamaGenerateEndpointCaller requestCaller = | ||||
|                 new OllamaGenerateEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose); | ||||
|     private OllamaResult generateSyncForOllamaRequestModel(OllamaGenerateRequest ollamaRequestModel, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException { | ||||
|         OllamaGenerateEndpointCaller requestCaller = new OllamaGenerateEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose); | ||||
|         OllamaResult result; | ||||
|         if (streamHandler != null) { | ||||
|             ollamaRequestModel.setStream(true); | ||||
| @@ -633,10 +841,7 @@ public class OllamaAPI { | ||||
|      * @return HttpRequest.Builder | ||||
|      */ | ||||
|     private HttpRequest.Builder getRequestBuilderDefault(URI uri) { | ||||
|         HttpRequest.Builder requestBuilder = | ||||
|                 HttpRequest.newBuilder(uri) | ||||
|                         .header("Content-Type", "application/json") | ||||
|                         .timeout(Duration.ofSeconds(requestTimeoutSeconds)); | ||||
|         HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).header("Content-Type", "application/json").timeout(Duration.ofSeconds(requestTimeoutSeconds)); | ||||
|         if (isBasicAuthCredentialsSet()) { | ||||
|             requestBuilder.header("Authorization", getBasicAuthHeaderValue()); | ||||
|         } | ||||
| @@ -662,7 +867,6 @@ public class OllamaAPI { | ||||
|         return basicAuth != null; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec) throws ToolInvocationException { | ||||
|         try { | ||||
|             String methodName = toolFunctionCallSpec.getName(); | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| package io.github.ollama4j.exceptions; | ||||
|  | ||||
| public class RoleNotFoundException extends Exception { | ||||
|  | ||||
|     public RoleNotFoundException(String s) { | ||||
|         super(s); | ||||
|     } | ||||
| } | ||||
| @@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||||
| import io.github.ollama4j.utils.FileToBase64Serializer; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| @@ -33,13 +34,13 @@ public class OllamaChatMessage { | ||||
|  | ||||
|     @JsonSerialize(using = FileToBase64Serializer.class) | ||||
|     private List<byte[]> images; | ||||
|      | ||||
|       @Override | ||||
|   public String toString() { | ||||
|     try { | ||||
|       return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); | ||||
|     } catch (JsonProcessingException e) { | ||||
|       throw new RuntimeException(e); | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         try { | ||||
|             return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); | ||||
|         } catch (JsonProcessingException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,19 +1,53 @@ | ||||
| package io.github.ollama4j.models.chat; | ||||
|  | ||||
| import com.fasterxml.jackson.annotation.JsonValue; | ||||
| import io.github.ollama4j.exceptions.RoleNotFoundException; | ||||
| import lombok.Getter; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * Defines the possible Chat Message roles. | ||||
|  */ | ||||
| public enum OllamaChatMessageRole { | ||||
|     SYSTEM("system"), | ||||
|     USER("user"), | ||||
|     ASSISTANT("assistant"); | ||||
| @Getter | ||||
| public class OllamaChatMessageRole { | ||||
|     private static final List<OllamaChatMessageRole> roles = new ArrayList<>(); | ||||
|  | ||||
|     public static final OllamaChatMessageRole SYSTEM = new OllamaChatMessageRole("system"); | ||||
|     public static final OllamaChatMessageRole USER = new OllamaChatMessageRole("user"); | ||||
|     public static final OllamaChatMessageRole ASSISTANT = new OllamaChatMessageRole("assistant"); | ||||
|     public static final OllamaChatMessageRole TOOL = new OllamaChatMessageRole("tool"); | ||||
|  | ||||
|     @JsonValue | ||||
|     private String roleName; | ||||
|     private final String roleName; | ||||
|  | ||||
|     private OllamaChatMessageRole(String roleName){ | ||||
|     private OllamaChatMessageRole(String roleName) { | ||||
|         this.roleName = roleName; | ||||
|         roles.add(this); | ||||
|     } | ||||
|  | ||||
|     public static OllamaChatMessageRole newCustomRole(String roleName) { | ||||
|         OllamaChatMessageRole customRole = new OllamaChatMessageRole(roleName); | ||||
|         roles.add(customRole); | ||||
|         return customRole; | ||||
|     } | ||||
|  | ||||
|     public static List<OllamaChatMessageRole> getRoles() { | ||||
|         return new ArrayList<>(roles); | ||||
|     } | ||||
|  | ||||
|     public static OllamaChatMessageRole getRole(String roleName) throws RoleNotFoundException { | ||||
|         for (OllamaChatMessageRole role : roles) { | ||||
|             if (role.roleName.equals(roleName)) { | ||||
|                 return role; | ||||
|             } | ||||
|         } | ||||
|         throw new RoleNotFoundException("Invalid role name: " + roleName); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return roleName; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,12 +8,11 @@ import io.github.ollama4j.models.response.OllamaResult; | ||||
|  * Specific chat-API result that contains the chat history sent to the model and appends the answer as {@link OllamaChatResult} given by the | ||||
|  * {@link OllamaChatMessageRole#ASSISTANT} role. | ||||
|  */ | ||||
| public class OllamaChatResult extends OllamaResult{ | ||||
| public class OllamaChatResult extends OllamaResult { | ||||
|  | ||||
|     private List<OllamaChatMessage> chatHistory; | ||||
|  | ||||
|     public OllamaChatResult(String response, long responseTime, int httpStatusCode, | ||||
|             List<OllamaChatMessage> chatHistory) { | ||||
|     public OllamaChatResult(String response, long responseTime, int httpStatusCode, List<OllamaChatMessage> chatHistory) { | ||||
|         super(response, responseTime, httpStatusCode); | ||||
|         this.chatHistory = chatHistory; | ||||
|         appendAnswerToChatHistory(response); | ||||
| @@ -21,12 +20,10 @@ public class OllamaChatResult extends OllamaResult{ | ||||
|  | ||||
|     public List<OllamaChatMessage> getChatHistory() { | ||||
|         return chatHistory; | ||||
|     }  | ||||
|     } | ||||
|  | ||||
|     private void appendAnswerToChatHistory(String answer){ | ||||
|     private void appendAnswerToChatHistory(String answer) { | ||||
|         OllamaChatMessage assistantMessage = new OllamaChatMessage(OllamaChatMessageRole.ASSISTANT, answer); | ||||
|         this.chatHistory.add(assistantMessage); | ||||
|     } | ||||
|      | ||||
|      | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,41 @@ | ||||
| package io.github.ollama4j.models.embeddings; | ||||
|  | ||||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| import static io.github.ollama4j.utils.Utils.getObjectMapper; | ||||
|  | ||||
| @Data | ||||
| @RequiredArgsConstructor | ||||
| @NoArgsConstructor | ||||
| public class OllamaEmbedRequestModel { | ||||
|     @NonNull | ||||
|     private String model; | ||||
|  | ||||
|     @NonNull | ||||
|     private List<String> input; | ||||
|  | ||||
|     private Map<String, Object> options; | ||||
|  | ||||
|     @JsonProperty(value = "keep_alive") | ||||
|     private String keepAlive; | ||||
|  | ||||
|     @JsonProperty(value = "truncate") | ||||
|     private Boolean truncate = true; | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         try { | ||||
|             return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); | ||||
|         } catch (JsonProcessingException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| package io.github.ollama4j.models.embeddings; | ||||
|  | ||||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @SuppressWarnings("unused") | ||||
| @Data | ||||
| public class OllamaEmbedResponseModel { | ||||
|     @JsonProperty("model") | ||||
|     private String model; | ||||
|  | ||||
|     @JsonProperty("embeddings") | ||||
|     private List<List<Double>> embeddings; | ||||
|  | ||||
|     @JsonProperty("total_duration") | ||||
|     private long totalDuration; | ||||
|  | ||||
|     @JsonProperty("load_duration") | ||||
|     private long loadDuration; | ||||
|  | ||||
|     @JsonProperty("prompt_eval_count") | ||||
|     private int promptEvalCount; | ||||
| } | ||||
| @@ -0,0 +1,16 @@ | ||||
| package io.github.ollama4j.models.response; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| @Data | ||||
| public class LibraryModel { | ||||
|  | ||||
|     private String name; | ||||
|     private String description; | ||||
|     private String pullCount; | ||||
|     private int totalTags; | ||||
|     private List<String> popularTags = new ArrayList<>(); | ||||
|     private String lastUpdated; | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| package io.github.ollama4j.models.response; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @Data | ||||
| public class LibraryModelDetail { | ||||
|  | ||||
|     private LibraryModel model; | ||||
|     private List<LibraryModelTag> tags; | ||||
| } | ||||
| @@ -0,0 +1,13 @@ | ||||
| package io.github.ollama4j.models.response; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @Data | ||||
| public class LibraryModelTag { | ||||
|     private String name; | ||||
|     private String tag; | ||||
|     private String size; | ||||
|     private String lastUpdated; | ||||
| } | ||||
| @@ -10,12 +10,9 @@ package io.github.ollama4j.types; | ||||
| public class OllamaModelType { | ||||
|     public static final String GEMMA = "gemma"; | ||||
|     public static final String GEMMA2 = "gemma2"; | ||||
|  | ||||
|  | ||||
|     public static final String LLAMA2 = "llama2"; | ||||
|     public static final String LLAMA3 = "llama3"; | ||||
|     public static final String LLAMA3_1 = "llama3.1"; | ||||
|  | ||||
|     public static final String MISTRAL = "mistral"; | ||||
|     public static final String MIXTRAL = "mixtral"; | ||||
|     public static final String LLAVA = "llava"; | ||||
| @@ -35,7 +32,6 @@ public class OllamaModelType { | ||||
|     public static final String ZEPHYR = "zephyr"; | ||||
|     public static final String OPENHERMES = "openhermes"; | ||||
|     public static final String QWEN = "qwen"; | ||||
|  | ||||
|     public static final String QWEN2 = "qwen2"; | ||||
|     public static final String WIZARDCODER = "wizardcoder"; | ||||
|     public static final String LLAMA2_CHINESE = "llama2-chinese"; | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package io.github.ollama4j.utils; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.HashMap; | ||||
|  | ||||
| /** Builder class for creating options for Ollama model. */ | ||||
| @@ -207,6 +208,34 @@ public class OptionsBuilder { | ||||
|     return this; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Alternative to the top_p, and aims to ensure a balance of qualityand variety. The parameter p | ||||
|    * represents the minimum probability for a token to be considered, relative to the probability | ||||
|    * of the most likely token. For example, with p=0.05 and the most likely token having a | ||||
|    * probability of 0.9, logits with a value less than 0.045 are filtered out. (Default: 0.0) | ||||
|    */ | ||||
|   public OptionsBuilder setMinP(float value) { | ||||
|     options.getOptionsMap().put("min_p", value); | ||||
|     return this; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Allows passing an option not formally supported by the library | ||||
|    * @param name The option name for the parameter. | ||||
|    * @param value The value for the "{name}" parameter. | ||||
|    * @return The updated OptionsBuilder. | ||||
|    * @throws IllegalArgumentException if parameter has an unsupported type | ||||
|    */ | ||||
|   public OptionsBuilder setCustomOption(String name, Object value) throws IllegalArgumentException { | ||||
|     if (!(value instanceof Integer || value instanceof Float || value instanceof String)) { | ||||
|       throw new IllegalArgumentException("Invalid type for parameter. Allowed types are: Integer, Float, or String."); | ||||
|     } | ||||
|     options.getOptionsMap().put(name, value); | ||||
|     return this; | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
|   /** | ||||
|    * Builds the options map. | ||||
|    * | ||||
| @@ -215,4 +244,6 @@ public class OptionsBuilder { | ||||
|   public Options build() { | ||||
|     return options; | ||||
|   } | ||||
|  | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,10 @@ package io.github.ollama4j.unittests; | ||||
|  | ||||
| import io.github.ollama4j.OllamaAPI; | ||||
| import io.github.ollama4j.exceptions.OllamaBaseException; | ||||
| import io.github.ollama4j.exceptions.RoleNotFoundException; | ||||
| import io.github.ollama4j.models.chat.OllamaChatMessageRole; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedRequestModel; | ||||
| import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel; | ||||
| import io.github.ollama4j.models.response.ModelDetail; | ||||
| import io.github.ollama4j.models.response.OllamaAsyncResultStreamer; | ||||
| import io.github.ollama4j.models.response.OllamaResult; | ||||
| @@ -14,7 +18,9 @@ import java.io.IOException; | ||||
| import java.net.URISyntaxException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| import static org.mockito.Mockito.*; | ||||
|  | ||||
| class TestMockedAPIs { | ||||
| @@ -97,6 +103,34 @@ class TestMockedAPIs { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testEmbed() { | ||||
|         OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class); | ||||
|         String model = OllamaModelType.LLAMA2; | ||||
|         List<String> inputs = List.of("some prompt text"); | ||||
|         try { | ||||
|             when(ollamaAPI.embed(model, inputs)).thenReturn(new OllamaEmbedResponseModel()); | ||||
|             ollamaAPI.embed(model, inputs); | ||||
|             verify(ollamaAPI, times(1)).embed(model, inputs); | ||||
|         } catch (IOException | OllamaBaseException | InterruptedException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testEmbedWithEmbedRequestModel() { | ||||
|         OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class); | ||||
|         String model = OllamaModelType.LLAMA2; | ||||
|         List<String> inputs = List.of("some prompt text"); | ||||
|         try { | ||||
|             when(ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs))).thenReturn(new OllamaEmbedResponseModel()); | ||||
|             ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs)); | ||||
|             verify(ollamaAPI, times(1)).embed(new OllamaEmbedRequestModel(model, inputs)); | ||||
|         } catch (IOException | OllamaBaseException | InterruptedException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testAsk() { | ||||
|         OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class); | ||||
| @@ -161,4 +195,68 @@ class TestMockedAPIs { | ||||
|         ollamaAPI.generateAsync(model, prompt, false); | ||||
|         verify(ollamaAPI, times(1)).generateAsync(model, prompt, false); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testAddCustomRole() { | ||||
|         OllamaAPI ollamaAPI = mock(OllamaAPI.class); | ||||
|         String roleName = "custom-role"; | ||||
|         OllamaChatMessageRole expectedRole = OllamaChatMessageRole.newCustomRole(roleName); | ||||
|         when(ollamaAPI.addCustomRole(roleName)).thenReturn(expectedRole); | ||||
|         OllamaChatMessageRole customRole = ollamaAPI.addCustomRole(roleName); | ||||
|         assertEquals(expectedRole, customRole); | ||||
|         verify(ollamaAPI, times(1)).addCustomRole(roleName); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testListRoles() { | ||||
|         OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class); | ||||
|         OllamaChatMessageRole role1 = OllamaChatMessageRole.newCustomRole("role1"); | ||||
|         OllamaChatMessageRole role2 = OllamaChatMessageRole.newCustomRole("role2"); | ||||
|         List<OllamaChatMessageRole> expectedRoles = List.of(role1, role2); | ||||
|         when(ollamaAPI.listRoles()).thenReturn(expectedRoles); | ||||
|         List<OllamaChatMessageRole> actualRoles = ollamaAPI.listRoles(); | ||||
|         assertEquals(expectedRoles, actualRoles); | ||||
|         verify(ollamaAPI, times(1)).listRoles(); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testGetRoleNotFound() { | ||||
|         OllamaAPI ollamaAPI = mock(OllamaAPI.class); | ||||
|         String roleName = "non-existing-role"; | ||||
|         try { | ||||
|             when(ollamaAPI.getRole(roleName)).thenThrow(new RoleNotFoundException("Role not found")); | ||||
|         } catch (RoleNotFoundException exception) { | ||||
|             throw new RuntimeException("Failed to run test: testGetRoleNotFound"); | ||||
|         } | ||||
|         try { | ||||
|             ollamaAPI.getRole(roleName); | ||||
|             fail("Expected RoleNotFoundException not thrown"); | ||||
|         } catch (RoleNotFoundException exception) { | ||||
|             assertEquals("Role not found", exception.getMessage()); | ||||
|         } | ||||
|         try { | ||||
|             verify(ollamaAPI, times(1)).getRole(roleName); | ||||
|         } catch (RoleNotFoundException exception) { | ||||
|             throw new RuntimeException("Failed to run test: testGetRoleNotFound"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testGetRoleFound() { | ||||
|         OllamaAPI ollamaAPI = mock(OllamaAPI.class); | ||||
|         String roleName = "existing-role"; | ||||
|         OllamaChatMessageRole expectedRole = OllamaChatMessageRole.newCustomRole(roleName); | ||||
|         try { | ||||
|             when(ollamaAPI.getRole(roleName)).thenReturn(expectedRole); | ||||
|         } catch (RoleNotFoundException exception) { | ||||
|             throw new RuntimeException("Failed to run test: testGetRoleFound"); | ||||
|         } | ||||
|         try { | ||||
|             OllamaChatMessageRole actualRole = ollamaAPI.getRole(roleName); | ||||
|             assertEquals(expectedRole, actualRole); | ||||
|             verify(ollamaAPI, times(1)).getRole(roleName); | ||||
|         } catch (RoleNotFoundException exception) { | ||||
|             throw new RuntimeException("Failed to run test: testGetRoleFound"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package io.github.ollama4j.unittests.jackson; | ||||
|  | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
| import static org.junit.jupiter.api.Assertions.assertThrowsExactly; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.util.List; | ||||
| @@ -59,6 +60,10 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla | ||||
|             .withOptions(b.setSeed(1).build()) | ||||
|             .withOptions(b.setTopK(1).build()) | ||||
|             .withOptions(b.setTopP(1).build()) | ||||
|             .withOptions(b.setMinP(1).build()) | ||||
|             .withOptions(b.setCustomOption("cust_float", 1.0f).build()) | ||||
|             .withOptions(b.setCustomOption("cust_int", 1).build()) | ||||
|             .withOptions(b.setCustomOption("cust_str", "custom").build()) | ||||
|             .build(); | ||||
|  | ||||
|         String jsonRequest = serialize(req); | ||||
| @@ -72,6 +77,20 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla | ||||
|         assertEquals(1, deserializeRequest.getOptions().get("seed")); | ||||
|         assertEquals(1, deserializeRequest.getOptions().get("top_k")); | ||||
|         assertEquals(1.0, deserializeRequest.getOptions().get("top_p")); | ||||
|         assertEquals(1.0, deserializeRequest.getOptions().get("min_p")); | ||||
|         assertEquals(1.0, deserializeRequest.getOptions().get("cust_float")); | ||||
|         assertEquals(1, deserializeRequest.getOptions().get("cust_int")); | ||||
|         assertEquals("custom", deserializeRequest.getOptions().get("cust_str")); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void testRequestWithInvalidCustomOption() { | ||||
|         OptionsBuilder b = new OptionsBuilder(); | ||||
|         assertThrowsExactly(IllegalArgumentException.class, () -> { | ||||
|                 OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt") | ||||
|                 .withOptions(b.setCustomOption("cust_obj", new Object()).build()) | ||||
|                 .build(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|   | ||||
		Reference in New Issue
	
	Block a user