|
@@ -42,14 +42,23 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
options: BookshelfAutoGroupOptions = BookshelfAutoGroupOptions(),
|
|
options: BookshelfAutoGroupOptions = BookshelfAutoGroupOptions(),
|
|
|
): BookshelfAutoGroupPreflight {
|
|
): BookshelfAutoGroupPreflight {
|
|
|
validateSource(source)
|
|
validateSource(source)
|
|
|
|
|
+ val analysisSource = source.forAnalysis(options)
|
|
|
|
|
+ if (analysisSource.books.isEmpty()) {
|
|
|
|
|
+ return BookshelfAutoGroupPreflight(
|
|
|
|
|
+ analyzedBookCount = 0,
|
|
|
|
|
+ effectiveInputCharLimit = 0,
|
|
|
|
|
+ estimatedRequestCount = 0,
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
val promptText = promptGateway.getPromptText()
|
|
val promptText = promptGateway.getPromptText()
|
|
|
val preset = resolvePreset()
|
|
val preset = resolvePreset()
|
|
|
val systemPrompt = resolveSystemPrompt(preset, promptText)
|
|
val systemPrompt = resolveSystemPrompt(preset, promptText)
|
|
|
val inputBudget = effectiveInputBudget(preset)
|
|
val inputBudget = effectiveInputBudget(preset)
|
|
|
- val batches = createBatches(source, batchInputBudget(inputBudget), systemPrompt) { books ->
|
|
|
|
|
- buildGeneratePrompt(source, books, groupingInstruction, emptyList(), options, promptText)
|
|
|
|
|
|
|
+ val batches = createBatches(analysisSource, batchInputBudget(inputBudget), systemPrompt) { books ->
|
|
|
|
|
+ buildGeneratePrompt(analysisSource, books, groupingInstruction, emptyList(), options, promptText)
|
|
|
}
|
|
}
|
|
|
return BookshelfAutoGroupPreflight(
|
|
return BookshelfAutoGroupPreflight(
|
|
|
|
|
+ analyzedBookCount = analysisSource.bookCount,
|
|
|
effectiveInputCharLimit = inputBudget.effectiveCharLimit,
|
|
effectiveInputCharLimit = inputBudget.effectiveCharLimit,
|
|
|
estimatedRequestCount = batches.size,
|
|
estimatedRequestCount = batches.size,
|
|
|
)
|
|
)
|
|
@@ -62,12 +71,14 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
onProgress: (BookshelfAutoGroupProgress) -> Unit = {},
|
|
onProgress: (BookshelfAutoGroupProgress) -> Unit = {},
|
|
|
): BookshelfAutoGroupPlan {
|
|
): BookshelfAutoGroupPlan {
|
|
|
validateSource(source)
|
|
validateSource(source)
|
|
|
|
|
+ val analysisSource = source.forAnalysis(options)
|
|
|
|
|
+ if (analysisSource.books.isEmpty()) return BookshelfAutoGroupPlan(emptyList())
|
|
|
val promptText = promptGateway.getPromptText()
|
|
val promptText = promptGateway.getPromptText()
|
|
|
val preset = resolvePreset()
|
|
val preset = resolvePreset()
|
|
|
val systemPrompt = resolveSystemPrompt(preset, promptText)
|
|
val systemPrompt = resolveSystemPrompt(preset, promptText)
|
|
|
val inputBudget = effectiveInputBudget(preset)
|
|
val inputBudget = effectiveInputBudget(preset)
|
|
|
- val batches = createBatches(source, batchInputBudget(inputBudget), systemPrompt) { books ->
|
|
|
|
|
- buildGeneratePrompt(source, books, groupingInstruction, emptyList(), options, promptText)
|
|
|
|
|
|
|
+ val batches = createBatches(analysisSource, batchInputBudget(inputBudget), systemPrompt) { books ->
|
|
|
|
|
+ buildGeneratePrompt(analysisSource, books, groupingInstruction, emptyList(), options, promptText)
|
|
|
}
|
|
}
|
|
|
val plans = mutableListOf<BookshelfAutoGroupPlan>()
|
|
val plans = mutableListOf<BookshelfAutoGroupPlan>()
|
|
|
val proposedGroupNames = linkedSetOf<String>()
|
|
val proposedGroupNames = linkedSetOf<String>()
|
|
@@ -78,13 +89,13 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
inputBudget = inputBudget,
|
|
inputBudget = inputBudget,
|
|
|
systemPrompt = systemPrompt,
|
|
systemPrompt = systemPrompt,
|
|
|
) { names ->
|
|
) { names ->
|
|
|
- buildGeneratePrompt(source, batch, groupingInstruction, names, options, promptText)
|
|
|
|
|
|
|
+ buildGeneratePrompt(analysisSource, batch, groupingInstruction, names, options, promptText)
|
|
|
}
|
|
}
|
|
|
val plan = generateBatch(
|
|
val plan = generateBatch(
|
|
|
preset = preset,
|
|
preset = preset,
|
|
|
systemPrompt = systemPrompt,
|
|
systemPrompt = systemPrompt,
|
|
|
prompt = buildGeneratePrompt(
|
|
prompt = buildGeneratePrompt(
|
|
|
- source,
|
|
|
|
|
|
|
+ analysisSource,
|
|
|
batch,
|
|
batch,
|
|
|
groupingInstruction,
|
|
groupingInstruction,
|
|
|
sharedGroupNames,
|
|
sharedGroupNames,
|
|
@@ -92,13 +103,13 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
promptText,
|
|
promptText,
|
|
|
),
|
|
),
|
|
|
books = batch,
|
|
books = batch,
|
|
|
- existingGroupNames = source.existingGroupNames.toSet(),
|
|
|
|
|
|
|
+ existingGroupNames = analysisSource.existingGroupNames.toSet(),
|
|
|
options = options,
|
|
options = options,
|
|
|
)
|
|
)
|
|
|
plans += plan
|
|
plans += plan
|
|
|
plan.groups.mapTo(proposedGroupNames, BookshelfAutoGroupPlanGroup::name)
|
|
plan.groups.mapTo(proposedGroupNames, BookshelfAutoGroupPlanGroup::name)
|
|
|
}
|
|
}
|
|
|
- return mergePlans(plans, source)
|
|
|
|
|
|
|
+ return mergePlans(plans, analysisSource)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
suspend fun revise(
|
|
suspend fun revise(
|
|
@@ -110,12 +121,14 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
): BookshelfAutoGroupPlan {
|
|
): BookshelfAutoGroupPlan {
|
|
|
require(instruction.isNotBlank()) { "Revision instruction is required" }
|
|
require(instruction.isNotBlank()) { "Revision instruction is required" }
|
|
|
validateSource(source)
|
|
validateSource(source)
|
|
|
|
|
+ val analysisSource = source.forAnalysis(options)
|
|
|
|
|
+ if (analysisSource.books.isEmpty()) return BookshelfAutoGroupPlan(emptyList())
|
|
|
val promptText = promptGateway.getPromptText()
|
|
val promptText = promptGateway.getPromptText()
|
|
|
val preset = resolvePreset()
|
|
val preset = resolvePreset()
|
|
|
val systemPrompt = resolveSystemPrompt(preset, promptText)
|
|
val systemPrompt = resolveSystemPrompt(preset, promptText)
|
|
|
val inputBudget = effectiveInputBudget(preset)
|
|
val inputBudget = effectiveInputBudget(preset)
|
|
|
- val batches = createBatches(source, batchInputBudget(inputBudget), systemPrompt) { books ->
|
|
|
|
|
- buildRevisePrompt(source, currentPlan, books, instruction, emptyList(), options, promptText)
|
|
|
|
|
|
|
+ val batches = createBatches(analysisSource, batchInputBudget(inputBudget), systemPrompt) { books ->
|
|
|
|
|
+ buildRevisePrompt(analysisSource, currentPlan, books, instruction, emptyList(), options, promptText)
|
|
|
}
|
|
}
|
|
|
val plans = mutableListOf<BookshelfAutoGroupPlan>()
|
|
val plans = mutableListOf<BookshelfAutoGroupPlan>()
|
|
|
val proposedGroupNames = currentPlan.groups
|
|
val proposedGroupNames = currentPlan.groups
|
|
@@ -127,13 +140,13 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
inputBudget = inputBudget,
|
|
inputBudget = inputBudget,
|
|
|
systemPrompt = systemPrompt,
|
|
systemPrompt = systemPrompt,
|
|
|
) { names ->
|
|
) { names ->
|
|
|
- buildRevisePrompt(source, currentPlan, batch, instruction, names, options, promptText)
|
|
|
|
|
|
|
+ buildRevisePrompt(analysisSource, currentPlan, batch, instruction, names, options, promptText)
|
|
|
}
|
|
}
|
|
|
val plan = generateBatch(
|
|
val plan = generateBatch(
|
|
|
preset = preset,
|
|
preset = preset,
|
|
|
systemPrompt = systemPrompt,
|
|
systemPrompt = systemPrompt,
|
|
|
prompt = buildRevisePrompt(
|
|
prompt = buildRevisePrompt(
|
|
|
- source,
|
|
|
|
|
|
|
+ analysisSource,
|
|
|
currentPlan,
|
|
currentPlan,
|
|
|
batch,
|
|
batch,
|
|
|
instruction,
|
|
instruction,
|
|
@@ -142,13 +155,13 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
promptText,
|
|
promptText,
|
|
|
),
|
|
),
|
|
|
books = batch,
|
|
books = batch,
|
|
|
- existingGroupNames = source.existingGroupNames.toSet(),
|
|
|
|
|
|
|
+ existingGroupNames = analysisSource.existingGroupNames.toSet(),
|
|
|
options = options,
|
|
options = options,
|
|
|
)
|
|
)
|
|
|
plans += plan
|
|
plans += plan
|
|
|
plan.groups.mapTo(proposedGroupNames, BookshelfAutoGroupPlanGroup::name)
|
|
plan.groups.mapTo(proposedGroupNames, BookshelfAutoGroupPlanGroup::name)
|
|
|
}
|
|
}
|
|
|
- return mergePlans(plans, source)
|
|
|
|
|
|
|
+ return mergePlans(plans, analysisSource)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private suspend fun generateBatch(
|
|
private suspend fun generateBatch(
|
|
@@ -205,6 +218,14 @@ class GenerateBookshelfAutoGroupPlanUseCase(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private fun BookshelfAutoGroupSource.forAnalysis(
|
|
|
|
|
+ options: BookshelfAutoGroupOptions,
|
|
|
|
|
+ ): BookshelfAutoGroupSource {
|
|
|
|
|
+ if (!options.incrementalOnly) return this
|
|
|
|
|
+ // Keep existing group names for reuse while removing grouped book metadata from AI input.
|
|
|
|
|
+ return copy(books = books.filter { it.currentGroupNames.isEmpty() })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private fun effectiveInputBudget(preset: AiTaskPresetConfig): InputBudget {
|
|
private fun effectiveInputBudget(preset: AiTaskPresetConfig): InputBudget {
|
|
|
val configuredLimit = preset.runtimeOptions.maxInputChars
|
|
val configuredLimit = preset.runtimeOptions.maxInputChars
|
|
|
.takeIf { it > 0 }
|
|
.takeIf { it > 0 }
|