Remove the Argos-Translate translation backend

This commit is contained in:
SKBotNL committed 2025-03-31 18:21:48 +02:00
1 parent 3ca5b1c4f0
commit dd4aef0f29
9 files changed
+22 -318

No files matched your search

+1 -4
View File
@@ -1,13 +1,10 @@
# Chat-OG
Chat plugin for [TrueOG](https://github.com/true-og/true-og)
> [!WARNING]
> Argos-Translate, which is enabled by default, requires libffi, openssl, lzma, and zlib.\
> This is not needed if you use the OpenAI(-compatible) API backend.
## Features
- Adds prefix, union and suffix to chat messages.
- Formats chat messages with MiniMessage if the player sending them has the `chat-og.color` permission.
- Translates chat messages using [argos-translate](https://github.com/argosopentech/argos-translate) or any OpenAI(-compatible) API.
- Translates chat messages using any OpenAI(-compatible) API.
- Discord bridge with custom and animated emoji (Minecraft to Discord only) support.
- Staff and premium chat.
-92
View File
@@ -1,10 +1,3 @@
import de.undercouch.gradle.tasks.download.Download
import java.io.BufferedOutputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
plugins {
id("org.jetbrains.kotlin.jvm") version "2.0.21"
id("com.gradleup.shadow") version "8.3.5" // Import shadow API.
@@ -77,93 +70,9 @@ tasks.withType<AbstractArchiveTask>().configureEach {
isReproducibleFileOrder = true
}
val downloadPython by tasks.registering(Download::class) {
src("https://github.com/python/cpython/archive/refs/heads/3.11.zip")
dest(layout.buildDirectory.file("python.zip"))
}
val unzipPython by tasks.registering(Copy::class) {
dependsOn(downloadPython)
from(zipTree(downloadPython.get().dest)) {
include("cpython*/**")
eachFile {
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
}
includeEmptyDirs = false
}
into(layout.buildDirectory.dir("python"))
}
val configurePython by tasks.registering(Exec::class) {
dependsOn(unzipPython)
doFirst {
Files.createDirectories(file("$rootDir/build/python/build").toPath())
}
workingDir("$rootDir/build/python")
commandLine("./configure")
args("--enable-optimizations")
}
val makePython by tasks.registering(Exec::class) {
dependsOn(configurePython)
workingDir("$rootDir/build/python")
commandLine("sh")
args("-c", "make -j$(nproc)")
}
val installPython by tasks.registering(Exec::class) {
dependsOn(makePython)
workingDir("$rootDir/build/python")
commandLine("make")
environment("DESTDIR", "$rootDir/build/python/install")
args("install")
}
val pythonZipFile = file("$rootDir/build/python/python.zip")
val createPythonZip by tasks.registering {
group = "Chat-OG"
dependsOn(installPython)
outputs.file(pythonZipFile)
doLast {
val inputDirectory = file("$rootDir/build/python/install/usr/local/")
if (!pythonZipFile.exists() && inputDirectory.exists()) {
println("Creating python.zip from $inputDirectory")
pythonZipFile.parentFile.mkdirs()
if (!pythonZipFile.exists()) {
pythonZipFile.createNewFile()
}
ZipOutputStream(BufferedOutputStream(FileOutputStream(pythonZipFile))).use { zos ->
inputDirectory.walkTopDown().forEach { file ->
val zipFileName = file.absolutePath
.removePrefix(inputDirectory.absolutePath)
.removePrefix("/")
val entry = ZipEntry(zipFileName + if (file.isDirectory) "/" else "")
zos.putNextEntry(entry)
if (file.isFile) {
file.inputStream().use { fis -> fis.copyTo(zos) }
}
}
}
}
}
}
val buildPython by tasks.registering {
if (file("$rootDir/build/python/python.zip").exists()) {
return@registering
}
group = "Chat-OG"
dependsOn(createPythonZip)
}
tasks.shadowJar {
dependsOn(buildPython)
minimize()
archiveClassifier.set("")
from(pythonZipFile) {
into("/")
}
}
tasks.named("clean").configure {
@@ -173,7 +82,6 @@ tasks.named("clean").configure {
}
tasks.build {
dependsOn(buildPython)
dependsOn("shadowJar")
}
+3 -11
View File
@@ -6,9 +6,6 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import net.milkbowl.vault.chat.Chat
import nl.skbotnl.chatog.commands.*
import nl.skbotnl.chatog.translator.ArgosTranslate
import nl.skbotnl.chatog.translator.OpenAI
import nl.skbotnl.chatog.translator.Translator
import org.bukkit.Bukkit
import org.bukkit.plugin.java.JavaPlugin
import java.util.*
@@ -18,7 +15,7 @@ class ChatOG : JavaPlugin() {
companion object {
lateinit var plugin: JavaPlugin
lateinit var chat: Chat
lateinit var translator: Translator
var translator: OpenAI? = null
var essentials = Bukkit.getServer().pluginManager.getPlugin("Essentials") as Essentials
// API
@@ -61,19 +58,14 @@ class ChatOG : JavaPlugin() {
Bukkit.getPluginManager().disablePlugin(this)
return
}
translator = if (Config.openAIEnabled) {
OpenAI()
} else {
ArgosTranslate()
}
} else null
LanguageDatabase.init()
GlobalScope.launch {
BlocklistManager.load()
EmojiConverter.load()
if (!Config.openAIEnabled) {
translator.init()
}
}
val rsp = server.servicesManager.getRegistration(Chat::class.java)
@@ -1,16 +1,17 @@
package nl.skbotnl.chatog.translator
package nl.skbotnl.chatog
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import net.kyori.adventure.text.Component
import net.trueog.utilitiesog.UtilitiesOG
import nl.skbotnl.chatog.ChatOG
import nl.skbotnl.chatog.Config
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
class OpenAI : Translator {
class OpenAI {
data class Translated(val translatedFrom: String?, val translatedText: String?, val error: Component?)
private var httpClient: OkHttpClient = OkHttpClient()
private var gson: Gson = Gson()
@@ -32,11 +33,7 @@ class OpenAI : Translator {
@SerializedName("message") val message: Message
)
override fun init() {
return
}
override fun translate(text: String, language: String): Translator.Translated {
fun translate(text: String, language: String): Translated {
val openAICompletion = CompletionReq(
model = Config.openAIModel,
messages = listOf(
@@ -58,11 +55,11 @@ class OpenAI : Translator {
httpClient.newCall(request).execute().use { response ->
val completionResp = gson.fromJson(response.body!!.string(), CompletionResp::class.java)
val respSplit = completionResp.choices[0].message.content.split(" | ", limit = 2)
return Translator.Translated(respSplit[0], respSplit[1], null)
return Translated(respSplit[0], respSplit[1], null)
}
} catch (e: Exception) {
ChatOG.plugin.logger.severe(e.toString())
return Translator.Translated(
return Translated(
null,
null,
UtilitiesOG.trueogColorize("${Config.prefix}<reset>: <red>Something went wrong while translating your message.")
@@ -8,12 +8,8 @@ import net.kyori.adventure.text.Component
import net.kyori.adventure.text.JoinConfiguration
import net.kyori.adventure.text.format.NamedTextColor
import net.trueog.utilitiesog.UtilitiesOG
import nl.skbotnl.chatog.ChatOG
import nl.skbotnl.chatog.Config
import nl.skbotnl.chatog.Helper
import nl.skbotnl.chatog.*
import nl.skbotnl.chatog.Helper.legacyToMm
import nl.skbotnl.chatog.LanguageDatabase
import nl.skbotnl.chatog.translator.Translator
import org.bukkit.Bukkit
import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
@@ -95,6 +91,13 @@ class TranslateMessage : CommandExecutor {
return true
}
if (ChatOG.translator == null) {
player.sendMessage(
UtilitiesOG.trueogColorize("${Config.prefix}<reset>: <red>The translator is disabled.")
)
return true
}
GlobalScope.launch {
val language = LanguageDatabase.getPlayerLanguage(player.uniqueId)
@@ -107,7 +110,7 @@ class TranslateMessage : CommandExecutor {
player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}<reset>: Translating message (this can take some time)..."))
val translated = ChatOG.translator.translate(sentMessage.message, language)
val translated = ChatOG.translator!!.translate(sentMessage.message, language)
translateCallback(translated, player, messageType, sentMessage, language)
}
@@ -115,7 +118,7 @@ class TranslateMessage : CommandExecutor {
}
private fun translateCallback(
translated: Translator.Translated,
translated: OpenAI.Translated,
player: Player,
messageType: Int,
sentMessage: ISentMessage?,
@@ -1,131 +0,0 @@
package nl.skbotnl.chatog.translator
import net.trueog.utilitiesog.UtilitiesOG
import nl.skbotnl.chatog.ChatOG
import nl.skbotnl.chatog.Config
import nl.skbotnl.chatog.translator.Translator.Translated
import java.io.File
import java.nio.file.Files
import java.util.zip.ZipFile
class ArgosTranslate : Translator {
private var initialised = false
override fun init() {
if (ChatOG.plugin.getResource("python.zip") == null) {
ChatOG.plugin.logger.warning("Python not found, the translator will be disabled. If you don't want this, read the README")
return
}
val pythonFolder = File(ChatOG.plugin.dataFolder, "python")
if (!pythonFolder.exists()) {
ChatOG.plugin.logger.info("Setting up Python for argos-translate...")
ChatOG.plugin.saveResource("python.zip", true)
ZipFile(File(ChatOG.plugin.dataFolder, "python.zip")).use { zip ->
zip.entries().asSequence().forEach { entry ->
if (entry.isDirectory) {
Files.createDirectory(File(pythonFolder, entry.name).toPath())
return@forEach
}
zip.getInputStream(entry).use { input ->
File(pythonFolder, entry.name).outputStream().use { output ->
input.copyTo(output)
}
}
}
}
val file = File("${ChatOG.plugin.dataFolder}/python/translator.py")
file.createNewFile()
val inputStream = ChatOG.plugin.getResource("translator.py")!!
inputStream.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
File(ChatOG.plugin.dataFolder, "python.zip").delete()
File("${ChatOG.plugin.dataFolder}/python/bin/python3").setExecutable(true)
ChatOG.plugin.logger.info("Creating venv...")
ProcessBuilder().command(
"${ChatOG.plugin.dataFolder}/python/bin/python3",
"-m",
"venv",
"${ChatOG.plugin.dataFolder}/python/venv"
).start().waitFor()
ChatOG.plugin.logger.info("Upgrading pip...")
ProcessBuilder().command(
"${ChatOG.plugin.dataFolder}/python/venv/bin/pip",
"install",
"--upgrade",
"pip"
).start().waitFor()
ChatOG.plugin.logger.info("Installing pip packages (this can take some time)...")
ProcessBuilder().command(
"${ChatOG.plugin.dataFolder}/python/venv/bin/pip",
"install",
"argostranslate",
"lingua-language-detector"
).start().waitFor()
ChatOG.plugin.logger.info("Installing translation packages (this can take a while)...")
File("${ChatOG.plugin.dataFolder}/argostranslate-packages").mkdir()
ProcessBuilder("${ChatOG.plugin.dataFolder}/python/venv/bin/argospm", "update").apply {
environment()["ARGOS_PACKAGES_DIR"] = "${ChatOG.plugin.dataFolder}/argostranslate-packages"
}.start().waitFor()
ProcessBuilder("${ChatOG.plugin.dataFolder}/python/venv/bin/argospm", "install", "translate").apply {
environment()["ARGOS_PACKAGES_DIR"] = "${ChatOG.plugin.dataFolder}/argostranslate-packages"
}.start().waitFor()
ChatOG.plugin.logger.info("Done with setting up Python and argos-translate")
} else {
ChatOG.plugin.logger.info("Upgrading pip...")
ProcessBuilder().command(
"${ChatOG.plugin.dataFolder}/python/venv/bin/pip",
"install",
"--upgrade",
"pip"
).start().waitFor()
ChatOG.plugin.logger.info("Upgrading argostranslate and the language detector...")
ProcessBuilder().command(
"${ChatOG.plugin.dataFolder}/python/venv/bin/pip",
"install",
"--upgrade",
"argostranslate",
"lingua-language-detector"
).start().waitFor()
ChatOG.plugin.logger.info("Everything is up-to-date!")
}
initialised = true
}
override fun translate(text: String, language: String): Translated {
if (!initialised) {
return Translated(
null,
null,
UtilitiesOG.trueogColorize("${Config.prefix}<reset>: <red>The translator has not yet been initialised, please wait.")
)
}
val pb = ProcessBuilder().command(
"${ChatOG.plugin.dataFolder}/python/venv/bin/python3",
"${ChatOG.plugin.dataFolder}/python/translator.py",
text,
language
).apply {
environment()["ARGOS_PACKAGES_DIR"] = "${ChatOG.plugin.dataFolder}/argostranslate-packages"
}.start()
val outputText = pb.inputStream.bufferedReader().readText().dropLast(1)
val split = outputText.split(" ", limit = 2)
return Translated(split[0], split[1], null)
}
}
@@ -1,11 +0,0 @@
package nl.skbotnl.chatog.translator
import net.kyori.adventure.text.Component
interface Translator {
data class Translated(val translatedFrom: String?, val translatedText: String?, val error: Component?)
fun init()
fun translate(text: String, language: String): Translated
}
-1
View File
@@ -7,7 +7,6 @@ redisUrl: 127.0.0.1:6379
# ---OpenAI---
# Any OpenAI-like (OpenAI, ollama, llama.cpp) API will work here
# openAIEnabled will implicitly disable Argos-Translate
openAIEnabled: false
# Will be used as: <baseurl>/v1/...
baseUrl: http://127.0.0.1:8080
-50
View File
@@ -1,50 +0,0 @@
import argostranslate.translate
import sys
from lingua import Language, LanguageDetectorBuilder
text = sys.argv[1]
to_code = sys.argv[2]
lingua_to_argos = {
Language.ARABIC: "ar",
Language.AZERBAIJANI: "az",
Language.CATALAN: "ca",
Language.CHINESE: "zh",
Language.CZECH: "cs",
Language.DANISH: "da",
Language.DUTCH: "nl",
Language.ENGLISH: "en",
Language.ESPERANTO: "eo",
Language.FINNISH: "fi",
Language.FRENCH: "fr",
Language.GERMAN: "de",
Language.GREEK: "el",
Language.HEBREW: "he",
Language.HINDI: "hi",
Language.HUNGARIAN: "hu",
Language.INDONESIAN: "id",
Language.IRISH: "ga",
Language.ITALIAN: "it",
Language.JAPANESE: "ja",
Language.KOREAN: "ko",
Language.PERSIAN: "fa",
Language.POLISH: "pl",
Language.PORTUGUESE: "pt",
Language.RUSSIAN: "ru",
Language.SLOVAK: "sk",
Language.SPANISH: "es",
Language.SWEDISH: "sv",
Language.TURKISH: "tr",
Language.UKRAINIAN: "uk"
}
languages = [Language.ARABIC, Language.AZERBAIJANI, Language.CATALAN, Language.CHINESE, Language.CZECH, Language.DANISH,
Language.DUTCH, Language.ENGLISH, Language.ESPERANTO, Language.FINNISH, Language.FRENCH, Language.GERMAN,
Language.GREEK, Language.HEBREW, Language.HINDI, Language.HUNGARIAN, Language.INDONESIAN, Language.IRISH,
Language.ITALIAN, Language.JAPANESE, Language.KOREAN, Language.PERSIAN, Language.POLISH,
Language.PORTUGUESE, Language.RUSSIAN, Language.SLOVAK, Language.SPANISH, Language.SWEDISH,
Language.TURKISH, Language.UKRAINIAN]
detector = LanguageDetectorBuilder.from_languages(*languages).build()
language = detector.detect_language_of(text)
print(lingua_to_argos[language] + " " + argostranslate.translate.translate(text, lingua_to_argos[language], to_code))