fix backend stuff
This commit is contained in:
+1
-1
@@ -18,7 +18,7 @@ class BackendChatRepository(
|
|||||||
) : ChatRepository {
|
) : ChatRepository {
|
||||||
|
|
||||||
override suspend fun query(afterId: Long?): List<Message> {
|
override suspend fun query(afterId: Long?): List<Message> {
|
||||||
val history = storage.query(userId, afterId, limit = 10)
|
val history = storage.query(userId, afterId, limit = 30)
|
||||||
return history.sortedBy { it.timestamp }
|
return history.sortedBy { it.timestamp }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-12
@@ -6,6 +6,9 @@ import ru.shadowsparky.chat.backend.domain.MessageStorage
|
|||||||
import ru.shadowsparky.chat.domain.Message
|
import ru.shadowsparky.chat.domain.Message
|
||||||
import ru.shadowsparky.domain.DispatcherProvider
|
import ru.shadowsparky.domain.DispatcherProvider
|
||||||
import ru.shadowsparky.vbox.backend.AppDatabase
|
import ru.shadowsparky.vbox.backend.AppDatabase
|
||||||
|
import ru.shadowsparky.vbox.server.GetInitialChatContext
|
||||||
|
import ru.shadowsparky.vbox.server.GetNewMessages
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
@Factory
|
@Factory
|
||||||
class SqlMessageStorage(
|
class SqlMessageStorage(
|
||||||
@@ -16,21 +19,32 @@ class SqlMessageStorage(
|
|||||||
|
|
||||||
override suspend fun query(userId: Long, afterId: Long?, limit: Int): List<Message> = withContext(dispatcherProvider.io) {
|
override suspend fun query(userId: Long, afterId: Long?, limit: Int): List<Message> = withContext(dispatcherProvider.io) {
|
||||||
val chatId = queries.getChatIdByUserId(userId).executeAsOneOrNull() ?: return@withContext emptyList()
|
val chatId = queries.getChatIdByUserId(userId).executeAsOneOrNull() ?: return@withContext emptyList()
|
||||||
val dbMessages = queries.getChatContext(
|
if (afterId == null) {
|
||||||
chatId = chatId,
|
queries.getInitialChatContext(
|
||||||
afterId = afterId,
|
chatId = chatId,
|
||||||
limit = limit.toLong()
|
limit = limit.toLong()
|
||||||
).executeAsList()
|
).executeAsList().reversed().map { it.toMessage() }
|
||||||
dbMessages.map { dbMsg ->
|
} else {
|
||||||
Message(
|
queries.getNewMessages(
|
||||||
id = dbMsg.id,
|
chatId = chatId,
|
||||||
role = dbMsg.role,
|
afterId = afterId,
|
||||||
content = dbMsg.content,
|
limit = limit.toLong()
|
||||||
timestamp = checkNotNull(dbMsg.created_at?.toInstant()?.toEpochMilli()) { "created_at required" }
|
).executeAsList().map { it.toMessage() }
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun GetNewMessages.toMessage(): Message {
|
||||||
|
return Message(id, role, content, created_at.asMillis())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GetInitialChatContext.toMessage(): Message {
|
||||||
|
return Message(id, role, content, created_at.asMillis())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun OffsetDateTime?.asMillis(): Long {
|
||||||
|
return checkNotNull(this?.toInstant()?.toEpochMilli()) { "created_at required" }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun insert(userId: Long, message: Message): Long = withContext(dispatcherProvider.io) {
|
override suspend fun insert(userId: Long, message: Message): Long = withContext(dispatcherProvider.io) {
|
||||||
val chatId = queries.getChatIdByUserId(userId).executeAsOneOrNull()
|
val chatId = queries.getChatIdByUserId(userId).executeAsOneOrNull()
|
||||||
?: queries.createChat(userId = userId).executeAsOne()
|
?: queries.createChat(userId = userId).executeAsOne()
|
||||||
|
|||||||
@@ -14,10 +14,19 @@ INSERT INTO messages (chat_id, role, content)
|
|||||||
VALUES (:chatId, :role, :content)
|
VALUES (:chatId, :role, :content)
|
||||||
RETURNING id;
|
RETURNING id;
|
||||||
|
|
||||||
getChatContext:
|
-- Просто берем последние N сообщений (прилетят в порядке: новые -> старые)
|
||||||
|
getInitialChatContext:
|
||||||
SELECT id, role, content, created_at
|
SELECT id, role, content, created_at
|
||||||
FROM messages
|
FROM messages
|
||||||
WHERE chat_id = :chatId
|
WHERE chat_id = :chatId
|
||||||
AND (:afterId IS NULL OR id > :afterId)
|
ORDER BY id DESC
|
||||||
|
LIMIT :limit;
|
||||||
|
|
||||||
|
-- Сюда новые сообщения всё так же дописываются по порядку (старые -> новые)
|
||||||
|
getNewMessages:
|
||||||
|
SELECT id, role, content, created_at
|
||||||
|
FROM messages
|
||||||
|
WHERE chat_id = :chatId
|
||||||
|
AND id > :afterId
|
||||||
ORDER BY id ASC
|
ORDER BY id ASC
|
||||||
LIMIT :limit;
|
LIMIT :limit;
|
||||||
|
|||||||
+5
-6
@@ -1,20 +1,23 @@
|
|||||||
package ru.shadowsparky.chat.backend.domain
|
package ru.shadowsparky.chat.backend.domain
|
||||||
|
|
||||||
import org.koin.core.annotation.Factory
|
import org.koin.core.annotation.Factory
|
||||||
|
import ru.shadowsparky.backend.data.EnvFetcher
|
||||||
import ru.shadowsparky.chat.domain.ChatRoles
|
import ru.shadowsparky.chat.domain.ChatRoles
|
||||||
import ru.shadowsparky.chat.domain.Message
|
import ru.shadowsparky.chat.domain.Message
|
||||||
|
|
||||||
@Factory
|
@Factory
|
||||||
class ProcessUserMessageUseCase(
|
class ProcessUserMessageUseCase(
|
||||||
private val storage: MessageStorage,
|
private val storage: MessageStorage,
|
||||||
private val chatService: ChatService
|
private val chatService: ChatService,
|
||||||
|
private val envFetcher: EnvFetcher
|
||||||
) {
|
) {
|
||||||
suspend fun execute(userId: Long): Message {
|
suspend fun execute(userId: Long): Message {
|
||||||
val history = storage.query(userId, null, limit = 10).toList()
|
val history = storage.query(userId, null, limit = 10).toList()
|
||||||
val sortedHistory = history.sortedBy { it.timestamp }
|
val sortedHistory = history.sortedBy { it.timestamp }
|
||||||
val systemMessage = Message(
|
val systemMessage = Message(
|
||||||
role = ChatRoles.SYSTEM,
|
role = ChatRoles.SYSTEM,
|
||||||
content = SYSTEM_PROMPT,
|
content = envFetcher.get("CHAT_SYSTEM_PROMPT").trim('"')
|
||||||
|
.ifEmpty { error("System prompt not set") },
|
||||||
timestamp = System.currentTimeMillis()
|
timestamp = System.currentTimeMillis()
|
||||||
)
|
)
|
||||||
val fullContext = listOf(systemMessage) + sortedHistory
|
val fullContext = listOf(systemMessage) + sortedHistory
|
||||||
@@ -27,8 +30,4 @@ class ProcessUserMessageUseCase(
|
|||||||
val messageId = storage.insert(userId, aiMessage)
|
val messageId = storage.insert(userId, aiMessage)
|
||||||
return aiMessage.copy(id = messageId)
|
return aiMessage.copy(id = messageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val SYSTEM_PROMPT = "Ты ИИ-помощник приложения \"Свиное рыло\". Ищи юзерам фильмы и сериалы. Правила: 1. Называй юзера \"свинорылец\" (Пример: \"Здорово, свинорылец!\"). 2. Общайся по-свойски, с юмором, иронично. 3. Если юзер сомневается, задай 2 наводящих вопроса. 4. Выдавай строго до 5 позиций максимум, даже если просят больше. Описание короткое (1-2 предложения). 5. Каждое название фильма/сериала ВСЕГДА строго оборачивай в теги [MOVIE]Название[/MOVIE]. 6. На нерелевантные темы не общайся, переводи разговор на кино в свиной тематике."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user