Add files via upload
更新 ComfyUI-ModelScope-API 支持Qwen3-VL系列模型反推
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
{
|
||||
"id": "6d37ea84-d0ab-4123-8c8c-965b62a18230",
|
||||
"revision": 0,
|
||||
"last_node_id": 19,
|
||||
"last_link_id": 31,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 17,
|
||||
"type": "easy showAnything",
|
||||
"pos": [
|
||||
2732.3588101299074,
|
||||
397.60778722933657
|
||||
],
|
||||
"size": [
|
||||
482.4299999999994,
|
||||
553.9499999999997
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"label": "输入任何",
|
||||
"name": "anything",
|
||||
"shape": 7,
|
||||
"type": "*",
|
||||
"link": 31
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output",
|
||||
"type": "*",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfyui-easy-use",
|
||||
"ver": "1.3.3",
|
||||
"Node name for S&R": "easy showAnything"
|
||||
},
|
||||
"widgets_values": [
|
||||
"一位年轻美丽的亚洲女性,身着精致的淡紫色丝绸旗袍,旗袍上绣有金色祥云与花卉纹样,领口为高立领配盘扣设计,前襟开衩至大腿中部,展现优雅曲线。她佩戴半透明薄纱长袖,袖口拼接红色织锦并饰以金色龙纹刺绣,搭配同色系红色过膝袜。发型为古典盘发,插有金质流苏发簪与珠饰,刘海轻柔垂落,妆容精致,红唇微启,眼神温柔含情,直视镜头。背景为中式室内场景,墙面挂有水墨风格的山水或花鸟画作,色调柔和偏暖,营造静谧典雅氛围。整体构图采用中景人像视角,人物居中站立,略微侧身,突出服装细节与身材比例。光影柔和均匀,强调丝绸面料的光泽感与刺绣纹理,皮肤质感细腻光滑,呈现数字绘画的超写实美感。风格参考新中式美学与现代商业人像摄影,融合传统元素与时尚表现力,色彩主调为淡紫、金、红三色,辅以米白与浅棕背景,形成高级和谐的视觉层次。画面干净无杂物,焦点集中于人物神态与服饰工艺,适合用于AI绘图生成高质量东方美人肖像。"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
1869.8370214843746,
|
||||
350.8748266601562
|
||||
],
|
||||
"size": [
|
||||
290.8019714355469,
|
||||
570.7747192382812
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"label": "图像",
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
30
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "遮罩",
|
||||
"name": "MASK",
|
||||
"type": "MASK"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.49",
|
||||
"Node name for S&R": "LoadImage",
|
||||
"ue_properties": {
|
||||
"version": "7.0.1",
|
||||
"widget_ue_connectable": {
|
||||
"image": true,
|
||||
"upload": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"widgets_values": [
|
||||
"ebe510f1a069ba899eec0f82fefd3746d26f2f95ec2378a10ec1cd56cbc53642.png",
|
||||
"image"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"type": "ModelScopeImageCaptionNode",
|
||||
"pos": [
|
||||
2266.803982765229,
|
||||
414.0277931000381
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
214
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 30
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "description",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
31
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ModelScopeImageCaptionNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"***已保存1个Token***",
|
||||
"帮我拆解这张图片的提示词,要求从主体内容、场景设定、风格参考、色条色彩、构图视角、细节补充等这些角度来用文字描述图片,并汇总生成一个能让我用 ai绘画工具的文生图提示词,字数在 800 字以内,只要求输出汇总后的最终提示词,不需要无用信息。如:提示词标题,总字数等信息。",
|
||||
"Qwen/Qwen3-VL-235B-A22B-Instruct",
|
||||
1000,
|
||||
0.7
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
30,
|
||||
5,
|
||||
0,
|
||||
19,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
31,
|
||||
19,
|
||||
0,
|
||||
17,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"id": 2,
|
||||
"title": "魔搭-图片编辑",
|
||||
"bounding": [
|
||||
1663.396484375,
|
||||
122.82080078125,
|
||||
1826.526123046875,
|
||||
960.4658203125
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
}
|
||||
],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.620921323059155,
|
||||
"offset": [
|
||||
-1125.4324556670972,
|
||||
206.079530787193
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.30.1"
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
+16
-5
@@ -1,11 +1,22 @@
|
||||
# 原有导入
|
||||
from .modelscope_image_node import NODE_CLASS_MAPPINGS as IMAGE_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as IMAGE_DISPLAY_MAPPINGS
|
||||
from .modelscope_vision_node import NODE_CLASS_MAPPINGS as VISION_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as VISION_DISPLAY_MAPPINGS
|
||||
from .modelscope_text_node import NODE_CLASS_MAPPINGS as TEXT_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as TEXT_DISPLAY_MAPPINGS
|
||||
|
||||
NODE_CLASS_MAPPINGS = {**IMAGE_MAPPINGS, **VISION_MAPPINGS, **TEXT_MAPPINGS}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {**IMAGE_DISPLAY_MAPPINGS, **VISION_DISPLAY_MAPPINGS, **TEXT_DISPLAY_MAPPINGS}
|
||||
|
||||
|
||||
# 新增:导入图像描述节点的映射
|
||||
from .modelscope_image_caption_node import NODE_CLASS_MAPPINGS as IMAGE_CAPTION_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as IMAGE_CAPTION_DISPLAY_MAPPINGS
|
||||
|
||||
# 合并所有节点映射(包含新增的图像描述节点)
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
**IMAGE_MAPPINGS,** VISION_MAPPINGS,
|
||||
**TEXT_MAPPINGS,** IMAGE_CAPTION_MAPPINGS # 新增
|
||||
}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
**IMAGE_DISPLAY_MAPPINGS,** VISION_DISPLAY_MAPPINGS,
|
||||
**TEXT_DISPLAY_MAPPINGS,** IMAGE_CAPTION_DISPLAY_MAPPINGS # 新增
|
||||
}
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
|
||||
|
||||
WEB_DIRECTORY = "./js"
|
||||
__version__ = "1.0.0"
|
||||
@@ -0,0 +1,177 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
import os
|
||||
import base64
|
||||
import re
|
||||
from .modelscope_image_node import load_config, load_api_tokens, save_api_tokens, tensor_to_base64_url
|
||||
|
||||
# 检查openai库是否可用
|
||||
try:
|
||||
from openai import OpenAI
|
||||
OPENAI_AVAILABLE = True
|
||||
except ImportError:
|
||||
OPENAI_AVAILABLE = False
|
||||
|
||||
class ModelScopeImageCaptionNode:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
if not OPENAI_AVAILABLE:
|
||||
return {
|
||||
"required": {
|
||||
"error_message": ("STRING", {
|
||||
"default": "请先安装openai库: pip install openai",
|
||||
"multiline": True
|
||||
}),
|
||||
}
|
||||
}
|
||||
saved_tokens = load_api_tokens()
|
||||
# 定义支持的模型列表
|
||||
supported_models = [
|
||||
"Qwen/Qwen3-VL-8B-Instruct",
|
||||
"Qwen/Qwen3-VL-235B-A22B-Instruct"
|
||||
]
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"api_tokens": ("STRING", {
|
||||
"default": f"***已保存{len(saved_tokens)}个Token***" if saved_tokens else "",
|
||||
"placeholder": "请输入API Token(支持多个,用逗号/换行分隔)",
|
||||
"multiline": True
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"prompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": "详细描述这张图片的内容,包括主体、背景、颜色、风格等信息"
|
||||
}),
|
||||
# 添加模型下拉选择
|
||||
"model": (supported_models, {
|
||||
"default": "Qwen/Qwen3-VL-8B-Instruct" # 默认选中原模型
|
||||
}),
|
||||
"max_tokens": ("INT", {
|
||||
"default": 1000,
|
||||
"min": 100,
|
||||
"max": 4000
|
||||
}),
|
||||
"temperature": ("FLOAT", {
|
||||
"default": 0.7,
|
||||
"min": 0.1,
|
||||
"max": 2.0,
|
||||
"step": 0.1
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("description",)
|
||||
FUNCTION = "generate_caption"
|
||||
CATEGORY = "ModelScopeAPI"
|
||||
|
||||
def parse_api_tokens(self, token_input):
|
||||
"""解析输入的多个API Token(支持逗号、分号、换行分隔)"""
|
||||
if not token_input or token_input.strip() in ["", f"***已保存{len(load_api_tokens())}个Token***"]:
|
||||
return load_api_tokens()
|
||||
|
||||
# 支持多种分隔符拆分Token
|
||||
tokens = re.split(r'[,;\n]+', token_input)
|
||||
return [token.strip() for token in tokens if token.strip()]
|
||||
|
||||
# 调整参数顺序,加入model参数(与INPUT_TYPES顺序匹配)
|
||||
def generate_caption(self, image=None, api_tokens="", prompt="详细描述这张图片的内容", model="Qwen/Qwen3-VL-8B-Instruct", max_tokens=1000, temperature=0.7):
|
||||
if not OPENAI_AVAILABLE:
|
||||
return ("请先安装openai库: pip install openai",)
|
||||
|
||||
# 解析Token列表(支持多个)
|
||||
tokens = self.parse_api_tokens(api_tokens)
|
||||
if not tokens:
|
||||
raise Exception("请提供至少一个有效的API Token")
|
||||
|
||||
# 保存新Token(如果有变化)
|
||||
saved_tokens = load_api_tokens()
|
||||
if api_tokens.strip() not in ["", f"***已保存{len(saved_tokens)}个Token***"]:
|
||||
if save_api_tokens(tokens):
|
||||
print(f"✅ 已保存 {len(tokens)} 个API Token")
|
||||
else:
|
||||
print("⚠️ API Token保存失败,但不影响当前使用")
|
||||
|
||||
try:
|
||||
print(f"🔍 开始生成图像描述...")
|
||||
print(f"📝 提示词: {prompt}")
|
||||
print(f"🤖 模型: {model}") # 显示选中的模型
|
||||
print(f"🔑 可用Token数量: {len(tokens)}")
|
||||
|
||||
# 转换图像为base64格式
|
||||
image_url = tensor_to_base64_url(image)
|
||||
print(f"🖼️ 图像已转换为base64格式")
|
||||
|
||||
# 构建消息体
|
||||
messages = [{
|
||||
'role': 'user',
|
||||
'content': [{
|
||||
'type': 'text',
|
||||
'text': prompt,
|
||||
}, {
|
||||
'type': 'image_url',
|
||||
'image_url': {
|
||||
'url': image_url,
|
||||
},
|
||||
}],
|
||||
}]
|
||||
|
||||
# 轮询尝试每个Token
|
||||
last_exception = None
|
||||
for i, token in enumerate(tokens):
|
||||
try:
|
||||
print(f"🔄 尝试使用第 {i+1}/{len(tokens)} 个Token...")
|
||||
|
||||
# 初始化OpenAI客户端
|
||||
client = OpenAI(
|
||||
base_url='https://api-inference.modelscope.cn/v1',
|
||||
api_key=token
|
||||
)
|
||||
|
||||
# 调用API(使用选中的模型)
|
||||
response = client.chat.completions.create(
|
||||
model=model,
|
||||
messages=messages,
|
||||
max_tokens=max_tokens,
|
||||
temperature=temperature,
|
||||
stream=False
|
||||
)
|
||||
|
||||
# 成功获取结果
|
||||
description = response.choices[0].message.content
|
||||
print(f"✅ 第 {i+1} 个Token调用成功!")
|
||||
print(f"📄 结果预览: {description[:100]}...")
|
||||
return (description,)
|
||||
|
||||
except Exception as e:
|
||||
last_exception = e
|
||||
print(f"❌ 第 {i+1} 个Token调用失败: {str(e)}")
|
||||
if i < len(tokens) - 1:
|
||||
print(f"⏳ 准备尝试下一个Token...")
|
||||
|
||||
# 所有Token都失败
|
||||
raise Exception(f"所有Token均调用失败: {str(last_exception)}")
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"图像描述生成失败: {str(e)}"
|
||||
print(f"❌ {error_msg}")
|
||||
return (error_msg,)
|
||||
|
||||
# 节点映射
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ModelScopeImageCaptionNode": ModelScopeImageCaptionNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ModelScopeImageCaptionNode": "ModelScope 图像描述生成"
|
||||
}
|
||||
Reference in New Issue
Block a user