Author SHA1 Message Date
Craig Wright e718e3d167 Merge pull request #6 from ComfyNodePRs/update-publish-yaml
Update Github Action for Publishing to Comfy Registry
2025-03-12 00:17:49 +00:00
snomiao 31ecc80084 chore(publish): update workflow for node publishing with permissions and conditional execution 2025-01-20 21:35:31 +00:00
Craig Wright 2933103dab Update pyproject.toml
remove @
2024-06-28 20:20:34 +01:00
Craig Wright a6ead677b3 Merge branch 'pr/3'
merge into main
2024-06-28 20:13:28 +01:00
Craig Wright 6d0bda1cd8 Update pyproject.toml 2024-06-28 20:11:39 +01:00
Craig Wright 09c7e069f1 Merge branch 'main' into pr/3 2024-06-28 20:09:47 +01:00
Craig Wright 1b2d64cd3b Merge pull request #2 from haohaocreates/publish
Add Github Action for Publishing to Comfy Registry
2024-06-28 20:06:31 +01:00
haohaocreates 05694aad61 chore(pyproject): Add pyproject.toml for Custom Node Registry 2024-05-22 14:15:46 -04:00
haohaocreates 029df18de8 chore(publish): Add Github Action for Publishing to Comfy Registry 2024-05-22 14:15:43 -04:00
Craig Wright 37ef5ca817 Merge pull request #1 from SOELexicon/SOELexicon-patch-1
Create LICENSE
2023-07-21 12:22:18 +01:00
Craig Wright a9ede7b09b Create LICENSE 2023-07-21 12:21:41 +01:00
craig_wright156 e2a4a73807 old nodes hide 2023-07-20 22:13:18 +01:00
14 changed files with 68 additions and 297 deletions
+25
View File
@@ -0,0 +1,25 @@
name: Publish to Comfy registry
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "pyproject.toml"
permissions:
issues: write
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'SOELexicon' }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@v1
with:
## Add your own personal access token to your Github Repository secrets and reference it here.
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Craig Wright
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+6 -52
View File
@@ -1,52 +1,6 @@
import configparser
import os
import pyodbc
from .models.TableInformation import TableInformation
from .nodes.QueryNode import QueryNode
from .nodes.TableNode import TableNode
from .nodes.SelectNode import SelectNode
class DatabaseConnection:
def __init__(self, config_file='config.ini'):
self.config_file = config_file
self.conn = None
self.connection_string= None
self._load_config()
def _load_config(self):
config = configparser.ConfigParser()
current_dir = os.path.dirname(os.path.realpath(__file__))
config_path = os.path.join(current_dir, self.config_file)
config.read(config_path)
server = config['MSSQL']['server']
database = config['MSSQL']['database']
username = config['MSSQL']['username']
password = config['MSSQL']['password']
driver = config['MSSQL']['driver']
integrated_security = config.getboolean('MSSQL', 'integrated_security', fallback=False)
self.connection_string = f'DRIVER={{{driver}}};SERVER={server};DATABASE={database};'
if integrated_security:
self.connection_string += 'Trusted_Connection=yes;'
else:
self.connection_string += f'UID={username};PWD={password};'
return self.connection_string
def connect(self):
if self.conn is None:
self.conn = pyodbc.connect(self.connection_string)
return self.conn
# Create a connection and table info instance to pass to the node classes
db_connection = DatabaseConnection('config.ini')
table_info = TableInformation(db_connection.connect())
# Node classes
node_classes = [QueryNode, TableNode, SelectNode]
# Mapping of node names to classes
NODE_CLASS_MAPPINGS = {node_class.__name__: node_class for node_class in node_classes}
# Mapping of node names to friendly display names
NODE_DISPLAY_NAME_MAPPINGS = {node_class.__name__: node_class.__name__.replace("Node", " Node") for node_class in node_classes}
#from .nodes.SegGPT import segGPTNode
from .nodes import MSSqlNode
NODE_CLASS_MAPPINGS = {
# **segGPTNode.NODE_CLASS_MAPPINGS,
**MSSqlNode.NODE_CLASS_MAPPINGS
}
-7
View File
@@ -1,7 +0,0 @@
[MSSQL]
server=WINDOWS-I1B2JBN
database=StableDiffusion
username=your_username
password=your_password
integrated_security=True
driver = SQL Server
-16
View File
@@ -1,16 +0,0 @@
class TableInformation:
def __init__(self, conn):
self.conn = conn
self.table_info = {}
self.fields = {}
def load_table_info(self):
cursor = self.conn.cursor()
cursor.execute("SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE'")
tables = [row.table_name for row in cursor.fetchall()]
for table in tables:
cursor.execute(f"SELECT * FROM {table}")
columns = {column[0]: column[1] for column in cursor.description}
# print(columns)
self.table_info[table] = columns
self.fields = self.table_info['txt2img']
-2
View File
@@ -305,8 +305,6 @@ class MSSqlNode:
return result
NODE_CLASS_MAPPINGS = {
"MSSQLQuery": MSSQLQueryNode,
"MSSqlNode": MSSqlNode,
"MSSqlTableNode": MSSqlTableNode,
"MSSqlSelectNode": MSSqlSelectNode,
}
-39
View File
@@ -1,39 +0,0 @@
class QueryNode:
def __init__(self):
self.CATEGORY = "LexNode.MSSQL"
self.FUNCTION = "execute_query"
self.RETURN_TYPES = ("Tuple", )
self.RETURN_NAMES = ("Query Results", )
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"query": ("STRING", {"default": ""})
},
}
def execute_query(self, **kwargs):
global conn
cursor = conn.cursor()
sql = kwargs.get('query')
cursor.execute(sql)
results = cursor.fetchall()
all_rows = []
for result in results:
all_rows.append(result)
return tuple(all_rows),
RETURN_TYPES = ("Tuple", )
RETURN_NAMES = ("Query Results", )
NODE_CLASS_MAPPINGS = {
"QueryNode": QueryNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"QueryNode": "Sql Query Node"
}
-71
View File
@@ -1,71 +0,0 @@
import io, torch
import numpy as np
from PIL import Image
class SelectNode:
def __init__(self, table_name = 'txt2img'):
self.table_name = table_name
self.RETURN_TYPES = self.getFields()
self.RETURN_NAMES = self.getFieldsNames()
table_name ="None"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"id": ("INT", {"default": "1"})
},
}
@property
def RETURN_TYPES(self):
return self.getFields()
@property
def RETURN_NAMES(self):
return self.getFieldsNames()
FUNCTION = "execute_query"
CATEGORY = "LexNodes.MSSQL"
def getFields(self):
global table_info
fields = table_info[self.table_name]
return tuple(fields.keys())
def getFieldsNames(self):
global table_info
fields = table_info[self.table_name]
return tuple(fields.values())
def execute_query(self, **kwargs):
global conn,table_info
cursor = conn.cursor()
columns = ', '.join(table_info[self.table_name].keys())
sql = f"SELECT {columns} FROM {self.table_name} WHERE Id = {kwargs.get('id')}"
cursor.execute(sql)
results = cursor.fetchall()
all_rows = []
for result in results:
result_dict = {}
for column, value in zip(table_info[self.table_name].keys(), result):
if column =='Image': # Check if the value is a bytearray
image = Image.open(io.BytesIO(value))
# Perform additional image processing
image = image.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,]
result_dict[column] = image
else:
result_dict[column] = value
all_rows.append(tuple(result_dict.values()))
return all_rows[0]
NODE_CLASS_MAPPINGS = {
"SelectNode": SelectNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"SelectNode": "Sql Select Node"
}
-109
View File
@@ -1,109 +0,0 @@
import datetime
import pyodbc
import io, torch
import numpy as np
from PIL import Image
class TableNode:
table_name="txt2img"
fields = {}
def __init__(self, db_connection, table_info):
self.conn = db_connection.connect()
self.table_info = table_info
self.table_name = "txt2img"
print(self.table_info)
@classmethod
def INPUT_TYPES(cls):
print()
tables = list(cls.table_info.keys())
fields = cls.table_info[cls.table_name]
# Create an input for each field
inputs = {"Table": (tables,)}
for field, field_type in fields.items():
if field_type == int:
input_type = "INT"
default_value = 0
elif field_type == str:
input_type = "STRING"
default_value = ""
elif field_type == bool:
input_type = "STRING"
default_value = "False"
elif field_type == float:
input_type = "FLOAT"
default_value = 0.0
elif field_type == bytearray:
input_type = "IMAGE"
default_value = None
else:
input_type = "STRING" # default type
default_value = ""
inputs[field] = (input_type, {"default": default_value})
print({"required": inputs})
return {"required": inputs}
RETURN_TYPES = ("STRING", "INT",)
FUNCTION = "execute_query"
CATEGORY = "LexNode.MSSQL"
def execute_query(self, **kwargs):
cursor = self.conn.cursor()
# Set the table name to the value of the "Table" field and remove it from kwargs
self.table_name = kwargs.pop('Table', self.table_name)
if kwargs.get('id', None) == 0: # Check if id is 0
# Remove 'id' from kwargs
kwargs.pop('id', None)
# Prepare the SQL statement for inserting a new record
kwargs['DateAdded'] = datetime.datetime.now() # Add current datetime
columns = ', '.join(kwargs.keys())
placeholders = ', '.join('?' for _ in kwargs)
sql = f"INSERT INTO {self.table_name} ({columns}) VALUES ({placeholders})"
values = []
for value in kwargs.values():
if isinstance(value, torch.Tensor): # Check if the value is a PyTorch tensor
# Convert the tensor to a numpy array
i = 255. * value[0].cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
byte_array = io.BytesIO()
img.save(byte_array, format='JPEG')
value = pyodbc.Binary(byte_array.getvalue())
elif isinstance(value, datetime.datetime): # Check if the value is a datetime object
value = value.strftime('%Y-%m-%d %H:%M:%S') # Format the datetime object to string
values.append(value)
cursor.execute(sql, tuple(values))
self.conn.commit() # Don't forget to commit the changes
cursor.execute("SELECT @@IDENTITY AS 'Identity'")
id_of_new_row = cursor.fetchone()[0]
return ["Insert operation completed.", id_of_new_row]
else:
for field, value in kwargs.items():
if field in self.table_info[self.table_name]: # Ensure the field exists in the table
if isinstance(value, torch.Tensor): # Check if the value is a numpy array
# Ensure the numpy array can be represented as an image
i = 255. * value[0].cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
# Convert the numpy array to a byte array
byte_arr = io.BytesIO()
img.save(byte_arr, format='JPEG')
value = pyodbc.Binary(byte_arr.getvalue())
cursor.execute(f"UPDATE {self.table_name} SET {field} = ? WHERE {field} = ?", (value, value))
self.conn.commit() # Don't forget to commit the changes
return ["Update operation completed.", kwargs.get('id')]
NODE_CLASS_MAPPINGS = {
"TableNode": TableNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"TableNode": "Sql Table Node"
}
+15
View File
@@ -0,0 +1,15 @@
[project]
name = "comfyui-lexmsdbnodes"
description = "Nodes: MSSqlTableNode, MSSqlSelectNode. This extension provides custom nodes to interact with MSSQL."
version = "1.0.0"
license = "LICENSE"
dependencies = ["numpy", "opencv-python", "git+https://github.com/facebookresearch/detectron2.git", "pyodbc"]
[project.urls]
Repository = "https://github.com/SOELexicon/ComfyUI-LexMSDBNodes"
# Used by Comfy Registry https://comfyregistry.org
[tool.comfy]
PublisherId = "lexicon"
DisplayName = "ComfyUI-LexMSDBNodes"
Icon = ""
+1 -1
View File
@@ -1,4 +1,4 @@
numpy
opencv-python
git+https://github.com/facebookresearch/detectron2.git
pyodbc
pyodbc