mirror of
https://github.com/amithkoujalgi/ollama4j.git
synced 2025-10-13 17:08:57 +02:00
Merge pull request #183 from ollama4j/refactor
Refactor: with breaking changes
This commit is contained in:
commit
6fce6ec777
10
.github/workflows/build-on-pull-request.yml
vendored
10
.github/workflows/build-on-pull-request.yml
vendored
@ -20,13 +20,17 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK 11
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt-hotspot'
|
||||
java-version: '21'
|
||||
distribution: 'oracle'
|
||||
server-id: github
|
||||
settings-path: ${{ github.workspace }}
|
||||
|
||||
|
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@ -28,8 +28,8 @@ jobs:
|
||||
if: matrix.language == 'java'
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: '11'
|
||||
distribution: oracle
|
||||
java-version: '21'
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
|
6
.github/workflows/gh-mvn-publish.yml
vendored
6
.github/workflows/gh-mvn-publish.yml
vendored
@ -14,11 +14,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
distribution: 'oracle'
|
||||
server-id: github
|
||||
settings-path: ${{ github.workspace }}
|
||||
|
||||
|
6
.github/workflows/maven-publish.yml
vendored
6
.github/workflows/maven-publish.yml
vendored
@ -26,11 +26,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
distribution: 'oracle'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
|
6
.github/workflows/publish-docs.yml
vendored
6
.github/workflows/publish-docs.yml
vendored
@ -30,11 +30,11 @@ jobs:
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK 11
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt-hotspot'
|
||||
java-version: '21'
|
||||
distribution: 'oracle'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
|
6
.github/workflows/run-tests.yml
vendored
6
.github/workflows/run-tests.yml
vendored
@ -36,11 +36,11 @@ jobs:
|
||||
run: |
|
||||
curl -fsSL https://ollama.com/install.sh | sh
|
||||
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
distribution: 'oracle'
|
||||
server-id: github
|
||||
settings-path: ${{ github.workspace }}
|
||||
|
||||
|
@ -21,11 +21,19 @@ repos:
|
||||
|
||||
# for commit message formatting
|
||||
- repo: https://github.com/commitizen-tools/commitizen
|
||||
rev: v4.9.0
|
||||
rev: v4.9.1
|
||||
hooks:
|
||||
- id: commitizen
|
||||
stages: [commit-msg]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: format-code
|
||||
name: Format Code
|
||||
entry: make apply-formatting
|
||||
language: system
|
||||
always_run: true
|
||||
|
||||
# # for java code quality
|
||||
# - repo: https://github.com/gherynos/pre-commit-java
|
||||
# rev: v0.6.10
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Amith Koujalgi
|
||||
Copyright (c) 2023 Amith Koujalgi and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
67
Makefile
67
Makefile
@ -2,41 +2,70 @@ dev:
|
||||
@echo "Setting up dev environment..."
|
||||
@command -v pre-commit >/dev/null 2>&1 || { echo "Error: pre-commit is not installed. Please install it first."; exit 1; }
|
||||
@command -v docker >/dev/null 2>&1 || { echo "Error: docker is not installed. Please install it first."; exit 1; }
|
||||
pre-commit install
|
||||
pre-commit autoupdate
|
||||
pre-commit install --install-hooks
|
||||
@pre-commit install
|
||||
@pre-commit autoupdate
|
||||
@pre-commit install --install-hooks
|
||||
|
||||
build:
|
||||
mvn -B clean install -Dgpg.skip=true
|
||||
check-formatting:
|
||||
@echo "\033[0;34mChecking code formatting...\033[0m"
|
||||
@mvn spotless:check
|
||||
|
||||
full-build:
|
||||
mvn -B clean install
|
||||
apply-formatting:
|
||||
@echo "\033[0;32mApplying code formatting...\033[0m"
|
||||
@mvn spotless:apply
|
||||
|
||||
unit-tests:
|
||||
mvn clean test -Punit-tests
|
||||
build: apply-formatting
|
||||
@echo "\033[0;34mBuilding project (GPG skipped)...\033[0m"
|
||||
@mvn -B clean install -Dgpg.skip=true -Dmaven.javadoc.skip=true
|
||||
|
||||
integration-tests:
|
||||
export USE_EXTERNAL_OLLAMA_HOST=false && mvn clean verify -Pintegration-tests
|
||||
full-build: apply-formatting
|
||||
@echo "\033[0;34mPerforming full build...\033[0m"
|
||||
@mvn -B clean install
|
||||
|
||||
integration-tests-remote:
|
||||
export USE_EXTERNAL_OLLAMA_HOST=true && export OLLAMA_HOST=http://192.168.29.223:11434 && mvn clean verify -Pintegration-tests -Dgpg.skip=true
|
||||
unit-tests: apply-formatting
|
||||
@echo "\033[0;34mRunning unit tests...\033[0m"
|
||||
@mvn clean test -Punit-tests
|
||||
|
||||
integration-tests: apply-formatting
|
||||
@echo "\033[0;34mRunning integration tests (local)...\033[0m"
|
||||
@export USE_EXTERNAL_OLLAMA_HOST=false && mvn clean verify -Pintegration-tests
|
||||
|
||||
integration-tests-remote: apply-formatting
|
||||
@echo "\033[0;34mRunning integration tests (remote)...\033[0m"
|
||||
@export USE_EXTERNAL_OLLAMA_HOST=true && export OLLAMA_HOST=http://192.168.29.229:11434 && mvn clean verify -Pintegration-tests -Dgpg.skip=true
|
||||
|
||||
doxygen:
|
||||
doxygen Doxyfile
|
||||
@echo "\033[0;34mGenerating documentation with Doxygen...\033[0m"
|
||||
@doxygen Doxyfile
|
||||
|
||||
javadoc:
|
||||
@echo "\033[0;34mGenerating Javadocs into '$(javadocfolder)'...\033[0m"
|
||||
@mvn clean javadoc:javadoc
|
||||
@if [ -f "target/reports/apidocs/index.html" ]; then \
|
||||
echo "\033[0;32mJavadocs generated in target/reports/apidocs/index.html\033[0m"; \
|
||||
else \
|
||||
echo "\033[0;31mFailed to generate Javadocs in target/reports/apidocs\033[0m"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
list-releases:
|
||||
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' \
|
||||
@echo "\033[0;34mListing latest releases...\033[0m"
|
||||
@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 -r '.components[].version'
|
||||
|
||||
docs-build:
|
||||
npm i --prefix docs && npm run build --prefix docs
|
||||
@echo "\033[0;34mBuilding documentation site...\033[0m"
|
||||
@cd ./docs && npm ci --no-audit --fund=false && npm run build
|
||||
|
||||
docs-serve:
|
||||
npm i --prefix docs && npm run start --prefix docs
|
||||
@echo "\033[0;34mServing documentation site...\033[0m"
|
||||
@cd ./docs && npm install && npm run start
|
||||
|
||||
start-cpu:
|
||||
docker run -it -v ~/ollama:/root/.ollama -p 11434:11434 ollama/ollama
|
||||
@echo "\033[0;34mStarting Ollama (CPU mode)...\033[0m"
|
||||
@docker run -it -v ~/ollama:/root/.ollama -p 11434:11434 ollama/ollama
|
||||
|
||||
start-gpu:
|
||||
docker run -it --gpus=all -v ~/ollama:/root/.ollama -p 11434:11434 ollama/ollama
|
||||
@echo "\033[0;34mStarting Ollama (GPU mode)...\033[0m"
|
||||
@docker run -it --gpus=all -v ~/ollama:/root/.ollama -p 11434:11434 ollama/ollama
|
54
README.md
54
README.md
@ -1,7 +1,8 @@
|
||||
<div align="center">
|
||||
<img src='https://raw.githubusercontent.com/ollama4j/ollama4j/65a9d526150da8fcd98e2af6a164f055572bf722/ollama4j.jpeg' width='100' alt="ollama4j-icon">
|
||||
|
||||
### Ollama4j
|
||||
### Ollama4j
|
||||
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
@ -40,15 +41,52 @@ _Find more details on the **[website](https://ollama4j.github.io/ollama4j/)**._
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Capabilities](#capabilities)
|
||||
- [How does it work?](#how-does-it-work)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation)
|
||||
- [API Spec](https://ollama4j.github.io/ollama4j/category/apis---model-management)
|
||||
- [Usage](#usage)
|
||||
- [For Maven](#for-maven)
|
||||
- [Using Maven Central](#using-maven-central)
|
||||
- [Using GitHub's Maven Package Repository](#using-githubs-maven-package-repository)
|
||||
- [For Gradle](#for-gradle)
|
||||
- [API Spec](#api-spec)
|
||||
- [Examples](#examples)
|
||||
- [Javadoc](https://ollama4j.github.io/ollama4j/apidocs/)
|
||||
- [Development](#development)
|
||||
- [Contributions](#get-involved)
|
||||
- [References](#references)
|
||||
- [Setup dev environment](#setup-dev-environment)
|
||||
- [Build](#build)
|
||||
- [Run unit tests](#run-unit-tests)
|
||||
- [Run integration tests](#run-integration-tests)
|
||||
- [Releases](#releases)
|
||||
- [Get Involved](#get-involved)
|
||||
- [Who's using Ollama4j?](#whos-using-ollama4j)
|
||||
- [Growth](#growth)
|
||||
- [References](#references)
|
||||
- [Credits](#credits)
|
||||
- [Appreciate the work?](#appreciate-the-work)
|
||||
|
||||
## Capabilities
|
||||
|
||||
- **Text generation**: Single-turn `generate` with optional streaming and advanced options
|
||||
- **Chat**: Multi-turn chat with conversation history and roles
|
||||
- **Tool/function calling**: Built-in tool invocation via annotations and tool specs
|
||||
- **Reasoning/thinking modes**: Generate and chat with “thinking” outputs where supported
|
||||
- **Image inputs (multimodal)**: Generate with images as inputs where models support vision
|
||||
- **Embeddings**: Create vector embeddings for text
|
||||
- **Async generation**: Fire-and-forget style generation APIs
|
||||
- **Custom roles**: Define and use custom chat roles
|
||||
- **Model management**: List, pull, create, delete, and get model details
|
||||
- **Connectivity utilities**: Server `ping` and process status (`ps`)
|
||||
- **Authentication**: Basic auth and bearer token support
|
||||
- **Options builder**: Type-safe builder for model parameters and request options
|
||||
- **Timeouts**: Configure connect/read/write timeouts
|
||||
- **Logging**: Built-in logging hooks for requests and responses
|
||||
- **Metrics & Monitoring** 🆕: Built-in Prometheus metrics export for real-time monitoring of requests, model usage, and
|
||||
performance. *(Beta feature – feedback/contributions welcome!)* -
|
||||
Checkout [ollama4j-examples](https://github.com/ollama4j/ollama4j-examples) repository for details.
|
||||
|
||||
<div align="center">
|
||||
<img src='metrics.png' width='100%' alt="ollama4j-icon">
|
||||
</div>
|
||||
|
||||
## How does it work?
|
||||
|
||||
@ -73,7 +111,7 @@ _Find more details on the **[website](https://ollama4j.github.io/ollama4j/)**._
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Installation
|
||||
## Usage
|
||||
|
||||
> [!NOTE]
|
||||
> We are now publishing the artifacts to both Maven Central and GitHub package repositories.
|
||||
@ -182,7 +220,7 @@ dependencies {
|
||||
|
||||
[lib-shield]: https://img.shields.io/badge/ollama4j-get_latest_version-blue.svg?style=just-the-message&labelColor=gray
|
||||
|
||||
#### API Spec
|
||||
### API Spec
|
||||
|
||||
> [!TIP]
|
||||
> Find the full API specifications on the [website](https://ollama4j.github.io/ollama4j/).
|
||||
|
184
docs/METRICS.md
Normal file
184
docs/METRICS.md
Normal file
@ -0,0 +1,184 @@
|
||||
# Prometheus Metrics Integration
|
||||
|
||||
Ollama4j now includes comprehensive Prometheus metrics collection to help you monitor and observe your Ollama API usage. This feature allows you to track request counts, response times, model usage, and other operational metrics.
|
||||
|
||||
## Features
|
||||
|
||||
The metrics integration provides the following metrics:
|
||||
|
||||
- **Request Metrics**: Total requests, duration histograms, and response time summaries by endpoint
|
||||
- **Model Usage**: Model-specific usage statistics and response times
|
||||
- **Token Generation**: Token count tracking per model
|
||||
- **Error Tracking**: Error counts by type and endpoint
|
||||
- **Active Connections**: Current number of active API connections
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Enable Metrics Collection
|
||||
|
||||
```java
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
|
||||
// Create API instance with metrics enabled
|
||||
OllamaAPI ollamaAPI = new OllamaAPI();
|
||||
ollamaAPI.setMetricsEnabled(true);
|
||||
```
|
||||
|
||||
### 2. Start Metrics Server
|
||||
|
||||
```java
|
||||
import io.prometheus.client.exporter.HTTPServer;
|
||||
|
||||
// Start Prometheus metrics HTTP server on port 8080
|
||||
HTTPServer metricsServer = new HTTPServer(8080);
|
||||
System.out.println("Metrics available at: http://localhost:8080/metrics");
|
||||
```
|
||||
|
||||
### 3. Use the API (Metrics are automatically collected)
|
||||
|
||||
```java
|
||||
// All API calls are automatically instrumented
|
||||
boolean isReachable = ollamaAPI.ping();
|
||||
|
||||
Map<String, Object> format = new HashMap<>();
|
||||
format.put("type", "json");
|
||||
OllamaResult result = ollamaAPI.generateWithFormat(
|
||||
"llama2",
|
||||
"Generate a JSON object",
|
||||
format
|
||||
);
|
||||
```
|
||||
|
||||
## Available Metrics
|
||||
|
||||
### Request Metrics
|
||||
|
||||
- `ollama_api_requests_total` - Total number of API requests by endpoint, method, and status
|
||||
- `ollama_api_request_duration_seconds` - Request duration histogram by endpoint and method
|
||||
- `ollama_api_response_time_seconds` - Response time summary with percentiles
|
||||
|
||||
### Model Metrics
|
||||
|
||||
- `ollama_model_usage_total` - Model usage count by model name and operation
|
||||
- `ollama_model_response_time_seconds` - Model response time histogram
|
||||
- `ollama_tokens_generated_total` - Total tokens generated by model
|
||||
|
||||
### System Metrics
|
||||
|
||||
- `ollama_api_active_connections` - Current number of active connections
|
||||
- `ollama_api_errors_total` - Error count by endpoint and error type
|
||||
|
||||
## Example Metrics Output
|
||||
|
||||
```
|
||||
# HELP ollama_api_requests_total Total number of Ollama API requests
|
||||
# TYPE ollama_api_requests_total counter
|
||||
ollama_api_requests_total{endpoint="/api/generate",method="POST",status="success"} 5.0
|
||||
ollama_api_requests_total{endpoint="/api/embed",method="POST",status="success"} 3.0
|
||||
|
||||
# HELP ollama_api_request_duration_seconds Duration of Ollama API requests in seconds
|
||||
# TYPE ollama_api_request_duration_seconds histogram
|
||||
ollama_api_request_duration_seconds_bucket{endpoint="/api/generate",method="POST",le="0.1"} 0.0
|
||||
ollama_api_request_duration_seconds_bucket{endpoint="/api/generate",method="POST",le="0.5"} 2.0
|
||||
ollama_api_request_duration_seconds_bucket{endpoint="/api/generate",method="POST",le="1.0"} 4.0
|
||||
ollama_api_request_duration_seconds_bucket{endpoint="/api/generate",method="POST",le="+Inf"} 5.0
|
||||
ollama_api_request_duration_seconds_sum{endpoint="/api/generate",method="POST"} 2.5
|
||||
ollama_api_request_duration_seconds_count{endpoint="/api/generate",method="POST"} 5.0
|
||||
|
||||
# HELP ollama_model_usage_total Total number of model usage requests
|
||||
# TYPE ollama_model_usage_total counter
|
||||
ollama_model_usage_total{model_name="llama2",operation="generate_with_format"} 5.0
|
||||
ollama_model_usage_total{model_name="llama2",operation="embed"} 3.0
|
||||
|
||||
# HELP ollama_tokens_generated_total Total number of tokens generated
|
||||
# TYPE ollama_tokens_generated_total counter
|
||||
ollama_tokens_generated_total{model_name="llama2"} 150.0
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable/Disable Metrics
|
||||
|
||||
```java
|
||||
OllamaAPI ollamaAPI = new OllamaAPI();
|
||||
|
||||
// Enable metrics collection
|
||||
ollamaAPI.setMetricsEnabled(true);
|
||||
|
||||
// Disable metrics collection (default)
|
||||
ollamaAPI.setMetricsEnabled(false);
|
||||
```
|
||||
|
||||
### Custom Metrics Server
|
||||
|
||||
```java
|
||||
import io.prometheus.client.exporter.HTTPServer;
|
||||
|
||||
// Start on custom port
|
||||
HTTPServer metricsServer = new HTTPServer(9090);
|
||||
|
||||
// Start on custom host and port
|
||||
HTTPServer metricsServer = new HTTPServer("0.0.0.0", 9090);
|
||||
```
|
||||
|
||||
## Integration with Prometheus
|
||||
|
||||
### Prometheus Configuration
|
||||
|
||||
Add this to your `prometheus.yml`:
|
||||
|
||||
```yaml
|
||||
scrape_configs:
|
||||
- job_name: 'ollama4j'
|
||||
static_configs:
|
||||
- targets: ['localhost:8080']
|
||||
scrape_interval: 15s
|
||||
```
|
||||
|
||||
### Grafana Dashboards
|
||||
|
||||
You can create Grafana dashboards using the metrics. Some useful queries:
|
||||
|
||||
- **Request Rate**: `rate(ollama_api_requests_total[5m])`
|
||||
- **Average Response Time**: `rate(ollama_api_request_duration_seconds_sum[5m]) / rate(ollama_api_request_duration_seconds_count[5m])`
|
||||
- **Error Rate**: `rate(ollama_api_requests_total{status="error"}[5m]) / rate(ollama_api_requests_total[5m])`
|
||||
- **Model Usage**: `rate(ollama_model_usage_total[5m])`
|
||||
- **Token Generation Rate**: `rate(ollama_tokens_generated_total[5m])`
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- Metrics collection adds minimal overhead (~1-2% in most cases)
|
||||
- Metrics are collected asynchronously and don't block API calls
|
||||
- You can disable metrics in production if needed: `ollamaAPI.setMetricsEnabled(false)`
|
||||
- The metrics server uses minimal resources
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Metrics Not Appearing
|
||||
|
||||
1. Ensure metrics are enabled: `ollamaAPI.setMetricsEnabled(true)`
|
||||
2. Check that the metrics server is running: `http://localhost:8080/metrics`
|
||||
3. Verify API calls are being made (metrics only appear after API usage)
|
||||
|
||||
### High Memory Usage
|
||||
|
||||
- Metrics accumulate over time. Consider restarting your application periodically
|
||||
- Use Prometheus to scrape metrics regularly to avoid accumulation
|
||||
|
||||
### Custom Metrics
|
||||
|
||||
You can extend the metrics by accessing the Prometheus registry directly:
|
||||
|
||||
```java
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.Counter;
|
||||
|
||||
// Create custom metrics
|
||||
Counter customCounter = Counter.build()
|
||||
.name("my_custom_metric_total")
|
||||
.help("My custom metric")
|
||||
.register();
|
||||
|
||||
// Use the metric
|
||||
customCounter.inc();
|
||||
```
|
@ -337,7 +337,7 @@ import com.couchbase.client.java.Scope;
|
||||
import com.couchbase.client.java.json.JsonObject;
|
||||
import com.couchbase.client.java.query.QueryResult;
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
import io.github.ollama4j.exceptions.OllamaException;
|
||||
import io.github.ollama4j.exceptions.ToolInvocationException;
|
||||
import io.github.ollama4j.tools.OllamaToolsResult;
|
||||
import io.github.ollama4j.tools.ToolFunction;
|
||||
@ -356,7 +356,7 @@ import java.util.Map;
|
||||
|
||||
public class CouchbaseToolCallingExample {
|
||||
|
||||
public static void main(String[] args) throws IOException, ToolInvocationException, OllamaBaseException, InterruptedException {
|
||||
public static void main(String[] args) throws IOException, ToolInvocationException, OllamaException, InterruptedException {
|
||||
String connectionString = Utilities.getFromEnvVar("CB_CLUSTER_URL");
|
||||
String username = Utilities.getFromEnvVar("CB_CLUSTER_USERNAME");
|
||||
String password = Utilities.getFromEnvVar("CB_CLUSTER_PASSWORD");
|
||||
|
@ -1,8 +1,8 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Set Basic Authentication
|
||||
# Basic Auth
|
||||
|
||||
This API lets you set the basic authentication for the Ollama client. This would help in scenarios where
|
||||
Ollama server would be setup behind a gateway/reverse proxy with basic auth.
|
||||
|
@ -1,8 +1,8 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Set Bearer Authentication
|
||||
# Bearer Auth
|
||||
|
||||
This API lets you set the bearer authentication for the Ollama client. This would help in scenarios where
|
||||
Ollama server would be setup behind a gateway/reverse proxy with bearer auth.
|
||||
|
26
docs/docs/apis-extras/logging.md
Normal file
26
docs/docs/apis-extras/logging.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
---
|
||||
|
||||
# Logging
|
||||
|
||||
### Using with SLF4J and Logback
|
||||
|
||||
Add a `logback.xml` file to your `src/main/resources` folder with the following content:
|
||||
|
||||
```xml
|
||||
|
||||
<configuration>
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
</configuration>
|
||||
|
||||
```
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Ping
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Prompt Builder
|
||||
@ -51,6 +51,7 @@ public class Main {
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
:::tip[LLM Response]
|
||||
```go
|
||||
package main
|
||||
|
||||
@ -72,3 +73,4 @@ func readFile(fileName string) {
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# PS
|
||||
@ -12,17 +12,14 @@ This API corresponds to the [PS](https://github.com/ollama/ollama/blob/main/docs
|
||||
package io.github.ollama4j.localtests;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
import io.github.ollama4j.models.ps.ModelsProcessResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import io.github.ollama4j.models.ps.ModelProcessesResult;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
|
||||
OllamaAPI ollamaAPI = new OllamaAPI("http://localhost:11434");
|
||||
|
||||
ModelsProcessResponse response = ollamaAPI.ps();
|
||||
ModelProcessesResult response = ollamaAPI.ps();
|
||||
|
||||
System.out.println(response);
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Set Request Timeout
|
||||
# Timeouts
|
||||
|
||||
### Set Request Timeout
|
||||
|
||||
This API lets you set the request timeout for the Ollama client.
|
||||
|
@ -21,25 +21,25 @@ session. The tool invocation and response handling are all managed internally by
|
||||
|
||||
<CodeEmbed src="https://raw.githubusercontent.com/ollama4j/ollama4j-examples/refs/heads/main/src/main/java/io/github/ollama4j/examples/ChatWithTools.java"/>
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
**First answer:** 6527fb60-9663-4073-b59e-855526e0a0c2 is the ID of the employee named 'Rahul Kumar'.
|
||||
|
||||
**Second answer:** _Kumar_ is the last name of the employee named 'Rahul Kumar'.
|
||||
::::
|
||||
:::
|
||||
|
||||
This tool calling can also be done using the streaming API.
|
||||
|
||||
### Client-managed tool calls (clientHandlesTools)
|
||||
### Client-managed tool calls (useTools)
|
||||
|
||||
By default, ollama4j automatically executes tool calls returned by the model during chat, runs the corresponding registered Java methods, and appends the tool results back into the conversation. For some applications, you may want to intercept tool calls and decide yourself when and how to execute them (for example, to queue them, to show a confirmation UI to the user, to run them in a sandbox, or to perform multi‑step orchestration).
|
||||
|
||||
To enable this behavior, set the clientHandlesTools flag to true on your OllamaAPI instance. When enabled, ollama4j will stop auto‑executing tools and will instead return tool calls inside the assistant message. You can then inspect the tool calls and execute them manually.
|
||||
To enable this behavior, set the useTools flag to true on your OllamaAPI instance. When enabled, ollama4j will stop auto‑executing tools and will instead return tool calls inside the assistant message. You can then inspect the tool calls and execute them manually.
|
||||
|
||||
|
||||
Notes:
|
||||
- Default value: clientHandlesTools is false for backward compatibility.
|
||||
- When clientHandlesTools is false, ollama4j auto‑executes tools and loops internally until tools are resolved or max retries is reached.
|
||||
- When clientHandlesTools is true, ollama4j will not execute tools; you are responsible for invoking tools and passing results back as TOOL messages, then re‑calling chat() to continue.
|
||||
- Default value: useTools is true.
|
||||
- When useTools is false, ollama4j auto‑executes tools and loops internally until tools are resolved or max retries is reached.
|
||||
- When useTools is true, ollama4j will not execute tools; you are responsible for invoking tools and passing results back as TOOL messages, then re‑calling chat() to continue.
|
||||
|
||||
### Annotation-Based Tool Registration
|
||||
|
||||
@ -74,8 +74,8 @@ The annotated method can then be used as a tool in the chat session:
|
||||
|
||||
Running the above would produce a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
**First answer:** 0.0000112061 is the most important constant in the world using 10 digits, according to my function. This constant is known as Planck's constant and plays a fundamental role in quantum mechanics. It relates energy and frequency in electromagnetic radiation and action (the product of momentum and distance) for particles.
|
||||
|
||||
**Second answer:** 3-digit constant: 8.001
|
||||
::::
|
||||
:::
|
||||
|
@ -16,7 +16,7 @@ information using the history of already asked questions and the respective answ
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
|
||||
> First answer: The capital of France is Paris.
|
||||
>
|
||||
@ -47,7 +47,7 @@ You will get a response similar to:
|
||||
"tool_calls" : null
|
||||
}]
|
||||
```
|
||||
::::
|
||||
:::
|
||||
|
||||
### Create a conversation where the answer is streamed
|
||||
|
||||
@ -75,9 +75,9 @@ You will get a response similar to:
|
||||
|
||||
You will get a response as:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
Shhh!
|
||||
::::
|
||||
:::
|
||||
|
||||
|
||||
## Create a conversation about an image (requires a vision model)
|
||||
@ -91,7 +91,7 @@ Let's use this image:
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
**First Answer:** The image shows a dog sitting on the bow of a boat that is docked in calm water. The boat has two
|
||||
levels, with the lower level containing seating and what appears to be an engine cover. The dog seems relaxed and
|
||||
comfortable on the boat, looking out over the water. The background suggests it might be late afternoon or early
|
||||
@ -101,4 +101,4 @@ evening, given the warm lighting and the low position of the sun in the sky.
|
||||
appears to be medium-sized with a short coat and a brown coloration, which might suggest that it is a **_Golden Retriever_**
|
||||
or a similar breed. Without more details like ear shape and tail length, it's not possible to identify the exact breed
|
||||
confidently.
|
||||
::::
|
||||
:::
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
import CodeEmbed from '@site/src/components/CodeEmbed';
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
import CodeEmbed from '@site/src/components/CodeEmbed';
|
||||
@ -12,7 +12,7 @@ Generate embeddings from a model.
|
||||
|
||||
<CodeEmbed src="https://raw.githubusercontent.com/ollama4j/ollama4j-examples/refs/heads/main/src/main/java/io/github/ollama4j/examples/GenerateEmbeddings.java" />
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
|
||||
```json
|
||||
[
|
||||
@ -40,7 +40,7 @@ Generate embeddings from a model.
|
||||
]
|
||||
```
|
||||
|
||||
::::
|
||||
:::
|
||||
|
||||
You could also use the `OllamaEmbedRequestModel` to specify the options such as `seed`, `temperature`, etc., to apply
|
||||
for generating embeddings.
|
||||
@ -49,7 +49,7 @@ for generating embeddings.
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
|
||||
```json
|
||||
[
|
||||
@ -77,4 +77,4 @@ You will get a response similar to:
|
||||
]
|
||||
```
|
||||
|
||||
::::
|
||||
:::
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
import CodeEmbed from '@site/src/components/CodeEmbed';
|
||||
|
@ -1,33 +0,0 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
import CodeEmbed from '@site/src/components/CodeEmbed';
|
||||
|
||||
# Generate with Image URLs
|
||||
|
||||
This API lets you ask questions along with the image files to the LLMs.
|
||||
This API corresponds to
|
||||
the [completion](https://github.com/jmorganca/ollama/blob/main/docs/api.md#generate-a-completion) API.
|
||||
|
||||
:::note
|
||||
|
||||
Executing this on Ollama server running in CPU-mode will take longer to generate response. Hence, GPU-mode is
|
||||
recommended.
|
||||
|
||||
:::
|
||||
|
||||
## Ask (Sync)
|
||||
|
||||
Passing the link of this image the following code:
|
||||
|
||||

|
||||
|
||||
<CodeEmbed src="https://raw.githubusercontent.com/ollama4j/ollama4j-examples/refs/heads/main/src/main/java/io/github/ollama4j/examples/GenerateWithImageURL.java" />
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
This image features a white boat with brown cushions, where a dog is sitting on the back of the boat. The dog seems to
|
||||
be enjoying its time outdoors, perhaps on a lake.
|
||||
::::
|
@ -1,10 +1,10 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
import CodeEmbed from '@site/src/components/CodeEmbed';
|
||||
|
||||
# Generate with Image Files
|
||||
# Generate with Images
|
||||
|
||||
This API lets you ask questions along with the image files to the LLMs.
|
||||
This API corresponds to
|
||||
@ -27,7 +27,35 @@ If you have this image downloaded and you pass the path to the downloaded image
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
This image features a white boat with brown cushions, where a dog is sitting on the back of the boat. The dog seems to
|
||||
be enjoying its time outdoors, perhaps on a lake.
|
||||
::::
|
||||
:::
|
||||
|
||||
# Generate with Image URLs
|
||||
|
||||
This API lets you ask questions along with the image files to the LLMs.
|
||||
This API corresponds to
|
||||
the [completion](https://github.com/jmorganca/ollama/blob/main/docs/api.md#generate-a-completion) API.
|
||||
|
||||
:::note
|
||||
|
||||
Executing this on Ollama server running in CPU-mode will take longer to generate response. Hence, GPU-mode is
|
||||
recommended.
|
||||
|
||||
:::
|
||||
|
||||
## Ask (Sync)
|
||||
|
||||
Passing the link of this image the following code:
|
||||
|
||||

|
||||
|
||||
<CodeEmbed src="https://raw.githubusercontent.com/ollama4j/ollama4j-examples/refs/heads/main/src/main/java/io/github/ollama4j/examples/GenerateWithImageURL.java" />
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
:::tip[LLM Response]
|
||||
This image features a white boat with brown cushions, where a dog is sitting on the back of the boat. The dog seems to
|
||||
be enjoying its time outdoors, perhaps on a lake.
|
||||
:::
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
import CodeEmbed from '@site/src/components/CodeEmbed';
|
||||
@ -79,7 +79,7 @@ Now put it all together by registering the tools and prompting with tools.
|
||||
|
||||
Run this full example and you will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
|
||||
[Result of executing tool 'current-fuel-price']: Current price of petrol in Bengaluru is Rs.103/L
|
||||
|
||||
@ -88,4 +88,4 @@ Run this full example and you will get a response similar to:
|
||||
[Result of executing tool 'get-employee-details']: Employee Details `{ID: 6bad82e6-b1a1-458f-a139-e3b646e092b1, Name:
|
||||
Rahul Kumar, Address: King St, Hyderabad, India, Phone: 9876543210}`
|
||||
|
||||
::::
|
||||
:::
|
||||
|
@ -1,11 +1,11 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
import CodeEmbed from '@site/src/components/CodeEmbed';
|
||||
import TypewriterTextarea from '@site/src/components/TypewriterTextarea';
|
||||
|
||||
# Generate (Sync)
|
||||
# Generate
|
||||
|
||||
This API lets you ask questions to the LLMs in a synchronous way.
|
||||
This API corresponds to
|
||||
@ -22,10 +22,10 @@ to [this](/apis-extras/options-builder).
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
I am a model of an AI trained by Mistral AI. I was designed to assist with a wide range of tasks, from answering
|
||||
questions to helping with complex computations and research. How can I help you toda
|
||||
::::
|
||||
:::
|
||||
|
||||
### Try asking a question, receiving the answer streamed
|
||||
|
||||
@ -49,7 +49,7 @@ width='100%'
|
||||
|
||||
You will get a response similar to:
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
|
||||
```json
|
||||
{
|
||||
@ -58,12 +58,12 @@ You will get a response similar to:
|
||||
}
|
||||
```
|
||||
|
||||
::::
|
||||
:::
|
||||
|
||||
### With response mapped to specified class type
|
||||
|
||||
<CodeEmbed src="https://raw.githubusercontent.com/ollama4j/ollama4j-examples/refs/heads/main/src/main/java/io/github/ollama4j/examples/GenerateStructuredOutputMappedToObject.java" />
|
||||
|
||||
::::tip[LLM Response]
|
||||
:::tip[LLM Response]
|
||||
HeroInfo(heroName=Batman, ageOfPerson=30)
|
||||
::::
|
||||
:::
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"label": "APIs - Model Management",
|
||||
"label": "APIs - Manage Models",
|
||||
"position": 2,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
|
BIN
metrics.png
Normal file
BIN
metrics.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 373 KiB |
77
pom.xml
77
pom.xml
@ -163,6 +163,69 @@
|
||||
<dateFormatTimeZone>Etc/UTC</dateFormatTimeZone>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>2.46.1</version>
|
||||
<configuration>
|
||||
<formats>
|
||||
<!-- you can define as many formats as you want, each is independent -->
|
||||
<format>
|
||||
<!-- define the files to apply to -->
|
||||
<includes>
|
||||
<include>.gitattributes</include>
|
||||
<include>.gitignore</include>
|
||||
</includes>
|
||||
<!-- define the steps to apply to those files -->
|
||||
<trimTrailingWhitespace/>
|
||||
<endWithNewline/>
|
||||
<indent>
|
||||
<tabs>true</tabs>
|
||||
<spacesPerTab>4</spacesPerTab>
|
||||
</indent>
|
||||
</format>
|
||||
</formats>
|
||||
<!-- define a language-specific format -->
|
||||
<java>
|
||||
<!-- no need to specify files, inferred automatically, but you can if you want -->
|
||||
|
||||
<!-- apply a specific flavor of google-java-format and reflow long strings -->
|
||||
<googleJavaFormat>
|
||||
<version>1.28.0</version>
|
||||
<style>AOSP</style>
|
||||
<reflowLongStrings>true</reflowLongStrings>
|
||||
<formatJavadoc>false</formatJavadoc>
|
||||
</googleJavaFormat>
|
||||
|
||||
<!-- make sure every file has the following copyright header.
|
||||
optionally, Spotless can set copyright years by digging
|
||||
through git history (see "license" section below) -->
|
||||
<licenseHeader>
|
||||
<content>
|
||||
<![CDATA[
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) $YEAR Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
]]>
|
||||
</content> <!-- or <file>${project.basedir}/license-header</file> -->
|
||||
</licenseHeader>
|
||||
</java>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<pluginManagement>
|
||||
@ -212,6 +275,7 @@
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.17</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
@ -243,6 +307,19 @@
|
||||
<version>1.21.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Prometheus metrics dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.prometheus</groupId>
|
||||
<artifactId>simpleclient</artifactId>
|
||||
<version>0.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.5.0-jre</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<distributionManagement>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +0,0 @@
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class OllamaBaseException extends Exception {
|
||||
|
||||
public OllamaBaseException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class OllamaException extends Exception {
|
||||
|
||||
public OllamaException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public OllamaException(String message, Exception exception) {
|
||||
super(message, exception);
|
||||
}
|
||||
}
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class RoleNotFoundException extends Exception {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class ToolInvocationException extends Exception {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class ToolNotFoundException extends Exception {
|
||||
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.impl;
|
||||
|
||||
import io.github.ollama4j.models.chat.OllamaChatStreamObserver;
|
||||
|
||||
public final class ConsoleOutputChatTokenHandler extends OllamaChatStreamObserver {
|
||||
public ConsoleOutputChatTokenHandler() {
|
||||
setThinkingStreamHandler(new ConsoleOutputGenerateTokenHandler());
|
||||
setResponseStreamHandler(new ConsoleOutputGenerateTokenHandler());
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.impl;
|
||||
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateTokenHandler;
|
||||
|
||||
public class ConsoleOutputGenerateTokenHandler implements OllamaGenerateTokenHandler {
|
||||
@Override
|
||||
public void accept(String message) {
|
||||
System.out.print(message);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package io.github.ollama4j.impl;
|
||||
|
||||
import io.github.ollama4j.models.generate.OllamaStreamHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ConsoleOutputStreamHandler implements OllamaStreamHandler {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConsoleOutputStreamHandler.class);
|
||||
|
||||
@Override
|
||||
public void accept(String message) {
|
||||
LOG.info(message);
|
||||
}
|
||||
}
|
129
src/main/java/io/github/ollama4j/metrics/MetricsRecorder.java
Normal file
129
src/main/java/io/github/ollama4j/metrics/MetricsRecorder.java
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.metrics;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import io.prometheus.client.Counter;
|
||||
import io.prometheus.client.Histogram;
|
||||
import java.util.Map;
|
||||
|
||||
public class MetricsRecorder {
|
||||
|
||||
// Corrected: Removed duplicate "format" label and ensured label count matches usage
|
||||
private static final Counter requests =
|
||||
Counter.build()
|
||||
.name("ollama_api_requests_total")
|
||||
.help("Total requests to Ollama API")
|
||||
.labelNames(
|
||||
"endpoint",
|
||||
"model",
|
||||
"raw",
|
||||
"streaming",
|
||||
"thinking",
|
||||
"http_status",
|
||||
"options",
|
||||
"format")
|
||||
.register();
|
||||
|
||||
private static final Histogram requestLatency =
|
||||
Histogram.build()
|
||||
.name("ollama_api_request_duration_seconds")
|
||||
.help("Request latency in seconds")
|
||||
.labelNames(
|
||||
"endpoint",
|
||||
"model",
|
||||
"raw",
|
||||
"streaming",
|
||||
"thinking",
|
||||
"http_status",
|
||||
"options",
|
||||
"format")
|
||||
.register();
|
||||
|
||||
private static final Histogram responseSize =
|
||||
Histogram.build()
|
||||
.name("ollama_api_response_size_bytes")
|
||||
.help("Response size in bytes")
|
||||
.labelNames("endpoint", "model", "options")
|
||||
.register();
|
||||
|
||||
public static void record(
|
||||
String endpoint,
|
||||
String model,
|
||||
boolean raw,
|
||||
boolean thinking,
|
||||
boolean streaming,
|
||||
Map<String, Object> options,
|
||||
Object format,
|
||||
long startTime,
|
||||
int responseHttpStatus,
|
||||
Object response) {
|
||||
long endTime = System.currentTimeMillis();
|
||||
|
||||
String httpStatus = String.valueOf(responseHttpStatus);
|
||||
|
||||
String formatString = "";
|
||||
if (format instanceof String) {
|
||||
formatString = (String) format;
|
||||
} else if (format instanceof Map) {
|
||||
formatString = mapToString((Map<String, Object>) format);
|
||||
} else if (format != null) {
|
||||
formatString = format.toString();
|
||||
}
|
||||
|
||||
// Ensure the number of labels matches the labelNames above (8 labels)
|
||||
requests.labels(
|
||||
endpoint,
|
||||
safe(model),
|
||||
String.valueOf(raw),
|
||||
String.valueOf(streaming),
|
||||
String.valueOf(thinking),
|
||||
httpStatus,
|
||||
safe(mapToString(options)),
|
||||
safe(formatString))
|
||||
.inc();
|
||||
double durationSeconds = (endTime - startTime) / 1000.0;
|
||||
|
||||
// Ensure the number of labels matches the labelNames above (8 labels)
|
||||
requestLatency
|
||||
.labels(
|
||||
endpoint,
|
||||
safe(model),
|
||||
String.valueOf(raw),
|
||||
String.valueOf(streaming),
|
||||
String.valueOf(thinking),
|
||||
httpStatus,
|
||||
safe(mapToString(options)),
|
||||
safe(formatString))
|
||||
.observe(durationSeconds);
|
||||
|
||||
// Record response size (only if response is a string or json-like object)
|
||||
if (response != null) {
|
||||
if (response instanceof Exception) {
|
||||
response = Throwables.getStackTraceAsString((Throwable) response);
|
||||
}
|
||||
int size = response.toString().length();
|
||||
responseSize.labels(endpoint, safe(model), safe(mapToString(options))).observe(size);
|
||||
}
|
||||
}
|
||||
|
||||
// Utility method to convert options Map to string (you can adjust this for more detailed
|
||||
// representation)
|
||||
private static String mapToString(Map<String, Object> map) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
return "none";
|
||||
}
|
||||
// Convert the map to a string (can be customized to fit the use case)
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return (value == null || value.isEmpty()) ? "none" : value;
|
||||
}
|
||||
}
|
@ -1,21 +1,31 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import io.github.ollama4j.utils.FileToBase64Serializer;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* Defines a single Message to be used inside a chat request against the ollama /api/chat endpoint.
|
||||
*
|
||||
* @see <a href="https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-chat-completion">Generate chat completion</a>
|
||||
* @see <a
|
||||
* href="https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-chat-completion">Generate
|
||||
* chat completion</a>
|
||||
*/
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@ -23,11 +33,11 @@ import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OllamaChatMessage {
|
||||
|
||||
@NonNull
|
||||
private OllamaChatMessageRole role;
|
||||
@NonNull private OllamaChatMessageRole role;
|
||||
|
||||
@JsonProperty("content")
|
||||
@NonNull
|
||||
private String content;
|
||||
private String response;
|
||||
|
||||
private String thinking;
|
||||
|
||||
|
@ -1,11 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Defines the possible Chat Message roles.
|
||||
@ -19,8 +26,7 @@ public class OllamaChatMessageRole {
|
||||
public static final OllamaChatMessageRole ASSISTANT = new OllamaChatMessageRole("assistant");
|
||||
public static final OllamaChatMessageRole TOOL = new OllamaChatMessageRole("tool");
|
||||
|
||||
@JsonValue
|
||||
private final String roleName;
|
||||
@JsonValue private final String roleName;
|
||||
|
||||
private OllamaChatMessageRole(String roleName) {
|
||||
this.roleName = roleName;
|
||||
@ -28,8 +34,6 @@ public class OllamaChatMessageRole {
|
||||
}
|
||||
|
||||
public static OllamaChatMessageRole newCustomRole(String roleName) {
|
||||
// OllamaChatMessageRole customRole = new OllamaChatMessageRole(roleName);
|
||||
// roles.add(customRole);
|
||||
return new OllamaChatMessageRole(roleName);
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,21 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.models.request.OllamaCommonRequest;
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Defines a Request to use against the ollama /api/chat endpoint.
|
||||
*
|
||||
@ -19,14 +27,24 @@ import java.util.List;
|
||||
@Setter
|
||||
public class OllamaChatRequest extends OllamaCommonRequest implements OllamaRequestBody {
|
||||
|
||||
private List<OllamaChatMessage> messages;
|
||||
private List<OllamaChatMessage> messages = Collections.emptyList();
|
||||
|
||||
private List<Tools.PromptFuncDefinition> tools;
|
||||
private List<Tools.Tool> tools;
|
||||
|
||||
private boolean think;
|
||||
|
||||
public OllamaChatRequest() {
|
||||
}
|
||||
/**
|
||||
* Controls whether tools are automatically executed.
|
||||
*
|
||||
* <p>If set to {@code true} (the default), tools will be automatically used/applied by the
|
||||
* library. If set to {@code false}, tool calls will be returned to the client for manual
|
||||
* handling.
|
||||
*
|
||||
* <p>Disabling this should be an explicit operation.
|
||||
*/
|
||||
private boolean useTools = true;
|
||||
|
||||
public OllamaChatRequest() {}
|
||||
|
||||
public OllamaChatRequest(String model, boolean think, List<OllamaChatMessage> messages) {
|
||||
this.model = model;
|
||||
@ -42,5 +60,4 @@ public class OllamaChatRequest extends OllamaCommonRequest implements OllamaRequ
|
||||
|
||||
return this.toString().equals(o.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,38 +1,59 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper class for creating {@link OllamaChatRequest} objects using the builder-pattern.
|
||||
*/
|
||||
/** Helper class for creating {@link OllamaChatRequest} objects using the builder-pattern. */
|
||||
public class OllamaChatRequestBuilder {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OllamaChatRequestBuilder.class);
|
||||
|
||||
private OllamaChatRequestBuilder(String model, List<OllamaChatMessage> messages) {
|
||||
request = new OllamaChatRequest(model, false, messages);
|
||||
}
|
||||
|
||||
private int imageURLConnectTimeoutSeconds = 10;
|
||||
private int imageURLReadTimeoutSeconds = 10;
|
||||
private OllamaChatRequest request;
|
||||
@Setter private boolean useTools = true;
|
||||
|
||||
public static OllamaChatRequestBuilder getInstance(String model) {
|
||||
return new OllamaChatRequestBuilder(model, new ArrayList<>());
|
||||
private OllamaChatRequestBuilder() {
|
||||
request = new OllamaChatRequest();
|
||||
request.setMessages(new ArrayList<>());
|
||||
}
|
||||
|
||||
public OllamaChatRequest build() {
|
||||
return request;
|
||||
public static OllamaChatRequestBuilder builder() {
|
||||
return new OllamaChatRequestBuilder();
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withImageURLConnectTimeoutSeconds(
|
||||
int imageURLConnectTimeoutSeconds) {
|
||||
this.imageURLConnectTimeoutSeconds = imageURLConnectTimeoutSeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withImageURLReadTimeoutSeconds(int imageURLReadTimeoutSeconds) {
|
||||
this.imageURLReadTimeoutSeconds = imageURLReadTimeoutSeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withModel(String model) {
|
||||
request.setModel(model);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
@ -43,50 +64,79 @@ public class OllamaChatRequestBuilder {
|
||||
return withMessage(role, content, Collections.emptyList());
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls) {
|
||||
public OllamaChatRequestBuilder withMessage(
|
||||
OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls) {
|
||||
List<OllamaChatMessage> messages = this.request.getMessages();
|
||||
messages.add(new OllamaChatMessage(role, content, null, toolCalls, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls, List<File> images) {
|
||||
public OllamaChatRequestBuilder withMessage(
|
||||
OllamaChatMessageRole role,
|
||||
String content,
|
||||
List<OllamaChatToolCalls> toolCalls,
|
||||
List<File> images) {
|
||||
List<OllamaChatMessage> messages = this.request.getMessages();
|
||||
|
||||
List<byte[]> binaryImages = images.stream().map(file -> {
|
||||
List<byte[]> binaryImages =
|
||||
images.stream()
|
||||
.map(
|
||||
file -> {
|
||||
try {
|
||||
return Files.readAllBytes(file.toPath());
|
||||
} catch (IOException e) {
|
||||
LOG.warn("File '{}' could not be accessed, will not add to message!", file.toPath(), e);
|
||||
LOG.warn(
|
||||
"File '{}' could not be accessed, will not add to"
|
||||
+ " message!",
|
||||
file.toPath(),
|
||||
e);
|
||||
return new byte[0];
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
messages.add(new OllamaChatMessage(role, content, null, toolCalls, binaryImages));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls, String... imageUrls) {
|
||||
public OllamaChatRequestBuilder withMessage(
|
||||
OllamaChatMessageRole role,
|
||||
String content,
|
||||
List<OllamaChatToolCalls> toolCalls,
|
||||
String... imageUrls)
|
||||
throws IOException, InterruptedException {
|
||||
List<OllamaChatMessage> messages = this.request.getMessages();
|
||||
List<byte[]> binaryImages = null;
|
||||
if (imageUrls.length > 0) {
|
||||
binaryImages = new ArrayList<>();
|
||||
for (String imageUrl : imageUrls) {
|
||||
try {
|
||||
binaryImages.add(Utils.loadImageBytesFromUrl(imageUrl));
|
||||
} catch (URISyntaxException e) {
|
||||
LOG.warn("URL '{}' could not be accessed, will not add to message!", imageUrl, e);
|
||||
binaryImages.add(
|
||||
Utils.loadImageBytesFromUrl(
|
||||
imageUrl,
|
||||
imageURLConnectTimeoutSeconds,
|
||||
imageURLReadTimeoutSeconds));
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error("Failed to load image from URL: '{}'. Cause: {}", imageUrl, e);
|
||||
Thread.currentThread().interrupt();
|
||||
throw new InterruptedException(
|
||||
"Interrupted while loading image from URL: " + imageUrl);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Content of URL '{}' could not be read, will not add to message!", imageUrl, e);
|
||||
LOG.error(
|
||||
"IOException occurred while loading image from URL '{}'. Cause: {}",
|
||||
imageUrl,
|
||||
e.getMessage(),
|
||||
e);
|
||||
throw new IOException(
|
||||
"IOException while loading image from URL: " + imageUrl, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
messages.add(new OllamaChatMessage(role, content, null, toolCalls, binaryImages));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withMessages(List<OllamaChatMessage> messages) {
|
||||
return new OllamaChatRequestBuilder(request.getModel(), messages);
|
||||
request.setMessages(messages);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withOptions(Options options) {
|
||||
@ -95,7 +145,7 @@ public class OllamaChatRequestBuilder {
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withGetJsonResponse() {
|
||||
this.request.setReturnFormatJson(true);
|
||||
this.request.setFormat("json");
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -118,4 +168,9 @@ public class OllamaChatRequestBuilder {
|
||||
this.request.setThink(think);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequest build() {
|
||||
request.setUseTools(useTools);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,25 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OllamaChatResponseModel {
|
||||
private String model;
|
||||
private @JsonProperty("created_at") String createdAt;
|
||||
private @JsonProperty("done_reason") String doneReason;
|
||||
private OllamaChatMessage message;
|
||||
private boolean done;
|
||||
private String error;
|
||||
private List<Integer> context;
|
||||
private @JsonProperty("total_duration") Long totalDuration;
|
||||
private @JsonProperty("load_duration") Long loadDuration;
|
||||
@ -20,4 +27,6 @@ public class OllamaChatResponseModel {
|
||||
private @JsonProperty("eval_duration") Long evalDuration;
|
||||
private @JsonProperty("prompt_eval_count") Integer promptEvalCount;
|
||||
private @JsonProperty("eval_count") Integer evalCount;
|
||||
private String error;
|
||||
private OllamaChatMessage message;
|
||||
}
|
||||
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -18,7 +25,8 @@ public class OllamaChatResult {
|
||||
|
||||
private final OllamaChatResponseModel responseModel;
|
||||
|
||||
public OllamaChatResult(OllamaChatResponseModel responseModel, List<OllamaChatMessage> chatHistory) {
|
||||
public OllamaChatResult(
|
||||
OllamaChatResponseModel responseModel, List<OllamaChatMessage> chatHistory) {
|
||||
this.chatHistory = chatHistory;
|
||||
this.responseModel = responseModel;
|
||||
appendAnswerToChatHistory(responseModel);
|
||||
@ -36,19 +44,4 @@ public class OllamaChatResult {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getResponse(){
|
||||
return responseModel != null ? responseModel.getMessage().getContent() : "";
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getHttpStatusCode(){
|
||||
return 200;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public long getResponseTime(){
|
||||
return responseModel != null ? responseModel.getTotalDuration() : 0L;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,24 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.models.generate.OllamaStreamHandler;
|
||||
import io.github.ollama4j.models.generate.OllamaTokenHandler;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateTokenHandler;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class OllamaChatStreamObserver implements OllamaTokenHandler {
|
||||
private final OllamaStreamHandler thinkingStreamHandler;
|
||||
private final OllamaStreamHandler responseStreamHandler;
|
||||
|
||||
private String message = "";
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OllamaChatStreamObserver implements OllamaChatTokenHandler {
|
||||
private OllamaGenerateTokenHandler thinkingStreamHandler;
|
||||
private OllamaGenerateTokenHandler responseStreamHandler;
|
||||
|
||||
@Override
|
||||
public void accept(OllamaChatResponseModel token) {
|
||||
@ -18,34 +27,15 @@ public class OllamaChatStreamObserver implements OllamaTokenHandler {
|
||||
}
|
||||
|
||||
String thinking = token.getMessage().getThinking();
|
||||
String content = token.getMessage().getContent();
|
||||
String response = token.getMessage().getResponse();
|
||||
|
||||
boolean hasThinking = thinking != null && !thinking.isEmpty();
|
||||
boolean hasContent = !content.isEmpty();
|
||||
boolean hasResponse = response != null && !response.isEmpty();
|
||||
|
||||
// if (hasThinking && !hasContent) {
|
||||
//// message += thinking;
|
||||
// message = thinking;
|
||||
// } else {
|
||||
//// message += content;
|
||||
// message = content;
|
||||
// }
|
||||
//
|
||||
// responseStreamHandler.accept(message);
|
||||
|
||||
|
||||
if (!hasContent && hasThinking && thinkingStreamHandler != null) {
|
||||
// message = message + thinking;
|
||||
|
||||
// use only new tokens received, instead of appending the tokens to the previous
|
||||
// ones and sending the full string again
|
||||
if (!hasResponse && hasThinking && thinkingStreamHandler != null) {
|
||||
thinkingStreamHandler.accept(thinking);
|
||||
} else if (hasContent && responseStreamHandler != null) {
|
||||
// message = message + response;
|
||||
|
||||
// use only new tokens received, instead of appending the tokens to the previous
|
||||
// ones and sending the full string again
|
||||
responseStreamHandler.accept(content);
|
||||
} else if (hasResponse) {
|
||||
responseStreamHandler.accept(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface OllamaChatTokenHandler extends Consumer<OllamaChatResponseModel> {}
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.tools.OllamaToolCallsFunction;
|
||||
@ -11,6 +19,4 @@ import lombok.NoArgsConstructor;
|
||||
public class OllamaChatToolCalls {
|
||||
|
||||
private OllamaToolCallsFunction function;
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,26 +1,29 @@
|
||||
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;
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embed;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.*;
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OllamaEmbedRequestModel {
|
||||
@NonNull
|
||||
private String model;
|
||||
public class OllamaEmbedRequest {
|
||||
@NonNull private String model;
|
||||
|
||||
@NonNull
|
||||
private List<String> input;
|
||||
@NonNull private List<String> input;
|
||||
|
||||
private Map<String, Object> options;
|
||||
|
@ -1,7 +1,14 @@
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embed;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -9,32 +16,32 @@ import java.util.List;
|
||||
*/
|
||||
public class OllamaEmbedRequestBuilder {
|
||||
|
||||
private final OllamaEmbedRequestModel request;
|
||||
private final OllamaEmbedRequest request;
|
||||
|
||||
private OllamaEmbedRequestBuilder(String model, List<String> input) {
|
||||
this.request = new OllamaEmbedRequestModel(model,input);
|
||||
this.request = new OllamaEmbedRequest(model, input);
|
||||
}
|
||||
|
||||
public static OllamaEmbedRequestBuilder getInstance(String model, String... input){
|
||||
public static OllamaEmbedRequestBuilder getInstance(String model, String... input) {
|
||||
return new OllamaEmbedRequestBuilder(model, List.of(input));
|
||||
}
|
||||
|
||||
public OllamaEmbedRequestBuilder withOptions(Options options){
|
||||
public OllamaEmbedRequestBuilder withOptions(Options options) {
|
||||
this.request.setOptions(options.getOptionsMap());
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaEmbedRequestBuilder withKeepAlive(String keepAlive){
|
||||
public OllamaEmbedRequestBuilder withKeepAlive(String keepAlive) {
|
||||
this.request.setKeepAlive(keepAlive);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaEmbedRequestBuilder withoutTruncate(){
|
||||
public OllamaEmbedRequestBuilder withoutTruncate() {
|
||||
this.request.setTruncate(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaEmbedRequestModel build() {
|
||||
public OllamaEmbedRequest build() {
|
||||
return this.request;
|
||||
}
|
||||
}
|
@ -1,13 +1,20 @@
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embed;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
public class OllamaEmbedResponseModel {
|
||||
public class OllamaEmbedResult {
|
||||
@JsonProperty("model")
|
||||
private String model;
|
||||
|
@ -1,14 +0,0 @@
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
@Deprecated(since="1.0.90")
|
||||
public class OllamaEmbeddingResponseModel {
|
||||
@JsonProperty("embedding")
|
||||
private List<Double> embedding;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
|
||||
@Deprecated(since="1.0.90")
|
||||
public class OllamaEmbeddingsRequestBuilder {
|
||||
|
||||
private OllamaEmbeddingsRequestBuilder(String model, String prompt){
|
||||
request = new OllamaEmbeddingsRequestModel(model, prompt);
|
||||
}
|
||||
|
||||
private OllamaEmbeddingsRequestModel request;
|
||||
|
||||
public static OllamaEmbeddingsRequestBuilder getInstance(String model, String prompt){
|
||||
return new OllamaEmbeddingsRequestBuilder(model, prompt);
|
||||
}
|
||||
|
||||
public OllamaEmbeddingsRequestModel build(){
|
||||
return request;
|
||||
}
|
||||
|
||||
public OllamaEmbeddingsRequestBuilder withOptions(Options options){
|
||||
this.request.setOptions(options.getOptionsMap());
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaEmbeddingsRequestBuilder withKeepAlive(String keepAlive){
|
||||
this.request.setKeepAlive(keepAlive);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
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.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Deprecated(since="1.0.90")
|
||||
public class OllamaEmbeddingsRequestModel {
|
||||
@NonNull
|
||||
private String model;
|
||||
@NonNull
|
||||
private String prompt;
|
||||
|
||||
protected Map<String, Object> options;
|
||||
@JsonProperty(value = "keep_alive")
|
||||
private String keepAlive;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +1,34 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
|
||||
import io.github.ollama4j.models.request.OllamaCommonRequest;
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class OllamaGenerateRequest extends OllamaCommonRequest implements OllamaRequestBody{
|
||||
public class OllamaGenerateRequest extends OllamaCommonRequest implements OllamaRequestBody {
|
||||
|
||||
private String prompt;
|
||||
private List<String> images;
|
||||
|
||||
private String system;
|
||||
private String context;
|
||||
private boolean raw;
|
||||
private boolean think;
|
||||
private boolean useTools;
|
||||
private List<Tools.Tool> tools;
|
||||
|
||||
public OllamaGenerateRequest() {
|
||||
}
|
||||
public OllamaGenerateRequest() {}
|
||||
|
||||
public OllamaGenerateRequest(String model, String prompt) {
|
||||
this.model = model;
|
||||
@ -39,8 +46,6 @@ public class OllamaGenerateRequest extends OllamaCommonRequest implements Ollama
|
||||
if (!(o instanceof OllamaGenerateRequest)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.toString().equals(o.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,55 +1,121 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
import io.github.ollama4j.utils.Options;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper class for creating {@link OllamaGenerateRequest}
|
||||
* objects using the builder-pattern.
|
||||
*/
|
||||
/** Helper class for creating {@link OllamaGenerateRequest} objects using the builder-pattern. */
|
||||
public class OllamaGenerateRequestBuilder {
|
||||
|
||||
private OllamaGenerateRequestBuilder(String model, String prompt){
|
||||
request = new OllamaGenerateRequest(model, prompt);
|
||||
private OllamaGenerateRequestBuilder() {
|
||||
request = new OllamaGenerateRequest();
|
||||
}
|
||||
|
||||
private OllamaGenerateRequest request;
|
||||
|
||||
public static OllamaGenerateRequestBuilder getInstance(String model){
|
||||
return new OllamaGenerateRequestBuilder(model,"");
|
||||
public static OllamaGenerateRequestBuilder builder() {
|
||||
return new OllamaGenerateRequestBuilder();
|
||||
}
|
||||
|
||||
public OllamaGenerateRequest build(){
|
||||
public OllamaGenerateRequest build() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withPrompt(String prompt){
|
||||
public OllamaGenerateRequestBuilder withPrompt(String prompt) {
|
||||
request.setPrompt(prompt);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withGetJsonResponse(){
|
||||
this.request.setReturnFormatJson(true);
|
||||
public OllamaGenerateRequestBuilder withTools(List<Tools.Tool> tools) {
|
||||
request.setTools(tools);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withOptions(Options options){
|
||||
public OllamaGenerateRequestBuilder withModel(String model) {
|
||||
request.setModel(model);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withGetJsonResponse() {
|
||||
this.request.setFormat("json");
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withOptions(Options options) {
|
||||
this.request.setOptions(options.getOptionsMap());
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withTemplate(String template){
|
||||
public OllamaGenerateRequestBuilder withTemplate(String template) {
|
||||
this.request.setTemplate(template);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withStreaming(){
|
||||
this.request.setStream(true);
|
||||
public OllamaGenerateRequestBuilder withStreaming(boolean streaming) {
|
||||
this.request.setStream(streaming);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withKeepAlive(String keepAlive){
|
||||
public OllamaGenerateRequestBuilder withKeepAlive(String keepAlive) {
|
||||
this.request.setKeepAlive(keepAlive);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withRaw(boolean raw) {
|
||||
this.request.setRaw(raw);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withThink(boolean think) {
|
||||
this.request.setThink(think);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withUseTools(boolean useTools) {
|
||||
this.request.setUseTools(useTools);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withFormat(java.util.Map<String, Object> format) {
|
||||
this.request.setFormat(format);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withSystem(String system) {
|
||||
this.request.setSystem(system);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withContext(String context) {
|
||||
this.request.setContext(context);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withImagesBase64(java.util.List<String> images) {
|
||||
this.request.setImages(images);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaGenerateRequestBuilder withImages(java.util.List<File> imageFiles)
|
||||
throws IOException {
|
||||
java.util.List<String> images = new ArrayList<>();
|
||||
for (File imageFile : imageFiles) {
|
||||
images.add(Base64.getEncoder().encodeToString(Files.readAllBytes(imageFile.toPath())));
|
||||
}
|
||||
this.request.setImages(images);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,32 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OllamaGenerateResponseModel {
|
||||
private String model;
|
||||
private @JsonProperty("created_at") String createdAt;
|
||||
private String response;
|
||||
private String thinking;
|
||||
private boolean done;
|
||||
private @JsonProperty("done_reason") String doneReason;
|
||||
private boolean done;
|
||||
private List<Integer> context;
|
||||
private @JsonProperty("total_duration") Long totalDuration;
|
||||
private @JsonProperty("load_duration") Long loadDuration;
|
||||
private @JsonProperty("prompt_eval_count") Integer promptEvalCount;
|
||||
private @JsonProperty("prompt_eval_duration") Long promptEvalDuration;
|
||||
private @JsonProperty("eval_count") Integer evalCount;
|
||||
private @JsonProperty("eval_duration") Long evalDuration;
|
||||
private @JsonProperty("prompt_eval_count") Integer promptEvalCount;
|
||||
private @JsonProperty("eval_count") Integer evalCount;
|
||||
private String response;
|
||||
private String thinking;
|
||||
}
|
||||
|
@ -1,20 +1,29 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class OllamaGenerateStreamObserver {
|
||||
|
||||
private final OllamaStreamHandler thinkingStreamHandler;
|
||||
private final OllamaStreamHandler responseStreamHandler;
|
||||
private final OllamaGenerateTokenHandler thinkingStreamHandler;
|
||||
private final OllamaGenerateTokenHandler responseStreamHandler;
|
||||
|
||||
private final List<OllamaGenerateResponseModel> responseParts = new ArrayList<>();
|
||||
|
||||
private String message = "";
|
||||
|
||||
public OllamaGenerateStreamObserver(OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) {
|
||||
this.responseStreamHandler = responseStreamHandler;
|
||||
public OllamaGenerateStreamObserver(
|
||||
OllamaGenerateTokenHandler thinkingStreamHandler,
|
||||
OllamaGenerateTokenHandler responseStreamHandler) {
|
||||
this.thinkingStreamHandler = thinkingStreamHandler;
|
||||
this.responseStreamHandler = responseStreamHandler;
|
||||
}
|
||||
|
||||
public void notify(OllamaGenerateResponseModel currentResponsePart) {
|
||||
@ -30,16 +39,8 @@ public class OllamaGenerateStreamObserver {
|
||||
boolean hasThinking = thinking != null && !thinking.isEmpty();
|
||||
|
||||
if (!hasResponse && hasThinking && thinkingStreamHandler != null) {
|
||||
// message = message + thinking;
|
||||
|
||||
// use only new tokens received, instead of appending the tokens to the previous
|
||||
// ones and sending the full string again
|
||||
thinkingStreamHandler.accept(thinking);
|
||||
} else if (hasResponse && responseStreamHandler != null) {
|
||||
// message = message + response;
|
||||
|
||||
// use only new tokens received, instead of appending the tokens to the previous
|
||||
// ones and sending the full string again
|
||||
responseStreamHandler.accept(response);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface OllamaGenerateTokenHandler extends Consumer<String> {
|
||||
void accept(String message);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface OllamaStreamHandler extends Consumer<String> {
|
||||
void accept(String message);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import io.github.ollama4j.models.chat.OllamaChatResponseModel;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface OllamaTokenHandler extends Consumer<OllamaChatResponseModel> {
|
||||
}
|
@ -1,21 +1,29 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.ps;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ModelsProcessResponse {
|
||||
public class ModelProcessesResult {
|
||||
@JsonProperty("models")
|
||||
private List<ModelProcess> models;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ModelProcess {
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
@ -33,7 +41,7 @@ public class ModelsProcessResponse {
|
||||
private ModelDetails details;
|
||||
|
||||
@JsonProperty("expires_at")
|
||||
private String expiresAt; // Consider using LocalDateTime if you need to process date/time
|
||||
private String expiresAt;
|
||||
|
||||
@JsonProperty("size_vram")
|
||||
private long sizeVram;
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
public abstract class Auth {
|
||||
|
@ -1,11 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import java.util.Base64;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
@ -1,11 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class CustomModelFileContentsRequest {
|
||||
|
@ -1,11 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class CustomModelFilePathRequest {
|
||||
|
@ -1,15 +1,21 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@ -20,7 +26,7 @@ public class CustomModelRequest {
|
||||
private Map<String, String> files;
|
||||
private Map<String, String> adapters;
|
||||
private String template;
|
||||
private Object license; // Using Object to handle both String and List<String>
|
||||
private Object license;
|
||||
private String system;
|
||||
private Map<String, Object> parameters;
|
||||
private List<Object> messages;
|
||||
|
@ -1,11 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ModelRequest {
|
||||
|
@ -1,15 +1,21 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
import io.github.ollama4j.exceptions.OllamaException;
|
||||
import io.github.ollama4j.metrics.MetricsRecorder;
|
||||
import io.github.ollama4j.models.chat.*;
|
||||
import io.github.ollama4j.models.generate.OllamaTokenHandler;
|
||||
import io.github.ollama4j.models.chat.OllamaChatTokenHandler;
|
||||
import io.github.ollama4j.models.response.OllamaErrorResponse;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -20,50 +26,49 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Specialization class for requests
|
||||
*/
|
||||
/** Specialization class for requests */
|
||||
@SuppressWarnings("resource")
|
||||
public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OllamaChatEndpointCaller.class);
|
||||
public static final String endpoint = "/api/chat";
|
||||
|
||||
private OllamaTokenHandler tokenHandler;
|
||||
private OllamaChatTokenHandler tokenHandler;
|
||||
|
||||
public OllamaChatEndpointCaller(String host, Auth auth, long requestTimeoutSeconds) {
|
||||
super(host, auth, requestTimeoutSeconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEndpointSuffix() {
|
||||
return "/api/chat";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses streamed Response line from ollama chat.
|
||||
* Using {@link com.fasterxml.jackson.databind.ObjectMapper#readValue(String, TypeReference)} should throw
|
||||
* {@link IllegalArgumentException} in case of null line or {@link com.fasterxml.jackson.core.JsonParseException}
|
||||
* in case the JSON Object cannot be parsed to a {@link OllamaChatResponseModel}. Thus, the ResponseModel should
|
||||
* never be null.
|
||||
* Parses streamed Response line from ollama chat. Using {@link
|
||||
* com.fasterxml.jackson.databind.ObjectMapper#readValue(String, TypeReference)} should throw
|
||||
* {@link IllegalArgumentException} in case of null line or {@link
|
||||
* com.fasterxml.jackson.core.JsonParseException} in case the JSON Object cannot be parsed to a
|
||||
* {@link OllamaChatResponseModel}. Thus, the ResponseModel should never be null.
|
||||
*
|
||||
* @param line streamed line of ollama stream response
|
||||
* @param responseBuffer Stringbuffer to add latest response message part to
|
||||
* @return TRUE, if ollama-Response has 'done' state
|
||||
*/
|
||||
@Override
|
||||
protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
protected boolean parseResponseAndAddToBuffer(
|
||||
String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
try {
|
||||
OllamaChatResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
// it seems that under heavy load ollama responds with an empty chat message part in the streamed response
|
||||
// thus, we null check the message and hope that the next streamed response has some message content again
|
||||
OllamaChatResponseModel ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
// It seems that under heavy load Ollama responds with an empty chat message part in the
|
||||
// streamed response.
|
||||
// Thus, we null check the message and hope that the next streamed response has some
|
||||
// message content again.
|
||||
OllamaChatMessage message = ollamaResponseModel.getMessage();
|
||||
if (message != null) {
|
||||
if (message.getThinking() != null) {
|
||||
thinkingBuffer.append(message.getThinking());
|
||||
}
|
||||
else {
|
||||
responseBuffer.append(message.getContent());
|
||||
} else {
|
||||
responseBuffer.append(message.getResponse());
|
||||
}
|
||||
if (tokenHandler != null) {
|
||||
tokenHandler.accept(ollamaResponseModel);
|
||||
@ -76,22 +81,22 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
}
|
||||
}
|
||||
|
||||
public OllamaChatResult call(OllamaChatRequest body, OllamaTokenHandler tokenHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
public OllamaChatResult call(OllamaChatRequest body, OllamaChatTokenHandler tokenHandler)
|
||||
throws OllamaException, IOException, InterruptedException {
|
||||
this.tokenHandler = tokenHandler;
|
||||
return callSync(body);
|
||||
}
|
||||
|
||||
public OllamaChatResult callSync(OllamaChatRequest body) throws OllamaBaseException, IOException, InterruptedException {
|
||||
// Create Request
|
||||
public OllamaChatResult callSync(OllamaChatRequest body)
|
||||
throws OllamaException, IOException, InterruptedException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
URI uri = URI.create(getHost() + getEndpointSuffix());
|
||||
URI uri = URI.create(getHost() + endpoint);
|
||||
HttpRequest.Builder requestBuilder =
|
||||
getRequestBuilderDefault(uri)
|
||||
.POST(
|
||||
body.getBodyPublisher());
|
||||
getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
|
||||
HttpRequest request = requestBuilder.build();
|
||||
LOG.debug("Asking model: {}", body);
|
||||
System.out.println("Asking model: " + Utils.toJSON(body));
|
||||
HttpResponse<InputStream> response =
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
|
||||
@ -101,51 +106,46 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
StringBuilder thinkingBuffer = new StringBuilder();
|
||||
OllamaChatResponseModel ollamaChatResponseModel = null;
|
||||
List<OllamaChatToolCalls> wantedToolsForStream = null;
|
||||
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) {
|
||||
if (statusCode == 404) {
|
||||
LOG.warn("Status code: 404 (Not Found)");
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 401) {
|
||||
LOG.warn("Status code: 401 (Unauthorized)");
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper()
|
||||
.readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 400) {
|
||||
LOG.warn("Status code: 400 (Bad Request)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line,
|
||||
OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 500) {
|
||||
LOG.warn("Status code: 500 (Internal Server Error)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line,
|
||||
OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else {
|
||||
boolean finished = parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
ollamaChatResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
if (handleErrorStatus(statusCode, line, responseBuffer)) {
|
||||
continue;
|
||||
}
|
||||
boolean finished =
|
||||
parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
ollamaChatResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
if (body.stream && ollamaChatResponseModel.getMessage().getToolCalls() != null) {
|
||||
wantedToolsForStream = ollamaChatResponseModel.getMessage().getToolCalls();
|
||||
}
|
||||
if (finished && body.stream) {
|
||||
ollamaChatResponseModel.getMessage().setContent(responseBuffer.toString());
|
||||
ollamaChatResponseModel.getMessage().setResponse(responseBuffer.toString());
|
||||
ollamaChatResponseModel.getMessage().setThinking(thinkingBuffer.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MetricsRecorder.record(
|
||||
endpoint,
|
||||
body.getModel(),
|
||||
false,
|
||||
body.isThink(),
|
||||
body.isStream(),
|
||||
body.getOptions(),
|
||||
body.getFormat(),
|
||||
startTime,
|
||||
statusCode,
|
||||
responseBuffer);
|
||||
if (statusCode != 200) {
|
||||
LOG.error("Status code " + statusCode);
|
||||
throw new OllamaBaseException(responseBuffer.toString());
|
||||
} else {
|
||||
if (wantedToolsForStream != null) {
|
||||
LOG.error("Status code: {}", statusCode);
|
||||
System.out.println(responseBuffer);
|
||||
throw new OllamaException(responseBuffer.toString());
|
||||
}
|
||||
if (wantedToolsForStream != null && ollamaChatResponseModel != null) {
|
||||
ollamaChatResponseModel.getMessage().setToolCalls(wantedToolsForStream);
|
||||
}
|
||||
OllamaChatResult ollamaResult =
|
||||
@ -153,5 +153,45 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
LOG.debug("Model response: {}", ollamaResult);
|
||||
return ollamaResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles error status codes and appends error messages to the response buffer. Returns true if
|
||||
* an error was handled, false otherwise.
|
||||
*/
|
||||
private boolean handleErrorStatus(int statusCode, String line, StringBuilder responseBuffer)
|
||||
throws IOException {
|
||||
switch (statusCode) {
|
||||
case 404:
|
||||
LOG.warn("Status code: 404 (Not Found)");
|
||||
responseBuffer.append(
|
||||
Utils.getObjectMapper()
|
||||
.readValue(line, OllamaErrorResponse.class)
|
||||
.getError());
|
||||
return true;
|
||||
case 401:
|
||||
LOG.warn("Status code: 401 (Unauthorized)");
|
||||
responseBuffer.append(
|
||||
Utils.getObjectMapper()
|
||||
.readValue(
|
||||
"{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class)
|
||||
.getError());
|
||||
return true;
|
||||
case 400:
|
||||
LOG.warn("Status code: 400 (Bad Request)");
|
||||
responseBuffer.append(
|
||||
Utils.getObjectMapper()
|
||||
.readValue(line, OllamaErrorResponse.class)
|
||||
.getError());
|
||||
return true;
|
||||
case 500:
|
||||
LOG.warn("Status code: 500 (Internal Server Error)");
|
||||
responseBuffer.append(
|
||||
Utils.getObjectMapper()
|
||||
.readValue(line, OllamaErrorResponse.class)
|
||||
.getError());
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,47 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import io.github.ollama4j.utils.BooleanToJsonFormatFlagSerializer;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public abstract class OllamaCommonRequest {
|
||||
|
||||
protected String model;
|
||||
@JsonSerialize(using = BooleanToJsonFormatFlagSerializer.class)
|
||||
@JsonProperty(value = "format")
|
||||
protected Boolean returnFormatJson;
|
||||
|
||||
/**
|
||||
* The value can either be
|
||||
* <pre>{@code json }</pre>
|
||||
* or
|
||||
* <pre>{@code {"key1": "val1", "key2": "val2"} }</pre>
|
||||
*/
|
||||
@JsonProperty(value = "format", required = false, defaultValue = "json")
|
||||
protected Object format;
|
||||
|
||||
protected Map<String, Object> options;
|
||||
protected String template;
|
||||
protected boolean stream;
|
||||
|
||||
@JsonProperty(value = "keep_alive")
|
||||
protected String keepAlive;
|
||||
|
||||
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -1,14 +1,21 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import io.github.ollama4j.utils.Constants;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.time.Duration;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Abstract helperclass to call the ollama api server.
|
||||
* Abstract helper class to call the ollama api server.
|
||||
*/
|
||||
@Getter
|
||||
public abstract class OllamaEndpointCaller {
|
||||
@ -17,16 +24,14 @@ public abstract class OllamaEndpointCaller {
|
||||
private final Auth auth;
|
||||
private final long requestTimeoutSeconds;
|
||||
|
||||
public OllamaEndpointCaller(String host, Auth auth, long requestTimeoutSeconds) {
|
||||
protected OllamaEndpointCaller(String host, Auth auth, long requestTimeoutSeconds) {
|
||||
this.host = host;
|
||||
this.auth = auth;
|
||||
this.requestTimeoutSeconds = requestTimeoutSeconds;
|
||||
}
|
||||
|
||||
protected abstract String getEndpointSuffix();
|
||||
|
||||
protected abstract boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer);
|
||||
|
||||
protected abstract boolean parseResponseAndAddToBuffer(
|
||||
String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer);
|
||||
|
||||
/**
|
||||
* Get default request builder.
|
||||
@ -37,7 +42,9 @@ public abstract class OllamaEndpointCaller {
|
||||
protected HttpRequest.Builder getRequestBuilderDefault(URI uri) {
|
||||
HttpRequest.Builder requestBuilder =
|
||||
HttpRequest.newBuilder(uri)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.timeout(Duration.ofSeconds(this.requestTimeoutSeconds));
|
||||
if (isAuthCredentialsSet()) {
|
||||
requestBuilder.header("Authorization", this.auth.getAuthHeaderValue());
|
||||
@ -53,5 +60,4 @@ public abstract class OllamaEndpointCaller {
|
||||
protected boolean isAuthCredentialsSet() {
|
||||
return this.auth != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,17 +1,22 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
import io.github.ollama4j.exceptions.OllamaException;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateResponseModel;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateStreamObserver;
|
||||
import io.github.ollama4j.models.generate.OllamaStreamHandler;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateTokenHandler;
|
||||
import io.github.ollama4j.models.response.OllamaErrorResponse;
|
||||
import io.github.ollama4j.models.response.OllamaResult;
|
||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -21,11 +26,14 @@ import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OllamaGenerateEndpointCaller.class);
|
||||
public static final String endpoint = "/api/generate";
|
||||
|
||||
private OllamaGenerateStreamObserver responseStreamObserver;
|
||||
|
||||
@ -34,14 +42,11 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEndpointSuffix() {
|
||||
return "/api/generate";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
protected boolean parseResponseAndAddToBuffer(
|
||||
String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
try {
|
||||
OllamaGenerateResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
OllamaGenerateResponseModel ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
if (ollamaResponseModel.getResponse() != null) {
|
||||
responseBuffer.append(ollamaResponseModel.getResponse());
|
||||
}
|
||||
@ -58,55 +63,61 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
}
|
||||
}
|
||||
|
||||
public OllamaResult call(OllamaRequestBody body, OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException {
|
||||
responseStreamObserver = new OllamaGenerateStreamObserver(thinkingStreamHandler, responseStreamHandler);
|
||||
public OllamaResult call(
|
||||
OllamaRequestBody body,
|
||||
OllamaGenerateTokenHandler thinkingStreamHandler,
|
||||
OllamaGenerateTokenHandler responseStreamHandler)
|
||||
throws OllamaException, IOException, InterruptedException {
|
||||
responseStreamObserver =
|
||||
new OllamaGenerateStreamObserver(thinkingStreamHandler, responseStreamHandler);
|
||||
return callSync(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the api server on the given host and endpoint suffix asynchronously, aka waiting for the response.
|
||||
* Calls the api server on the given host and endpoint suffix asynchronously, aka waiting for
|
||||
* the response.
|
||||
*
|
||||
* @param body POST body payload
|
||||
* @return result answer given by the assistant
|
||||
* @throws OllamaBaseException any response code than 200 has been returned
|
||||
* @throws OllamaException 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
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public OllamaResult callSync(OllamaRequestBody body) throws OllamaBaseException, IOException, InterruptedException {
|
||||
// Create Request
|
||||
public OllamaResult callSync(OllamaRequestBody body)
|
||||
throws OllamaException, IOException, InterruptedException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
URI uri = URI.create(getHost() + getEndpointSuffix());
|
||||
HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
|
||||
URI uri = URI.create(getHost() + endpoint);
|
||||
HttpRequest.Builder requestBuilder =
|
||||
getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
|
||||
HttpRequest request = requestBuilder.build();
|
||||
LOG.debug("Asking model: {}", body);
|
||||
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
HttpResponse<InputStream> response =
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
|
||||
int statusCode = response.statusCode();
|
||||
InputStream responseBodyStream = response.body();
|
||||
StringBuilder responseBuffer = new StringBuilder();
|
||||
StringBuilder thinkingBuffer = new StringBuilder();
|
||||
OllamaGenerateResponseModel ollamaGenerateResponseModel = null;
|
||||
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) {
|
||||
if (statusCode == 404) {
|
||||
LOG.warn("Status code: 404 (Not Found)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 401) {
|
||||
LOG.warn("Status code: 401 (Unauthorized)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 400) {
|
||||
LOG.warn("Status code: 400 (Bad Request)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
if (statusCode >= 400) {
|
||||
LOG.warn("Error code: {}", statusCode);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else {
|
||||
boolean finished = parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
boolean finished =
|
||||
parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
if (finished) {
|
||||
ollamaGenerateResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
ollamaGenerateResponseModel =
|
||||
Utils.getObjectMapper()
|
||||
.readValue(line, OllamaGenerateResponseModel.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -115,11 +126,16 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
|
||||
if (statusCode != 200) {
|
||||
LOG.error("Status code: {}", statusCode);
|
||||
throw new OllamaBaseException(responseBuffer.toString());
|
||||
LOG.error("Response: {}", responseBuffer);
|
||||
throw new OllamaException(responseBuffer.toString());
|
||||
} else {
|
||||
long endTime = System.currentTimeMillis();
|
||||
OllamaResult ollamaResult = new OllamaResult(responseBuffer.toString(), thinkingBuffer.toString(), endTime - startTime, statusCode);
|
||||
|
||||
OllamaResult ollamaResult =
|
||||
new OllamaResult(
|
||||
responseBuffer.toString(),
|
||||
thinkingBuffer.toString(),
|
||||
endTime - startTime,
|
||||
statusCode);
|
||||
ollamaResult.setModel(ollamaGenerateResponseModel.getModel());
|
||||
ollamaResult.setCreatedAt(ollamaGenerateResponseModel.getCreatedAt());
|
||||
ollamaResult.setDone(ollamaGenerateResponseModel.isDone());
|
||||
|
@ -1,17 +0,0 @@
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@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;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class LibraryModelDetail {
|
||||
|
||||
private LibraryModel model;
|
||||
private List<LibraryModelTag> tags;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LibraryModelTag {
|
||||
private String name;
|
||||
private String tag;
|
||||
private String size;
|
||||
private String lastUpdated;
|
||||
}
|
@ -1,8 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ListModelsResponse {
|
||||
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@ -14,16 +21,19 @@ public class Model {
|
||||
|
||||
private String name;
|
||||
private String model;
|
||||
|
||||
@JsonProperty("modified_at")
|
||||
private OffsetDateTime modifiedAt;
|
||||
|
||||
@JsonProperty("expires_at")
|
||||
private OffsetDateTime expiresAt;
|
||||
|
||||
private String digest;
|
||||
private long size;
|
||||
|
||||
@JsonProperty("details")
|
||||
private ModelMeta modelMeta;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the model name without its version
|
||||
*
|
||||
@ -45,10 +55,11 @@ public class Model {
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
@ -22,7 +30,9 @@ public class ModelDetail {
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
@ -27,7 +35,9 @@ public class ModelMeta {
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
@ -1,15 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
import io.github.ollama4j.exceptions.OllamaException;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateRequest;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateResponseModel;
|
||||
import io.github.ollama4j.utils.Constants;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -19,6 +22,10 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ -31,32 +38,30 @@ public class OllamaAsyncResultStreamer extends Thread {
|
||||
private String completeResponse;
|
||||
private String completeThinkingResponse;
|
||||
|
||||
|
||||
/**
|
||||
* -- GETTER -- Returns the status of the request. Indicates if the request was successful or a
|
||||
* failure. If the request was a failure, the `getResponse()` method will return the error
|
||||
* message.
|
||||
*/
|
||||
@Getter
|
||||
private boolean succeeded;
|
||||
@Getter private boolean succeeded;
|
||||
|
||||
@Setter
|
||||
private long requestTimeoutSeconds;
|
||||
@Setter private long requestTimeoutSeconds;
|
||||
|
||||
/**
|
||||
* -- GETTER -- Returns the HTTP response status code for the request that was made to Ollama
|
||||
* server.
|
||||
*/
|
||||
@Getter
|
||||
private int httpStatusCode;
|
||||
@Getter private int httpStatusCode;
|
||||
|
||||
/**
|
||||
* -- GETTER -- Returns the response time in milliseconds.
|
||||
*/
|
||||
@Getter
|
||||
private long responseTime = 0;
|
||||
@Getter private long responseTime = 0;
|
||||
|
||||
public OllamaAsyncResultStreamer(HttpRequest.Builder requestBuilder, OllamaGenerateRequest ollamaRequestModel, long requestTimeoutSeconds) {
|
||||
public OllamaAsyncResultStreamer(
|
||||
HttpRequest.Builder requestBuilder,
|
||||
OllamaGenerateRequest ollamaRequestModel,
|
||||
long requestTimeoutSeconds) {
|
||||
this.requestBuilder = requestBuilder;
|
||||
this.ollamaRequestModel = ollamaRequestModel;
|
||||
this.completeResponse = "";
|
||||
@ -70,25 +75,41 @@ public class OllamaAsyncResultStreamer extends Thread {
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
HttpRequest request = requestBuilder.POST(HttpRequest.BodyPublishers.ofString(Utils.getObjectMapper().writeValueAsString(ollamaRequestModel))).header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).timeout(Duration.ofSeconds(requestTimeoutSeconds)).build();
|
||||
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
HttpRequest request =
|
||||
requestBuilder
|
||||
.POST(
|
||||
HttpRequest.BodyPublishers.ofString(
|
||||
Utils.getObjectMapper()
|
||||
.writeValueAsString(ollamaRequestModel)))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
|
||||
.build();
|
||||
HttpResponse<InputStream> response =
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
int statusCode = response.statusCode();
|
||||
this.httpStatusCode = statusCode;
|
||||
|
||||
InputStream responseBodyStream = response.body();
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8));
|
||||
reader =
|
||||
new BufferedReader(
|
||||
new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8));
|
||||
String line;
|
||||
StringBuilder thinkingBuffer = new StringBuilder();
|
||||
StringBuilder responseBuffer = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (statusCode == 404) {
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseStream.add(ollamaResponseModel.getError());
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else {
|
||||
OllamaGenerateResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
OllamaGenerateResponseModel ollamaResponseModel =
|
||||
Utils.getObjectMapper()
|
||||
.readValue(line, OllamaGenerateResponseModel.class);
|
||||
String thinkingTokens = ollamaResponseModel.getThinking();
|
||||
String responseTokens = ollamaResponseModel.getResponse();
|
||||
if (thinkingTokens == null) {
|
||||
@ -115,24 +136,27 @@ public class OllamaAsyncResultStreamer extends Thread {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
// Optionally log or handle
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
if (responseBodyStream != null) {
|
||||
try {
|
||||
responseBodyStream.close();
|
||||
} catch (IOException e) {
|
||||
// Optionally log or handle
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (statusCode != 200) {
|
||||
throw new OllamaBaseException(this.completeResponse);
|
||||
throw new OllamaException(this.completeResponse);
|
||||
}
|
||||
} catch (IOException | InterruptedException | OllamaBaseException e) {
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
this.succeeded = false;
|
||||
this.completeResponse = "[FAILED] " + e.getMessage();
|
||||
} catch (IOException | OllamaException e) {
|
||||
this.succeeded = false;
|
||||
this.completeResponse = "[FAILED] " + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
@ -1,21 +1,30 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* The type Ollama result.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@ -24,14 +33,17 @@ public class OllamaResult {
|
||||
* Get the completion/response text
|
||||
*/
|
||||
private final String response;
|
||||
|
||||
/**
|
||||
* Get the thinking text (if available)
|
||||
*/
|
||||
private final String thinking;
|
||||
|
||||
/**
|
||||
* Get the response status code.
|
||||
*/
|
||||
private int httpStatusCode;
|
||||
|
||||
/**
|
||||
* Get the response time in milliseconds.
|
||||
*/
|
||||
@ -75,7 +87,9 @@ public class OllamaResult {
|
||||
responseMap.put("promptEvalDuration", this.promptEvalDuration);
|
||||
responseMap.put("evalCount", this.evalCount);
|
||||
responseMap.put("evalDuration", this.evalDuration);
|
||||
return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(responseMap);
|
||||
return getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(responseMap);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -95,17 +109,16 @@ public class OllamaResult {
|
||||
|
||||
try {
|
||||
// Check if the response is a valid JSON
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) ||
|
||||
(!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("["))
|
||||
|| (!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
throw new IllegalArgumentException("Response is not a valid JSON object");
|
||||
}
|
||||
|
||||
Map<String, Object> response = getObjectMapper().readValue(responseStr,
|
||||
new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
return response;
|
||||
return getObjectMapper()
|
||||
.readValue(responseStr, new TypeReference<Map<String, Object>>() {});
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,13 +139,14 @@ public class OllamaResult {
|
||||
|
||||
try {
|
||||
// Check if the response is a valid JSON
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) ||
|
||||
(!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("["))
|
||||
|| (!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
throw new IllegalArgumentException("Response is not a valid JSON object");
|
||||
}
|
||||
return getObjectMapper().readValue(responseStr, clazz);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
@ -1,18 +1,25 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
@ -58,10 +65,8 @@ public class OllamaStructuredResult {
|
||||
*/
|
||||
public Map<String, Object> getStructuredResponse() {
|
||||
try {
|
||||
Map<String, Object> response = getObjectMapper().readValue(this.getResponse(),
|
||||
new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
return response;
|
||||
return getObjectMapper()
|
||||
.readValue(this.getResponse(), new TypeReference<Map<String, Object>>() {});
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,18 +1,24 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OllamaToolCallsFunction
|
||||
{
|
||||
public class OllamaToolCallsFunction {
|
||||
private String name;
|
||||
private Map<String,Object> arguments;
|
||||
private Map<String, Object> arguments;
|
||||
}
|
||||
|
@ -1,13 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import io.github.ollama4j.models.response.OllamaResult;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -22,7 +29,8 @@ public class OllamaToolsResult {
|
||||
return results;
|
||||
}
|
||||
for (Map.Entry<ToolFunctionCallSpec, Object> r : this.toolResults.entrySet()) {
|
||||
results.add(new ToolResult(r.getKey().getName(), r.getKey().getArguments(), r.getValue()));
|
||||
results.add(
|
||||
new ToolResult(r.getKey().getName(), r.getKey().getArguments(), r.getValue()));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
@ -1,13 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Specification of a {@link ToolFunction} that provides the implementation via java reflection calling.
|
||||
@ -15,17 +22,18 @@ import java.util.Map;
|
||||
@Setter
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class ReflectionalToolFunction implements ToolFunction{
|
||||
public class ReflectionalToolFunction implements ToolFunction {
|
||||
|
||||
private Object functionHolder;
|
||||
private Method function;
|
||||
private LinkedHashMap<String,String> propertyDefinition;
|
||||
private LinkedHashMap<String, String> propertyDefinition;
|
||||
|
||||
@Override
|
||||
public Object apply(Map<String, Object> arguments) {
|
||||
LinkedHashMap<String, Object> argumentsCopy = new LinkedHashMap<>(this.propertyDefinition);
|
||||
for (Map.Entry<String,String> param : this.propertyDefinition.entrySet()){
|
||||
argumentsCopy.replace(param.getKey(),typeCast(arguments.get(param.getKey()),param.getValue()));
|
||||
for (Map.Entry<String, String> param : this.propertyDefinition.entrySet()) {
|
||||
argumentsCopy.replace(
|
||||
param.getKey(), typeCast(arguments.get(param.getKey()), param.getValue()));
|
||||
}
|
||||
try {
|
||||
return function.invoke(functionHolder, argumentsCopy.values().toArray());
|
||||
@ -35,7 +43,7 @@ public class ReflectionalToolFunction implements ToolFunction{
|
||||
}
|
||||
|
||||
private Object typeCast(Object inputValue, String className) {
|
||||
if(className == null || inputValue == null) {
|
||||
if (className == null || inputValue == null) {
|
||||
return null;
|
||||
}
|
||||
String inputValueString = inputValue.toString();
|
||||
@ -50,5 +58,4 @@ public class ReflectionalToolFunction implements ToolFunction{
|
||||
return inputValueString;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,11 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
|
@ -1,28 +1,47 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import io.github.ollama4j.exceptions.ToolNotFoundException;
|
||||
import java.util.*;
|
||||
|
||||
public class ToolRegistry {
|
||||
private final Map<String, Tools.ToolSpecification> tools = new HashMap<>();
|
||||
private final List<Tools.Tool> tools = new ArrayList<>();
|
||||
|
||||
public ToolFunction getToolFunction(String name) {
|
||||
final Tools.ToolSpecification toolSpecification = tools.get(name);
|
||||
return toolSpecification != null ? toolSpecification.getToolFunction() : null;
|
||||
public ToolFunction getToolFunction(String name) throws ToolNotFoundException {
|
||||
for (Tools.Tool tool : tools) {
|
||||
if (tool.getToolSpec().getName().equals(name)) {
|
||||
return tool.getToolFunction();
|
||||
}
|
||||
}
|
||||
throw new ToolNotFoundException(String.format("Tool '%s' not found.", name));
|
||||
}
|
||||
|
||||
public void addTool(String name, Tools.ToolSpecification specification) {
|
||||
tools.put(name, specification);
|
||||
public void addTool(Tools.Tool tool) {
|
||||
try {
|
||||
getToolFunction(tool.getToolSpec().getName());
|
||||
} catch (ToolNotFoundException e) {
|
||||
tools.add(tool);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Tools.ToolSpecification> getRegisteredSpecs() {
|
||||
return tools.values();
|
||||
public void addTools(List<Tools.Tool> tools) {
|
||||
for (Tools.Tool tool : tools) {
|
||||
addTool(tool);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all registered tools from the registry.
|
||||
*/
|
||||
public List<Tools.Tool> getRegisteredTools() {
|
||||
return tools;
|
||||
}
|
||||
|
||||
/** Removes all registered tools from the registry. */
|
||||
public void clear() {
|
||||
tools.clear();
|
||||
}
|
||||
|
@ -1,58 +1,105 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Tools {
|
||||
private Tools() {}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public static class ToolSpecification {
|
||||
private String functionName;
|
||||
private String functionDescription;
|
||||
private PromptFuncDefinition toolPrompt;
|
||||
private ToolFunction toolFunction;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Tool {
|
||||
@JsonProperty("function")
|
||||
private ToolSpec toolSpec;
|
||||
|
||||
@Builder.Default private String type = "function";
|
||||
@JsonIgnore private ToolFunction toolFunction;
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class PromptFuncDefinition {
|
||||
private String type;
|
||||
private PromptFuncSpec function;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class PromptFuncSpec {
|
||||
public static class ToolSpec {
|
||||
private String name;
|
||||
private String description;
|
||||
private Parameters parameters;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Parameters {
|
||||
private String type;
|
||||
private Map<String, Property> properties;
|
||||
private List<String> required;
|
||||
private List<String> required = new ArrayList<>();
|
||||
|
||||
public static Parameters of(Map<String, Property> properties) {
|
||||
Parameters params = new Parameters();
|
||||
params.setProperties(properties);
|
||||
// Optionally, populate required from properties' required flags
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, Property> entry : properties.entrySet()) {
|
||||
if (entry.getValue() != null && entry.getValue().isRequired()) {
|
||||
params.getRequired().add(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ObjectNode node =
|
||||
com.fasterxml.jackson.databind.json.JsonMapper.builder()
|
||||
.build()
|
||||
.createObjectNode();
|
||||
node.put("type", "object");
|
||||
if (properties != null) {
|
||||
ObjectNode propsNode = node.putObject("properties");
|
||||
for (Map.Entry<String, Property> entry : properties.entrySet()) {
|
||||
ObjectNode propNode = propsNode.putObject(entry.getKey());
|
||||
Property prop = entry.getValue();
|
||||
propNode.put("type", prop.getType());
|
||||
propNode.put("description", prop.getDescription());
|
||||
if (prop.getEnumValues() != null) {
|
||||
propNode.putArray("enum")
|
||||
.addAll(
|
||||
prop.getEnumValues().stream()
|
||||
.map(
|
||||
com.fasterxml.jackson.databind.node.TextNode
|
||||
::new)
|
||||
.collect(java.util.stream.Collectors.toList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (required != null && !required.isEmpty()) {
|
||||
node.putArray("required")
|
||||
.addAll(
|
||||
required.stream()
|
||||
.map(com.fasterxml.jackson.databind.node.TextNode::new)
|
||||
.collect(java.util.stream.Collectors.toList()));
|
||||
}
|
||||
return node.toPrettyString();
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@ -62,65 +109,11 @@ public class Tools {
|
||||
public static class Property {
|
||||
private String type;
|
||||
private String description;
|
||||
|
||||
@JsonProperty("enum")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> enumValues;
|
||||
@JsonIgnore
|
||||
private boolean required;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PropsBuilder {
|
||||
private final Map<String, PromptFuncDefinition.Property> props = new HashMap<>();
|
||||
|
||||
public PropsBuilder withProperty(String key, PromptFuncDefinition.Property property) {
|
||||
props.put(key, property);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, PromptFuncDefinition.Property> build() {
|
||||
return props;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PromptBuilder {
|
||||
private final List<PromptFuncDefinition> tools = new ArrayList<>();
|
||||
|
||||
private String promptText;
|
||||
|
||||
public String build() throws JsonProcessingException {
|
||||
return "[AVAILABLE_TOOLS] " + Utils.getObjectMapper().writeValueAsString(tools) + "[/AVAILABLE_TOOLS][INST] " + promptText + " [/INST]";
|
||||
}
|
||||
|
||||
public PromptBuilder withPrompt(String prompt) throws JsonProcessingException {
|
||||
promptText = prompt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PromptBuilder withToolSpecification(ToolSpecification spec) {
|
||||
PromptFuncDefinition def = new PromptFuncDefinition();
|
||||
def.setType("function");
|
||||
|
||||
PromptFuncDefinition.PromptFuncSpec functionDetail = new PromptFuncDefinition.PromptFuncSpec();
|
||||
functionDetail.setName(spec.getFunctionName());
|
||||
functionDetail.setDescription(spec.getFunctionDescription());
|
||||
|
||||
PromptFuncDefinition.Parameters parameters = new PromptFuncDefinition.Parameters();
|
||||
parameters.setType("object");
|
||||
parameters.setProperties(spec.getToolPrompt().getFunction().parameters.getProperties());
|
||||
|
||||
List<String> requiredValues = new ArrayList<>();
|
||||
for (Map.Entry<String, PromptFuncDefinition.Property> p : spec.getToolPrompt().getFunction().getParameters().getProperties().entrySet()) {
|
||||
if (p.getValue().isRequired()) {
|
||||
requiredValues.add(p.getKey());
|
||||
}
|
||||
}
|
||||
parameters.setRequired(requiredValues);
|
||||
functionDetail.setParameters(parameters);
|
||||
def.setFunction(functionDetail);
|
||||
|
||||
tools.add(def);
|
||||
return this;
|
||||
}
|
||||
@JsonIgnore private boolean required;
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,37 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools.annotations;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a class that calls {@link io.github.ollama4j.OllamaAPI} such that the Method
|
||||
* {@link OllamaAPI#registerAnnotatedTools()} can be used to auto-register all provided classes (resp. all
|
||||
* contained Methods of the provider classes annotated with {@link ToolSpec}).
|
||||
* Annotation to mark a class as an Ollama tool service.
|
||||
* <p>
|
||||
* When a class is annotated with {@code @OllamaToolService}, the method
|
||||
* {@link OllamaAPI#registerAnnotatedTools()} can be used to automatically register all tool provider
|
||||
* classes specified in the {@link #providers()} array. All methods in those provider classes that are
|
||||
* annotated with {@link ToolSpec} will be registered as tools.
|
||||
* </p>
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface OllamaToolService {
|
||||
|
||||
/**
|
||||
* @return Classes with no-arg constructor that will be used for tool-registration.
|
||||
* Specifies the provider classes whose methods annotated with {@link ToolSpec} should be registered as tools.
|
||||
* Each provider class must have a public no-argument constructor.
|
||||
*
|
||||
* @return an array of provider classes to be used for tool registration
|
||||
*/
|
||||
Class<?>[] providers();
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
@ -1,28 +1,44 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools.annotations;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates Methods of classes that should be registered as tools by {@link OllamaAPI#registerAnnotatedTools()}
|
||||
* automatically.
|
||||
* Annotation to mark a method as a tool that can be registered automatically by
|
||||
* {@link OllamaAPI#registerAnnotatedTools()}.
|
||||
* <p>
|
||||
* Methods annotated with {@code @ToolSpec} will be discovered and registered as tools
|
||||
* when the containing class is specified as a provider in {@link OllamaToolService}.
|
||||
* </p>
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ToolSpec {
|
||||
|
||||
/**
|
||||
* @return tool-name that the method should be used as. Defaults to the methods name.
|
||||
* Specifies the name of the tool as exposed to the LLM.
|
||||
* If left empty, the method's name will be used as the tool name.
|
||||
*
|
||||
* @return the tool name
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* @return a detailed description of the method that can be interpreted by the llm, whether it should call the tool
|
||||
* or not.
|
||||
* Provides a detailed description of the tool's functionality.
|
||||
* This description is used by the LLM to determine when to call the tool.
|
||||
*
|
||||
* @return the tool description
|
||||
*/
|
||||
String desc();
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
package io.github.ollama4j.tools.sampletools;
|
||||
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public class WeatherTool {
|
||||
private String paramCityName = "cityName";
|
||||
|
||||
public WeatherTool() {
|
||||
}
|
||||
|
||||
public String getCurrentWeather(Map<String, Object> arguments) {
|
||||
String city = (String) arguments.get(paramCityName);
|
||||
return "It is sunny in " + city;
|
||||
}
|
||||
|
||||
public Tools.ToolSpecification getSpecification() {
|
||||
return Tools.ToolSpecification.builder()
|
||||
.functionName("weather-reporter")
|
||||
.functionDescription(
|
||||
"You are a tool who simply finds the city name from the user's message input/query about weather.")
|
||||
.toolFunction(this::getCurrentWeather)
|
||||
.toolPrompt(
|
||||
Tools.PromptFuncDefinition.builder()
|
||||
.type("prompt")
|
||||
.function(
|
||||
Tools.PromptFuncDefinition.PromptFuncSpec
|
||||
.builder()
|
||||
.name("get-city-name")
|
||||
.description("Get the city name")
|
||||
.parameters(
|
||||
Tools.PromptFuncDefinition.Parameters
|
||||
.builder()
|
||||
.type("object")
|
||||
.properties(
|
||||
Map.of(
|
||||
paramCityName,
|
||||
Tools.PromptFuncDefinition.Property
|
||||
.builder()
|
||||
.type("string")
|
||||
.description(
|
||||
"The name of the city. e.g. Bengaluru")
|
||||
.required(true)
|
||||
.build()))
|
||||
.required(java.util.List
|
||||
.of(paramCityName))
|
||||
.build())
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user