+ nlp reatech

This commit is contained in:
xds
2025-04-08 12:13:20 +03:00
parent af7577c65b
commit 5d9cc167fc
5 changed files with 58 additions and 28 deletions

View File

@@ -179,31 +179,17 @@ class SpaceController(
} }
} }
@GetMapping("/{spaceId}/transactions/csv") @GetMapping("/transactions/csv")
suspend fun getTransactionsCSV( suspend fun getTransactionsCSV(
@PathVariable spaceId: String,
@RequestParam(value = "transaction_type") transactionType: String? = null,
@RequestParam(value = "category_type") categoryType: String? = null,
@RequestParam(value = "user_id") userId: String? = null,
@RequestParam(value = "is_child") isChild: Boolean? = null,
@RequestParam(value = "limit") limit: Int = 20000,
@RequestParam(value = "offset") offset: Int = 0
): ResponseEntity<Any> { ): ResponseEntity<Any> {
try { try {
val bos = ByteArrayOutputStream() val bos = ByteArrayOutputStream()
val writer = CSVWriter(OutputStreamWriter(bos)) val writer = CSVWriter(OutputStreamWriter(bos))
val CSVHeaders = arrayOf("id", "name", "category") val CSVHeaders = arrayOf("id", "comment", "category")
writer.writeNext(CSVHeaders) writer.writeNext(CSVHeaders)
financialService.getTransactions( financialService.getAllTransactions(
spaceId = spaceId, ).map {
transactionType = transactionType, val data = arrayOf(it.id, it.comment, it.category.id)
categoryType = categoryType,
userId = userId,
isChild = isChild,
limit = limit,
offset = offset
).awaitSingle().map {
val data = arrayOf(it.id, it.comment, it.category.name)
writer.writeNext(data) writer.writeNext(data)
} }
writer.close() writer.close()
@@ -224,7 +210,8 @@ class SpaceController(
@GetMapping("/{spaceId}/category-predict") @GetMapping("/{spaceId}/category-predict")
suspend fun getTransactionCategoryPredict( suspend fun getTransactionCategoryPredict(
@PathVariable spaceId: String, @PathVariable spaceId: String,
@RequestParam comment: String @RequestParam comment: String,
@RequestParam cloud: Int
): List<Category> { ): List<Category> {
val user = authService.getSecurityUser() val user = authService.getSecurityUser()
spaceService.isValidRequest(spaceId, user) spaceService.isValidRequest(spaceId, user)
@@ -233,7 +220,8 @@ class SpaceController(
"EXPENSE", "EXPENSE",
sortBy = "name", sortBy = "name",
direction = "ASC", direction = "ASC",
predict = comment predict = comment,
cloud = cloud
) )
} }

View File

@@ -64,7 +64,7 @@ class BotService(
for (category in predictedCategories) { for (category in predictedCategories) {
filteredCategories.add(categories.first { it.name == category.category }) filteredCategories.add(categories.first { it.id == category.category })
} }
} else { } else {
filteredCategories.addAll(categories) filteredCategories.addAll(categories)

View File

@@ -75,7 +75,8 @@ class CategoryService(
sortBy: String, sortBy: String,
direction: String, direction: String,
tagCode: String? = null, tagCode: String? = null,
predict: String? = null predict: String? = null,
cloud: Int? = null
): MutableList<Category> { ): MutableList<Category> {
val lookupSpaces = lookup("spaces", "space.\$id", "_id", "spaceDetails") val lookupSpaces = lookup("spaces", "space.\$id", "_id", "spaceDetails")
val unwindSpace = unwind("spaceDetails") val unwindSpace = unwind("spaceDetails")
@@ -112,12 +113,12 @@ class CategoryService(
}.awaitSingle().toMutableList() }.awaitSingle().toMutableList()
val predictedCategories = mutableListOf<CategoryPrediction>() val predictedCategories = mutableListOf<CategoryPrediction>()
if (!predict.isNullOrBlank()) { if (!predict.isNullOrBlank() && cloud != null) {
predictedCategories.addAll(nlpService.predictCategory(predict, 1)) predictedCategories.addAll(nlpService.predictCategory(predict, cloud))
} }
val filteredCategories = mutableListOf<Category>() val filteredCategories = mutableListOf<Category>()
for (category in predictedCategories) { for (category in predictedCategories) {
categories.find { it.name == category.category }?.let { filteredCategories.add(it) } categories.find { it.id == category.category }?.let { filteredCategories.add(it) }
} }
return if (filteredCategories.isEmpty()) categories else filteredCategories return if (filteredCategories.isEmpty()) categories else filteredCategories
} }

View File

@@ -48,6 +48,7 @@ class FinancialService(
val transactionsMapper: TransactionsMapper, val transactionsMapper: TransactionsMapper,
val budgetMapper: BudgetMapper, val budgetMapper: BudgetMapper,
private val subscriptionService: SubscriptionService, private val subscriptionService: SubscriptionService,
private val nlpService: NLPService
) { ) {
private val logger = LoggerFactory.getLogger(FinancialService::class.java) private val logger = LoggerFactory.getLogger(FinancialService::class.java)
@@ -761,6 +762,37 @@ class FinancialService(
} }
} }
suspend fun getAllTransactions(): List<Transaction>{
// Сборка агрегации
val lookup = lookup("categories", "category.\$id", "_id", "categoryDetails")
val unwindCategory = unwind("categoryDetails")
val lookupSpaces = lookup("spaces", "space.\$id", "_id", "spaceDetails")
val unwindSpace = unwind("spaceDetails")
val lookupUsers = lookup("users", "user.\$id", "_id", "userDetails")
val unwindUser = unwind("userDetails")
val sort =
sort(Sort.by(Direction.DESC, "date").and(Sort.by(Direction.DESC, "createdAt")))
val aggregationBuilder = mutableListOf(
lookup,
unwindCategory,
lookupSpaces,
unwindSpace,
lookupUsers,
unwindUser,
sort
)
val aggregation = newAggregation(aggregationBuilder)
return reactiveMongoTemplate.aggregate(
aggregation, "transactions", Document::class.java
).collectList().awaitSingle().map { doc ->
transactionsMapper.fromDocument(doc)
}
}
suspend fun getTransactionByParentId(parentId: String): Transaction? { suspend fun getTransactionByParentId(parentId: String): Transaction? {
// Сборка агрегации // Сборка агрегации
@@ -885,6 +917,9 @@ class FinancialService(
) )
) )
} }
scope.launch {
nlpService.reteach()
}
return savedTransaction return savedTransaction
} }

View File

@@ -1,8 +1,11 @@
package space.luminic.budgerapp.services package space.luminic.budgerapp.services
import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.awaitSingle
import kotlinx.coroutines.reactor.awaitSingleOrNull
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.bodyToMono
import space.luminic.budgerapp.configs.NLPConfig import space.luminic.budgerapp.configs.NLPConfig
import space.luminic.budgerapp.models.CategoryPrediction import space.luminic.budgerapp.models.CategoryPrediction
@@ -14,9 +17,12 @@ class NLPService(
// .defaultHeader("Authorization", "Bearer YOUR_API_KEY") // .defaultHeader("Authorization", "Bearer YOUR_API_KEY")
.build(), .build(),
) { ) {
private val logging = LoggerFactory.getLogger(NLPService::class.java)
suspend fun reteach() {
logging.info("Reteaching NLP")
webClient.get().uri("/reteach").retrieve().bodyToMono<Void>().awaitSingleOrNull()
}
suspend fun predictCategory(category: String, cloud: Int): List<CategoryPrediction> { suspend fun predictCategory(category: String, cloud: Int): List<CategoryPrediction> {
val response = webClient.get().uri("/predict?req=$category&cloud=$cloud") val response = webClient.get().uri("/predict?req=$category&cloud=$cloud")