14 KiB
14 KiB
Documentation
- Class name: IF_PromptMkr
- Category: ImpactFrames💥🎞️
- Output node: False
- Repo Ref: https://github.com/ImACodeLearner/ComfyUI-IMPACT-PACK
IF_PromptMkr节点旨在将输入的提示转化为更详细或风格化的提示,利用各种人工智能引擎和自定义选项。它根据用户定义的参数,通过添加修饰、风格或否定来丰富原始提示,目的是为创意或分析应用生成更具影响力和上下文丰富的提示。
Input types
Required
- input_prompt
- 用户提供的初始提示,作为进一步修饰或修改的基础。它对定义生成输出的主题方向至关重要。
- Comfy dtype: STRING
- Python dtype: str
- base_ip
- 指定人工智能引擎API的基本IP地址,决定提示转换请求的发送目标。
- Comfy dtype: STRING
- Python dtype: str
- port
- 与基本IP一起使用的端口号,用于访问人工智能引擎的API。
- Comfy dtype: STRING
- Python dtype: str
- engine
- 选择用于处理输入提示的人工智能引擎(如ollama、openai、anthropic),影响生成输出的风格和功能。
- Comfy dtype: COMBO[STRING]
- Python dtype: list[str]
- selected_model
- 用于生成输出的具体模型,取决于所选引擎和可用模型。
- Comfy dtype: []
- Python dtype: tuple
- profile
- 预定义的参数集或"配置文件",影响生成过程,如语气或复杂度。
- Comfy dtype: COMBO[STRING]
- Python dtype: list[str]
- embellish_prompt
- 可选参数,用于为输入提示添加额外的描述元素,增强其细节或主题深度。
- Comfy dtype: COMBO[STRING]
- Python dtype: list[str]
- style_prompt
- 可选参数,用于对输入提示应用特定的风格或语气,改变其呈现方式或叙述声音。
- Comfy dtype: COMBO[STRING]
- Python dtype: list[str]
- neg_prompt
- 可选参数,用于引入否定或约束到输入提示中,引导生成远离某些主题或概念。
- Comfy dtype: COMBO[STRING]
- Python dtype: list[str]
- temperature
- 控制生成输出的创造性或随机性,较高的值允许更多样化的响应。
- Comfy dtype: FLOAT
- Python dtype: float
Optional
- max_tokens
- 生成输出可包含的最大标记(单词或字符)数量,设定其长度限制。
- Comfy dtype: INT
- Python dtype: int
- seed
- 随机数生成器的种子值,设置时确保生成输出的可重复性。
- Comfy dtype: INT
- Python dtype: int
- random
- 布尔参数,为真时使用随机种子进行生成,否则使用固定的温度设置。
- Comfy dtype: BOOLEAN
- Python dtype: bool
- keep_alive
- 决定AI模型在生成后是否保持加载状态,影响响应时间和资源使用。
- Comfy dtype: BOOLEAN
- Python dtype: bool
Output types
- Question
- Comfy dtype: STRING
- 原始输入提示,作为输出的一部分不变返回。
- Python dtype: str
- Response
- Comfy dtype: STRING
- 基于输入提示和自定义选项生成的丰富或风格化的提示。
- Python dtype: str
- Negative
- Comfy dtype: STRING
- 基于neg_prompt参数生成的带有否定或约束的提示。
- Python dtype: str
Usage tips
- Infra type:
CPU - Common nodes: unknown
Source code
class IFPrompt2Prompt:
RETURN_TYPES = ("STRING", "STRING", "STRING",)
RETURN_NAMES = ("Question", "Response", "Negative",)
FUNCTION = "sample"
OUTPUT_NODE = False
CATEGORY = "ImpactFrames💥🎞️"
@classmethod
def INPUT_TYPES(cls):
node = cls()
return {
"required": {
"input_prompt": ("STRING", {"multiline": True, "default": "Ancient mega-structure, small lone figure in the foreground"}),
"base_ip": ("STRING", {"default": node.base_ip}),
"port": ("STRING", {"default": node.port}),
"engine": (["ollama", "openai", "anthropic"], {"default": node.engine}),
#"selected_model": (node.get_models("node.engine", node.base_ip, node.port), {}),
"selected_model": ((), {}),
"profile": ([name for name in node.profiles.keys()], {"default": node.profile}),
"embellish_prompt": ([name for name in node.embellish_prompts.keys()], {}),
"style_prompt": ([name for name in node.style_prompts.keys()], {}),
"neg_prompt": ([name for name in node.neg_prompts.keys()], {}),
"temperature": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.1}),
},
"optional": {
"max_tokens": ("INT", {"default": 256, "min": 1, "max": 8192}),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"random": ("BOOLEAN", {"default": False, "label_on": "Seed", "label_off": "Temperature"}),
"keep_alive": ("BOOLEAN", {"default": False, "label_on": "Keeps_Model", "label_off": "Unloads_Model"}),
},
"hidden": {
"model": ("STRING", {"default": ""}),
},
}
@classmethod
def IS_CHANGED(cls, engine, base_ip, port, profile, keep_alive):
node = cls()
if engine != node.engine or base_ip != node.base_ip or port != node.port or node.selected_model != node.get_models(engine, base_ip, port) or keep_alive != node.keep_alive:
node.engine = engine
node.base_ip = base_ip
node.port = port
node.selected_model = node.get_models(engine, base_ip, port)
node.profile = profile
node.keep_alive = keep_alive
return True
return False
def __init__(self):
self.base_ip = "localhost"
self.port = "11434"
self.engine = "ollama"
self.selected_model = ""
self.profile = "IF_PromptMKR"
self.comfy_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
self.presets_dir = os.path.join(os.path.dirname(__file__), "presets")
self.profiles_file = os.path.join(self.presets_dir, "profiles.json")
self.profiles = self.load_presets(self.profiles_file)
self.neg_prompts_file = os.path.join(self.presets_dir, "neg_prompts.json")
self.embellish_prompts_file = os.path.join(self.presets_dir, "embellishments.json")
self.style_prompts_file = os.path.join(self.presets_dir, "style_prompts.json")
self.neg_prompts = self.load_presets(self.neg_prompts_file)
self.embellish_prompts = self.load_presets(self.embellish_prompts_file)
self.style_prompts = self.load_presets(self.style_prompts_file)
def load_presets(self, file_path):
with open(file_path, 'r') as f:
presets = json.load(f)
return presets
def get_api_key(self, api_key_name, engine):
if engine != "ollama":
api_key = os.getenv(api_key_name)
if api_key:
return api_key
else:
print(f'you are using ollama as the engine, no api key is required')
def get_models(self, engine, base_ip, port):
if engine == "ollama":
api_url = f'http://{base_ip}:{port}/api/tags'
try:
response = requests.get(api_url)
response.raise_for_status()
models = [model['name'] for model in response.json().get('models', [])]
return models
except Exception as e:
print(f"Failed to fetch models from Ollama: {e}")
return []
elif engine == "anthropic":
return ["claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307"]
elif engine == "openai":
return ["gpt-4-0125-preview", "gpt-4-1106-preview", "gpt-4-vision-preview", "gpt-4-1106-vision-preview", "gpt-3.5-turbo-0125", "gpt-3.5-turbo-1106"]
else:
print(f"Unsupported engine - {engine}")
return []
def sample(self, input_prompt, engine, base_ip, port, selected_model, embellish_prompt, style_prompt, neg_prompt, temperature, max_tokens, seed, random, keep_alive, profile):
embellish_content = self.embellish_prompts.get(embellish_prompt, "")
style_content = self.style_prompts.get(style_prompt, "")
neg_content = self.neg_prompts.get(neg_prompt, "")
profile_selected = self.profiles.get(profile, "")
if engine == "anthropic":
data = {
'model': selected_model,
'system': profile_selected ,
'messages': [
{"role": "user", "content": input_prompt}
],
'temperature': temperature,
'max_tokens': max_tokens
}
elif engine == "openai":
if random == True:
data = {
'model': selected_model,
'messages': [
{"role": "system", "content": profile_selected },
{"role": "user", "content": input_prompt}
],
'temperature': temperature,
'seed': seed,
'max_tokens': max_tokens
}
else:
data = {
'model': selected_model,
'messages': [
{"role": "system", "content": profile_selected },
{"role": "user", "content": input_prompt}
],
'temperature': temperature,
'max_tokens': max_tokens
}
else:
if random == True:
data = {
"model": selected_model,
"system": profile_selected ,
"prompt": input_prompt,
"stream": False,
"options": {
"temperature": temperature,
"seed": seed,
"num_ctx": max_tokens,
},
"keep_alive": -1 if keep_alive else 0,
}
else:
data = {
"model": selected_model,
"system": profile_selected ,
"prompt": input_prompt,
"stream": False,
"options": {
"temperature": temperature,
"seed": seed,
"num_ctx": max_tokens,
},
"keep_alive": -1 if keep_alive else 0,
}
generated_text = self.send_request(engine, base_ip, port, data, headers={"Content-Type": "application/json"})
if generated_text:
combined_prompt = f"{embellish_content} {generated_text} {style_content}"
return input_prompt, combined_prompt, neg_content
else:
return None, None, None
def send_request(self, engine, base_ip, port, data, headers):
if engine == "ollama":
api_url = f'http://{base_ip}:{port}/api/generate'
response = requests.post(api_url, headers=headers, json=data)
if response.status_code == 200:
response_data = response.json()
prompt_response = response_data.get('response', 'No response text found')
# Ensure there is a response to construct the full description
if prompt_response != 'No response text found':
return prompt_response
else:
return "No valid response generated for the image."
else:
print(f"Failed to fetch response, status code: {response.status_code}")
return "Failed to fetch response from Ollama."
elif engine == "anthropic":
anthropic_api_key = self.get_api_key("ANTHROPIC_API_KEY", engine)
try:
base_url = 'https://api.anthropic.com/v1/messages'
anthropic_headers = {
"x-api-key": anthropic_api_key,
"anthropic-version": "2023-06-01",
"Content-Type": "application/json"
}
response = requests.post(base_url, headers=anthropic_headers, json=data)
if response.status_code == 200:
messages = response.json().get('content', [])
generated_text = ''.join([msg.get('text', '') for msg in messages if msg.get('type') == 'text'])
return generated_text
else:
print(f"Error: Request failed with status code {response.status_code}, Response: {response.text}")
return None
except Exception as e:
print(f"Error: Anthropic request failed - {e}")
return None
elif engine == "openai":
openai_api_key = self.get_api_key("OPENAI_API_KEY", engine)
try:
base_url = 'https://api.openai.com/v1/chat/completions'
openai_headers = {
"Authorization": f"Bearer {openai_api_key}",
"Content-Type": "application/json"
}
response = requests.post(base_url, headers=openai_headers, json=data)
if response.status_code == 200:
response_data = response.json()
print("Debug Response:", response_data)
choices = response_data.get('choices', [])
if choices:
choice = choices[0]
messages = choice.get('message', {'content': ''})
generated_text = messages.get('content', '')
return generated_text
else:
print("No choices found in response")
return None
else:
print(f"Error: Request failed with status code {response.status_code}, Response: {response.text}")
return None
except Exception as e:
print(f"Error: OpenAI request failed - {e}")
return None, None, None