3131import stroom .ai .shared .AskStroomAiRequest ;
3232import stroom .ai .shared .AskStroomAiResponse ;
3333import stroom .ai .shared .DashboardTableContext ;
34+ import stroom .ai .shared .DownloadChatHistoryRequest ;
3435import stroom .ai .shared .GeneralTableContext ;
3536import stroom .ai .shared .QueryTableContext ;
3637import stroom .ai .shared .TableAnalysisConfig ;
37- import stroom .ai .shared .DownloadChatHistoryRequest ;
3838import stroom .config .global .api .GlobalConfig ;
3939import stroom .dashboard .impl .DashboardService ;
4040import stroom .dashboard .shared .ComponentResultRequest ;
@@ -96,7 +96,6 @@ public class AskStroomAIService {
9696 private static final LambdaLogger LOGGER = LambdaLoggerFactory .getLogger (AskStroomAIService .class );
9797
9898
99-
10099 /**
101100 * Sentinel model ID that activates the stub ChatModel for offline testing.
102101 * Create an OpenAIModel document with this as the modelId — no API key or base URL needed.
@@ -159,15 +158,15 @@ public AskStroomAiResponse askStroomAi(final AskStroomAiRequest request) {
159158 aiService .verifyOwnership (chatId );
160159
161160 LOGGER .debug (() -> "askStroomAi: chatId=" + chatId
162- + " hasContext=" + (request .getContext () != null )
163- + " hasMessage=" + (request .getMessage () != null ));
161+ + " hasContext=" + (request .getContext () != null )
162+ + " hasMessage=" + (request .getMessage () != null ));
164163
165164 // Stage 1: If context is present, create an attachment (and start async download if needed).
166165 if (request .getContext () != null ) {
167166 try {
168167 createAttachment (chatId , request .getContext (), request .getConfig ());
169168 LOGGER .debug (() -> "Attachment created for chatId=" + chatId
170- + " contextType=" + request .getContext ().getClass ().getSimpleName ());
169+ + " contextType=" + request .getContext ().getClass ().getSimpleName ());
171170 } catch (final RuntimeException e ) {
172171 LOGGER .debug (e ::getMessage , e );
173172 aiService .storeMessage (chatId , AiMessageType .ERROR , e .getMessage ());
@@ -186,7 +185,7 @@ public AskStroomAiResponse askStroomAi(final AskStroomAiRequest request) {
186185 aiService .storeMessage (chatId , AiMessageType .AI_RESPONSE , responseText );
187186 final String rt = responseText ;
188187 LOGGER .debug (() -> "Response stored for chatId=" + chatId
189- + " responseLength=" + rt .length ());
188+ + " responseLength=" + rt .length ());
190189 }
191190 } catch (final RuntimeException e ) {
192191 LOGGER .debug (e ::getMessage , e );
@@ -225,8 +224,8 @@ private void createAttachment(final int chatId,
225224 }
226225
227226 LOGGER .debug (() -> "createAttachment: chatId=" + chatId
228- + " type=" + attachmentType
229- + " description='" + context .getDescription () + "'" );
227+ + " type=" + attachmentType
228+ + " description='" + context .getDescription () + "'" );
230229
231230 final String contextJson = JsonUtil .writeValueAsString (context );
232231 final AiChatAttachment attachment = aiService .createAttachment (chatId , attachmentType , contextJson );
@@ -251,8 +250,8 @@ private void createAttachment(final int chatId,
251250 private void processGeneralAttachment (final int attachmentId ,
252251 final GeneralTableContext generalTableContext ) {
253252 LOGGER .debug (() -> "processGeneralAttachment: attachmentId=" + attachmentId
254- + " cols=" + generalTableContext .getColumns ().size ()
255- + " rows=" + generalTableContext .getRows ().size ());
253+ + " cols=" + generalTableContext .getColumns ().size ()
254+ + " rows=" + generalTableContext .getRows ().size ());
256255 try {
257256 aiService .updateAttachmentStatus (attachmentId , AiAttachmentStatus .DOWNLOADING ,
258257 null , null , null , false );
@@ -278,7 +277,7 @@ private void processGeneralAttachment(final int attachmentId,
278277 throw new UncheckedIOException (e );
279278 }
280279 }, () -> "processGeneralAttachment attachmentId=" + attachmentId
281- + " rows=" + rowCountHolder [0 ]);
280+ + " rows=" + rowCountHolder [0 ]);
282281 final int rowCount = rowCountHolder [0 ];
283282
284283 final String description = generalTableContext .getDescription ()
@@ -308,8 +307,8 @@ private void submitAsyncDownload(final int attachmentId,
308307 taskContext -> {
309308 try {
310309 LOGGER .debug (() -> "Async download started: attachmentId=" + attachmentId
311- + " chatId=" + chatId
312- + " contextType=" + context .getClass ().getSimpleName ());
310+ + " chatId=" + chatId
311+ + " contextType=" + context .getClass ().getSimpleName ());
313312 aiService .updateAttachmentStatus (attachmentId , AiAttachmentStatus .DOWNLOADING ,
314313 null , null , null , false );
315314
@@ -346,7 +345,7 @@ private void submitAsyncDownload(final int attachmentId,
346345 final Path trimmedFile = targetFile .resolveSibling (
347346 targetFile .getFileName () + ".tmp" );
348347 try (final BufferedReader reader = Files .newBufferedReader (targetFile );
349- final BufferedWriter writer = Files .newBufferedWriter (trimmedFile )) {
348+ final BufferedWriter writer = Files .newBufferedWriter (trimmedFile )) {
350349 int linesWritten = 0 ;
351350 String line ;
352351 while ((line = reader .readLine ()) != null ) {
@@ -381,8 +380,8 @@ private void submitAsyncDownload(final int attachmentId,
381380 : "" ) + ")" ;
382381
383382 LOGGER .debug (() -> "Async download finished: attachmentId=" + attachmentId
384- + " rows=" + reportedRowCount + " cols=" + colCount
385- + " truncated=" + truncated );
383+ + " rows=" + reportedRowCount + " cols=" + colCount
384+ + " truncated=" + truncated );
386385 aiService .updateAttachmentStatus (attachmentId , AiAttachmentStatus .READY ,
387386 reportedRowCount , description , null , truncated );
388387 } finally {
@@ -494,8 +493,10 @@ private String processQuestion(final AskStroomAiRequest request) {
494493 .toList ();
495494
496495 LOGGER .debug (() -> "processQuestion: chatId=" + chatId
497- + " readyAttachments=" + readyAttachments .size ()
498- + " \u2192 " + (readyAttachments .isEmpty () ? "conversational" : "batch analysis" ));
496+ + " readyAttachments=" + readyAttachments .size ()
497+ + " -> " + (readyAttachments .isEmpty ()
498+ ? "conversational"
499+ : "batch analysis" ));
499500
500501 if (!readyAttachments .isEmpty ()) {
501502 // Has attachments → full batch analysis with conversation context.
@@ -533,8 +534,8 @@ private String analyseWithAttachments(final AskStroomAiRequest request,
533534 final String conversationContext = buildConversationSummary (chatId );
534535
535536 LOGGER .debug (() -> "analyseWithAttachments: chatId=" + chatId
536- + " attachments=" + attachments .size ()
537- + " maxParallel=" + tableAnalysisConfig .getMaxParallelBatches ());
537+ + " attachments=" + attachments .size ()
538+ + " maxParallel=" + tableAnalysisConfig .getMaxParallelBatches ());
538539
539540 // Build batches from CSV files on disk.
540541 final List <String > batches = new ArrayList <>();
@@ -558,7 +559,7 @@ private String analyseWithAttachments(final AskStroomAiRequest request,
558559
559560 final boolean truncatedData = anyTruncated ;
560561 LOGGER .debug (() -> "analyseWithAttachments: chatId=" + chatId
561- + " batches=" + batches .size () + " anyTruncated=" + truncatedData );
562+ + " batches=" + batches .size () + " anyTruncated=" + truncatedData );
562563
563564 // Include truncation note in the user query if applicable.
564565 final String userQuery = anyTruncated
@@ -589,7 +590,7 @@ private String analyseWithAttachments(final AskStroomAiRequest request,
589590 if (cancelled .get ()) {
590591 final int batchIdx = i ;
591592 LOGGER .debug (() -> "analyseWithAttachments: cancelled for chatId=" + chatId
592- + " at batch " + batchIdx + "/" + totalBatches );
593+ + " at batch " + batchIdx + "/" + totalBatches );
593594 break ;
594595 }
595596 final String batch = batches .get (i );
@@ -614,7 +615,7 @@ private String analyseWithAttachments(final AskStroomAiRequest request,
614615 .replace ("{{context}}" , conversationContext );
615616
616617 LOGGER .trace (() -> "Batch " + batchNum + "/" + totalBatches
617- + " prompt (chatId=" + chatId + "):\n " + userPrompt );
618+ + " prompt (chatId=" + chatId + "):\n " + userPrompt );
618619
619620 final List <ChatMessage > messages = List .of (
620621 new SystemMessage (systemPrompt ),
@@ -626,7 +627,7 @@ private String analyseWithAttachments(final AskStroomAiRequest request,
626627 + " chatId=" + chatId
627628 + " responseLength=" + r .aiMessage ().text ().length ());
628629 LOGGER .trace (() -> "Batch " + batchNum + "/" + totalBatches
629- + " response:\n " + response .aiMessage ().text ());
630+ + " response:\n " + response .aiMessage ().text ());
630631 return response .aiMessage ().text ();
631632 } finally {
632633 semaphore .release ();
@@ -657,8 +658,10 @@ private String analyseWithAttachments(final AskStroomAiRequest request,
657658
658659 // Merge summaries.
659660 LOGGER .debug (() -> "analyseWithAttachments: chatId=" + chatId
660- + " summaries=" + summaries .size ()
661- + (summaries .size () > 1 ? " \u2192 merging" : " \u2192 single result" ));
661+ + " summaries=" + summaries .size ()
662+ + (summaries .size () > 1
663+ ? " -> merging"
664+ : " -> single result" ));
662665 if (summaries .size () == 1 ) {
663666 return summaries .getFirst ();
664667 }
@@ -710,8 +713,8 @@ List<String> buildBatchesFromCsv(final Path csvFile,
710713 }
711714 return batches ;
712715 }, batches -> "buildBatchesFromCsv: file=" + csvFile .getFileName ()
713- + " maxRowsPerBatch=" + config .getMaxRowsPerBatch ()
714- + " \u2192 " + batches . size () + " batch(es)" );
716+ + ", maxRowsPerBatch=" + config .getMaxRowsPerBatch ()
717+ + ", batch(es)=" + batches . size () );
715718 }
716719
717720 /**
@@ -759,7 +762,7 @@ private String processConversational(final AskStroomAiRequest request,
759762 final List <ChatMessage > messages = new ArrayList <>();
760763
761764 LOGGER .debug (() -> "processConversational: chatId=" + chatId
762- + " historyMessages=" + history .size ());
765+ + " historyMessages=" + history .size ());
763766
764767 messages .add (new SystemMessage (NullSafe .getOrElse (
765768 defaultConfigProvider .get (),
@@ -792,7 +795,7 @@ private String processConversational(final AskStroomAiRequest request,
792795 messages .add (new UserMessage (request .getMessage ()));
793796
794797 LOGGER .trace (() -> "processConversational: sending " + messages .size ()
795- + " messages to LLM for chatId=" + chatId );
798+ + " messages to LLM for chatId=" + chatId );
796799
797800 final ChatResponse response = LOGGER .logDurationIfDebugEnabled (
798801 () -> chatModel .chat (messages ),
@@ -836,9 +839,9 @@ private void waitForAttachments(final int chatId, final int thinkingMessageId) {
836839 }
837840
838841 LOGGER .trace (() -> "waitForAttachments: chatId=" + chatId
839- + " still waiting, statuses=" + attachments .stream ()
840- .map (a -> a .getId () + ":" + a .getStatus ())
841- .collect (java .util .stream .Collectors .joining ("," )));
842+ + " still waiting, statuses=" + attachments .stream ()
843+ .map (a -> a .getId () + ":" + a .getStatus ())
844+ .collect (java .util .stream .Collectors .joining ("," )));
842845
843846 aiService .updateMessageText (thinkingMessageId ,
844847 "Waiting for table data download..." );
@@ -985,7 +988,7 @@ private ChatModel getChatModel(final AskStroomAIConfig config) {
985988 }
986989
987990 LOGGER .debug (() -> "getChatModel: modelId='" + openAIModelDoc .getModelId ()
988- + "' docRef=" + docRef .getUuid ());
991+ + "' docRef=" + docRef .getUuid ());
989992 return aiService .getChatModel (openAIModelDoc );
990993 }
991994
@@ -1168,8 +1171,8 @@ public ResourceGeneration downloadChatHistory(final DownloadChatHistoryRequest r
11681171 final List <AiChatMessage > messages = aiService .getMessages (chatId );
11691172
11701173 LOGGER .debug (() -> "downloadChatHistory: chatId=" + chatId
1171- + " includeDataContexts=" + includeDataContexts
1172- + " messageCount=" + messages .size ());
1174+ + " includeDataContexts=" + includeDataContexts
1175+ + " messageCount=" + messages .size ());
11731176
11741177 final String title = chat != null && chat .getTitle () != null
11751178 ? chat .getTitle ()
@@ -1224,7 +1227,9 @@ public ResourceGeneration downloadChatHistory(final DownloadChatHistoryRequest r
12241227 // Stream the CSV from the attachment file store as a Markdown table.
12251228 writeAttachmentAsMarkdownTable (writer , msg .getAttachmentId (), msg .getMessage ());
12261229 } else {
1227- final String body = msg .getMessage () != null ? msg .getMessage () : "" ;
1230+ final String body = msg .getMessage () != null
1231+ ? msg .getMessage ()
1232+ : "" ;
12281233 writer .write (body );
12291234 writer .newLine ();
12301235 }
@@ -1237,7 +1242,7 @@ public ResourceGeneration downloadChatHistory(final DownloadChatHistoryRequest r
12371242 LOGGER .debug (() -> {
12381243 try {
12391244 return "downloadChatHistory: wrote " + filename
1240- + " (" + Files .size (file ) + " bytes)" ;
1245+ + " (" + Files .size (file ) + " bytes)" ;
12411246 } catch (final IOException e ) {
12421247 return "downloadChatHistory: wrote " + filename ;
12431248 }
@@ -1256,7 +1261,7 @@ private void writeAttachmentAsMarkdownTable(final BufferedWriter writer,
12561261 final Path csvFile = attachmentFileStore .getAttachmentFile (attachmentId );
12571262 if (!Files .exists (csvFile )) {
12581263 LOGGER .debug (() -> "writeAttachmentAsMarkdownTable: CSV not found for attachmentId="
1259- + attachmentId + " (may have been cleaned up)" );
1264+ + attachmentId + " (may have been cleaned up)" );
12601265 writer .write ("_Data not available (attachment " );
12611266 writer .write (String .valueOf (attachmentId ));
12621267 writer .write (" may have been cleaned up)_\n " );
@@ -1282,6 +1287,7 @@ private void writeAttachmentAsMarkdownTable(final BufferedWriter writer,
12821287 }
12831288 }
12841289 }
1290+
12851291 private static String sanitiseFilename (final String name ) {
12861292 if (name == null || name .isBlank ()) {
12871293 return "chat-history" ;
0 commit comments