Remove obsolete files and add new node implementations

This commit removes some obsolete Python files related to latent, logging, and prompt functionalities. It also adds new implementations for node classes, including ShowText, ImageSizer, ImageDimensionResizer, RandomTitleCharacter, and others. The new implementations restructure and optimize the existing functionalities.
This commit is contained in:
Vince
2024-04-22 17:49:12 +02:00
parent db75b96fd3
commit 585a9ff673
14 changed files with 526 additions and 448 deletions
+14 -8
View File
@@ -1,21 +1,25 @@
from custom_nodes.GR85.latent import ImageSizer, ImageDimensionResizer
from custom_nodes.GR85.logging import ShowString
from custom_nodes.GR85.prompt import RandomTitleCharacter, InsertCharacter, RandomElements, ElementsConcatenator, \
LlmEnhancer
from custom_nodes.GR85.nodes.latent.image_dimension_resizer import ImageDimensionResizer
from custom_nodes.GR85.nodes.latent.image_sizer import ImageSizer
from custom_nodes.GR85.nodes.logging.show_text import ShowText
from custom_nodes.GR85.nodes.prompt.element_concatenator import ElementConcatenator
from custom_nodes.GR85.nodes.prompt.insert_character import InsertCharacter
from custom_nodes.GR85.nodes.prompt.llm_enhance import LlmEnhancer
from custom_nodes.GR85.nodes.prompt.wildcard.random_elements import RandomElements
from custom_nodes.GR85.nodes.prompt.wildcard.random_title_character import RandomTitleCharacter
NODE_CLASS_MAPPINGS = {
"GR85_ShowString": ShowString,
"GR85_ShowText": ShowText,
"GR85_ImageSizer": ImageSizer,
"GR85_ImageDimensionResizer": ImageDimensionResizer,
"GR85_RandomTitleCharacter": RandomTitleCharacter,
"GR85_InsertCharacter": InsertCharacter,
"GR85_RandomElements": RandomElements,
"GR85_ElementsConcatenator": ElementsConcatenator,
"GR85_ElementsConcatenator": ElementConcatenator,
"GR85_LlmEnhancer": LlmEnhancer,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"GR85_ShowString": "Show String",
"GR85_ShowText": "Show Text",
"GR85_ImageSizer": "Image Sizer",
"GR85_ImageDimensionResizer": "Image Dimension Resizer",
"GR85_RandomTitleCharacter": "Random Title Character",
@@ -25,4 +29,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"GR85_LlmEnhancer": "Llm Enhancer",
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
WEB_DIRECTORY = "./js"
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
+55
View File
@@ -0,0 +1,55 @@
import {app} from '../../scripts/app.js'
import {ComfyWidgets} from '../../scripts/widgets.js'
/**
* @typedef {import("types/comfy").ComfyExtension} ComfyExtension
*/
// Displays input text on a node
app.registerExtension({
name: 'GR85.ShowText',
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === 'GR85_ShowText') {
/**
* @param text {string[]}
* @this {ComfyNode}
*/
function populate(text) {
console.log(this)
if (this.widgets) {
for (let i = 1; i < this.widgets.length; i++) {
this.widgets[i].onRemove?.()
}
this.widgets.length = 1
}
const v = [...text]
if (!v[0]) {
v.shift()
}
for (const list of v) {
const w = ComfyWidgets['STRING'](this, 'text', ['STRING', {multiline: true}], app).widget
w.inputEl.readOnly = true
w.inputEl.style.opacity = 0.6
w.value = list
}
}
// When the node is executed we will be sent the input text, display this in the widget
const onExecuted = nodeType.prototype.onExecuted
nodeType.prototype.onExecuted = function (message) {
onExecuted?.apply(this, arguments)
populate.call(this, message.text)
}
const onConfigure = nodeType.prototype.onConfigure
nodeType.prototype.onConfigure = function () {
onConfigure?.apply(this, arguments)
if (this.widgets_values?.length) {
populate.call(this, this.widgets_values)
}
}
}
},
})
-116
View File
@@ -1,116 +0,0 @@
import math
class ImageSizer:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"original_dimensions": (["512x512", "512*768", "768x768", "1024x1024", "1280x720", "1920x1080"],),
"ratio_1": ("INT", {
"default": 1,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"ratio_2": ("INT", {
"default": 1,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"orientation": (["landscape", "portrait"],),
}
}
RETURN_TYPES = ("INT", "INT")
RETURN_NAMES = ("width", "height")
FUNCTION = "resize_dimensions"
CATEGORY = "GR85/Latent"
def resize_dimensions(self, original_dimensions, ratio_1, ratio_2, orientation):
original_width, original_height = map(int, original_dimensions.split("x"))
"""Calculates new dimensions for an image while maintaining the same pixel count
and a specified aspect ratio.
Args:
original_width: The original width of the image in pixels.
original_height: The original height of the image in pixels.
ratio_1: The first part of the desired aspect ratio.
ratio_2: The second part of the desired aspect ratio.
orientation: Either "landscape" or "portrait" (used for clarity, not calculation)
Returns:
A tuple containing the new width and height of the image.
"""
total_pixels = original_width * original_height
new_width = math.sqrt(total_pixels * ratio_1 / ratio_2)
new_height = new_width * ratio_2 / ratio_1
# Adjust if the desired orientation is different from the original
if (orientation == 'landscape' and original_height > original_width) or \
(orientation == 'portrait' and original_width > original_height):
new_width, new_height = new_height, new_width # Swap dimensions
return int(round(new_width)), int(round(new_height))
class ImageDimensionResizer:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"original_width": ("INT", {
"forceInput": True,
"default": 512,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"original_height": ("INT", {
"forceInput": True,
"default": 512,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"target_dimensions": (["512x512", "512*768", "768x768", "1024x1024", "1280x720", "1920x1080"],),
}
}
RETURN_TYPES = ("INT", "INT")
RETURN_NAMES = ("width", "height")
FUNCTION = "resize_dimensions"
CATEGORY = "GR85/Latent"
def resize_dimensions(self, original_width, original_height, target_dimensions):
"""
Calculates new dimensions while maintaining pixel count
and maintaining the ratio of the original dimensions.
first calculate the original ratio
then calculate the target pixel count
then calculate the new dimensions
"""
original_ratio = original_width / original_height
target_width, target_height = map(int, target_dimensions.split("x"))
target_pixels = target_width * target_height
new_width = math.sqrt(target_pixels * original_ratio)
new_height = new_width / original_ratio
return int(round(new_width)), int(round(new_height))
-19
View File
@@ -1,19 +0,0 @@
class ShowString:
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"str": ("STRING", {"forceInput": True}),
"key": ('STRING', {"default": "text"}),
}
}
RETURN_TYPES = ("STRING",)
FUNCTION = "show"
CATEGORY = "GR85/Logging"
OUTPUT_NODE = True
def show(self, str, key):
return {"ui": {key: (str,)}, "result": (str,)}
+53
View File
@@ -0,0 +1,53 @@
import math
class ImageDimensionResizer:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"original_width": ("INT", {
"forceInput": True,
"default": 512,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"original_height": ("INT", {
"forceInput": True,
"default": 512,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"target_dimensions": (["512x512", "512*768", "768x768", "1024x1024", "1280x720", "1920x1080"],),
}
}
RETURN_TYPES = ("INT", "INT")
RETURN_NAMES = ("width", "height")
FUNCTION = "resize_dimensions"
CATEGORY = "GR85/Latent"
def resize_dimensions(self, original_width, original_height, target_dimensions):
"""
Calculates new dimensions while maintaining pixel count
and maintaining the ratio of the original dimensions.
first calculate the original ratio
then calculate the target pixel count
then calculate the new dimensions
"""
original_ratio = original_width / original_height
target_width, target_height = map(int, target_dimensions.split("x"))
target_pixels = target_width * target_height
new_width = math.sqrt(target_pixels * original_ratio)
new_height = new_width / original_ratio
return int(round(new_width)), int(round(new_height))
+65
View File
@@ -0,0 +1,65 @@
import math
class ImageSizer:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"original_dimensions": (["512x512", "512*768", "768x768", "1024x1024", "1280x720", "1920x1080"],),
"ratio_1": ("INT", {
"default": 1,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"ratio_2": ("INT", {
"default": 1,
"min": 1,
"max": 4096,
"step": 1,
"display": "number"
}),
"orientation": (["landscape", "portrait"],),
}
}
RETURN_TYPES = ("INT", "INT")
RETURN_NAMES = ("width", "height")
FUNCTION = "resize_dimensions"
CATEGORY = "GR85/Latent"
def resize_dimensions(self, original_dimensions, ratio_1, ratio_2, orientation):
original_width, original_height = map(int, original_dimensions.split("x"))
"""Calculates new dimensions for an image while maintaining the same pixel count
and a specified aspect ratio.
Args:
original_width: The original width of the image in pixels.
original_height: The original height of the image in pixels.
ratio_1: The first part of the desired aspect ratio.
ratio_2: The second part of the desired aspect ratio.
orientation: Either "landscape" or "portrait" (used for clarity, not calculation)
Returns:
A tuple containing the new width and height of the image.
"""
total_pixels = original_width * original_height
side_1 = math.sqrt(total_pixels * ratio_1 / ratio_2)
side_2 = side_1 * ratio_2 / ratio_1
bigger_side = max(side_1, side_2)
smaller_side = min(side_1, side_2)
if orientation == 'landscape':
return int(round(bigger_side)), int(round(smaller_side))
else:
return int(round(smaller_side)), int(round(bigger_side))
+40
View File
@@ -0,0 +1,40 @@
class ShowText:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING", {"forceInput": True}),
},
"hidden": {
"unique_id": "UNIQUE_ID",
"extra_pnginfo": "EXTRA_PNGINFO",
},
}
INPUT_IS_LIST = True
RETURN_TYPES = ("STRING",)
FUNCTION = "notify"
OUTPUT_NODE = True
OUTPUT_IS_LIST = (True,)
CATEGORY = "GR85/Logging"
def notify(self, text, unique_id=None, extra_pnginfo=None):
if unique_id is not None and extra_pnginfo is not None:
if not isinstance(extra_pnginfo, list):
print("Error: extra_pnginfo is not a list")
elif (
not isinstance(extra_pnginfo[0], dict)
or "workflow" not in extra_pnginfo[0]
):
print("Error: extra_pnginfo[0] is not a dict or missing 'workflow' key")
else:
workflow = extra_pnginfo[0]["workflow"]
node = next(
(x for x in workflow["nodes"] if str(x["id"]) == str(unique_id[0])),
None,
)
if node:
node["widgets_values"] = [text]
return {"ui": {"text": text}, "result": (text,)}
+30
View File
@@ -0,0 +1,30 @@
class ElementConcatenator:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"title_character_elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"random_elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("concatenated_elements",)
FUNCTION = "concatenate_elements"
CATEGORY = "GR85/Prompt"
def concatenate_elements(self, title_character_elements, random_elements):
return (f"{title_character_elements}, {random_elements}",)
+74
View File
@@ -0,0 +1,74 @@
class InsertCharacter:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"title_character": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True,
}),
"elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"facial_features": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"append": ("STRING", {
"default": "",
"multiline": True
}),
"anime_template": ("STRING", {
"default": "1girl, {title_character}, anime, {elements}, {append}",
"multiline": True
}),
"realistic_template": ("STRING", {
"default": "realistic, 1girl, {title_character}, {facial_features}, {elements}, {append}",
"multiline": True
}),
"face_detailer_template": ("STRING", {
"default": "realistic, 1girl, {title_character}, {facial_features}, cute eyes, natural beauty, attractive face, {append}",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("anime_string", "realistic_string", "face_detailer_string")
FUNCTION = "insert_character"
CATEGORY = "GR85/Prompt"
def insert_character(self, title_character, elements, facial_features, append, anime_template, realistic_template,
face_detailer_template):
"""
This function takes the output of the RandomTitleCharacter node and inserts it into three different templates.
The templates are strings that contain placeholders for the different elements of the character.
The placeholders are:
- {title_character}
- {elements}
- {facial_features}
- {append}
The function will replace these placeholders with the corresponding elements and return the resulting strings.
"""
anime = anime_template.format(title_character=title_character, elements=elements,
facial_features=facial_features, append=append)
realistic = realistic_template.format(title_character=title_character, elements=elements,
facial_features=facial_features, append=append)
face_detailer = face_detailer_template.format(title_character=title_character, elements=elements,
facial_features=facial_features, append=append)
print("Anime:", anime)
print("Realistic:", realistic)
print("Face Detailer:", face_detailer)
return anime, realistic, face_detailer
+57
View File
@@ -0,0 +1,57 @@
import openai
class LlmEnhancer:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"title_character": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"system_prompt": ("STRING", {
"default": "Enhance the following elements into a short and simple movie still that is coherent with the character.",
"multiline": True
}),
"user_prompt": ("STRING", {
"default": "Character in scene: {title_character}, Props: {elements}",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("enhanced_string",)
FUNCTION = "enhance_string"
CATEGORY = "GR85/Prompt"
def enhance_string(self, title_character, elements, system_prompt, user_prompt):
"""
This makes a call to: http://localhost:7875/v1/chat/completions
This service is a ChatGPT model that has been fine-tuned to respond with an enhanced version of the input text.
"""
client = openai.OpenAI(base_url="http://localhost:7875/v1", api_key="lm-studio")
completion = client.chat.completions.create(
model="Undi95/Xwin-MLewd-13B-V0.2-GGUF",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt.format(title_character=title_character, elements=elements)},
],
temperature=0.7,
)
try:
return (completion.choices[0].message.content,)
except Exception as e:
return (str(e),)
+45
View File
@@ -0,0 +1,45 @@
import yaml
import random
class RandomElements:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"seed": ("INT", {"forceInput": True, "default": 0, "min": 0, "max": 0xffffffffffffffff}),
"elements_amount": ("INT", {
"default": 4,
"min": 1,
"max": 100,
"step": 1,
"display": "number"
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("random_elements",)
FUNCTION = "choose_random_elements"
CATEGORY = "GR85/Prompt/Wildcard"
def choose_random_elements(self, seed, elements_amount):
with open("ComfyUI/custom_nodes/GR85/wildcards/elements.txt", "r") as file:
elements = file.readlines()
result = []
for element in elements:
parts = element.split(':')
if len(parts) == 2: # Check if we have two parts
amount_str, name = parts
amount = int(amount_str)
result.extend([name.strip()] * amount)
else:
result.append(element.strip()) # Handle elements without ':'
random.seed(seed)
chosen_elements = random.sample(result, elements_amount)
return (", ".join(chosen_elements),)
@@ -0,0 +1,93 @@
import random
import yaml
class RandomTitleCharacter:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"seed": ("INT", {
"forceInput": True, "default": 0, "min": 0, "max": 0xffffffffffffffff}),
"title_elements_amount": ("INT", {
"default": 1,
"min": 1,
"max": 10,
"step": 1,
"display": "number"
}),
"character_elements_amount": ("INT", {
"default": 2,
"min": 1,
"max": 10,
"step": 1,
"display": "number"
}),
"facial_features_amount": ("INT", {
"default": 2,
"min": 1,
"max": 10,
"step": 1,
"display": "number"
}),
}
}
RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("random_character", "elements", "facial_features")
FUNCTION = "choose_random_title_characters"
CATEGORY = "GR85/Prompt/Wildcard"
def choose_random_title_characters(self,
seed,
title_elements_amount,
character_elements_amount,
facial_features_amount):
"""
There is a YAML file in the same directory as this file named: characters.yaml
It contains a list of characters in the following format:
- Movie/TV Show/Video Game Title:
Title_Elements:
- Title Element
Characters:
- Character Name:
Elements:
- Character element
Facial Features:
- Facial feature
This function will:
- Choose a random title
- Choose a random character from that title
- Choose 3 random elements from that character
- Choose a random element from that title
Returns a string in the following format:
"Character Name, Title Name, Character element 1, Character element 2, Title Element 1"
"""
with open("characters.yaml", "r") as file:
titles = yaml.load(file, Loader=yaml.FullLoader)
# Use the seed to generate a random number
random.seed(seed)
title = random.choice(titles)
title_name = list(title.keys())[0]
title_elements = random.sample(title["Title_Elements"], title_elements_amount)
title_character = random.choice(title["Characters"])
title_character_name = list(title_character.keys())[0]
title_character_elements = random.sample(title_character["Elements"], character_elements_amount)
facial_features = random.sample(title_character["Facial Features"], facial_features_amount)
return (f"{title_character_name}, {title_name}",
f"{', '.join(title_character_elements)}, {', '.join(title_elements)}",
f"{', '.join(facial_features)}")
-305
View File
@@ -1,305 +0,0 @@
import random
import openai
import yaml
class RandomTitleCharacter:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"seed": ("INT", {
"forceInput": True, "default": 0, "min": 0, "max": 0xffffffffffffffff}),
"title_elements_amount": ("INT", {
"default": 1,
"min": 1,
"max": 10,
"step": 1,
"display": "number"
}),
"character_elements_amount": ("INT", {
"default": 2,
"min": 1,
"max": 10,
"step": 1,
"display": "number"
}),
"facial_features_amount": ("INT", {
"default": 2,
"min": 1,
"max": 10,
"step": 1,
"display": "number"
}),
}
}
RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("random_character", "elements", "facial_features")
FUNCTION = "choose_random_title_characters"
CATEGORY = "GR85/Prompt"
def choose_random_title_characters(self,
seed,
title_elements_amount,
character_elements_amount,
facial_features_amount):
"""
There is a YAML file in the same directory as this file named: characters.yaml
It contains a list of characters in the following format:
- Movie/TV Show/Video Game Title:
Title_Elements:
- Title Element
Characters:
- Character Name:
Elements:
- Character element
Facial Features:
- Facial feature
This function will:
- Choose a random title
- Choose a random character from that title
- Choose 3 random elements from that character
- Choose a random element from that title
Returns a string in the following format:
"Character Name, Title Name, Character element 1, Character element 2, Title Element 1"
"""
with open("characters.yaml", "r") as file:
titles = yaml.load(file, Loader=yaml.FullLoader)
# Use the seed to generate a random number
random.seed(seed)
title = random.choice(titles)
title_name = list(title.keys())[0]
title_elements = random.sample(title["Title_Elements"], title_elements_amount)
title_character = random.choice(title["Characters"])
title_character_name = list(title_character.keys())[0]
title_character_elements = random.sample(title_character["Elements"], character_elements_amount)
facial_features = random.sample(title_character["Facial Features"], facial_features_amount)
return (f"{title_character_name}, {title_name}",
f"{', '.join(title_character_elements)}, {', '.join(title_elements)}",
f"{', '.join(facial_features)}")
class InsertCharacter:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"title_character": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True,
}),
"elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"facial_features": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"append": ("STRING", {
"default": "",
"multiline": True
}),
"anime_template": ("STRING", {
"default": "1girl, {title_character}, anime, {elements}, {append}",
"multiline": True
}),
"realistic_template": ("STRING", {
"default": "realistic, 1girl, {title_character}, {facial_features}, {elements}, {append}",
"multiline": True
}),
"face_detailer_template": ("STRING", {
"default": "realistic, 1girl, {title_character}, {facial_features}, cute eyes, natural beauty, attractive face, {append}",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("anime_string", "realistic_string", "face_detailer_string")
FUNCTION = "insert_character"
CATEGORY = "GR85/Prompt"
def insert_character(self, title_character, elements, facial_features, append, anime_template, realistic_template,
face_detailer_template):
"""
This function takes the output of the RandomTitleCharacter node and inserts it into three different templates.
The templates are strings that contain placeholders for the different elements of the character.
The placeholders are:
- {title_character}
- {elements}
- {facial_features}
- {append}
The function will replace these placeholders with the corresponding elements and return the resulting strings.
"""
anime = anime_template.format(title_character=title_character, elements=elements,
facial_features=facial_features, append=append)
realistic = realistic_template.format(title_character=title_character, elements=elements,
facial_features=facial_features, append=append)
face_detailer = face_detailer_template.format(title_character=title_character, elements=elements,
facial_features=facial_features, append=append)
print("Anime:", anime)
print("Realistic:", realistic)
print("Face Detailer:", face_detailer)
return anime, realistic, face_detailer
class RandomElements:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"seed": ("INT", {"forceInput": True, "default": 0, "min": 0, "max": 0xffffffffffffffff}),
"elements_amount": ("INT", {
"default": 4,
"min": 1,
"max": 100,
"step": 1,
"display": "number"
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("random_elements",)
FUNCTION = "choose_random_elements"
CATEGORY = "GR85/Prompt"
def choose_random_elements(self, seed, elements_amount):
with open("elements.yaml", "r") as file:
elements = yaml.load(file, Loader=yaml.FullLoader)
result = []
for element in elements:
parts = element.split(':')
if len(parts) == 2: # Check if we have two parts
amount_str, name = parts
amount = int(amount_str)
result.extend([name] * amount)
else:
result.append(element) # Handle elements without ':'
random.seed(seed)
chosen_elements = random.sample(result, elements_amount)
return (", ".join(chosen_elements),)
class ElementsConcatenator:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"title_character_elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"random_elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("concatenated_elements",)
FUNCTION = "concatenate_elements"
CATEGORY = "GR85/Prompt"
def concatenate_elements(self, title_character_elements, random_elements):
return (f"{title_character_elements}, {random_elements}",)
class LlmEnhancer:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"title_character": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"elements": ("STRING", {
"forceInput": True,
"default": "",
"multiline": True
}),
"system_prompt": ("STRING", {
"default": "Enhance the following elements into a short and simple movie still that is coherent with the character.",
"multiline": True
}),
"user_prompt": ("STRING", {
"default": "Character in scene: {title_character}, Props: {elements}",
"multiline": True
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("enhanced_string",)
FUNCTION = "enhance_string"
CATEGORY = "GR85/Prompt"
def enhance_string(self, title_character, elements, system_prompt, user_prompt):
"""
This makes a call to: http://localhost:7875/v1/chat/completions
This service is a ChatGPT model that has been fine-tuned to respond with an enhanced version of the input text.
"""
client = openai.OpenAI(base_url="http://localhost:7875/v1", api_key="lm-studio")
completion = client.chat.completions.create(
model="Undi95/Xwin-MLewd-13B-V0.2-GGUF",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt.format(title_character=title_character, elements=elements)},
],
temperature=0.7,
)
try:
return (completion.choices[0].message.content,)
except Exception as e:
return (str(e),)
View File