mirror of
https://github.com/jie65535/JChatGPT.git
synced 2026-06-23 00:49:31 +08:00
Add visit web tool
Add send message tools Update version to v1.7.0
This commit is contained in:
@@ -3,7 +3,11 @@ package top.jie65535.mirai.tools
|
||||
import com.aallam.openai.api.chat.Tool
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.okhttp.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
|
||||
abstract class BaseAgent(
|
||||
val tool: Tool
|
||||
@@ -18,11 +22,27 @@ abstract class BaseAgent(
|
||||
*/
|
||||
open val loadingMessage: String = ""
|
||||
|
||||
/**
|
||||
* HTTP客户端
|
||||
*/
|
||||
protected val httpClient by lazy {
|
||||
HttpClient(OkHttp)
|
||||
}
|
||||
|
||||
abstract suspend fun execute(args: JsonObject?): String
|
||||
/**
|
||||
* 协程作用域
|
||||
*/
|
||||
protected val scope by lazy {
|
||||
CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
}
|
||||
|
||||
open suspend fun execute(args: JsonObject?): String {
|
||||
return "OK"
|
||||
}
|
||||
|
||||
open suspend fun execute(args: JsonObject?, event: MessageEvent): String {
|
||||
return execute(args)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "${tool.function.name}: ${tool.function.description}"
|
||||
|
||||
@@ -43,7 +43,7 @@ class ReasoningAgent : BaseAgent(
|
||||
val answerContent = StringBuilder()
|
||||
llm.chatCompletions(ChatCompletionRequest(
|
||||
model = ModelId(PluginConfig.reasoningModel),
|
||||
messages = listOf(ChatMessage.Companion.User(prompt))
|
||||
messages = listOf(ChatMessage.User(prompt))
|
||||
)).collect {
|
||||
if (it.choices.isNotEmpty()) {
|
||||
val delta = it.choices[0].delta ?: return@collect
|
||||
|
||||
50
src/main/kotlin/tools/SendCompositeMessage.kt
Normal file
50
src/main/kotlin/tools/SendCompositeMessage.kt
Normal file
@@ -0,0 +1,50 @@
|
||||
package top.jie65535.mirai.tools
|
||||
|
||||
import com.aallam.openai.api.chat.Tool
|
||||
import com.aallam.openai.api.core.Parameters
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.add
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import kotlinx.serialization.json.put
|
||||
import kotlinx.serialization.json.putJsonArray
|
||||
import kotlinx.serialization.json.putJsonObject
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
import net.mamoe.mirai.message.data.buildForwardMessage
|
||||
import top.jie65535.mirai.JChatGPT
|
||||
import top.jie65535.mirai.PluginConfig
|
||||
import kotlin.collections.getValue
|
||||
|
||||
class SendCompositeMessage : BaseAgent(
|
||||
tool = Tool.function(
|
||||
name = "sendCompositeMessage",
|
||||
description = "发送组合消息,适合发送较长消息而避免刷屏(不支持Markdown)",
|
||||
parameters = Parameters.buildJsonObject {
|
||||
put("type", "object")
|
||||
putJsonObject("properties") {
|
||||
putJsonObject("content") {
|
||||
put("type", "string")
|
||||
put("description", "消息内容")
|
||||
}
|
||||
}
|
||||
putJsonArray("required") {
|
||||
add("content")
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
override suspend fun execute(args: JsonObject?, event: MessageEvent): String {
|
||||
requireNotNull(args)
|
||||
val content = args.getValue("content").jsonPrimitive.content
|
||||
val msg = JChatGPT.toMessage(event.subject, content)
|
||||
event.subject.sendMessage(
|
||||
if (content.length > PluginConfig.messageMergeThreshold) {
|
||||
event.buildForwardMessage {
|
||||
event.bot says msg
|
||||
}
|
||||
} else {
|
||||
msg
|
||||
}
|
||||
)
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
33
src/main/kotlin/tools/SendSingleMessageAgent.kt
Normal file
33
src/main/kotlin/tools/SendSingleMessageAgent.kt
Normal file
@@ -0,0 +1,33 @@
|
||||
package top.jie65535.mirai.tools
|
||||
|
||||
import com.aallam.openai.api.chat.Tool
|
||||
import com.aallam.openai.api.core.Parameters
|
||||
import kotlinx.serialization.json.*
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
import top.jie65535.mirai.JChatGPT
|
||||
|
||||
class SendSingleMessageAgent : BaseAgent(
|
||||
tool = Tool.function(
|
||||
name = "sendSingleMessage",
|
||||
description = "发送一条消息,适合发送一行以内的短句(不支持Markdown)",
|
||||
parameters = Parameters.buildJsonObject {
|
||||
put("type", "object")
|
||||
putJsonObject("properties") {
|
||||
putJsonObject("content") {
|
||||
put("type", "string")
|
||||
put("description", "消息内容")
|
||||
}
|
||||
}
|
||||
putJsonArray("required") {
|
||||
add("content")
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
override suspend fun execute(args: JsonObject?, event: MessageEvent): String {
|
||||
requireNotNull(args)
|
||||
val content = args.getValue("content").jsonPrimitive.content
|
||||
event.subject.sendMessage(JChatGPT.toMessage(event.subject, content))
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
12
src/main/kotlin/tools/StopLoopAgent.kt
Normal file
12
src/main/kotlin/tools/StopLoopAgent.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package top.jie65535.mirai.tools
|
||||
|
||||
import com.aallam.openai.api.chat.Tool
|
||||
import com.aallam.openai.api.core.Parameters
|
||||
|
||||
class StopLoopAgent : BaseAgent(
|
||||
tool = Tool.function(
|
||||
name = "endConversation",
|
||||
description = "结束本轮对话",
|
||||
parameters = Parameters.Empty
|
||||
)
|
||||
)
|
||||
71
src/main/kotlin/tools/VisitWeb.kt
Normal file
71
src/main/kotlin/tools/VisitWeb.kt
Normal file
@@ -0,0 +1,71 @@
|
||||
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 kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.serialization.json.*
|
||||
import top.jie65535.mirai.PluginConfig
|
||||
|
||||
class VisitWeb : BaseAgent(
|
||||
tool = Tool.function(
|
||||
name = "visit",
|
||||
description = "Visit webpage(s) and return the summary of the content.",
|
||||
parameters = Parameters.buildJsonObject {
|
||||
put("type", "object")
|
||||
putJsonObject("properties") {
|
||||
putJsonObject("url") {
|
||||
putJsonArray("type") {
|
||||
add("string")
|
||||
add("array")
|
||||
}
|
||||
putJsonObject("items") {
|
||||
put("type", "string")
|
||||
}
|
||||
put("minItems", 1)
|
||||
put("description", "The URL(s) of the webpage(s) to visit. Can be a single URL or an array of URLs.")
|
||||
}
|
||||
}
|
||||
|
||||
putJsonArray("required") {
|
||||
add("url")
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
companion object {
|
||||
// Visit Tool (Using Jina Reader)
|
||||
const val JINA_READER_URL_PREFIX = "https://r.jina.ai/"
|
||||
}
|
||||
|
||||
override val isEnabled: Boolean
|
||||
get() = PluginConfig.jinaApiKey.isNotEmpty()
|
||||
|
||||
override val loadingMessage: String
|
||||
get() = "访问网页中..."
|
||||
|
||||
override suspend fun execute(args: JsonObject?): String {
|
||||
requireNotNull(args)
|
||||
val urlJson = args.getValue("url")
|
||||
if (urlJson is JsonPrimitive) {
|
||||
return jinaReadPage(urlJson.content)
|
||||
} else if (urlJson is JsonArray) {
|
||||
return urlJson.map {
|
||||
scope.async { jinaReadPage(it.jsonPrimitive.content) }
|
||||
}.awaitAll().joinToString()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
private suspend fun jinaReadPage(url: String): String {
|
||||
return try {
|
||||
httpClient.get(JINA_READER_URL_PREFIX + url) {
|
||||
header("Authorization", "Bearer ${PluginConfig.jinaApiKey}")
|
||||
}.bodyAsText()
|
||||
} catch (e: Throwable) {
|
||||
"Error fetching \"$url\": ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import kotlinx.serialization.json.*
|
||||
import org.apache.commons.text.StringEscapeUtils
|
||||
import top.jie65535.mirai.JChatGPT
|
||||
import top.jie65535.mirai.PluginConfig
|
||||
|
||||
class WebSearch : BaseAgent(
|
||||
@@ -21,33 +22,6 @@ class WebSearch : BaseAgent(
|
||||
put("type", "string")
|
||||
put("description", "查询内容关键字")
|
||||
}
|
||||
putJsonObject("categories") {
|
||||
put("type", "array")
|
||||
putJsonObject("items") {
|
||||
put("type", "string")
|
||||
putJsonArray("enum") {
|
||||
add("general")
|
||||
add("images")
|
||||
add("videos")
|
||||
add("news")
|
||||
add("music")
|
||||
add("it")
|
||||
add("science")
|
||||
add("files")
|
||||
add("social_media")
|
||||
}
|
||||
}
|
||||
put("description", "可选择多项查询分类,通常情况下不传或用general即可。")
|
||||
}
|
||||
putJsonObject("time_range") {
|
||||
put("type", "string")
|
||||
putJsonArray("enum") {
|
||||
add("day")
|
||||
add("month")
|
||||
add("year")
|
||||
}
|
||||
put("description", "可选择获取最新消息,例如day表示只查询最近一天相关信息,以此类推。")
|
||||
}
|
||||
}
|
||||
putJsonArray("required") {
|
||||
add("q")
|
||||
@@ -67,25 +41,17 @@ class WebSearch : BaseAgent(
|
||||
override suspend fun execute(args: JsonObject?): String {
|
||||
requireNotNull(args)
|
||||
val q = args.getValue("q").jsonPrimitive.content
|
||||
val categories = args["categories"]?.jsonArray
|
||||
val timeRange = args["time_range"]?.jsonPrimitive?.contentOrNull
|
||||
val response = httpClient.get(
|
||||
buildString {
|
||||
append(PluginConfig.searXngUrl)
|
||||
append("?q=")
|
||||
append(q.encodeURLParameter())
|
||||
append("&format=json")
|
||||
if (categories != null) {
|
||||
append("&")
|
||||
append(categories.joinToString { it.jsonPrimitive.content })
|
||||
}
|
||||
if (timeRange != null) {
|
||||
append("&")
|
||||
append(timeRange)
|
||||
}
|
||||
}
|
||||
)
|
||||
val url = buildString {
|
||||
append(PluginConfig.searXngUrl)
|
||||
append("?q=")
|
||||
append(q.encodeURLParameter())
|
||||
append("&format=json")
|
||||
}
|
||||
|
||||
val response = httpClient.get(url)
|
||||
JChatGPT.logger.info("Request: $url")
|
||||
val body = response.bodyAsText()
|
||||
JChatGPT.logger.info("Response: $body")
|
||||
val responseJsonElement = Json.parseToJsonElement(body)
|
||||
val filteredResponse = buildJsonObject {
|
||||
val root = responseJsonElement.jsonObject
|
||||
|
||||
Reference in New Issue
Block a user