Skip to content

Commit

Permalink
feat: add setting & import docs & exports
Browse files Browse the repository at this point in the history
  • Loading branch information
TaTaLiao committed May 25, 2024
1 parent 58a776d commit ec3aa22
Show file tree
Hide file tree
Showing 11 changed files with 566 additions and 52 deletions.
Empty file added .cache/.cache_directory
Empty file.
1 change: 1 addition & 0 deletions .cache/.setting.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"contribute": true}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ __pycache__
*.ini
.vscode/
.idea/
node_modules/
node_modules/
.cache/**
!.cache/.cache_directory
!.cache/.setting.json
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ Node output types

Node source code
</code></pre>

11 changes: 10 additions & 1 deletion README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,13 @@ Node output types
# Source code

Node source code
</code></pre>
</code></pre>

## 更新日志

### 2024-05-25
- 在设置中增加了开关,可以选择是否显示节点的文档
- 增加文档本地修改功能,如果觉得文档有问题,可以在本地修改,不会影响到其他人
- 在设置中增加了是否参与共建的开关,可以选择是否参与共建,默认打开,打开后会把本地修改的记录,记录到云DB上,后期经过审核后会合并到主分支上
- 增加导出文档和导入文档功能,导出文档会把本地修改的记录和仓库提供的文档导出下载,导入文档会把导出的文档导入到本地,不会影响主仓库的文档。
- 修复了一些bug
24 changes: 3 additions & 21 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
import os
from server import PromptServer
from aiohttp import web
from .server import *

WEB_DIRECTORY = "./web/comfyui"
NODE_CLASS_MAPPINGS = {}

__all__ = ['WEB_DIRECTORY', 'NODE_CLASS_MAPPINGS']

CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

@PromptServer.instance.routes.get("/customnode/getNodeInfo")
async def fetch_customnode_node_info(request):
try:
node_name = request.rel_url.query["nodeName"]

if not node_name:
return web.json_response({"content": ""})

file_path = os.path.join(CURRENT_DIR, 'docs', node_name + '.md')
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return web.json_response({"content": file.read()})
else:
return web.json_response({"content": ""})
except Exception as e:
return web.json_response({"content": ""})

MAGENTA = '\033[95m'
RESET = '\033[0m'
print(f"{MAGENTA}==============================================")
print(f"{MAGENTA}[comfyui-nodes-docs]{RESET}Loaded comfyui-nodes-docs plugin")
print(f"{MAGENTA}=============================================={RESET}")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "comfyui-nodes-docs"
description = "This is a plugin for displaying documentation for each comfyui node. "
version = "1.0.0"
version = "1.1.0"
license = "LICENSE"

[project.urls]
Expand Down
1 change: 1 addition & 0 deletions server/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .request import *
296 changes: 296 additions & 0 deletions server/request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@

import json
import os
from server import PromptServer
from aiohttp import web,ClientSession
import asyncio
import zipfile
import tempfile

CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

root_dir = os.path.join(CURRENT_DIR, '..')

cache_dir = os.path.join(root_dir, '.cache')
docs_dir = os.path.join(root_dir, 'docs')
setting_path = os.path.join(cache_dir, '.setting.json')
device_id_path = os.path.join(cache_dir, '.cache_d_id')

# 根据设备名称和设备信息 ip地址,创建一个唯一的设备ID
def create_device_id():
import hashlib
import socket
import uuid

# 获取设备名称
device_name = socket.gethostname()
# 获取设备IP地址
device_ip = socket.gethostbyname(device_name)
# 获取设备唯一标识
device_uuid = str(uuid.getnode())
# 创建设备ID
device_id = hashlib.md5((device_name + device_ip + device_uuid ).encode('utf-8')).hexdigest()
return device_id

if not os.path.exists(cache_dir):
os.makedirs(cache_dir, 755)

# 获取节点文档内容
def get_node_doc_file_content(node_name):
file_path = os.path.join(docs_dir, node_name + '.md')
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
else:
return ""

# 获取节点缓存文档
def get_node_cache_file_content(node_name):
file_path = os.path.join(cache_dir, node_name + '.md')
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
else:
return ""

# 写入缓存文件
def write_cache_file(node_name, content):
file_path = os.path.join(cache_dir, node_name + '.md')
print(file_path)
with open(file_path, 'w', encoding='utf-8') as file:
file.write(content)

def write_device_id():
# 创建设备ID
device_id = create_device_id()
# 写入缓存文件
with open(device_id_path, 'w', encoding='utf-8') as file:
file.write(device_id)
return device_id

write_device_id()

def get_device_id():
if os.path.exists(device_id_path):
with open(device_id_path, 'r', encoding='utf-8') as file:
return file.read()
else:
divce_id = write_device_id()
return divce_id

# Add route to fetch node info
@PromptServer.instance.routes.get("/customnode/getNodeInfo")
async def fetch_customnode_node_info(request):
try:
node_name = request.rel_url.query["nodeName"]

if not node_name:
return web.json_response({"content": ""})

cache_content = get_node_cache_file_content(node_name)

if len(cache_content) > 0 :
return web.json_response({"content": cache_content})

content = get_node_doc_file_content(node_name)
return web.json_response({"content": content})
except Exception as e:
return web.json_response({"content": ""})

# Add route to cache node info
@PromptServer.instance.routes.get("/customnode/cacheNodeInfo")
async def cache_customnode_node_info(request):
try:
node_name = request.rel_url.query["nodeName"]

if not node_name:
return web.json_response({"success": False, "content": ""})

print('cache start')
if not os.path.exists(os.path.join(cache_dir, node_name + '.md')):
print('cache file not exists')
content = get_node_doc_file_content(node_name)
write_cache_file(node_name, content)
print('cache success')
return web.json_response({"success": True, "content": content})
return web.json_response({"success": True, "content": ''})
except Exception as e:
print(e)
return web.json_response({"success": False, "content": ''})

# Add route to update node info
@PromptServer.instance.routes.post("/customnode/updateNodeInfo")
async def update_customnode_node_info(request):
try:
json_data = await request.json()
node_name = json_data["nodeName"]
# node_name = request.rel_url.query["nodeName"]
content = json_data["content"]

if not node_name:
return web.json_response({"success": False})

write_cache_file(node_name, content)

contribute = get_setting_item('contribute')
if contribute == True:
print('send doc to cloud')
asyncio.create_task(send_doc_to_cloud(node_name, content))

return web.json_response({"success": True})
except Exception as e:
return web.json_response({"success": False})


# ================================== 以下是导出节点文档的代码 ==================================
def get_all_files(directory):
""" 获取目录下所有文件的路径 """
file_paths = []
for root, _, files in os.walk(directory):
for file in files:
file_paths.append(os.path.join(root, file))
return file_paths

def collect_unique_files(dir1, dir2):
""" 收集两个目录下的所有文件,按文件名去重 """
unique_files = {}
for file_path in get_all_files(dir1) + get_all_files(dir2):
file_name = os.path.basename(file_path)
if file_name not in unique_files:
unique_files[file_name] = file_path
return unique_files.values()

def zip_files(file_paths, output_zip):
""" 将文件打包成ZIP,并平铺存储 """
with zipfile.ZipFile(output_zip, 'w') as zipf:
for file_path in file_paths:
arcname = os.path.basename(file_path) # 只使用文件名,不保留路径
zipf.write(file_path, arcname=arcname)

# Add route to export node info
@PromptServer.instance.routes.get("/customnode/exportNodeInfo")
async def export_customnode_node_info(request):
# 把所有的缓存文件和docs文件夹下的文件打包成zip文件
""" 生成ZIP文件并返回文件流响应 """

unique_files = collect_unique_files(cache_dir, docs_dir)

# 使用临时文件存储ZIP
temp_zip = tempfile.NamedTemporaryFile(delete=False)
try:
with zipfile.ZipFile(temp_zip, 'w') as zipf:
for file_path in unique_files:
arcname = os.path.basename(file_path)
zipf.write(file_path, arcname=arcname)

temp_zip.seek(0)

# 生成StreamResponse响应
response = web.StreamResponse()
response.headers['Content-Type'] = 'application/zip'
response.headers['Content-Disposition'] = 'attachment; filename="output.zip"'

await response.prepare(request)

with open(temp_zip.name, 'rb') as f:
while chunk := f.read(8192):
await response.write(chunk)

await response.write_eof()
print(response)
return response
except Exception as e:
print(e)
finally:
os.remove(temp_zip.name) # 删除临时文件


# Add route to import node info
@PromptServer.instance.routes.post("/customnode/importNodeInfo")
async def import_customnode_node_info(request):
# 接收上传的ZIP文件并解压到指定目录
""" 接收上传的ZIP文件并解压到指定目录 """
try:
data = await request.post()
zip_file = data.get('file')

# 保存上传的ZIP文件
zip_path = os.path.join(CURRENT_DIR, 'upload.zip')
with open(zip_path, 'wb') as f:
f.write(zip_file.file.read())

# 解压ZIP文件到.cache目录,并且覆盖原有文件
with zipfile.ZipFile(zip_path, 'r') as zipf:
zipf.extractall(cache_dir)

os.remove(zip_path) # 删除上传的ZIP文件
return web.json_response({"success": True})
except Exception as e:
return web.json_response({"success": False})


# 获取设置
def get_setting():
if os.path.exists(setting_path):
with open(setting_path, 'r', encoding='utf-8') as file:
return file.read()
else:
return "{}"

# 获取设置的每一项
def get_setting_item(key):
setting = get_setting()
setting_json = json.loads(setting)
return setting_json[key]

# 保存设置到文件
def save_setting(setting):
with open(setting_path, 'w', encoding='utf-8') as file:
file.write(setting)

if not os.path.exists(setting_path):
save_setting('{"contribute": true}')

# 更新设置到本地.setting.json
@PromptServer.instance.routes.post("/customnode/updateSetting")
async def update_setting(request):
try:
json_data = await request.json()
setting = json_data
# 跟缓存文件的设置项每一项对比,如果有不同则更新
cache_setting = get_setting()
cache_setting_json = json.loads(cache_setting)
for key in setting:
cache_setting_json[key] = setting[key]

# 保存设置到文件,缩近2空格
save_setting(json.dumps(cache_setting_json, indent=2))

return web.json_response({"success": True})
except Exception as e:
return web.json_response({"success": False})

# 发送当前文档到云
async def send_doc_to_cloud(node_type, content):
url = 'http://comfy.zukmb.cn/api/saveNodesDocs'
async with ClientSession() as session:
device_id = get_device_id()
data = {
'device_id': device_id,
'node_type': node_type,
'content': content
}
print('send doc to cloud')
async with session.post(url, data=data) as response:
print(await response.text())
# try:

# # url = 'http://localhost:8080/api/saveNodesDocs'
# # data = {
# # 'device_id': device_id,
# # 'node_type': node_type,
# # 'content': content
# # }
# # requests.post(url, data=data)
# except Exception as e:
# print(e)
Loading

0 comments on commit ec3aa22

Please sign in to comment.