diff --git a/core/deployment/src/main/java/io/quarkiverse/langchain4j/deployment/devservice/DevServicesOllamaProcessor.java b/core/deployment/src/main/java/io/quarkiverse/langchain4j/deployment/devservice/DevServicesOllamaProcessor.java index 740cee026..b3a96af73 100644 --- a/core/deployment/src/main/java/io/quarkiverse/langchain4j/deployment/devservice/DevServicesOllamaProcessor.java +++ b/core/deployment/src/main/java/io/quarkiverse/langchain4j/deployment/devservice/DevServicesOllamaProcessor.java @@ -93,6 +93,7 @@ private void handleModels(List devService for (String model : modelsToPull) { // we pull one model at a time and provide progress updates to the user via logging LOGGER.info("Pulling model " + model); + AtomicReference LAST_UPDATE_REF = new AtomicReference<>(); CompletableFuture cf = new CompletableFuture<>(); client.pullAsync(model).subscribe(new Flow.Subscriber<>() { @@ -109,6 +110,11 @@ public void onNext(OllamaClient.PullAsyncLine line) { clientThreadName.compareAndSet(null, Thread.currentThread().getName()); if ((line.total() != null) && (line.completed() != null) && (line.status() != null) && line.status().contains("pulling")) { + if (!logUpdate(LAST_UPDATE_REF.get())) { + return; + } + + LAST_UPDATE_REF.set(System.nanoTime()); BigDecimal percentage = new BigDecimal(line.completed()).divide(new BigDecimal(line.total()), 4, RoundingMode.HALF_DOWN).multiply(ONE_HUNDRED); BigDecimal progress = percentage.setScale(2, RoundingMode.HALF_DOWN); @@ -116,11 +122,27 @@ public void onNext(OllamaClient.PullAsyncLine line) { // avoid showing 100% for too long LOGGER.infof("Verifying and cleaning up\n", progress); } else { - LOGGER.infof("Progress: %s%%\n", progress); + LOGGER.infof("%s - Progress: %s%%\n", model, progress); } } } + /** + * @param lastUpdate The last update time in nanoseconds + * Determines whether we should log an update. + * This is done in order to not overwhelm the console with updates which might make + * canceling the download difficult. See + * this + */ + private boolean logUpdate(Long lastUpdate) { + if (lastUpdate == null) { + return true; + } else { + return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) + - TimeUnit.NANOSECONDS.toMillis(lastUpdate) > 1_000; + } + } + @Override public void onError(Throwable throwable) { cf.completeExceptionally(throwable); diff --git a/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily.adoc b/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily.adoc index c5fe266be..f0a0b21d5 100644 --- a/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily.adoc +++ b/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily.adoc @@ -185,6 +185,193 @@ a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-exclude-domains]] [.p A list of domains to specifically exclude from the search results. Default is ++[]++, which doesn't exclude any domains. +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_EXCLUDE_DOMAINS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_EXCLUDE_DOMAINS+++` +endif::add-copy-button-to-env-var[] +-- +|list of string +|`[]` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-base-url]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-base-url[`quarkus.langchain4j.tavily.base-url`]## + +[.description] +-- +Base URL of the Tavily API + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_BASE_URL+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_BASE_URL+++` +endif::add-copy-button-to-env-var[] +-- +|string +|`https://api.tavily.com` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-api-key]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-api-key[`quarkus.langchain4j.tavily.api-key`]## + +[.description] +-- +API key for the Tavily API + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_API_KEY+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_API_KEY+++` +endif::add-copy-button-to-env-var[] +-- +|string +|required icon:exclamation-circle[title=Configuration property is required] + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-max-results]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-max-results[`quarkus.langchain4j.tavily.max-results`]## + +[.description] +-- +Maximum number of results to return + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_MAX_RESULTS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_MAX_RESULTS+++` +endif::add-copy-button-to-env-var[] +-- +|int +|`5` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-timeout]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-timeout[`quarkus.langchain4j.tavily.timeout`]## + +[.description] +-- +The timeout duration for Tavily requests. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_TIMEOUT+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_TIMEOUT+++` +endif::add-copy-button-to-env-var[] +-- +|link:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html[Duration] link:#duration-note-anchor-{summaryTableId}[icon:question-circle[title=More information about the Duration format]] +|`60S` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-requests]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-requests[`quarkus.langchain4j.tavily.log-requests`]## + +[.description] +-- +Whether requests to Tavily should be logged + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_REQUESTS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_REQUESTS+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-responses]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-responses[`quarkus.langchain4j.tavily.log-responses`]## + +[.description] +-- +Whether responses from Tavily should be logged + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_RESPONSES+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_RESPONSES+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-search-depth]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-search-depth[`quarkus.langchain4j.tavily.search-depth`]## + +[.description] +-- +The search depth to use. This can be "basic" or "advanced". Basic is the default. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_SEARCH_DEPTH+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_SEARCH_DEPTH+++` +endif::add-copy-button-to-env-var[] +-- +a|SearchDepth +|`basic` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-answer]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-answer[`quarkus.langchain4j.tavily.include-answer`]## + +[.description] +-- +Include a short answer to original query. Default is false. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_ANSWER+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_ANSWER+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-raw-content]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-raw-content[`quarkus.langchain4j.tavily.include-raw-content`]## + +[.description] +-- +Include the cleaned and parsed HTML content of each search result. Default is false. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_RAW_CONTENT+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_RAW_CONTENT+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-domains]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-domains[`quarkus.langchain4j.tavily.include-domains`]## + +[.description] +-- +A list of domains to specifically include in the search results. Default is ++[]++, which includes all domains. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_DOMAINS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_DOMAINS+++` +endif::add-copy-button-to-env-var[] +-- +|list of string +|`[]` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-exclude-domains]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-exclude-domains[`quarkus.langchain4j.tavily.exclude-domains`]## + +[.description] +-- +A list of domains to specifically exclude from the search results. Default is ++[]++, which doesn't exclude any domains. + + ifdef::add-copy-button-to-env-var[] Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_EXCLUDE_DOMAINS+++[] endif::add-copy-button-to-env-var[] diff --git a/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily_quarkus.langchain4j.adoc b/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily_quarkus.langchain4j.adoc index c5fe266be..f0a0b21d5 100644 --- a/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily_quarkus.langchain4j.adoc +++ b/docs/modules/ROOT/pages/includes/quarkus-langchain4j-tavily_quarkus.langchain4j.adoc @@ -185,6 +185,193 @@ a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-exclude-domains]] [.p A list of domains to specifically exclude from the search results. Default is ++[]++, which doesn't exclude any domains. +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_EXCLUDE_DOMAINS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_EXCLUDE_DOMAINS+++` +endif::add-copy-button-to-env-var[] +-- +|list of string +|`[]` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-base-url]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-base-url[`quarkus.langchain4j.tavily.base-url`]## + +[.description] +-- +Base URL of the Tavily API + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_BASE_URL+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_BASE_URL+++` +endif::add-copy-button-to-env-var[] +-- +|string +|`https://api.tavily.com` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-api-key]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-api-key[`quarkus.langchain4j.tavily.api-key`]## + +[.description] +-- +API key for the Tavily API + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_API_KEY+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_API_KEY+++` +endif::add-copy-button-to-env-var[] +-- +|string +|required icon:exclamation-circle[title=Configuration property is required] + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-max-results]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-max-results[`quarkus.langchain4j.tavily.max-results`]## + +[.description] +-- +Maximum number of results to return + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_MAX_RESULTS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_MAX_RESULTS+++` +endif::add-copy-button-to-env-var[] +-- +|int +|`5` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-timeout]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-timeout[`quarkus.langchain4j.tavily.timeout`]## + +[.description] +-- +The timeout duration for Tavily requests. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_TIMEOUT+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_TIMEOUT+++` +endif::add-copy-button-to-env-var[] +-- +|link:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html[Duration] link:#duration-note-anchor-{summaryTableId}[icon:question-circle[title=More information about the Duration format]] +|`60S` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-requests]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-requests[`quarkus.langchain4j.tavily.log-requests`]## + +[.description] +-- +Whether requests to Tavily should be logged + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_REQUESTS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_REQUESTS+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-responses]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-log-responses[`quarkus.langchain4j.tavily.log-responses`]## + +[.description] +-- +Whether responses from Tavily should be logged + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_RESPONSES+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_LOG_RESPONSES+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-search-depth]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-search-depth[`quarkus.langchain4j.tavily.search-depth`]## + +[.description] +-- +The search depth to use. This can be "basic" or "advanced". Basic is the default. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_SEARCH_DEPTH+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_SEARCH_DEPTH+++` +endif::add-copy-button-to-env-var[] +-- +a|SearchDepth +|`basic` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-answer]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-answer[`quarkus.langchain4j.tavily.include-answer`]## + +[.description] +-- +Include a short answer to original query. Default is false. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_ANSWER+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_ANSWER+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-raw-content]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-raw-content[`quarkus.langchain4j.tavily.include-raw-content`]## + +[.description] +-- +Include the cleaned and parsed HTML content of each search result. Default is false. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_RAW_CONTENT+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_RAW_CONTENT+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`false` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-domains]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-include-domains[`quarkus.langchain4j.tavily.include-domains`]## + +[.description] +-- +A list of domains to specifically include in the search results. Default is ++[]++, which includes all domains. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_DOMAINS+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_LANGCHAIN4J_TAVILY_INCLUDE_DOMAINS+++` +endif::add-copy-button-to-env-var[] +-- +|list of string +|`[]` + +a| [[quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-exclude-domains]] [.property-path]##link:#quarkus-langchain4j-tavily_quarkus-langchain4j-tavily-exclude-domains[`quarkus.langchain4j.tavily.exclude-domains`]## + +[.description] +-- +A list of domains to specifically exclude from the search results. Default is ++[]++, which doesn't exclude any domains. + + ifdef::add-copy-button-to-env-var[] Environment variable: env_var_with_copy_button:+++QUARKUS_LANGCHAIN4J_TAVILY_EXCLUDE_DOMAINS+++[] endif::add-copy-button-to-env-var[] diff --git a/model-providers/jlama/deployment/src/main/java/io/quarkiverse/langchain4j/jlama/deployment/JlamaProcessor.java b/model-providers/jlama/deployment/src/main/java/io/quarkiverse/langchain4j/jlama/deployment/JlamaProcessor.java index 5321f1db8..fbf8edc0f 100644 --- a/model-providers/jlama/deployment/src/main/java/io/quarkiverse/langchain4j/jlama/deployment/JlamaProcessor.java +++ b/model-providers/jlama/deployment/src/main/java/io/quarkiverse/langchain4j/jlama/deployment/JlamaProcessor.java @@ -13,6 +13,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import jakarta.enterprise.context.ApplicationScoped; @@ -189,6 +191,8 @@ void downloadModels(List selectedChatModels, // we pull one model at a time and provide progress updates to the user via logging LOGGER.info("Pulling model " + modelName); + AtomicReference LAST_UPDATE_REF = new AtomicReference<>(); + try { registry.downloadModel(modelName, Optional.empty(), Optional.of(new ProgressReporter() { @Override @@ -199,6 +203,12 @@ public void update(String filename, long sizeDownloaded, long totalSize) { return; } + if (!logUpdate(LAST_UPDATE_REF.get())) { + return; + } + + LAST_UPDATE_REF.set(System.nanoTime()); + BigDecimal percentage = new BigDecimal(sizeDownloaded).divide(new BigDecimal(totalSize), 4, RoundingMode.HALF_DOWN).multiply(ONE_HUNDRED); BigDecimal progress = percentage.setScale(2, RoundingMode.HALF_DOWN); @@ -206,7 +216,23 @@ public void update(String filename, long sizeDownloaded, long totalSize) { // avoid showing 100% for too long LOGGER.infof("Verifying and cleaning up\n", progress); } else { - LOGGER.infof("Progress: %s%%\n", progress); + LOGGER.infof("%s - Progress: %s%%\n", modelName, progress); + } + } + + /** + * @param lastUpdate The last update time in nanoseconds + * Determines whether we should log an update. + * This is done in order to not overwhelm the console with updates which might make + * canceling the download difficult. See + * this + */ + private boolean logUpdate(Long lastUpdate) { + if (lastUpdate == null) { + return true; + } else { + return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) + - TimeUnit.NANOSECONDS.toMillis(lastUpdate) > 1_000; } } })); diff --git a/model-providers/llama3-java/deployment/src/main/java/io/quarkiverse/langchain4j/llama3/deployment/Llama3Processor.java b/model-providers/llama3-java/deployment/src/main/java/io/quarkiverse/langchain4j/llama3/deployment/Llama3Processor.java index 7299f48a1..1a905a9b7 100644 --- a/model-providers/llama3-java/deployment/src/main/java/io/quarkiverse/langchain4j/llama3/deployment/Llama3Processor.java +++ b/model-providers/llama3-java/deployment/src/main/java/io/quarkiverse/langchain4j/llama3/deployment/Llama3Processor.java @@ -12,6 +12,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import jakarta.enterprise.context.ApplicationScoped; @@ -169,6 +171,8 @@ void downloadModels(List selectedChatModels, // we pull one model at a time and provide progress updates to the user via logging LOGGER.info("Pulling model " + model.name()); + AtomicReference LAST_UPDATE_REF = new AtomicReference<>(); + try { registry.downloadModel(model.name(), model.quantization(), Optional.empty(), Optional.of(new ProgressReporter() { @@ -181,6 +185,12 @@ public void update(String filename, long sizeDownloaded, long totalSize) { return; } + if (!logUpdate(LAST_UPDATE_REF.get())) { + return; + } + + LAST_UPDATE_REF.set(System.nanoTime()); + BigDecimal percentage = new BigDecimal(sizeDownloaded) .divide(new BigDecimal(totalSize), 4, @@ -191,7 +201,25 @@ public void update(String filename, long sizeDownloaded, long totalSize) { // avoid showing 100% for too long LOGGER.infof("Verifying and cleaning up\n", progress); } else { - LOGGER.infof("Progress: %s%%\n", progress); + LOGGER.infof("%s - Progress: %s%%\n", model.name(), progress); + } + } + + /** + * @param lastUpdate The last update time in nanoseconds + * Determines whether we should log an update. + * This is done in order to not overwhelm the console with updates which might + * make + * canceling the download difficult. See + * this + */ + private boolean logUpdate(Long lastUpdate) { + if (lastUpdate == null) { + return true; + } else { + return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) + - TimeUnit.NANOSECONDS.toMillis(lastUpdate) > 1_000; } } }));