Remove the Argos-Translate translation backend
This commit is contained in:
9 files changed
+22
-318
No files matched your search
@@ -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.
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+8
-11
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
Reference in new issue
Block a user