Skip to content

Commit

Permalink
feat: суммаризация видео с помощью yandex api
Browse files Browse the repository at this point in the history
  • Loading branch information
Djaler committed Jul 7, 2024
1 parent f92f9a9 commit 84ff527
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.github.djaler.evilbot.clients

import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.annotation.JsonNaming
import com.github.djaler.evilbot.components.RecordBreadcrumb
import com.github.djaler.evilbot.config.yandex.YandexApiCondition
import com.github.djaler.evilbot.config.yandex.YandexApiProperties
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.contentType
import org.springframework.context.annotation.Conditional
import org.springframework.stereotype.Component

Expand Down Expand Up @@ -41,23 +43,64 @@ class YandexGptClient(
url("https://300.ya.ru/api/sharing")

contentType(ContentType.Application.Json)
setBody(mapOf(
"token" to token
))
setBody(
mapOf(
"token" to token
)
)
}.body()
}

suspend fun generateVideoSummary(
link: String,
sessionId: String? = null,
): VideoSummaryResult {
return httpClient.post {
url("https://300.ya.ru/api/generation")

contentType(ContentType.Application.Json)
cookie("Session_id", yandexApiProperties.cookie)
setBody(
mapOf(
"video_url" to link,
"session_id" to sessionId,
)
)
}.body()
}
}

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
data class SharingUrlResult(
val sharingUrl: String
)

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
data class SummaryResult(
val thesis: List<Thesis>
)

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
data class VideoSummaryResult(
val statusCode: Int,
val errorCode: Int?,
val message: String?,
val sessionId: String,
val pollIntervalMs: Long,
val keypoints: List<Keypoint>?
)

data class Keypoint(
val content: String,
val theses: List<Thesis>,
)

data class Thesis(
var content: String
)

object ResponseStatus {
const val SUCCESS_VIDEO = 0
const val IN_PROGRESS = 1
const val ERROR = 3
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import org.springframework.boot.context.properties.ConstructorBinding
@ConfigurationProperties(prefix = "yandex.api")
@ConstructorBinding
data class YandexApiProperties(
val token: String = ""
val token: String = "",
val cookie: String = "",
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.message.content.TextMessage
import dev.inmo.tgbotapi.utils.boldln
import dev.inmo.tgbotapi.utils.buildEntities
import dev.inmo.tgbotapi.utils.regular
import org.apache.logging.log4j.LogManager
import org.springframework.context.annotation.Conditional
import org.springframework.stereotype.Component
Expand All @@ -32,6 +35,7 @@ class TlDrHandler(
) {
companion object {
private val log = LogManager.getLogger()
private val youtubeVideoLinkRegex = Regex("^(https?://)?(www\\.|m\\.)?youtu(\\.be|be\\.\\w{2,3})+/.*")
}

override suspend fun handleCommand(
Expand All @@ -58,12 +62,7 @@ class TlDrHandler(

requestsExecutor.withTypingAction(message.chat) {
try {
val thesis = yandexGptService.generateLinkThesis(link)
if (thesis != null) {
requestsExecutor.reply(messageToReply, thesis)
} else {
log.warn("Empty thesis generation result")
}
replyWithTlDr(link, messageToReply)
} catch (e: Exception) {
log.error("Exception in thesis generation", e)
sentryClient.captureException(e)
Expand All @@ -72,10 +71,51 @@ class TlDrHandler(
}
}

private suspend fun replyWithTlDr(link: String, messageToReply: Message) {
if (isYoutubeLink(link)) {
replyWithVideoKeypoints(link, messageToReply)
} else {
replyWithArticleThesis(link, messageToReply)
}
}

private suspend fun replyWithVideoKeypoints(link: String, messageToReply: Message) {
val videoKeypoints = yandexGptService.generateVideoKeypoints(link)
if (videoKeypoints.isEmpty()) {
log.warn("Empty keypoints generation result")
return
}

requestsExecutor.reply(
messageToReply,
buildEntities {
for (keypoint in videoKeypoints) {
boldln(keypoint.content)
for (thesis in keypoint.theses) {
regular("$thesis")
}
}
}
)
}

private suspend fun replyWithArticleThesis(link: String, messageToReply: Message) {
val thesis = yandexGptService.generateLinkThesis(link)
if (thesis != null) {
requestsExecutor.reply(messageToReply, thesis)
} else {
log.warn("Empty thesis generation result")
}
}

private fun extractLink(message: ContentMessage<*>): String? {
return when (val content = message.content) {
is TextContent -> content.textSources.firstNotNullOfOrNull { it.asURLTextSource()?.source }
else -> null
}
}

private fun isYoutubeLink(link: String): Boolean {
return link.matches(youtubeVideoLinkRegex)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.github.djaler.evilbot.service

import com.github.djaler.evilbot.clients.Keypoint
import com.github.djaler.evilbot.clients.ResponseStatus
import com.github.djaler.evilbot.clients.VideoSummaryResult
import com.github.djaler.evilbot.clients.YandexGptClient
import kotlinx.coroutines.delay
import org.springframework.stereotype.Service

@Service
Expand All @@ -14,4 +18,20 @@ class YandexGptService(

return generatedResult.thesis.joinToString(separator = "\n") { it.content }
}

suspend fun generateVideoKeypoints(link: String): List<Keypoint> {
var result = yandexGptClient.generateVideoSummary(link)

while (result.statusCode == ResponseStatus.IN_PROGRESS) {
delay(result.pollIntervalMs)

result = yandexGptClient.generateVideoSummary(link, sessionId = result.sessionId)
}

return result.keypoints ?: throw VideoThesisGenerationException(link, result)
}
}

class VideoThesisGenerationException(link: String, result: VideoSummaryResult) : RuntimeException(
"Error on video generation for $link. Status: ${result.statusCode}, error: ${result.errorCode}, message: ${result.message}"
)

0 comments on commit 84ff527

Please sign in to comment.