fix for timeout

This commit is contained in:
Michael Peter Christen committed 2026-07-04 17:08:36 +02:00
1 parent 8f2f9c3ce4
commit e5d9efe653
2 files changed
+36 -5

No files matched your search

+30 -1
View File
@@ -227,6 +227,11 @@ public class LLM {
private static String sendPostRequest(final String urls, final JSONObject data, final String apiKey) throws IOException, URISyntaxException {
final URL url = new URI(urls).toURL();
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Batch calls like the log report generation run large models on CPU and may
// take many minutes for a single response. Nothing on our side is allowed to
// abort such a call: connecting must fail fast, but reading must never time out.
conn.setConnectTimeout(10000);
conn.setReadTimeout(0);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
if (apiKey != null && !apiKey.isEmpty()) {
@@ -387,11 +392,35 @@ public class LLM {
final JSONObject choice = choices.getJSONObject(0);
final JSONObject message = choice.getJSONObject("message");
final String content = message.optString("content", "");
return content;
// A truncated answer is not an abort on our side but a generation limit;
// make the cause visible because the caller only sees a fragment.
final String finishReason = choice.optString("finish_reason", "");
if ("length".equals(finishReason)) {
log.warn("chat response was truncated by the max_tokens limit (" + max_tokens
+ "), model=" + LogRedaction.redact(model)
+ ", contentChars=" + content.length()
+ ". Configure a higher max_tokens for this model if complete outputs are required.");
}
return stripThinkBlocks(content);
} catch (JSONException | URISyntaxException e) {
throw new IOException(e.getMessage());
}
}
/**
* Remove reasoning blocks from a chat answer. Some backends deliver the chain of
* thought of thinking models inline as <think>...</think> in the content;
* a report or answer must only contain the text after the reasoning. An unclosed
* think block (e.g. because the response was cut by the token limit) is removed
* up to the end of the content.
*/
protected static String stripThinkBlocks(final String content) {
if (content == null || content.indexOf("<think>") < 0) return content;
final String withoutClosed = content.replaceAll("(?s)<think>.*?</think>", "");
final int unclosed = withoutClosed.indexOf("<think>");
final String result = unclosed < 0 ? withoutClosed : withoutClosed.substring(0, unclosed);
return result.trim();
}
public String chat(final String model, final String systemPrompt, final String userPrompt, final int max_tokens) throws IOException {
try {
+6 -4
View File
@@ -236,10 +236,12 @@ public class LogReportService {
log.info("Log report scheduler is disabled by " + CONFIG_ENABLED + ".");
return null;
}
if (!hasConfiguredLogReportModel()) {
log.info("Log report scheduler is inactive because no production model is configured for logreport usage.");
return null;
}
// Note: the scheduler is started even when no logreport model is configured
// yet. The model assignment can happen at any time on /LLMSelection_p.html
// and must not require a restart; the tick below skips (with a single log
// line) as long as the model is missing and picks up work automatically once
// it is configured. Do not add an early return here for a missing model -
// that would silently disable report generation until the next restart.
final LogReportService service = new LogReportService(sb);
final long initialDelay = Math.max(0L, sb.getConfigLong(CONFIG_INITIAL_DELAY_MINUTES, DEFAULT_INITIAL_DELAY_MINUTES));