diff --git a/README.md b/README.md index 7463b79..e138e21 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,10 @@ reasoningModelExtraBody: '' visualModelExtraBody: '' # 百炼平台API KEY dashScopeApiKey: '' -# 百炼平台图片编辑模型 -imageEditModel: 'qwen-image-edit' +# 百炼平台图像模型(文生图 + 图像编辑) +imageModel: 'qwen-image-2.0' +# 是否在生成图片右下角添加 Qwen-Image 水印 +imageWatermark: false # 百炼平台TTS模型 ttsModel: 'qwen-tts' # Jina API Key @@ -280,7 +282,7 @@ JChatGPT 默认配置为使用阿里云百炼平台的通义千问系列模型 6. **GroupManageAgent** - 群管理功能(如禁言) 7. **SendSingleMessage/CompositeMessage** - 发送消息 8. **SendVoiceMessage** - 发送语音消息 -9. **ImageEdit** - 图像编辑 +9. **ImageAgent** - 图像生成与编辑(文生图、单图编辑、多图融合) 10. **WeatherService** - 天气查询 11. **SearchChatHistory** - 按关键词、发送者、时间范围搜索群聊消息历史(依赖 mirai-hibernate-plugin) diff --git a/src/main/kotlin/JChatGPT.kt b/src/main/kotlin/JChatGPT.kt index b3562c5..a330ad6 100644 --- a/src/main/kotlin/JChatGPT.kt +++ b/src/main/kotlin/JChatGPT.kt @@ -848,8 +848,8 @@ object JChatGPT : KotlinPlugin( // 视觉代理 VisualAgent(), - // 图像编辑模型 - ImageEdit(), + // 图像生成与编辑 + ImageAgent(), // 天气服务 WeatherService(), diff --git a/src/main/kotlin/PluginConfig.kt b/src/main/kotlin/PluginConfig.kt index 26fab94..3430793 100644 --- a/src/main/kotlin/PluginConfig.kt +++ b/src/main/kotlin/PluginConfig.kt @@ -50,8 +50,11 @@ object PluginConfig : AutoSavePluginConfig("Config") { @ValueDescription("百炼平台API KEY") val dashScopeApiKey: String by value("") - @ValueDescription("百炼平台图片编辑模型") - val imageEditModel: String by value("qwen-image-edit") + @ValueDescription("百炼平台图像模型,支持文生图与图像编辑。可选:qwen-image-2.0 / qwen-image-2.0-pro / qwen-image-edit-max / qwen-image-edit-plus 等") + val imageModel: String by value("qwen-image-2.0") + + @ValueDescription("是否在生成的图片右下角添加 Qwen-Image 水印") + val imageWatermark: Boolean by value(false) @ValueDescription("百炼平台TTS模型") val ttsModel: String by value("qwen-tts") diff --git a/src/main/kotlin/tools/ImageEdit.kt b/src/main/kotlin/tools/ImageAgent.kt similarity index 62% rename from src/main/kotlin/tools/ImageEdit.kt rename to src/main/kotlin/tools/ImageAgent.kt index e788eb4..d43b59e 100644 --- a/src/main/kotlin/tools/ImageEdit.kt +++ b/src/main/kotlin/tools/ImageAgent.kt @@ -22,29 +22,30 @@ import kotlinx.serialization.json.putJsonObject import top.jie65535.mirai.JChatGPT import top.jie65535.mirai.PluginConfig -class ImageEdit : BaseAgent( +class ImageAgent : BaseAgent( tool = Tool.function( - name = "imageEdit", - description = "可通过调用图像编辑模型来修改图片。备注:该方法成本较高,非必要尽量不要调用。编辑图片前无需识别图片内容,图像编辑模型自己会理解图片内容!", + name = "imageAgent", + description = "调用千问图像模型生成或编辑图片。不传 image_urls 即纯文生图;" + + "传 1~3 张图片可进行编辑、修改或多图融合。" + + "备注:该方法成本较高,非必要尽量不要调用。" + + "编辑图片前无需识别图片内容,模型自己会理解图片内容。", parameters = Parameters.buildJsonObject { put("type", "object") putJsonObject("properties") { - putJsonObject("image_url") { - put("type", "string") - put("description", "原始图片地址") + putJsonObject("image_urls") { + put("type", "array") + putJsonObject("items") { + put("type", "string") + } + put("description", "参考图片地址列表,可传 0~3 张。" + + "不传或为空即纯文生图;传 1 张为编辑;多张为融合,输出比例与最后一张对齐。") } putJsonObject("prompt") { put("type", "string") - put("description", "正向提示词,用来描述需要对图片进行修改的要求。") + put("description", "提示词,描述期望生成或修改的画面内容。") } -// putJsonObject("negative_prompt") { -// put("type", "string") -// put("description", "反向提示词,用来描述不希望在画面中看到的内容,可以对画面进行限制。" + -// "示例值:低分辨率、错误、最差质量、低质量、残缺、多余的手指、比例不良等。") -// } } putJsonArray("required") { - add("image_url") add("prompt") } } @@ -58,25 +59,29 @@ 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 imageUrls = args["image_urls"]?.jsonArray + ?.map { it.jsonPrimitive.content } + ?: emptyList() + val response = httpClient.post(API_URL) { contentType(ContentType("application", "json")) header("Authorization", "Bearer " + PluginConfig.dashScopeApiKey) setBody(buildJsonObject { - put("model", PluginConfig.imageEditModel) + put("model", PluginConfig.imageModel) putJsonObject("input") { putJsonArray("messages") { addJsonObject { put("role", "user") putJsonArray("content") { - addJsonObject { - put("image", imageUrl) + for (url in imageUrls) { + addJsonObject { + put("image", url) + } } addJsonObject { put("text", prompt) @@ -85,11 +90,11 @@ class ImageEdit : BaseAgent( } } } -// if (negativePrompt != null) { -// putJsonObject("parameters") { -// put("negative_prompt", negativePrompt) -// } -// } + putJsonObject("parameters") { + put("n", 1) + put("prompt_extend", true) + put("watermark", PluginConfig.imageWatermark) + } }.toString()) } @@ -102,10 +107,10 @@ class ImageEdit : BaseAgent( .getValue("message").jsonObject .getValue("content").jsonArray[0].jsonObject .getValue("image").jsonPrimitive.content - "图片已编辑完成,发送时请务必包含完整的url和查询参数,因为下载地址存在鉴权:![图片]($url)" + "图片已生成,发送时请务必包含完整的url和查询参数,因为下载地址存在鉴权:![图片]($url)" } catch (e: Throwable) { - JChatGPT.logger.error("图像编辑结果解析异常", e) + JChatGPT.logger.error("图像生成结果解析异常", e) responseJson } } -} \ No newline at end of file +}