添加项目目录结构
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
# GitHub 仓库设置指南
|
||||
|
||||
## 自动设置(推荐)
|
||||
1. 双击运行 `setup_github.bat`
|
||||
2. 按照向导提示操作即可
|
||||
|
||||
## 手动设置
|
||||
如果自动设置失败,您可以:
|
||||
1. 访问 https://github.com/settings/tokens/new
|
||||
2. 创建新的访问令牌:
|
||||
- 名称:WanAPI
|
||||
- 有效期:永不过期
|
||||
- 权限:勾选 repo
|
||||
3. 复制生成的token
|
||||
4. 编辑 config.json:
|
||||
```json
|
||||
{
|
||||
"GITHUB_TOKEN": "你的token",
|
||||
"GITHUB_REPO": "你的用户名/仓库名",
|
||||
"GITHUB_BRANCH": "main"
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
1. Token无效
|
||||
- 检查是否正确复制
|
||||
- 确保有 repo 权限
|
||||
2. 仓库创建失败
|
||||
- 检查仓库名是否已存在
|
||||
- 确保token权限正确
|
||||
@@ -0,0 +1,10 @@
|
||||
# 避免在顶层导入,改为按需导入
|
||||
def get_image_processor():
|
||||
from .image_processor import tensor_to_pil, validate_image_url
|
||||
return tensor_to_pil, validate_image_url
|
||||
|
||||
def get_github_client():
|
||||
from .github_client import GitHubUploader
|
||||
return GitHubUploader
|
||||
|
||||
print("✅ utils模块已加载")
|
||||
@@ -0,0 +1,91 @@
|
||||
import os
|
||||
import time
|
||||
import base64
|
||||
import requests
|
||||
from pathlib import Path
|
||||
|
||||
class GitHubUploader:
|
||||
def __init__(self, repo, branch, token):
|
||||
self.repo = repo
|
||||
self.branch = branch
|
||||
self.headers = {
|
||||
"Authorization": f"token {token}",
|
||||
"Accept": "application/vnd.github.v3+json"
|
||||
}
|
||||
|
||||
def _validate_permissions(self):
|
||||
"""验证Token权限"""
|
||||
try:
|
||||
# 验证Token
|
||||
auth_check = requests.get(
|
||||
"https://api.github.com/user",
|
||||
headers=self.headers,
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if auth_check.status_code != 200:
|
||||
print(f"❌ Token验证失败: {auth_check.json().get('message')}")
|
||||
return False
|
||||
|
||||
# 验证仓库访问权限
|
||||
repo_check = requests.get(
|
||||
f"https://api.github.com/repos/{self.repo}",
|
||||
headers=self.headers
|
||||
)
|
||||
|
||||
if repo_check.status_code != 200:
|
||||
print(f"❌ 仓库访问失败: {repo_check.json().get('message')}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 权限验证失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def upload(self, file_path):
|
||||
"""上传文件到GitHub"""
|
||||
if not self._validate_permissions():
|
||||
return None
|
||||
|
||||
try:
|
||||
# 读取文件内容
|
||||
with open(file_path, 'rb') as f:
|
||||
content = base64.b64encode(f.read()).decode('utf-8')
|
||||
|
||||
# 生成文件名
|
||||
filename = f"wanx_{int(time.time())}.jpg"
|
||||
|
||||
# 上传到GitHub
|
||||
response = requests.put(
|
||||
f"https://api.github.com/repos/{self.repo}/contents/images/{filename}",
|
||||
headers=self.headers,
|
||||
json={
|
||||
"message": "Auto-upload from ComfyUI",
|
||||
"content": content,
|
||||
"branch": self.branch
|
||||
},
|
||||
timeout=10
|
||||
)
|
||||
|
||||
# 处理响应
|
||||
if response.status_code == 201:
|
||||
# 返回原始 GitHub URL 而不是 CDN URL
|
||||
return f"https://raw.githubusercontent.com/{self.repo}/{self.branch}/images/{filename}"
|
||||
elif response.status_code == 403:
|
||||
error_msg = response.json().get('message', '')
|
||||
if 'resource is not accessible' in error_msg:
|
||||
print("""❌ 权限不足,请检查:
|
||||
1. Token是否具有repo权限
|
||||
2. 仓库是否设置为私有
|
||||
3. Token是否已过期""")
|
||||
return None
|
||||
|
||||
print(f"❌ 上传失败: {response.status_code} - {response.text}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 上传失败: {str(e)}")
|
||||
import traceback
|
||||
print(f"🔍 详细错误:\n{traceback.format_exc()}")
|
||||
return None
|
||||
@@ -0,0 +1,37 @@
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
import traceback
|
||||
|
||||
def tensor_to_pil(tensor):
|
||||
"""将图像张量转换为PIL图像(兼容4D/3D张量)"""
|
||||
try:
|
||||
# 转换为CPU张量
|
||||
image = tensor.cpu().detach()
|
||||
|
||||
# 处理不同维度
|
||||
if len(image.shape) == 4:
|
||||
image = image[0] # 取批次中第一张
|
||||
if len(image.shape) == 3 and image.shape[0] in [1, 3, 4]:
|
||||
image = image.permute(1, 2, 0) # CHW -> HWC
|
||||
|
||||
# 转换为numpy数组
|
||||
image = (image * 255).clamp(0, 255).byte().numpy()
|
||||
|
||||
# 处理通道数
|
||||
if image.shape[-1] == 1:
|
||||
image = np.concatenate([image]*3, axis=-1)
|
||||
elif image.shape[-1] == 4:
|
||||
image = image[..., :3] # 移除Alpha通道
|
||||
|
||||
return Image.fromarray(image)
|
||||
except Exception as e:
|
||||
print(f"❌ 图像处理失败: {traceback.format_exc()}")
|
||||
return None
|
||||
|
||||
def validate_image_url(url):
|
||||
"""验证图片URL格式"""
|
||||
if not url.startswith(("http://", "https://")):
|
||||
raise ValueError("图片URL必须以http/https开头")
|
||||
if "cdn.jsdelivr.net" not in url and "aliyuncs.com" not in url:
|
||||
print("⚠️ 警告:非受信图片源,可能影响生成稳定性")
|
||||
@@ -0,0 +1,7 @@
|
||||
✅ utils模块已加载
|
||||
# 在ComfyUI的Python控制台中测试
|
||||
from Comfyui_wan_api.utils import image_processor, github_client
|
||||
print("图像处理器模块:", dir(image_processor))
|
||||
print("GitHub客户端:", dir(github_client))
|
||||
图像处理器模块: ['tensor_to_pil', 'validate_image_url']
|
||||
GitHub客户端: ['GitHubUploader']
|
||||
@@ -0,0 +1,465 @@
|
||||
{
|
||||
"last_node_id": 7,
|
||||
"last_link_id": 6,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 3,
|
||||
"type": "easy showAnything",
|
||||
"pos": [
|
||||
-1191.599365234375,
|
||||
2210.471435546875
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
76
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "anything",
|
||||
"type": "*",
|
||||
"link": 2,
|
||||
"shape": 7,
|
||||
"label": "输入任何"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output",
|
||||
"type": "*",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "easy showAnything"
|
||||
},
|
||||
"widgets_values": [
|
||||
"https://raw.githubusercontent.com/penposs/image/main/images/wanx_1740562663.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "WanAPIImageToVideo",
|
||||
"pos": [
|
||||
-877.1105346679688,
|
||||
2040.0242919921875
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
226
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image_url",
|
||||
"type": "STRING",
|
||||
"link": 4,
|
||||
"widget": {
|
||||
"name": "image_url"
|
||||
},
|
||||
"label": "image_url"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video_url",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
5,
|
||||
6
|
||||
],
|
||||
"slot_index": 0,
|
||||
"label": "video_url"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "WanAPIImageToVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
"wanx2.1-i2v-plus",
|
||||
5,
|
||||
"",
|
||||
"动漫风格,镜头环绕,女人跳起挥剑,剑光闪耀,黑雾傀儡碎裂成无数碎片,碎片缓缓飘落,闪闪发光,头发衣服飘动。",
|
||||
896448203,
|
||||
"randomize",
|
||||
"False"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "ShowText|pysssss",
|
||||
"pos": [
|
||||
-851.0746459960938,
|
||||
2318.310302734375
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
476
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"link": 5,
|
||||
"widget": {
|
||||
"name": "text"
|
||||
},
|
||||
"label": "文本"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": null,
|
||||
"shape": 6,
|
||||
"label": "字符串"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ShowText|pysssss"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
"https://dashscope-result-sh.oss-cn-shanghai.aliyuncs.com/1d/51/20250226/72e40b15/a8624ac4-cdf8-433b-9803-d273f99638f1.mp4?Expires=1740648892&OSSAccessKeyId=LTAI5tQZd8AEcZX6KZV4G8qL&Signature=qkCtiHjGJXSoHrHqmtV%2FRqCHziE%3D"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "VHS_LoadVideoPath",
|
||||
"pos": [
|
||||
-441.0176086425781,
|
||||
2044.71484375
|
||||
],
|
||||
"size": [
|
||||
231.8896484375,
|
||||
238
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null,
|
||||
"shape": 7,
|
||||
"label": "批次管理"
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null,
|
||||
"shape": 7,
|
||||
"label": "vae"
|
||||
},
|
||||
{
|
||||
"name": "video",
|
||||
"type": "STRING",
|
||||
"link": 6,
|
||||
"widget": {
|
||||
"name": "video"
|
||||
},
|
||||
"label": "视频"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
3
|
||||
],
|
||||
"slot_index": 0,
|
||||
"label": "图像"
|
||||
},
|
||||
{
|
||||
"name": "frame_count",
|
||||
"type": "INT",
|
||||
"links": [],
|
||||
"slot_index": 1,
|
||||
"label": "帧计数"
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"links": null,
|
||||
"label": "音频"
|
||||
},
|
||||
{
|
||||
"name": "video_info",
|
||||
"type": "VHS_VIDEOINFO",
|
||||
"links": [],
|
||||
"slot_index": 3,
|
||||
"label": "视频信息"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_LoadVideoPath"
|
||||
},
|
||||
"widgets_values": {
|
||||
"video": "https://p1.a.kwimgs.com/bs2/upload-ylab-stunt/special-effect/output/HB1_PROD_ai_web_46554461/-2878350957757294165/output.mp4",
|
||||
"force_rate": 0,
|
||||
"force_size": "Disabled",
|
||||
"custom_width": 512,
|
||||
"custom_height": 512,
|
||||
"frame_load_cap": 0,
|
||||
"skip_first_frames": 0,
|
||||
"select_every_nth": 1,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"frame_load_cap": 0,
|
||||
"skip_first_frames": 0,
|
||||
"force_rate": 0,
|
||||
"filename": "https://p1.a.kwimgs.com/bs2/upload-ylab-stunt/special-effect/output/HB1_PROD_ai_web_46554461/-2878350957757294165/output.mp4",
|
||||
"type": "path",
|
||||
"format": "video/mp4",
|
||||
"select_every_nth": 1
|
||||
},
|
||||
"muted": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "VHS_VideoCombine",
|
||||
"pos": [
|
||||
-143.3603057861328,
|
||||
2037.040771484375
|
||||
],
|
||||
"size": [
|
||||
247.27825927734375,
|
||||
657.9598999023438
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 3,
|
||||
"label": "图像"
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": null,
|
||||
"shape": 7,
|
||||
"label": "音频"
|
||||
},
|
||||
{
|
||||
"name": "meta_batch",
|
||||
"type": "VHS_BatchManager",
|
||||
"link": null,
|
||||
"shape": 7,
|
||||
"label": "批次管理"
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null,
|
||||
"shape": 7,
|
||||
"label": "vae"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Filenames",
|
||||
"type": "VHS_FILENAMES",
|
||||
"links": [],
|
||||
"slot_index": 0,
|
||||
"label": "文件名"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VHS_VideoCombine"
|
||||
},
|
||||
"widgets_values": {
|
||||
"frame_rate": 30,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "wan/test",
|
||||
"format": "video/h264-mp4",
|
||||
"pix_fmt": "yuv420p",
|
||||
"crf": 19,
|
||||
"save_metadata": true,
|
||||
"pingpong": false,
|
||||
"save_output": true,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "test_00002.mp4",
|
||||
"subfolder": "wan",
|
||||
"type": "output",
|
||||
"format": "video/h264-mp4",
|
||||
"frame_rate": 30,
|
||||
"workflow": "test_00002.png",
|
||||
"fullpath": "I:\\ComfyUI_windows_portable\\ComfyUI\\output\\wan\\test_00002.mp4"
|
||||
},
|
||||
"muted": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
-1545.814208984375,
|
||||
1985.2684326171875
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
314
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0,
|
||||
"label": "图像"
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"label": "遮罩"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"46.jpg",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "WanAPIImageUploader",
|
||||
"pos": [
|
||||
-1187.8138427734375,
|
||||
1991.5435791015625
|
||||
],
|
||||
"size": [
|
||||
231.67236328125,
|
||||
130
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 1,
|
||||
"label": "images"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0,
|
||||
"label": "STRING"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "WanAPIImageUploader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"GitHub",
|
||||
"",
|
||||
"main",
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
3,
|
||||
7,
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
4,
|
||||
3,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
5,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
6,
|
||||
5,
|
||||
0,
|
||||
7,
|
||||
2,
|
||||
"STRING"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 1,
|
||||
"offset": [
|
||||
1584.863449468461,
|
||||
-1739.5341228629436
|
||||
]
|
||||
},
|
||||
"groupNodes": {},
|
||||
"ue_links": []
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Reference in New Issue
Block a user