Add files via upload

This commit is contained in:
yunxiang wei
2024-07-26 22:28:33 +08:00
committed by GitHub
parent 1f8286a32f
commit 0dd77f33ea
6 changed files with 558 additions and 15 deletions
+16 -15
View File
@@ -1,29 +1,30 @@
from .groqchat import NODE_CLASS_MAPPINGS as GROQ_CLASS_MAPPINGS
from .groqchat import NODE_DISPLAY_NAME_MAPPINGS as GROQ_DISPLAY_MAPPINGS
from .moonshot_chat_nodes import NODE_CLASS_MAPPINGS as MOONSHOT_CLASS_MAPPINGS
from .moonshot_chat_nodes import NODE_DISPLAY_NAME_MAPPINGS as MOONSHOT_DISPLAY_MAPPINGS
from .SD3LongCaptioner_v2 import NODE_CLASS_MAPPINGS as SD3_V2_CLASS_MAPPINGS
from .SD3LongCaptioner_v2 import NODE_DISPLAY_NAME_MAPPINGS as SD3_V2_DISPLAY_MAPPINGS
from .file_based_chat import NODE_CLASS_MAPPINGS as FILE_CHAT_CLASS_MAPPINGS
from .file_based_chat import NODE_DISPLAY_NAME_MAPPINGS as FILE_CHAT_DISPLAY_MAPPINGS
from .dwimage2 import NODE_CLASS_MAPPINGS as MOONDREAM2_V2_NODE_CLASS_MAPPINGS
from .dwimage2 import NODE_DISPLAY_NAME_MAPPINGS as MOONDREAM2_V2_NODE_DISPLAY_NAME_MAPPINGS
from .nodes.groqchat import NODE_CLASS_MAPPINGS as GROQ_CLASS_MAPPINGS
from .nodes.groqchat import NODE_DISPLAY_NAME_MAPPINGS as GROQ_DISPLAY_MAPPINGS
from .nodes.moonshot_chat_nodes import NODE_CLASS_MAPPINGS as MOONSHOT_CLASS_MAPPINGS
from .nodes.moonshot_chat_nodes import NODE_DISPLAY_NAME_MAPPINGS as MOONSHOT_DISPLAY_MAPPINGS
from .nodes.SD3LongCaptioner_v2 import NODE_CLASS_MAPPINGS as SD3_V2_CLASS_MAPPINGS
from .nodes.SD3LongCaptioner_v2 import NODE_DISPLAY_NAME_MAPPINGS as SD3_V2_DISPLAY_MAPPINGS
from .nodes.file_based_chat import NODE_CLASS_MAPPINGS as FILE_CHAT_CLASS_MAPPINGS
from .nodes.file_based_chat import NODE_DISPLAY_NAME_MAPPINGS as FILE_CHAT_DISPLAY_MAPPINGS
from .nodes.dwimage2 import NODE_CLASS_MAPPINGS as MOONDREAM2_V2_NODE_CLASS_MAPPINGS
from .nodes.dwimage2 import NODE_DISPLAY_NAME_MAPPINGS as MOONDREAM2_V2_NODE_DISPLAY_NAME_MAPPINGS
NODE_CLASS_MAPPINGS = {
**GROQ_CLASS_MAPPINGS,
**MOONSHOT_CLASS_MAPPINGS,
**SD3_V2_CLASS_MAPPINGS,
**FILE_CHAT_CLASS_MAPPINGS
**MOONDREAM2_V2_NODE_CLASS_MAPPINGS
**FILE_CHAT_CLASS_MAPPINGS,
**MOONDREAM2_V2_NODE_CLASS_MAPPINGS,
}
NODE_DISPLAY_NAME_MAPPINGS = {
**GROQ_DISPLAY_MAPPINGS,
**MOONSHOT_DISPLAY_MAPPINGS,
**SD3_V2_DISPLAY_MAPPINGS,
**FILE_CHAT_DISPLAY_MAPPINGS
**MOONDREAM2_V2_NODE_DISPLAY_NAME_MAPPINGS
**FILE_CHAT_DISPLAY_MAPPINGS,
**MOONDREAM2_V2_NODE_DISPLAY_NAME_MAPPINGS,
}
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
+93
View File
@@ -0,0 +1,93 @@
import os
from pathlib import Path
import torch
from PIL import Image
from torchvision.transforms import ToPILImage
from transformers import AutoProcessor, AutoModelForVision2Seq
import folder_paths
from huggingface_hub import snapshot_download
import gc
# 定义模型文件存储目录
files_for_sd3_long_captioner_v2 = Path(os.path.join(folder_paths.models_dir, "LLavacheckpoints", "files_for_sd3_long_captioner_v2"))
files_for_sd3_long_captioner_v2.mkdir(parents=True, exist_ok=True)
class SD3LongCaptionerV2:
def __init__(self):
self.model_id = "gokaygokay/sd3-long-captioner-v2"
self.device = "cuda" if torch.cuda.is_available() else "cpu"
self.model = None
self.processor = None
def load_model(self):
if self.model is None or self.processor is None:
self.model_path = snapshot_download(self.model_id,
local_dir=files_for_sd3_long_captioner_v2,
force_download=False,
local_files_only=False,
local_dir_use_symlinks="auto")
self.model = AutoModelForVision2Seq.from_pretrained(self.model_path).to(self.device).eval()
self.processor = AutoProcessor.from_pretrained(self.model_path)
def clear_memory(self):
# 清理内存
if self.model is not None:
del self.model
self.model = None
if self.processor is not None:
del self.processor
self.processor = None
gc.collect()
if torch.cuda.is_available():
torch.cuda.empty_cache()
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"prompt": ("STRING", {"multiline": False, "default": "Describe in detail what's in this image."}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("caption",)
FUNCTION = "generate_caption"
CATEGORY = "🌙DW/SD3LongCaptionerV2"
def generate_caption(self, image, prompt):
self.load_model() # 确保模型已加载
# 将图像张量转换为PIL图像
pil_image = ToPILImage()(image[0].permute(2, 0, 1))
# 处理图像和提示
model_inputs = self.processor(text=prompt, images=pil_image, return_tensors="pt").to(self.device)
# 生成描述
with torch.inference_mode():
generation = self.model.generate(
**model_inputs,
repetition_penalty=1.05,
max_new_tokens=512,
do_sample=False
)
# 解码生成的文本
decoded = self.processor.decode(generation[0], skip_special_tokens=True)
# 移除开头的提示词(如果存在)
decoded = decoded.replace(prompt, "", 1).strip()
# 清理内存
self.clear_memory()
return (decoded,)
NODE_CLASS_MAPPINGS = {
"SD3LongCaptionerV2": SD3LongCaptionerV2
}
NODE_DISPLAY_NAME_MAPPINGS = {
"SD3LongCaptionerV2": "SD3 Long Captioner V2"
}
+96
View File
@@ -0,0 +1,96 @@
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from PIL import Image
from pathlib import Path
import folder_paths
import os
import shutil
import re
from torchvision.transforms import ToPILImage
# 定义模型存储目录
models_dir = Path(folder_paths.base_path) / "models"
llava_checkpoints_dir = models_dir / "LLavacheckpoints"
files_for_moondream2 = llava_checkpoints_dir / "files_for_moondream2"
files_for_moondream2.mkdir(parents=True, exist_ok=True)
class Moondream2Predictor:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(Moondream2Predictor, cls).__new__(cls)
cls._instance.model = None
cls._instance.tokenizer = None
return cls._instance
def load_model(self):
if self.model is None:
self.device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"使用设备: {self.device}")
print("加载模型中...")
self.model = AutoModelForCausalLM.from_pretrained(files_for_moondream2, trust_remote_code=True).to(self.device)
self.tokenizer = AutoTokenizer.from_pretrained(files_for_moondream2)
print("模型加载成功")
def generate_predictions(self, image_path, question):
self.load_model() # 确保模型已加载
try:
image_input = Image.open(image_path).convert("RGB")
enc_image = self.model.encode_image(image_input)
generated_text = self.model.answer_question(enc_image, question, self.tokenizer)
return generated_text
finally:
if os.path.exists(image_path):
os.remove(image_path)
def clear_memory(self):
if self.model:
del self.model
del self.tokenizer
self.model = None
self.tokenizer = None
torch.cuda.empty_cache()
print("模型已卸载,内存已清理")
class Moondream2model:
def __init__(self):
self.predictor = Moondream2Predictor()
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"text_input": ("STRING", {"multiline": True, "default": ""}),
},
}
RETURN_TYPES = ("STRING",)
FUNCTION = "moondream2_generate_predictions"
CATEGORY = "🌙DW/dwimage2"
def moondream2_generate_predictions(self, image, text_input):
try:
pil_image = ToPILImage()(image[0].permute(2, 0, 1))
temp_path = files_for_moondream2 / "temp_image.png"
pil_image.save(temp_path)
response = self.predictor.generate_predictions(temp_path, text_input)
response = ' '.join(response.strip().split())
# 使用正则表达式移除开头的特定短语
response = re.sub(r'^(The image contains|The image contains|This picture contains|This picture contains|The image contains|The image contains|This image contains|This image contains)\s*', '', response, flags=re.IGNORECASE)
return (response,)
finally:
# 确保在函数结束时卸载模型
self.predictor.clear_memory()
NODE_CLASS_MAPPINGS = {
"dwimage2": Moondream2model
}
NODE_DISPLAY_NAME_MAPPINGS = {
"dwimage2": "DW Image2 Chat"
}
+158
View File
@@ -0,0 +1,158 @@
import os
import json
from typing import List, Dict, Any, Optional
from pathlib import Path
import httpx
from openai import OpenAI
class FileBasedChatNode:
def __init__(self):
self.config = self.load_config()
self.client = OpenAI(
base_url="https://api.moonshot.cn/v1",
api_key=self.config.get("MOONSHOT_API_KEY"),
)
self.file_messages = []
self.conversation_history = []
self.cache_tag = None
def load_config(self):
config_path = Path(__file__).parent / "config.json"
if config_path.exists():
with open(config_path, "r") as f:
return json.load(f)
else:
raise FileNotFoundError(f"Config file not found: {config_path}")
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"file_paths": ("STRING", {"multiline": True}),
"user_input": ("STRING", {"multiline": True}),
"use_cache": ("BOOLEAN", {"default": True}),
"cache_tag": ("STRING", {"default": "file_cache"}),
"ttl": ("INT", {"default": 300, "min": 60, "max": 3600})
}
}
RETURN_TYPES = ("STRING",)
FUNCTION = "chat"
CATEGORY = "🌙DW/fileBaseChat"
def upload_files(self, files: List[str]) -> List[Dict[str, Any]]:
messages = []
for file in files:
try:
with open(file, 'rb') as f:
response = httpx.post(
f"{self.client.base_url}/files",
headers={"Authorization": f"Bearer {self.client.api_key}"},
files={"file": f},
data={"purpose": "assistants"}
)
response.raise_for_status()
file_id = response.json()['id']
# 获取文件内容
content_response = httpx.get(
f"{self.client.base_url}/files/{file_id}/content",
headers={"Authorization": f"Bearer {self.client.api_key}"}
)
content_response.raise_for_status()
file_content = content_response.text
messages.append({
"role": "system",
"content": file_content,
})
except Exception as e:
print(f"Error uploading file {file}: {e}")
continue
return messages
def chat(self, file_paths, user_input, use_cache, cache_tag, ttl):
if not self.file_messages:
files = file_paths.split('\n')
self.file_messages = self.upload_files(files=files)
messages = [
*self.file_messages,
{
"role": "system",
"content": "你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。"
"你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,"
"种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。",
},
*self.conversation_history,
{
"role": "user",
"content": user_input,
}
]
try:
if use_cache:
cache_response = self.get_cache(cache_tag)
if cache_response:
return (cache_response,)
completion = self.client.chat.completions.create(
model="moonshot-v1-8k",
messages=messages,
)
assistant_response = completion.choices[0].message.content
self.conversation_history.extend([
{"role": "user", "content": user_input},
{"role": "assistant", "content": assistant_response}
])
if use_cache:
self.set_cache(cache_tag, assistant_response, ttl)
return (assistant_response,)
except Exception as e:
error_message = f"An error occurred: {str(e)}"
print(error_message)
return (error_message,)
def get_cache(self, cache_tag):
try:
response = httpx.get(
f"{self.client.base_url}/caching",
headers={"Authorization": f"Bearer {self.client.api_key}"},
params={"tags": cache_tag}
)
response.raise_for_status()
cache_data = response.json()
if cache_data and cache_data.get('data'):
return cache_data['data'][0]['content']
except Exception as e:
print(f"Error getting cache: {e}")
return None
def set_cache(self, cache_tag, content, ttl):
try:
response = httpx.post(
f"{self.client.base_url}/caching",
headers={"Authorization": f"Bearer {self.client.api_key}"},
json={
"tags": [cache_tag],
"content": content,
"ttl": ttl
}
)
response.raise_for_status()
except Exception as e:
print(f"Error setting cache: {e}")
# 在 ComfyUI 的节点定义文件中注册这个新节点
NODE_CLASS_MAPPINGS = {
"FileBasedChatNode": FileBasedChatNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"FileBasedChatNode": "File-based Chat"
}
+75
View File
@@ -0,0 +1,75 @@
import os
import json
from groq import Groq
class GroqChatNode:
def __init__(self):
self.client = None
self.load_api_key()
def load_api_key(self):
config_path = os.path.join(os.path.dirname(__file__), 'config.json')
try:
with open(config_path, 'r') as config_file:
config = json.load(config_file)
api_key = config.get('GROQ_API_KEY')
if api_key:
self.client = Groq(api_key=api_key)
else:
print("Error: GROQ_API_KEY not found in config.json")
except FileNotFoundError:
print(f"Error: config.json not found at {config_path}")
except json.JSONDecodeError:
print(f"Error: Invalid JSON in config.json at {config_path}")
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"model": (["gemma-7b-it", "llama3-70b-8192", "mixtral-8x7b-32768", "llama3-8b-8192", "llama-3.1-8b-versatile", "llama-3.1-70b-versatile"],),
"prompt": ("STRING", {"multiline": True}),
"max_tokens": ("INT", {"default": 1000, "min": 1, "max": 32768}),
"temperature": ("FLOAT", {"default": 0.7, "min": 0, "max": 2, "step": 0.1}),
"top_p": ("FLOAT", {"default": 1.0, "min": 0, "max": 1, "step": 0.1}),
},
"optional": {
"system_message": ("STRING", {"multiline": True}),
"presence_penalty": ("FLOAT", {"default": 0, "min": -2, "max": 2, "step": 0.1}),
"frequency_penalty": ("FLOAT", {"default": 0, "min": -2, "max": 2, "step": 0.1}),
}
}
RETURN_TYPES = ("STRING",)
FUNCTION = "generate_text"
CATEGORY = "🌙DW/groqchat"
def generate_text(self, model, prompt, max_tokens, temperature, top_p, system_message="", presence_penalty=0, frequency_penalty=0):
if not self.client:
return ("Error: GROQ_API_KEY not set or invalid. Please check your config.json file.",)
messages = []
if system_message:
messages.append({"role": "system", "content": system_message})
messages.append({"role": "user", "content": prompt})
try:
chat_completion = self.client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
temperature=temperature,
top_p=top_p,
presence_penalty=presence_penalty,
frequency_penalty=frequency_penalty
)
return (chat_completion.choices[0].message.content,)
except Exception as e:
return (f"Error: {str(e)}",)
NODE_CLASS_MAPPINGS = {
"GroqChatNode": GroqChatNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"GroqChatNode": "Groq Chat"
}
+120
View File
@@ -0,0 +1,120 @@
import os
import json
from openai import OpenAI
def get_moonshot_api_key():
try:
config_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config.json')
with open(config_path, 'r') as f:
config = json.load(f)
api_key = config["MOONSHOT_API_KEY"]
except:
print("出错啦 Error: API key is required")
return ""
return api_key
class MoonshotChatBaseNode:
def __init__(self):
self.client = None
self.api_key = get_moonshot_api_key()
if self.api_key:
self.client = OpenAI(api_key=self.api_key, base_url="https://api.moonshot.cn/v1")
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"prompt": ("STRING", {"multiline": True}),
"model": (["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],),
"temperature": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 2.0, "step": 0.1}),
"max_tokens": ("INT", {"default": 1000, "min": 1, "max": 128000}),
},
"optional": {
"system_message": ("STRING", {"multiline": True}),
}
}
RETURN_TYPES = ("STRING",)
class MoonshotSingleChatNode(MoonshotChatBaseNode):
FUNCTION = "generate_single_response"
RETURN_NAMES = ("response",)
def generate_single_response(self, prompt, model, temperature, max_tokens, system_message=""):
if not self.client:
return ("Error: MOONSHOT_API_KEY not set or invalid. Please check your config.json file.",)
messages = []
if system_message:
messages.append({"role": "system", "content": system_message})
messages.append({"role": "user", "content": prompt})
try:
completion = self.client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
)
return (completion.choices[0].message.content,)
except Exception as e:
return (f"Error: {str(e)}",)
class MoonshotMultiChatNode(MoonshotChatBaseNode):
FUNCTION = "generate_chat"
RETURN_NAMES = ("chat_history",)
CATEGORY = "🌙DW/moonshotChat"
def __init__(self):
super().__init__()
self.conversation_history = []
@classmethod
def INPUT_TYPES(cls):
input_types = super().INPUT_TYPES()
input_types["optional"]["reset_conversation"] = ("BOOLEAN", {"default": False})
return input_types
def generate_chat(self, prompt, model, temperature, max_tokens, system_message="", reset_conversation=False):
if not self.client:
return ("Error: MOONSHOT_API_KEY not set or invalid. Please check your config.json file.",)
if reset_conversation:
self.conversation_history = []
if not self.conversation_history and system_message:
self.conversation_history.append({"role": "system", "content": system_message})
self.conversation_history.append({"role": "user", "content": prompt})
try:
completion = self.client.chat.completions.create(
model=model,
messages=self.conversation_history,
temperature=temperature,
max_tokens=max_tokens,
)
response = completion.choices[0].message.content
self.conversation_history.append({"role": "assistant", "content": response})
chat_history = self.format_chat_history()
return (chat_history,)
except Exception as e:
return (f"Error: {str(e)}",)
def format_chat_history(self):
formatted_history = []
for message in self.conversation_history:
formatted_message = f"{message['role']}: {message['content']}"
formatted_history.append(formatted_message)
formatted_history.append("-" * 40) # 添加分隔线
return "\n".join(formatted_history)
NODE_CLASS_MAPPINGS = {
"MoonshotSingleChatNode": MoonshotSingleChatNode,
"MoonshotMultiChatNode": MoonshotMultiChatNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"MoonshotSingleChatNode": "🌙Moonshot Single Chat",
"MoonshotMultiChatNode": "🌙Moonshot Multi Chat"
}