llm节点支持链接分析

This commit is contained in:
yp 2025-09-07 17:25:35 +08:00
parent aeec2f1939
commit e35664c204
4 changed files with 85 additions and 8 deletions

View File

@ -18,6 +18,7 @@ from .nodes.video_agent import VideoSubmitNode
from .nodes.save_node import ExtSaveNode from .nodes.save_node import ExtSaveNode
from .nodes.video_preview import VideoDownloaderNode from .nodes.video_preview import VideoDownloaderNode
from .nodes.fetch_task_result import FetchTaskResult from .nodes.fetch_task_result import FetchTaskResult
from .nodes.file_upload import FileUploadNode
NODE_CLASS_MAPPINGS = { NODE_CLASS_MAPPINGS = {
"FaceOccDetect": FaceDetect, "FaceOccDetect": FaceDetect,
@ -63,7 +64,8 @@ NODE_CLASS_MAPPINGS = {
"VideoSubmitNode": VideoSubmitNode, "VideoSubmitNode": VideoSubmitNode,
"ExtSaveNode": ExtSaveNode, "ExtSaveNode": ExtSaveNode,
"VideoDownloaderNode": VideoDownloaderNode, "VideoDownloaderNode": VideoDownloaderNode,
"FetchTaskResult": FetchTaskResult "FetchTaskResult": FetchTaskResult,
"FileUploadNode": FileUploadNode
} }
NODE_DISPLAY_NAME_MAPPINGS = { NODE_DISPLAY_NAME_MAPPINGS = {
@ -110,5 +112,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"VideoSubmitNode": "提交视频生成", "VideoSubmitNode": "提交视频生成",
"ExtSaveNode": "通用文件保存", "ExtSaveNode": "通用文件保存",
"VideoDownloaderNode": "视频下载", "VideoDownloaderNode": "视频下载",
"FetchTaskResult": "获取生成结果 (图片/视频链接)" "FetchTaskResult": "获取生成结果 (图片/视频链接)",
"FileUploadNode": "文件上传"
} }

View File

@ -27,7 +27,8 @@ image = (
.run_commands("comfy node install https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite.git") .run_commands("comfy node install https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite.git")
.run_commands("comfy node install https://github.com/WASasquatch/was-node-suite-comfyui.git") .run_commands("comfy node install https://github.com/WASasquatch/was-node-suite-comfyui.git")
.run_commands("comfy node install https://github.com/cubiq/ComfyUI_essentials.git") .run_commands("comfy node install https://github.com/cubiq/ComfyUI_essentials.git")
.add_local_dir(local_path='/Users/charon/Desktop/ComfyUI-CustomNode', remote_path='/root/comfy/ComfyUI/custom_nodes', .add_local_dir(local_path='/Users/charon/Desktop/ComfyUI-CustomNode',
remote_path='/root/comfy/ComfyUI/custom_nodes',
copy=True copy=True
) )
.run_commands("comfy node install https://github.com/jamesWalker55/comfyui-various.git") .run_commands("comfy node install https://github.com/jamesWalker55/comfyui-various.git")
@ -59,6 +60,7 @@ vol = modal.Volume.from_name("comfy_model", environment_name="dev", create_if_mi
def ui_1(): def ui_1():
subprocess.Popen("comfy launch -- --cpu --listen 0.0.0.0 --port 8000", shell=True) subprocess.Popen("comfy launch -- --cpu --listen 0.0.0.0 --port 8000", shell=True)
@app.function( @app.function(
min_containers=0, min_containers=0,
buffer_containers=0, buffer_containers=0,

73
nodes/file_upload.py Normal file
View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
"""
Author charon
Date 2025/9/7 13:12
"""
import os
import requests
import mimetypes
import folder_paths
class FileUploadNode:
ENVIRONMENT_URL_MAP = {
"prod": "https://bowongai-prod--text-video-agent-fastapi-app.modal.run",
"test": "https://bowongai-test--text-video-agent-fastapi-app.modal.run",
"dev": "https://bowongai-dev--text-video-agent-fastapi-app.modal.run"
}
API_ENDPOINT = "/api/file/upload/s3"
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"file_to_upload": ("*", {"file_upload": True}),
"environment": (list(s.ENVIRONMENT_URL_MAP.keys()), {"default": "dev"}),
"form_field_name": ("STRING", {"multiline": False, "default": "file"}),
},
}
CATEGORY = "不忘科技-自定义节点🚩/utils/文件上传"
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("url",)
FUNCTION = "handler_file_upload"
def handler_file_upload(self, file_to_upload, environment, form_field_name):
if not file_to_upload or not isinstance(file_to_upload, str):
return (f"Error: Invalid file input. Please upload a file.",)
base_url = self.ENVIRONMENT_URL_MAP.get(environment)
if not base_url:
error_message = f"Error: Invalid environment '{environment}' selected."
return (error_message,)
full_api_url = base_url + self.API_ENDPOINT
local_filepath = folder_paths.get_annotated_filepath(file_to_upload)
if not os.path.exists(local_filepath):
return (f"Error: File not found at path: {local_filepath}",)
headers = {'accept': 'application/json'}
filename = os.path.basename(local_filepath)
mime_type, _ = mimetypes.guess_type(local_filepath)
if mime_type is None:
mime_type = 'application/octet-stream'
try:
with open(local_filepath, 'rb') as f:
files = {form_field_name: (filename, f, mime_type)}
print(f"Uploading '{filename}' to '{full_api_url}'...")
response = requests.post(full_api_url, headers=headers, files=files)
response.raise_for_status()
json_response = response.json()
if json_response.get("status"):
result_url = json_response.get("data")
print(f"Success! URL: {result_url}")
return (result_url,)
else:
api_msg = json_response.get("msg", "Unknown API error")
error_message = f"Error from API: '{api_msg}'"
return (error_message,)
except Exception as e:
raise ValueError(f'File upload process failed: {e}')

View File

@ -28,7 +28,7 @@ def handler_google_analytics(prompt: str, model_id: str, media_file_path: str, b
if media_file_path and os.path.exists(media_file_path): if media_file_path and os.path.exists(media_file_path):
files['img_file'] = (os.path.basename(media_file_path), open(media_file_path, 'rb'), files['img_file'] = (os.path.basename(media_file_path), open(media_file_path, 'rb'),
mimetypes.guess_type(media_file_path)[0] or 'application/octet-stream') mimetypes.guess_type(media_file_path)[0] or 'application/octet-stream')
if media_file_path.startswith("gs:"): if bool(media_file_path) and media_file_path.startswith("gs:"):
files['img_url'] = (None, media_file_path) files['img_url'] = (None, media_file_path)
try: try:
response = requests.post(f'{base_url}/api/llm/google/analysis', headers=headers, files=files, response = requests.post(f'{base_url}/api/llm/google/analysis', headers=headers, files=files,
@ -62,7 +62,7 @@ class LLMUionNode:
"video": ("*",), "video": ("*",),
"image": ("IMAGE",), "image": ("IMAGE",),
"audio": ("AUDIO",), "audio": ("AUDIO",),
"url": ("STRING", {"multiline": True, "default": "", "placeholder": "【可选】输入要分析的链接"}), "url": ("STRING", {"multiline": True, "default": None, "placeholder": "【可选】输入要分析的链接"}),
"environment": (s.ENVIRONMENTS,), "environment": (s.ENVIRONMENTS,),
"timeout": ("INT", {"default": 300, "min": 10, "max": 1200}), "timeout": ("INT", {"default": 300, "min": 10, "max": 1200}),
} }
@ -155,7 +155,7 @@ class LLMUionNode:
timeout=300): timeout=300):
base_url = self.ENV_URLS.get(environment, self.ENV_URLS["prod"]) base_url = self.ENV_URLS.get(environment, self.ENV_URLS["prod"])
media_path = None media_path = None
url = url.strip()
if video is not None: if video is not None:
if 'gemini' not in model_name: if 'gemini' not in model_name:
raise ValueError(f'{model_name}暂不支持视频分析,\n请使用gemini-2.5-flash或者gemini-2.5-pro') raise ValueError(f'{model_name}暂不支持视频分析,\n请使用gemini-2.5-flash或者gemini-2.5-pro')
@ -180,7 +180,6 @@ class LLMUionNode:
media_path = full_path media_path = full_path
else: else:
return (f"错误: 无法在 'input' 文件夹中找到文件 '{unwrapped_input}'",) return (f"错误: 无法在 'input' 文件夹中找到文件 '{unwrapped_input}'",)
elif image is not None: elif image is not None:
print('多模态处理图片输出...') print('多模态处理图片输出...')
pil_image = self.tensor_to_pil(image) pil_image = self.tensor_to_pil(image)
@ -218,7 +217,7 @@ class LLMUionNode:
else: else:
return (f"错误: 不支持的音频输入格式或结构。收到类型: {type(audio_info)}",) return (f"错误: 不支持的音频输入格式或结构。收到类型: {type(audio_info)}",)
elif url is not None: elif url:
url = url.strip() url = url.strip()
model_name = model_name.strip() model_name = model_name.strip()
is_google = model_name.startswith('gemini') is_google = model_name.startswith('gemini')