themefinder 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of themefinder might be problematic. Click here for more details.

@@ -0,0 +1,22 @@
1
+ from .core import (
2
+ find_themes,
3
+ sentiment_analysis,
4
+ theme_condensation,
5
+ theme_generation,
6
+ theme_mapping,
7
+ theme_refinement,
8
+ theme_target_alignment,
9
+ detail_detection,
10
+ )
11
+
12
+ __all__ = [
13
+ "find_themes",
14
+ "sentiment_analysis",
15
+ "theme_generation",
16
+ "theme_condensation",
17
+ "theme_refinement",
18
+ "theme_target_alignment",
19
+ "theme_mapping",
20
+ "detail_detection",
21
+ ]
22
+ __version__ = "0.1.0"
themefinder/core.py ADDED
@@ -0,0 +1,544 @@
1
+ import logging
2
+ from pathlib import Path
3
+
4
+ import pandas as pd
5
+ from langchain_core.prompts import PromptTemplate
6
+ from langchain.schema.runnable import RunnableWithFallbacks
7
+
8
+ from .llm_batch_processor import batch_and_run, load_prompt_from_file
9
+ from .models import (
10
+ SentimentAnalysisResponses,
11
+ ThemeGenerationResponses,
12
+ ThemeCondensationResponses,
13
+ ThemeRefinementResponses,
14
+ ThemeMappingResponses,
15
+ DetailDetectionResponses,
16
+ )
17
+ from .themefinder_logging import logger
18
+
19
+ CONSULTATION_SYSTEM_PROMPT = load_prompt_from_file("consultation_system_prompt")
20
+
21
+
22
+ async def find_themes(
23
+ responses_df: pd.DataFrame,
24
+ llm: RunnableWithFallbacks,
25
+ question: str,
26
+ target_n_themes: int | None = None,
27
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
28
+ verbose: bool = True,
29
+ concurrency: int = 10,
30
+ ) -> dict[str, str | pd.DataFrame]:
31
+ """Process survey responses through a multi-stage theme analysis pipeline.
32
+
33
+ This pipeline performs sequential analysis steps:
34
+ 1. Sentiment analysis of responses
35
+ 2. Initial theme generation
36
+ 3. Theme condensation (combining similar themes)
37
+ 4. Theme refinement
38
+ 5. Theme target alignment (optional, if target_n_themes is specified)
39
+ 6. Mapping responses to refined themes
40
+
41
+ Args:
42
+ responses_df (pd.DataFrame): DataFrame containing survey responses
43
+ llm (RunnableWithFallbacks): Language model instance for text analysis
44
+ question (str): The survey question
45
+ target_n_themes (int | None, optional): Target number of themes to consolidate to.
46
+ If None, skip theme target alignment step. Defaults to None.
47
+ system_prompt (str): System prompt to guide the LLM's behavior.
48
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
49
+ verbose (bool): Whether to show information messages during processing.
50
+ Defaults to True.
51
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
52
+
53
+ Returns:
54
+ dict[str, str | pd.DataFrame]: Dictionary containing results from each pipeline stage:
55
+ - question: The survey question string
56
+ - sentiment: DataFrame with sentiment analysis results
57
+ - themes: DataFrame with the final themes output
58
+ - mapping: DataFrame mapping responses to final themes
59
+ - unprocessables: Dataframe containing the inputs that could not be processed by the LLM
60
+ """
61
+ logger.setLevel(logging.INFO if verbose else logging.CRITICAL)
62
+
63
+ sentiment_df, sentiment_unprocessables = await sentiment_analysis(
64
+ responses_df,
65
+ llm,
66
+ question=question,
67
+ system_prompt=system_prompt,
68
+ concurrency=concurrency,
69
+ )
70
+ theme_df, _ = await theme_generation(
71
+ sentiment_df,
72
+ llm,
73
+ question=question,
74
+ system_prompt=system_prompt,
75
+ concurrency=concurrency,
76
+ )
77
+ condensed_theme_df, _ = await theme_condensation(
78
+ theme_df,
79
+ llm,
80
+ question=question,
81
+ system_prompt=system_prompt,
82
+ concurrency=concurrency,
83
+ )
84
+ refined_theme_df, _ = await theme_refinement(
85
+ condensed_theme_df,
86
+ llm,
87
+ question=question,
88
+ system_prompt=system_prompt,
89
+ concurrency=concurrency,
90
+ )
91
+ if target_n_themes is not None:
92
+ refined_theme_df, _ = await theme_target_alignment(
93
+ refined_theme_df,
94
+ llm,
95
+ question=question,
96
+ target_n_themes=target_n_themes,
97
+ system_prompt=system_prompt,
98
+ concurrency=concurrency,
99
+ )
100
+ mapping_df, mapping_unprocessables = await theme_mapping(
101
+ sentiment_df[["response_id", "response"]],
102
+ llm,
103
+ question=question,
104
+ refined_themes_df=refined_theme_df,
105
+ system_prompt=system_prompt,
106
+ concurrency=concurrency,
107
+ )
108
+ detailed_df, _ = await detail_detection(
109
+ responses_df[["response_id", "response"]],
110
+ llm,
111
+ question=question,
112
+ system_prompt=system_prompt,
113
+ concurrency=concurrency,
114
+ )
115
+
116
+ logger.info("Finished finding themes")
117
+ logger.info(
118
+ "Provide feedback or report bugs: https://forms.gle/85xUSMvxGzSSKQ499 or packages@cabinetoffice.gov.uk"
119
+ )
120
+ return {
121
+ "question": question,
122
+ "sentiment": sentiment_df,
123
+ "themes": refined_theme_df,
124
+ "mapping": mapping_df,
125
+ "detailed_responses": detailed_df,
126
+ "unprocessables": pd.concat([sentiment_unprocessables, mapping_unprocessables]),
127
+ }
128
+
129
+
130
+ async def sentiment_analysis(
131
+ responses_df: pd.DataFrame,
132
+ llm: RunnableWithFallbacks,
133
+ question: str,
134
+ batch_size: int = 20,
135
+ prompt_template: str | Path | PromptTemplate = "sentiment_analysis",
136
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
137
+ concurrency: int = 10,
138
+ ) -> tuple[pd.DataFrame, pd.DataFrame]:
139
+ """Perform sentiment analysis on survey responses using an LLM.
140
+
141
+ This function processes survey responses in batches to analyze their sentiment
142
+ using a language model. It maintains response integrity by checking response IDs.
143
+
144
+ Args:
145
+ responses_df (pd.DataFrame): DataFrame containing survey responses to analyze.
146
+ Must contain 'response_id' and 'response' columns.
147
+ llm (RunnableWithFallbacks): Language model instance to use for sentiment analysis.
148
+ question (str): The survey question.
149
+ batch_size (int, optional): Number of responses to process in each batch.
150
+ Defaults to 20.
151
+ prompt_template (str | Path | PromptTemplate, optional): Template for structuring
152
+ the prompt to the LLM. Can be a string identifier, path to template file,
153
+ or PromptTemplate instance. Defaults to "sentiment_analysis".
154
+ system_prompt (str): System prompt to guide the LLM's behavior.
155
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
156
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
157
+
158
+ Returns:
159
+ tuple[pd.DataFrame, pd.DataFrame]:
160
+ A tuple containing two DataFrames:
161
+ - The first DataFrame contains the rows that were successfully processed by the LLM
162
+ - The second DataFrame contains the rows that could not be processed by the LLM
163
+
164
+ Note:
165
+ The function uses integrity_check to ensure responses maintain
166
+ their original order and association after processing.
167
+ """
168
+ logger.info(f"Running sentiment analysis on {len(responses_df)} responses")
169
+ sentiment, unprocessable = await batch_and_run(
170
+ responses_df,
171
+ prompt_template,
172
+ llm.with_structured_output(SentimentAnalysisResponses),
173
+ batch_size=batch_size,
174
+ question=question,
175
+ integrity_check=True,
176
+ system_prompt=system_prompt,
177
+ concurrency=concurrency,
178
+ )
179
+
180
+ return sentiment, unprocessable
181
+
182
+
183
+ async def theme_generation(
184
+ responses_df: pd.DataFrame,
185
+ llm: RunnableWithFallbacks,
186
+ question: str,
187
+ batch_size: int = 50,
188
+ partition_key: str | None = "position",
189
+ prompt_template: str | Path | PromptTemplate = "theme_generation",
190
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
191
+ concurrency: int = 10,
192
+ ) -> tuple[pd.DataFrame, pd.DataFrame]:
193
+ """Generate themes from survey responses using an LLM.
194
+
195
+ This function processes batches of survey responses to identify common themes or topics.
196
+
197
+ Args:
198
+ responses_df (pd.DataFrame): DataFrame containing survey responses.
199
+ Must include 'response_id' and 'response' columns.
200
+ llm (RunnableWithFallbacks): Language model instance to use for theme generation.
201
+ question (str): The survey question.
202
+ batch_size (int, optional): Number of responses to process in each batch.
203
+ Defaults to 50.
204
+ partition_key (str | None, optional): Column name to use for batching related
205
+ responses together. Defaults to "position" for sentiment-enriched responses,
206
+ but can be set to None for sequential batching or another column name for
207
+ different grouping strategies.
208
+ prompt_template (str | Path | PromptTemplate, optional): Template for structuring
209
+ the prompt to the LLM. Can be a string identifier, path to template file,
210
+ or PromptTemplate instance. Defaults to "theme_generation".
211
+ system_prompt (str): System prompt to guide the LLM's behavior.
212
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
213
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
214
+
215
+ Returns:
216
+ tuple[pd.DataFrame, pd.DataFrame]:
217
+ A tuple containing two DataFrames:
218
+ - The first DataFrame contains the rows that were successfully processed by the LLM
219
+ - The second DataFrame contains the rows that could not be processed by the LLM
220
+
221
+ """
222
+ logger.info(f"Running theme generation on {len(responses_df)} responses")
223
+ generated_themes, _ = await batch_and_run(
224
+ responses_df,
225
+ prompt_template,
226
+ llm.with_structured_output(ThemeGenerationResponses),
227
+ batch_size=batch_size,
228
+ partition_key=partition_key,
229
+ question=question,
230
+ system_prompt=system_prompt,
231
+ concurrency=concurrency,
232
+ )
233
+ return generated_themes, _
234
+
235
+
236
+ async def theme_condensation(
237
+ themes_df: pd.DataFrame,
238
+ llm: RunnableWithFallbacks,
239
+ question: str,
240
+ batch_size: int = 75,
241
+ prompt_template: str | Path | PromptTemplate = "theme_condensation",
242
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
243
+ concurrency: int = 10,
244
+ **kwargs,
245
+ ) -> tuple[pd.DataFrame, pd.DataFrame]:
246
+ """Condense and combine similar themes identified from survey responses.
247
+
248
+ This function processes the initially identified themes to combine similar or
249
+ overlapping topics into more cohesive, broader categories using an LLM.
250
+
251
+ Args:
252
+ themes_df (pd.DataFrame): DataFrame containing the initial themes identified
253
+ from survey responses.
254
+ llm (RunnableWithFallbacks): Language model instance to use for theme condensation.
255
+ question (str): The survey question.
256
+ batch_size (int, optional): Number of themes to process in each batch.
257
+ Defaults to 100.
258
+ prompt_template (str | Path | PromptTemplate, optional): Template for structuring
259
+ the prompt to the LLM. Can be a string identifier, path to template file,
260
+ or PromptTemplate instance. Defaults to "theme_condensation".
261
+ system_prompt (str): System prompt to guide the LLM's behavior.
262
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
263
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
264
+
265
+ Returns:
266
+ tuple[pd.DataFrame, pd.DataFrame]:
267
+ A tuple containing two DataFrames:
268
+ - The first DataFrame contains the rows that were successfully processed by the LLM
269
+ - The second DataFrame contains the rows that could not be processed by the LLM
270
+
271
+ """
272
+ logger.info(f"Running theme condensation on {len(themes_df)} themes")
273
+ themes_df["response_id"] = themes_df.index + 1
274
+
275
+ n_themes = themes_df.shape[0]
276
+ while n_themes > batch_size:
277
+ logger.info(
278
+ f"{n_themes} larger than batch size, using recursive theme condensation"
279
+ )
280
+ themes_df, _ = await batch_and_run(
281
+ themes_df,
282
+ prompt_template,
283
+ llm.with_structured_output(ThemeCondensationResponses),
284
+ batch_size=batch_size,
285
+ question=question,
286
+ system_prompt=system_prompt,
287
+ concurrency=concurrency,
288
+ **kwargs,
289
+ )
290
+ themes_df = themes_df.sample(frac=1).reset_index(drop=True)
291
+ themes_df["response_id"] = themes_df.index + 1
292
+ if len(themes_df) == n_themes:
293
+ logger.info("Themes no longer being condensed")
294
+ break
295
+ n_themes = themes_df.shape[0]
296
+
297
+ themes_df, _ = await batch_and_run(
298
+ themes_df,
299
+ prompt_template,
300
+ llm.with_structured_output(ThemeCondensationResponses),
301
+ batch_size=batch_size,
302
+ question=question,
303
+ system_prompt=system_prompt,
304
+ concurrency=concurrency,
305
+ **kwargs,
306
+ )
307
+
308
+ logger.info(f"Final number of condensed themes: {themes_df.shape[0]}")
309
+ return themes_df, _
310
+
311
+
312
+ async def theme_refinement(
313
+ condensed_themes_df: pd.DataFrame,
314
+ llm: RunnableWithFallbacks,
315
+ question: str,
316
+ batch_size: int = 10000,
317
+ prompt_template: str | Path | PromptTemplate = "theme_refinement",
318
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
319
+ concurrency: int = 10,
320
+ ) -> tuple[pd.DataFrame, pd.DataFrame]:
321
+ """Refine and standardize condensed themes using an LLM.
322
+
323
+ This function processes previously condensed themes to create clear, standardized
324
+ theme descriptions. It also transforms the output format for improved readability
325
+ by transposing the results into a single-row DataFrame where columns represent
326
+ individual themes.
327
+
328
+ Args:
329
+ condensed_themes (pd.DataFrame): DataFrame containing the condensed themes
330
+ from the previous pipeline stage.
331
+ llm (RunnableWithFallbacks): Language model instance to use for theme refinement.
332
+ question (str): The survey question.
333
+ batch_size (int, optional): Number of themes to process in each batch.
334
+ Defaults to 10000.
335
+ prompt_template (str | Path | PromptTemplate, optional): Template for structuring
336
+ the prompt to the LLM. Can be a string identifier, path to template file,
337
+ or PromptTemplate instance. Defaults to "theme_refinement".
338
+ system_prompt (str): System prompt to guide the LLM's behavior.
339
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
340
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
341
+
342
+ Returns:
343
+ tuple[pd.DataFrame, pd.DataFrame]:
344
+ A tuple containing two DataFrames:
345
+ - The first DataFrame contains the rows that were successfully processed by the LLM
346
+ - The second DataFrame contains the rows that could not be processed by the LLM
347
+
348
+ Note:
349
+ The function adds sequential response_ids to the input DataFrame and
350
+ transposes the output for improved readability and easier downstream
351
+ processing.
352
+ """
353
+ logger.info(f"Running theme refinement on {len(condensed_themes_df)} responses")
354
+ condensed_themes_df["response_id"] = condensed_themes_df.index + 1
355
+
356
+ refined_themes, _ = await batch_and_run(
357
+ condensed_themes_df,
358
+ prompt_template,
359
+ llm.with_structured_output(ThemeRefinementResponses),
360
+ batch_size=batch_size,
361
+ question=question,
362
+ system_prompt=system_prompt,
363
+ concurrency=concurrency,
364
+ )
365
+ return refined_themes, _
366
+
367
+
368
+ async def theme_target_alignment(
369
+ refined_themes_df: pd.DataFrame,
370
+ llm: RunnableWithFallbacks,
371
+ question: str,
372
+ target_n_themes: int = 10,
373
+ batch_size: int = 10000,
374
+ prompt_template: str | Path | PromptTemplate = "theme_target_alignment",
375
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
376
+ concurrency: int = 10,
377
+ ) -> tuple[pd.DataFrame, pd.DataFrame]:
378
+ """Align themes to target number using an LLM.
379
+
380
+ This function processes refined themes to consolidate them into a target number of
381
+ distinct categories while preserving all significant details and perspectives.
382
+ It transforms the output format for improved readability by transposing the
383
+ results into a single-row DataFrame where columns represent individual themes.
384
+
385
+ Args:
386
+ refined_themes_df (pd.DataFrame): DataFrame containing the refined themes
387
+ from the previous pipeline stage.
388
+ llm (RunnableWithFallbacks): Language model instance to use for theme alignment.
389
+ question (str): The survey question.
390
+ target_n_themes (int, optional): Target number of themes to consolidate to.
391
+ Defaults to 10.
392
+ batch_size (int, optional): Number of themes to process in each batch.
393
+ Defaults to 10000.
394
+ prompt_template (str | Path | PromptTemplate, optional): Template for structuring
395
+ the prompt to the LLM. Can be a string identifier, path to template file,
396
+ or PromptTemplate instance. Defaults to "theme_target_alignment".
397
+ system_prompt (str): System prompt to guide the LLM's behavior.
398
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
399
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
400
+
401
+ Returns:
402
+ tuple[pd.DataFrame, pd.DataFrame]:
403
+ A tuple containing two DataFrames:
404
+ - The first DataFrame contains the rows that were successfully processed by the LLM
405
+ - The second DataFrame contains the rows that could not be processed by the LLM
406
+
407
+ Note:
408
+ The function adds sequential response_ids to the input DataFrame and
409
+ transposes the output for improved readability and easier downstream
410
+ processing.
411
+ """
412
+ logger.info(
413
+ f"Running theme target alignment on {len(refined_themes_df)} themes compressing to {target_n_themes} themes"
414
+ )
415
+ refined_themes_df["response_id"] = refined_themes_df.index + 1
416
+ aligned_themes, _ = await batch_and_run(
417
+ refined_themes_df,
418
+ prompt_template,
419
+ llm.with_structured_output(ThemeRefinementResponses),
420
+ batch_size=batch_size,
421
+ question=question,
422
+ system_prompt=system_prompt,
423
+ target_n_themes=target_n_themes,
424
+ concurrency=concurrency,
425
+ )
426
+ return aligned_themes, _
427
+
428
+
429
+ async def theme_mapping(
430
+ responses_df: pd.DataFrame,
431
+ llm: RunnableWithFallbacks,
432
+ question: str,
433
+ refined_themes_df: pd.DataFrame,
434
+ batch_size: int = 20,
435
+ prompt_template: str | Path | PromptTemplate = "theme_mapping",
436
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
437
+ concurrency: int = 10,
438
+ ) -> tuple[pd.DataFrame, pd.DataFrame]:
439
+ """Map survey responses to refined themes using an LLM.
440
+
441
+ This function analyzes each survey response and determines which of the refined
442
+ themes best matches its content. Multiple themes can be assigned to a single response.
443
+
444
+ Args:
445
+ responses_df (pd.DataFrame): DataFrame containing survey responses.
446
+ Must include 'response_id' and 'response' columns.
447
+ llm (RunnableWithFallbacks): Language model instance to use for theme mapping.
448
+ question (str): The survey question.
449
+ refined_themes_df (pd.DataFrame): Single-row DataFrame where each column
450
+ represents a theme (from theme_refinement stage).
451
+ batch_size (int, optional): Number of responses to process in each batch.
452
+ Defaults to 20.
453
+ prompt_template (str | Path | PromptTemplate, optional): Template for structuring
454
+ the prompt to the LLM. Can be a string identifier, path to template file,
455
+ or PromptTemplate instance. Defaults to "theme_mapping".
456
+ system_prompt (str): System prompt to guide the LLM's behavior.
457
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
458
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
459
+
460
+ Returns:
461
+ tuple[pd.DataFrame, pd.DataFrame]:
462
+ A tuple containing two DataFrames:
463
+ - The first DataFrame contains the rows that were successfully processed by the LLM
464
+ - The second DataFrame contains the rows that could not be processed by the LLM
465
+
466
+ """
467
+ logger.info(
468
+ f"Running theme mapping on {len(responses_df)} responses using {len(refined_themes_df)} themes"
469
+ )
470
+
471
+ def transpose_refined_themes(refined_themes: pd.DataFrame):
472
+ """Transpose topics for increased legibility."""
473
+ transposed_df = pd.DataFrame(
474
+ [refined_themes["topic"].to_numpy()], columns=refined_themes["topic_id"]
475
+ )
476
+ return transposed_df
477
+
478
+ mapping, unprocessable = await batch_and_run(
479
+ responses_df,
480
+ prompt_template,
481
+ llm.with_structured_output(ThemeMappingResponses),
482
+ batch_size=batch_size,
483
+ question=question,
484
+ refined_themes=transpose_refined_themes(refined_themes_df).to_dict(
485
+ orient="records"
486
+ ),
487
+ integrity_check=True,
488
+ system_prompt=system_prompt,
489
+ concurrency=concurrency,
490
+ )
491
+ return mapping, unprocessable
492
+
493
+
494
+ async def detail_detection(
495
+ responses_df: pd.DataFrame,
496
+ llm: RunnableWithFallbacks,
497
+ question: str,
498
+ batch_size: int = 20,
499
+ prompt_template: str | Path | PromptTemplate = "detail_detection",
500
+ system_prompt: str = CONSULTATION_SYSTEM_PROMPT,
501
+ concurrency: int = 10,
502
+ ) -> tuple[pd.DataFrame, pd.DataFrame]:
503
+ """Identify responses that provide high-value detailed evidence.
504
+
505
+ This function processes survey responses in batches to analyze their level of detail
506
+ and evidence using a language model. It identifies responses that contain specific
507
+ examples, data, or detailed reasoning that provide strong supporting evidence.
508
+
509
+ Args:
510
+ responses_df (pd.DataFrame): DataFrame containing survey responses to analyze.
511
+ Must contain 'response_id' and 'response' columns.
512
+ llm (RunnableWithFallbacks): Language model instance to use for detail detection.
513
+ question (str): The survey question.
514
+ batch_size (int, optional): Number of responses to process in each batch.
515
+ Defaults to 20.
516
+ prompt_template (str | Path | PromptTemplate, optional): Template for structuring
517
+ the prompt to the LLM. Can be a string identifier, path to template file,
518
+ or PromptTemplate instance. Defaults to "detail_detection".
519
+ system_prompt (str): System prompt to guide the LLM's behavior.
520
+ Defaults to CONSULTATION_SYSTEM_PROMPT.
521
+ concurrency (int): Number of concurrent API calls to make. Defaults to 10.
522
+
523
+ Returns:
524
+ tuple[pd.DataFrame, pd.DataFrame]:
525
+ A tuple containing two DataFrames:
526
+ - The first DataFrame contains the rows that were successfully processed by the LLM
527
+ - The second DataFrame contains the rows that could not be processed by the LLM
528
+
529
+ Note:
530
+ The function uses response_id_integrity_check to ensure responses maintain
531
+ their original order and association after processing.
532
+ """
533
+ logger.info(f"Running detail detection on {len(responses_df)} responses")
534
+ detailed, _ = await batch_and_run(
535
+ responses_df,
536
+ prompt_template,
537
+ llm.with_structured_output(DetailDetectionResponses),
538
+ batch_size=batch_size,
539
+ question=question,
540
+ integrity_check=True,
541
+ system_prompt=system_prompt,
542
+ concurrency=concurrency,
543
+ )
544
+ return detailed, _