Compare commits

...

10 Commits

Author SHA1 Message Date
89dbe3b916 增加从URL加载音频节点 2025-05-15 19:21:11 +08:00
e004083989 update 2024-10-27 03:30:23 +00:00
a69e6a5017 update 2024-10-27 03:29:14 +00:00
77976deb2c update 2024-10-27 03:18:28 +00:00
f688712e27 update 2024-10-27 02:09:31 +00:00
023511075c update 2024-10-27 01:46:59 +00:00
4cd6809cea update 2024-10-27 01:46:36 +00:00
b46856148c 123 2024-10-27 01:45:32 +00:00
014f3369c4 update 2024-10-27 01:42:39 +00:00
a08e57ada4 update 2024-10-27 01:42:22 +00:00
5 changed files with 79 additions and 15 deletions

View File

@ -19,9 +19,10 @@ If you have ComfyUI-Manager, you can simply search "Easyai for ComfyUI" from `Cu
If you have a comfy-cli, you can simply execute `comfy node registry-install comfyui-easyai` in command line. If you have a comfy-cli, you can simply execute `comfy node registry-install comfyui-easyai` in command line.
## Usage ## Usage
![use](./docs/use.gif)
- After installation, you can use the Easyai nodes in your ComfyUI workflows. - After installation, you can use the Easyai nodes in your ComfyUI workflows.
- For more detailed usage, please refer to the [金华岩石](https://jinhuayanshi.cn) or [三景AI](https://easyai.jinhuayanshi.cn) websites. - For more detailed usage, please refer to the [金华岩石](https://jinhuayanshi.cn) or [三景AI](https://easyai.jinhuayanshi.cn) websites.
- Follow me: <img src="./docs/douyin.jpg" width="200" /> - Follow me: <img src="./docs/douyin.jpg" width="200" />
## License ## License
This project is licensed under the MIT License. See the LICENSE file for details. This project is licensed under the MIT License. See the LICENSE file for details.

View File

@ -1,5 +1,5 @@
WEB_DIRECTORY = "js" WEB_DIRECTORY = "js"
NODE_CLASS_MAPPINGS = {} from .nodes import NODE_CLASS_MAPPINGS
__all__ = ['NODE_CLASS_MAPPINGS'] __all__ = ['NODE_CLASS_MAPPINGS']
from aiohttp import ClientSession, web from aiohttp import ClientSession, web
@ -9,7 +9,7 @@ from server import PromptServer
async def upload_workflow(request): async def upload_workflow(request):
try: try:
data = await request.json() data = await request.json()
url = data["domain"] + "/api/v1/openapi/upload/workflow" url = data["domain"] + "/v1/openapi/upload/workflow"
headers = { headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-comfy-api-key': data["apiKey"] 'x-comfy-api-key': data["apiKey"]

BIN
docs/use.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 MiB

View File

@ -6,17 +6,8 @@ app.registerExtension({
name: "ComfyUI-Easyai", name: "ComfyUI-Easyai",
async setup() { async setup() {
const menu = document.querySelector(".comfy-menu"); const menu = document.querySelector(".comfy-menu");
const separator = document.createElement("hr");
separator.style.margin = "20px 0"; const upload = () => {
separator.style.width = "100%";
menu.append(separator);
const uploadEasyaiButton = document.createElement("button");
uploadEasyaiButton.id = "uploadEasyaiButton";
uploadEasyaiButton.textContent = "上传Easyai";
// 点击按钮时弹出对话框
uploadEasyaiButton.onclick = () => {
// 创建遮罩层 // 创建遮罩层
const overlay = document.createElement('div'); const overlay = document.createElement('div');
overlay.style.position = 'fixed'; overlay.style.position = 'fixed';
@ -50,7 +41,7 @@ app.registerExtension({
// 添加域名输入框标签 // 添加域名输入框标签
const domainLabel = document.createElement('label'); const domainLabel = document.createElement('label');
domainLabel.setAttribute('for', 'domainInput'); domainLabel.setAttribute('for', 'domainInput');
domainLabel.innerText = 'Domain (域名):'; domainLabel.innerText = 'BaseURL (接口地址):';
domainLabel.style.color = 'white'; // 白色标签文字 domainLabel.style.color = 'white'; // 白色标签文字
dialog.appendChild(domainLabel); dialog.appendChild(domainLabel);
@ -165,7 +156,7 @@ app.registerExtension({
localStorage.setItem('easyai-x-comfy-api-key', apiKey); localStorage.setItem('easyai-x-comfy-api-key', apiKey);
localStorage.setItem('easyai-domain', domain); localStorage.setItem('easyai-domain', domain);
app.graphToPrompt().then((p2) => { app.graphToPrompt().then((p2) => {
const workflow = JSON.stringify(p2.output); const workflow = JSON.stringify(p2.output, null, 2);
api.fetchApi('/easyai/upload_workflow', { api.fetchApi('/easyai/upload_workflow', {
method: 'POST', method: 'POST',
headers: { headers: {
@ -209,6 +200,27 @@ app.registerExtension({
} }
}; };
try {
let cmGroup = new (await import("../../scripts/ui/components/buttonGroup.js")).ComfyButtonGroup(
new(await import("../../scripts/ui/components/button.js")).ComfyButton({
icon: "upload",
action: upload,
tooltip: "上传Easyai"
}).element
);
app.menu?.settingsGroup.element.after(cmGroup.element);
}
catch(exception) {
console.log('ComfyUI is outdated. New style menu based features are disabled.');
}
const uploadEasyaiButton = document.createElement("button");
uploadEasyaiButton.id = "uploadEasyaiButton";
uploadEasyaiButton.textContent = "上传Easyai";
// 点击按钮时弹出对话框
uploadEasyaiButton.onclick = upload;
uploadEasyaiButton.style.background = "linear-gradient(135deg, #8A00FF 0%, #00FFC6 100%)"; uploadEasyaiButton.style.background = "linear-gradient(135deg, #8A00FF 0%, #00FFC6 100%)";
uploadEasyaiButton.style.color = "black"; uploadEasyaiButton.style.color = "black";
uploadEasyaiButton.style.display = "inline-block"; uploadEasyaiButton.style.display = "inline-block";

51
nodes.py Normal file
View File

@ -0,0 +1,51 @@
import soundfile as sf
import requests
import io
import numpy as np
import torch
class AudioLoadPath:
@classmethod
def INPUT_TYPES(s):
return {"required": { "path": ("STRING", {"default": "X://insert/path/here.mp4"}),
"sample_rate": ("INT", {"default": 22050, "min": 6000, "max": 192000, "step": 1}),
"offset": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1e6, "step": 0.001}),
"duration": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1e6, "step": 0.001})}}
RETURN_TYPES = ("AUDIO", )
CATEGORY = "Audio Reactor"
FUNCTION = "load"
def load(self, path: str, sample_rate: int, offset: float, duration: float|None):
if duration == 0.0:
duration = None
if path.startswith(('http://', 'https://')):
# 对于网络路径,直接从内存加载
try:
response = requests.get(path)
response.raise_for_status()
audio_data = io.BytesIO(response.content)
# 使用 soundfile 从内存中读取音频数据
audio, file_sr = sf.read(audio_data)
# 如果需要重采样
if file_sr != sample_rate:
# 这里需要添加重采样逻辑
# 可以使用 librosa.resample 或其他方法
pass
except Exception as e:
raise Exception(f"加载网络音频失败: {str(e)}")
else:
# 本地文件使用原有的 librosa 方式加载
audio, _ = librosa.load(path, sr=sample_rate, offset=offset, duration=duration)
# 转换为 torch tensor 并调整维度
audio = torch.from_numpy(audio)[None,:,None]
return (audio,)
NODE_CLASS_MAPPINGS = {
"AudioLoadPath": AudioLoadPath,
}