mirror of
https://github.com/jie65535/JChatGPT.git
synced 2025-10-20 17:13:37 +08:00
Update version to 1.8.0
Add SendVoiceMessage tool Move prompt to SystemPrompt.md file Add tool calling message switch config
This commit is contained in:
@@ -7,15 +7,22 @@ plugins {
|
||||
}
|
||||
|
||||
group = "top.jie65535.mirai"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
|
||||
mirai {
|
||||
jvmTarget = JavaVersion.VERSION_11
|
||||
noTestCore = true
|
||||
setupConsoleTestRuntime {
|
||||
// 移除 mirai-core 依赖
|
||||
classpath = classpath.filter {
|
||||
!it.nameWithoutExtension.startsWith("mirai-core-jvm")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://maven.aliyun.com/repository/public")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val openaiClientVersion = "4.0.1"
|
||||
@@ -23,6 +30,7 @@ val ktorVersion = "3.0.3"
|
||||
val jLatexMathVersion = "1.0.7"
|
||||
val commonTextVersion = "1.13.0"
|
||||
val hibernateVersion = "2.9.0"
|
||||
val overflowVersion = "1.0.7"
|
||||
|
||||
dependencies {
|
||||
implementation("com.aallam.openai:openai-client:$openaiClientVersion")
|
||||
@@ -32,4 +40,6 @@ dependencies {
|
||||
|
||||
// 聊天记录插件
|
||||
compileOnly("xyz.cssxsh.mirai:mirai-hibernate-plugin:$hibernateVersion")
|
||||
|
||||
testConsoleRuntime("top.mrxiaom.mirai:overflow-core:$overflowVersion")
|
||||
}
|
@@ -46,7 +46,7 @@ object JChatGPT : KotlinPlugin(
|
||||
JvmPluginDescription(
|
||||
id = "top.jie65535.mirai.JChatGPT",
|
||||
name = "J ChatGPT",
|
||||
version = "1.7.0",
|
||||
version = "1.8.0",
|
||||
) {
|
||||
author("jie65535")
|
||||
// dependsOn("xyz.cssxsh.mirai.plugin.mirai-hibernate-plugin", true)
|
||||
@@ -57,8 +57,14 @@ object JChatGPT : KotlinPlugin(
|
||||
*/
|
||||
private var includeHistory: Boolean = false
|
||||
|
||||
/**
|
||||
* 聊天权限
|
||||
*/
|
||||
val chatPermission = PermissionId("JChatGPT", "Chat")
|
||||
|
||||
/**
|
||||
* 唤醒关键字
|
||||
*/
|
||||
private var keyword: Regex? = null
|
||||
|
||||
override fun onEnable() {
|
||||
@@ -130,7 +136,7 @@ object JChatGPT : KotlinPlugin(
|
||||
|
||||
private fun getSystemPrompt(event: MessageEvent): String {
|
||||
val now = OffsetDateTime.now()
|
||||
val prompt = StringBuilder(PluginConfig.prompt)
|
||||
val prompt = StringBuilder(LargeLanguageModels.systemPrompt)
|
||||
fun replace(target: String, replacement: () -> String) {
|
||||
val i = prompt.indexOf(target)
|
||||
if (i != -1) {
|
||||
@@ -297,7 +303,7 @@ object JChatGPT : KotlinPlugin(
|
||||
val imageUrl = runBlocking {
|
||||
it.queryUrl()
|
||||
}
|
||||
""
|
||||
""
|
||||
} catch (e: Throwable) {
|
||||
logger.warning("图片地址获取失败", e)
|
||||
it.content
|
||||
@@ -320,13 +326,13 @@ object JChatGPT : KotlinPlugin(
|
||||
|
||||
try {
|
||||
val history = mutableListOf<ChatMessage>()
|
||||
if (PluginConfig.prompt.isNotEmpty()) {
|
||||
|
||||
val prompt = getSystemPrompt(event)
|
||||
if (PluginConfig.logPrompt) {
|
||||
logger.info("Prompt: $prompt")
|
||||
}
|
||||
history.add(ChatMessage(ChatRole.System, prompt))
|
||||
}
|
||||
|
||||
val historyText = getHistory(event)
|
||||
logger.info("History: $historyText")
|
||||
history.add(ChatMessage.User(historyText))
|
||||
@@ -563,6 +569,9 @@ object JChatGPT : KotlinPlugin(
|
||||
// 发送组合消息
|
||||
SendCompositeMessage(),
|
||||
|
||||
// 发送语音消息
|
||||
SendVoiceMessage(),
|
||||
|
||||
// 结束循环
|
||||
StopLoopAgent(),
|
||||
|
||||
@@ -669,7 +678,7 @@ object JChatGPT : KotlinPlugin(
|
||||
val agent = myTools.find { it.tool.function.name == function.name }
|
||||
?: return "Function ${function.name} not found"
|
||||
// 提示正在执行函数
|
||||
val receipt = if (agent.loadingMessage.isNotEmpty()) {
|
||||
val receipt = if (PluginConfig.showToolCallingMessage && agent.loadingMessage.isNotEmpty()) {
|
||||
event.subject.sendMessage(agent.loadingMessage)
|
||||
} else null
|
||||
// 执行函数
|
||||
|
@@ -7,12 +7,34 @@ import com.aallam.openai.client.OpenAIHost
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
object LargeLanguageModels {
|
||||
|
||||
|
||||
/**
|
||||
* 系统提示词
|
||||
*/
|
||||
var systemPrompt: String = "你是一个乐于助人的助手"
|
||||
private set
|
||||
|
||||
/**
|
||||
* 聊天助手
|
||||
*/
|
||||
var chat: Chat? = null
|
||||
|
||||
/**
|
||||
* 推理模型
|
||||
*/
|
||||
var reasoning: Chat? = null
|
||||
|
||||
/**
|
||||
* 视觉模型
|
||||
*/
|
||||
var visual: Chat? = null
|
||||
|
||||
fun reload() {
|
||||
// 载入超时时间
|
||||
val timeout = PluginConfig.timeout.milliseconds
|
||||
|
||||
// 初始化聊天模型
|
||||
if (PluginConfig.openAiApi.isNotBlank() && PluginConfig.openAiToken.isNotBlank()) {
|
||||
chat = OpenAI(
|
||||
token = PluginConfig.openAiToken,
|
||||
@@ -21,6 +43,7 @@ object LargeLanguageModels {
|
||||
)
|
||||
}
|
||||
|
||||
// 初始化推理模型
|
||||
if (PluginConfig.reasoningModelApi.isNotBlank() && PluginConfig.reasoningModelToken.isNotBlank()) {
|
||||
reasoning = OpenAI(
|
||||
token = PluginConfig.reasoningModelToken,
|
||||
@@ -29,6 +52,7 @@ object LargeLanguageModels {
|
||||
)
|
||||
}
|
||||
|
||||
// 初始化视觉模型
|
||||
if (PluginConfig.visualModelApi.isNotBlank() && PluginConfig.visualModelToken.isNotBlank()) {
|
||||
visual = OpenAI(
|
||||
token = PluginConfig.visualModelToken,
|
||||
@@ -36,5 +60,22 @@ object LargeLanguageModels {
|
||||
timeout = Timeout(request = timeout, connect = timeout, socket = timeout)
|
||||
)
|
||||
}
|
||||
|
||||
// 载入提示词
|
||||
if (PluginConfig.promptFile.isNotEmpty()) {
|
||||
val file = JChatGPT.resolveConfigFile(PluginConfig.promptFile)
|
||||
systemPrompt = if (file.exists()) {
|
||||
file.readText()
|
||||
} else {
|
||||
// 迁移提示词
|
||||
file.writeText(PluginConfig.prompt)
|
||||
PluginConfig.prompt
|
||||
}
|
||||
|
||||
// 空提示词兜底
|
||||
if (systemPrompt.isEmpty()) {
|
||||
systemPrompt = "你是一个乐于助人的助手"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -41,6 +41,9 @@ object PluginConfig : AutoSavePluginConfig("Config") {
|
||||
@ValueDescription("百炼平台图片编辑模型")
|
||||
val imageEditModel: String by value("qwen-image-edit")
|
||||
|
||||
@ValueDescription("百炼平台TTS模型")
|
||||
val ttsModel: String by value("qwen-tts")
|
||||
|
||||
@ValueDescription("Jina API Key")
|
||||
val jinaApiKey by value("")
|
||||
|
||||
@@ -65,9 +68,13 @@ object PluginConfig : AutoSavePluginConfig("Config") {
|
||||
@ValueDescription("等待响应超时时间,单位毫秒,默认60秒")
|
||||
val timeout: Long by value(60000L)
|
||||
|
||||
@Deprecated("使用外部文件而不是在配置文件内保存提示词")
|
||||
@ValueDescription("系统提示词")
|
||||
var prompt: String by value("你是一个乐于助人的助手")
|
||||
|
||||
@ValueDescription("系统提示词文件路径,相对于插件配置目录")
|
||||
val promptFile: String by value("SystemPrompt.md")
|
||||
|
||||
@ValueDescription("创建Prompt时取最近多少分钟内的消息")
|
||||
val historyWindowMin: Int by value(10)
|
||||
|
||||
@@ -85,4 +92,7 @@ object PluginConfig : AutoSavePluginConfig("Config") {
|
||||
|
||||
@ValueDescription("关键字呼叫,支持正则表达式")
|
||||
val callKeyword by value("[小筱][林淋月玥]")
|
||||
|
||||
@ValueDescription("是否显示工具调用消息,默认是")
|
||||
val showToolCallingMessage by value(true)
|
||||
}
|
@@ -30,6 +30,7 @@ object PluginData : AutoSavePluginData("data") {
|
||||
contactMemory[contactId] = newMemory
|
||||
} else {
|
||||
contactMemory[contactId] = memory.replace(oldMemory, newMemory)
|
||||
.replace("\n\n", "\n")
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,7 +2,6 @@ package top.jie65535.mirai.tools
|
||||
|
||||
import com.aallam.openai.api.chat.Tool
|
||||
import com.aallam.openai.api.core.Parameters
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.post
|
||||
import io.ktor.client.request.setBody
|
||||
@@ -38,11 +37,11 @@ class ImageEdit : BaseAgent(
|
||||
put("type", "string")
|
||||
put("description", "正向提示词,用来描述需要对图片进行修改的要求。")
|
||||
}
|
||||
putJsonObject("negative_prompt") {
|
||||
put("type", "string")
|
||||
put("description", "反向提示词,用来描述不希望在画面中看到的内容,可以对画面进行限制。" +
|
||||
"示例值:低分辨率、错误、最差质量、低质量、残缺、多余的手指、比例不良等。")
|
||||
}
|
||||
// putJsonObject("negative_prompt") {
|
||||
// put("type", "string")
|
||||
// put("description", "反向提示词,用来描述不希望在画面中看到的内容,可以对画面进行限制。" +
|
||||
// "示例值:低分辨率、错误、最差质量、低质量、残缺、多余的手指、比例不良等。")
|
||||
// }
|
||||
}
|
||||
putJsonArray("required") {
|
||||
add("image_url")
|
||||
@@ -59,13 +58,13 @@ class ImageEdit : BaseAgent(
|
||||
get() = PluginConfig.dashScopeApiKey.isNotEmpty()
|
||||
|
||||
override val loadingMessage: String
|
||||
get() = "图片编辑中..."
|
||||
get() = "改图中..."
|
||||
|
||||
override suspend fun execute(args: JsonObject?): String {
|
||||
requireNotNull(args)
|
||||
val imageUrl = args.getValue("image_url").jsonPrimitive.content
|
||||
val prompt = args.getValue("prompt").jsonPrimitive.content
|
||||
val negativePrompt = args["negative_prompt"]?.jsonPrimitive?.content
|
||||
// val negativePrompt = args["negative_prompt"]?.jsonPrimitive?.content
|
||||
val response = httpClient.post(API_URL) {
|
||||
contentType(ContentType("application", "json"))
|
||||
header("Authorization", "Bearer " + PluginConfig.dashScopeApiKey)
|
||||
@@ -86,11 +85,11 @@ class ImageEdit : BaseAgent(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (negativePrompt != null) {
|
||||
putJsonObject("parameters") {
|
||||
put("negative_prompt", negativePrompt)
|
||||
}
|
||||
}
|
||||
// if (negativePrompt != null) {
|
||||
// putJsonObject("parameters") {
|
||||
// put("negative_prompt", negativePrompt)
|
||||
// }
|
||||
// }
|
||||
}.toString())
|
||||
}
|
||||
|
||||
@@ -103,10 +102,10 @@ class ImageEdit : BaseAgent(
|
||||
.getValue("message").jsonObject
|
||||
.getValue("content").jsonArray[0].jsonObject
|
||||
.getValue("image").jsonPrimitive.content
|
||||
"图片已编辑完成,发送时请务必包含完整的url和查询参数,因为下载地址存在鉴权。图片地址:$url"
|
||||
} catch (e: Exception) {
|
||||
"图片已编辑完成,发送时请务必包含完整的url和查询参数,因为下载地址存在鉴权:"
|
||||
} catch (e: Throwable) {
|
||||
JChatGPT.logger.error("图像编辑结果解析异常", e)
|
||||
responseObject.toString()
|
||||
responseJson
|
||||
}
|
||||
}
|
||||
}
|
@@ -28,7 +28,7 @@ class ReasoningAgent : BaseAgent(
|
||||
)
|
||||
) {
|
||||
override val loadingMessage: String
|
||||
get() = "深度思考中..."
|
||||
get() = "思考中..."
|
||||
|
||||
override val isEnabled: Boolean
|
||||
get() = LargeLanguageModels.reasoning != null
|
||||
|
@@ -88,7 +88,7 @@ class RunCode : BaseAgent(
|
||||
get() = PluginConfig.glotToken.isNotEmpty()
|
||||
|
||||
override val loadingMessage: String
|
||||
get() = "执行代码中..."
|
||||
get() = "执行中..."
|
||||
|
||||
override suspend fun execute(args: JsonObject?): String {
|
||||
requireNotNull(args)
|
||||
|
140
src/main/kotlin/tools/SendVoiceMessage.kt
Normal file
140
src/main/kotlin/tools/SendVoiceMessage.kt
Normal file
@@ -0,0 +1,140 @@
|
||||
package top.jie65535.mirai.tools
|
||||
|
||||
import com.aallam.openai.api.chat.Tool
|
||||
import com.aallam.openai.api.core.Parameters
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import kotlinx.serialization.json.*
|
||||
import net.mamoe.mirai.contact.AudioSupported
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
|
||||
import top.jie65535.mirai.JChatGPT
|
||||
import top.jie65535.mirai.PluginConfig
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.measureTime
|
||||
|
||||
/**
|
||||
* 发送语音消息,调用阿里TTS,需要系统中存在ffmpeg,因为要转换到QQ支持的amr格式。
|
||||
*/
|
||||
class SendVoiceMessage : BaseAgent(
|
||||
tool = Tool.function(
|
||||
name = "sendVoiceMessage",
|
||||
description = "发送一条文本转语音消息。",
|
||||
parameters = Parameters.buildJsonObject {
|
||||
put("type", "object")
|
||||
putJsonObject("properties") {
|
||||
putJsonObject("content") {
|
||||
put("type", "string")
|
||||
put("description", "语音消息文本内容")
|
||||
}
|
||||
}
|
||||
putJsonArray("required") {
|
||||
add("content")
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
companion object {
|
||||
const val API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"
|
||||
}
|
||||
|
||||
override val loadingMessage: String
|
||||
get() = "录音中..."
|
||||
|
||||
override val isEnabled: Boolean
|
||||
get() = PluginConfig.dashScopeApiKey.isNotEmpty()
|
||||
|
||||
|
||||
override suspend fun execute(args: JsonObject?, event: MessageEvent): String {
|
||||
requireNotNull(args)
|
||||
if (event.subject !is AudioSupported) return "当前聊天环境不支持发送语音!"
|
||||
|
||||
val content = args.getValue("content").jsonPrimitive.content
|
||||
|
||||
// https://help.aliyun.com/zh/model-studio/qwen-tts
|
||||
val response = httpClient.post(API_URL) {
|
||||
contentType(ContentType("application", "json"))
|
||||
header("Authorization", "Bearer " + PluginConfig.dashScopeApiKey)
|
||||
setBody(buildJsonObject {
|
||||
put("model", PluginConfig.ttsModel)
|
||||
putJsonObject("input") {
|
||||
put("text", content)
|
||||
put("voice", "Chelsie") // Chelsie(女) Cherry(女) Ethan(男) Serena(女)
|
||||
}
|
||||
}.toString())
|
||||
}
|
||||
|
||||
val responseJson = response.bodyAsText()
|
||||
val responseObject = Json.parseToJsonElement(responseJson).jsonObject
|
||||
return try {
|
||||
val url = responseObject
|
||||
.getValue("output").jsonObject
|
||||
.getValue("audio").jsonObject
|
||||
.getValue("url").jsonPrimitive.content
|
||||
|
||||
val voiceFolder = JChatGPT.resolveDataFile("voice")
|
||||
voiceFolder.mkdir()
|
||||
val amrFile = File(voiceFolder, "${System.currentTimeMillis()}.amr")
|
||||
// 下载WAV并转到AMR
|
||||
downloadWav2Amr(url, amrFile.absolutePath)
|
||||
// 如果转换出来了则发送消息
|
||||
if (amrFile.exists()) {
|
||||
val audioMessage = amrFile.toExternalResource("amr").use {
|
||||
(event.subject as AudioSupported).uploadAudio(it)
|
||||
}
|
||||
event.subject.sendMessage(audioMessage)
|
||||
"OK"
|
||||
} else {
|
||||
"语音转换失败"
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
JChatGPT.logger.error("语音生成结果解析异常", e)
|
||||
responseJson
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载WAV并转换到AMR语音文件
|
||||
* @param url 下载地址
|
||||
* @param outputAmrPath 目标文件路径
|
||||
*/
|
||||
private suspend fun downloadWav2Amr(url: String, outputAmrPath: String) {
|
||||
val wavBytes: ByteArray
|
||||
val downloadDuration = measureTime {
|
||||
wavBytes = httpClient.get(url).bodyAsBytes()
|
||||
}
|
||||
JChatGPT.logger.info("下载语音文件耗时 $downloadDuration,文件大小 ${wavBytes.size} Bytes,开始转换为AMR...")
|
||||
|
||||
val convertDuration = measureTime {
|
||||
val ffmpeg = ProcessBuilder(
|
||||
"ffmpeg",
|
||||
"-f", "wav", // 指定输入格式
|
||||
"-i", "pipe:0", // 从标准输入读取
|
||||
"-ar", "8000",
|
||||
"-ac", "1",
|
||||
"-b:a", "12.2k",
|
||||
"-y", // 覆盖输出文件
|
||||
outputAmrPath // 输出到目标文件位置
|
||||
).start()
|
||||
ffmpeg.outputStream.use {
|
||||
it.write(wavBytes)
|
||||
}
|
||||
// 等待FFmpeg处理完成
|
||||
val completed = ffmpeg.waitFor(PluginConfig.timeout, TimeUnit.MILLISECONDS)
|
||||
|
||||
if (!completed) {
|
||||
ffmpeg.destroy()
|
||||
JChatGPT.logger.error("转换文件超时")
|
||||
}
|
||||
|
||||
if (ffmpeg.exitValue() != 0) {
|
||||
JChatGPT.logger.error("FFmpeg执行失败,退出代码:${ffmpeg.exitValue()}")
|
||||
}
|
||||
}
|
||||
|
||||
JChatGPT.logger.info("转换音频耗时 $convertDuration")
|
||||
}
|
||||
|
||||
}
|
@@ -44,7 +44,7 @@ class VisitWeb : BaseAgent(
|
||||
get() = PluginConfig.jinaApiKey.isNotEmpty()
|
||||
|
||||
override val loadingMessage: String
|
||||
get() = "访问网页中..."
|
||||
get() = "上网中..."
|
||||
|
||||
override suspend fun execute(args: JsonObject?): String {
|
||||
requireNotNull(args)
|
||||
|
@@ -40,7 +40,7 @@ class VisualAgent : BaseAgent(
|
||||
)
|
||||
) {
|
||||
override val loadingMessage: String
|
||||
get() = "图片识别中..."
|
||||
get() = "识别中..."
|
||||
|
||||
override val isEnabled: Boolean
|
||||
get() = LargeLanguageModels.visual != null
|
||||
|
@@ -34,7 +34,7 @@ class WeatherService : BaseAgent(
|
||||
)
|
||||
) {
|
||||
override val loadingMessage: String
|
||||
get() = "查询天气中..."
|
||||
get() = "观天中..."
|
||||
|
||||
override suspend fun execute(args: JsonObject?): String {
|
||||
requireNotNull(args)
|
||||
|
@@ -5,6 +5,8 @@ import com.aallam.openai.api.core.Parameters
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.serialization.json.*
|
||||
import org.apache.commons.text.StringEscapeUtils
|
||||
import top.jie65535.mirai.JChatGPT
|
||||
@@ -19,8 +21,15 @@ class WebSearch : BaseAgent(
|
||||
put("type", "object")
|
||||
putJsonObject("properties") {
|
||||
putJsonObject("q") {
|
||||
putJsonArray("type") {
|
||||
add("string")
|
||||
add("array")
|
||||
}
|
||||
putJsonObject("items") {
|
||||
put("type", "string")
|
||||
put("description", "查询内容关键字")
|
||||
}
|
||||
put("minItems", 1)
|
||||
put("description", "查询关键字,可为单组关键字查询,也可并发多组同时查询。")
|
||||
}
|
||||
}
|
||||
putJsonArray("required") {
|
||||
@@ -36,11 +45,23 @@ class WebSearch : BaseAgent(
|
||||
get() = PluginConfig.searXngUrl.isNotEmpty()
|
||||
|
||||
override val loadingMessage: String
|
||||
get() = "联网搜索中..."
|
||||
get() = "搜索中..."
|
||||
|
||||
override suspend fun execute(args: JsonObject?): String {
|
||||
requireNotNull(args)
|
||||
val q = args.getValue("q").jsonPrimitive.content
|
||||
val q = args.getValue("q")
|
||||
if (q is JsonPrimitive) {
|
||||
return search(q.content)
|
||||
} else if (q is JsonArray) {
|
||||
return q.map {
|
||||
scope.async { search(it.jsonPrimitive.content) }
|
||||
}.awaitAll().joinToString()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
private suspend fun search(q: String): String {
|
||||
return try {
|
||||
val url = buildString {
|
||||
append(PluginConfig.searXngUrl)
|
||||
append("?q=")
|
||||
@@ -51,7 +72,7 @@ class WebSearch : BaseAgent(
|
||||
val response = httpClient.get(url)
|
||||
JChatGPT.logger.info("Request: $url")
|
||||
val body = response.bodyAsText()
|
||||
JChatGPT.logger.info("Response: $body")
|
||||
JChatGPT.logger.debug("Response: $body")
|
||||
val responseJsonElement = Json.parseToJsonElement(body)
|
||||
val filteredResponse = buildJsonObject {
|
||||
val root = responseJsonElement.jsonObject
|
||||
@@ -87,6 +108,10 @@ class WebSearch : BaseAgent(
|
||||
root["answers"]?.let { put("answers", it) }
|
||||
root["infoboxes"]?.let { put("infoboxes", it) }
|
||||
}.toString()
|
||||
return StringEscapeUtils.unescapeJava(filteredResponse)
|
||||
|
||||
StringEscapeUtils.unescapeJava(filteredResponse)
|
||||
} catch (e: Throwable) {
|
||||
"Failed to search \"$q\": ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user