трансфер c github

This commit is contained in:
2026-08-30 18:02:00 +06:00
parent 9699bedc96
commit 5c05276a30
9 changed files with 1787 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
python-telegram-bot --pre
Pillow
requests
aiohttp
aiofiles
websockets
BIN
View File
Binary file not shown.
+456
View File
@@ -0,0 +1,456 @@
import asyncio
import json
import os
import sqlite3
import tempfile
import uuid
from datetime import datetime
from PIL import Image
import subprocess
import requests
import shutil
import glob
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes, ConversationHandler, CallbackQueryHandler
RULES_CALLBACK = "show_rules"
BACK_CALLBACK = "back_to_main"
COMFYUI_WORKFLOW = "video_generate.json"
TELEGRAM_TOKEN = "TELEGRAM_TOKEN"
COMFYUI_URL = "http://127.0.0.1:8188"
COMFYUI_OUTPUT_DIR = "output/"
COMFYUI_INPUT_DIR = "input/"
COMFYUI_COMMON_PROMT = ["woman take off her clothes, full nudity, full naked, pyssy, boobs, nipples. camera zooms out",""]
COMFYUI_MAX_SIZE = 580
COMFYUI_COST = 20
ADMIN_IDS = [1145483994, 498845556]
WAITING_CONFIRM = 0
def init_db():
conn = sqlite3.connect('bot.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
username TEXT,
balance INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)''')
c.execute('''CREATE TABLE IF NOT EXISTS admin_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
admin_id INTEGER NOT NULL,
admin_username TEXT,
target_user_id INTEGER NOT NULL,
tokens_added INTEGER NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)''')
conn.commit()
conn.close()
def log_admin_action(admin_id, admin_username, target_user_id, tokens):
"""Записывает действие админа в файл"""
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
log_entry = (
f"[{timestamp}] Admin {admin_id} (@{admin_username}) "
f"added {tokens} tokens to user {target_user_id}\n"
)
with open('admin_actions.log', 'a', encoding='utf-8') as f:
f.write(log_entry)
def get_user_balance(user_id):
conn = sqlite3.connect('bot.db')
c = conn.cursor()
c.execute('SELECT balance FROM users WHERE user_id = ?', (user_id,))
result = c.fetchone()
conn.close()
return result[0] if result else 0
def add_user(user_id, username):
conn = sqlite3.connect('bot.db')
c = conn.cursor()
c.execute('INSERT OR IGNORE INTO users (user_id, username) VALUES (?, ?)', (user_id, username))
conn.commit()
conn.close()
def update_balance(user_id, amount):
conn = sqlite3.connect('bot.db')
c = conn.cursor()
c.execute('UPDATE users SET balance = balance + ? WHERE user_id = ?', (amount, user_id))
conn.commit()
conn.close()
def deduct_balance(user_id, amount):
conn = sqlite3.connect('bot.db')
c = conn.cursor()
c.execute('UPDATE users SET balance = balance - ? WHERE user_id = ?', (amount, user_id))
conn.commit()
conn.close()
def resize_image(image_path, max_size=COMFYUI_MAX_SIZE):
with Image.open(image_path) as img:
img = img.convert('RGBA')
width, height = img.size
if width > height:
new_width = min(width, max_size)
new_height = int(height * new_width / width)
else:
new_height = min(height, max_size)
new_width = int(width * new_height / height)
resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
return new_width, new_height, resized
def find_video_output_node(workflow_dict):
for node_id, node in workflow_dict.items():
inputs = node.get("inputs", {})
if isinstance(inputs, dict) and "filename_prefix" in inputs:
return node_id
raise ValueError("No video output node with 'filename_prefix' found in workflow!")
def find_latest_video(output_dir, extensions=('.mp4', '.webm', '.mkv')):
"""Ищет самый свежий видеофайл в output_dir"""
all_videos = []
for root, _, files in os.walk(output_dir):
for f in files:
if f.lower().endswith(extensions):
full_path = os.path.join(root, f)
all_videos.append(full_path)
if not all_videos:
return None
return max(all_videos, key=os.path.getmtime)
def modify_workflow(workflow_str, prompt, image_filename, width, height, video_prefix):
wf_raw = json.loads(workflow_str)
wf = {}
for key, value in wf_raw.items():
clean_key = key.strip()
if isinstance(value, dict) and 'inputs' in value:
inputs_raw = value['inputs']
if isinstance(inputs_raw, dict):
clean_inputs = {}
for in_key, in_val in inputs_raw.items():
clean_inputs[in_key.strip()] = in_val
value = {k: v for k, v in value.items() if k != 'inputs'}
value['inputs'] = clean_inputs
wf[clean_key] = value
if '93' in wf and 'inputs' in wf['93']:
wf['93']['inputs']['text'] = f"{COMFYUI_COMMON_PROMT}"
height = (height // 16) * 16
width = (width // 16) * 16
if '183' in wf and 'inputs' in wf['183']:
wf['183']['inputs']['value'] = height
if '184' in wf and 'inputs' in wf['184']:
wf['184']['inputs']['value'] = width
if '193' in wf and 'inputs' in wf['193']:
wf['193']['inputs']['image'] = image_filename
if '214' in wf and 'inputs' in wf['214']:
wf['214']['inputs']['filename_prefix'] = video_prefix
return json.dumps(wf)
def find_video_by_prefix(output_dir, prefix, extensions=('.mp4', '.webm', '.mkv')):
for ext in extensions:
pattern = os.path.join(output_dir, '**', f"{prefix}*{ext}")
matches = glob.glob(pattern, recursive=True)
if matches:
return max(matches, key=os.path.getmtime)
return None
async def run_comfyui_workflow(workflow_json_str, input_image_path, video_prefix, update: Update):
workflow_dict = json.loads(workflow_json_str)
client_id = str(uuid.uuid4())
async with aiohttp.ClientSession() as session:
async with session.post(f"{COMFYUI_URL}/prompt", json={
"prompt": workflow_dict,
"client_id": client_id
}) as resp:
if resp.status != 200:
raise Exception(f"ComfyUI API error {resp.status}")
prompt_id = (await resp.json())["prompt_id"]
progress_msg = await update.message.reply_text("🚀 Запуск генерации...")
uri = f"ws://127.0.0.1:8188/ws?clientId={client_id}"
try:
async with websockets.connect(uri) as websocket:
while True:
try:
msg = await asyncio.wait_for(websocket.recv(), timeout=300.0)
data = json.loads(msg)
if data["type"] == "executing":
node = data["data"].get("node")
if node is None:
break
try:
await progress_msg.edit_text("🔄 Обрабатываю...")
except BadRequest as e:
if "Message is not modified" not in str(e):
raise
elif data["type"] == "progress":
value = data["data"].get("value", 0)
max_val = data["data"].get("max", 1)
pct = int(100 * value / max_val) if max_val else 0
await progress_msg.edit_text(f"⏳ Прогресс: {pct}%")
elif data["type"] == "execution_error":
err = data["data"].get("exception_message", "Ошибка")
raise Exception(err)
except asyncio.TimeoutError:
break
except Exception as e:
print(f"WebSocket error: {e}")
await progress_msg.edit_text("🎥 Собираю видео...")
for _ in range(60):
await asyncio.sleep(2)
video_path = find_latest_video(COMFYUI_OUTPUT_DIR)
if video_path and os.path.getsize(video_path) > 1024:
await progress_msg.edit_text("✅ Готово!")
return video_path
raise Exception("Видео не найдено")
def clean_metadata(video_path):
temp_dir = os.path.dirname(video_path)
with tempfile.NamedTemporaryFile(suffix='.mp4', dir=temp_dir, delete=False) as tmp:
temp_path = tmp.name
try:
subprocess.run([
'ffmpeg', '-y', '-i', video_path,
'-map_metadata', '-1',
'-c:v', 'libx264',
'-c:a', 'aac',
'-pix_fmt', 'yuv420p',
temp_path
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
shutil.copy2(temp_path, video_path)
os.unlink(temp_path)
return video_path
except Exception as e:
if os.path.exists(temp_path):
os.unlink(temp_path)
raise Exception(f"Metadata cleanup failed: {str(e)}")
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
add_user(user.id, user.username)
balance = get_user_balance(user.id)
keyboard = [[InlineKeyboardButton("ПРАВИЛА", callback_data=RULES_CALLBACK)]]
await update.message.reply_text(
f"👋🏻 Привет, Творец!\n\n"
"Рада видеть тебя в SecretRoom\n\n"
"✅ Любая фантазия о которой ты мечтал оживёт в этом боте\n\n"
"Жми «🔮 Оживить фото» и наслаждайся\n\n"
"Стоимость: 20 токен за запрос.\n\n"
f"Ваш баланс: {balance} токенов.",
reply_markup=InlineKeyboardMarkup(keyboard),
)
return ConversationHandler.END
async def handle_admin_add(update: Update, context: ContextTypes.DEFAULT_TYPE):
if update.effective_user.id not in ADMIN_IDS:
await update.message.reply_text("У вас нет прав администратора.")
return
try:
tokens = int(context.args[0])
target_id = int(context.args[1])
update_balance(target_id, tokens)
log_admin_action(
update.effective_user.id,
update.effective_user.username or 'unknown',
target_id,
tokens
)
await update.message.reply_text(f"Добавлено {tokens} токенов пользователю {target_id}.")
except (IndexError, ValueError):
await update.message.reply_text("Использование: /add <токены> <user_id>")
async def handle_photo(update: Update, context: ContextTypes.DEFAULT_TYPE):
photo_file = await update.message.photo[-1].get_file()
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
temp_image = tmp.name
await photo_file.download_to_drive(temp_image)
width, height, resized_img = resize_image(temp_image)
resized_path = temp_image.replace('.png', '_resized.png')
resized_img.save(resized_path, format='PNG')
os.unlink(temp_image)
context.user_data['image_path'] = resized_path
context.user_data['width'] = width
context.user_data['height'] = height
video_prefix = f"video_{uuid.uuid4().hex[:12]}"
context.user_data['video_prefix'] = video_prefix
cost = COMFYUI_COST
balance = get_user_balance(update.effective_user.id)
keyboard = [
[InlineKeyboardButton("✅ Начать (Пресет 1)", callback_data="preset_1")],
[InlineKeyboardButton("🎭 Начать (Пресет 2)", callback_data="preset_2")],
[InlineKeyboardButton("❌ Отмена", callback_data="cancel_gen")]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
f"Стоимость генерации: {cost} токенов.\n"
f"Ваш баланс: {balance}\n"
"Выберите пресет для генерации:",
reply_markup=reply_markup
)
return ConversationHandler.END
async def handle_photo_anywhere(update: Update, context: ContextTypes.DEFAULT_TYPE):
return await handle_photo(update, context)
async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
if query.data == "preset_1":COMFYUI_COMMON_PROMT[0]
if query.data == "preset_2":COMFYUI_COMMON_PROMT[1]
if query.data == RULES_CALLBACK:
keyboard = [[InlineKeyboardButton("← Назад", callback_data=BACK_CALLBACK)]]
await query.message.reply_text(
"🖼 Творец, отправь фото ниже!:\n\n"
"Выбери фото человека или из аниме🙈:\n\n"
"Для лучшего результата следуй этим правилам:\n\n"
"✅ Фотография в полный рост\n"
"✅ Девушка смотрит прямо в камеру\n"
"✅ Хорошее освещение\n"
"❌ Нет солнцезащитных очков\n"
"❌ Не закрывать лицо волосами",
reply_markup=InlineKeyboardMarkup(keyboard)
)
await query.message.delete()
elif query.data == "preset_1":
await query.answer()
await start_generation(update, context, preset_index=0)
elif query.data == "preset_2":
await query.answer()
await start_generation(update, context, preset_index=1)
elif query.data == "cancel_gen":
await query.answer()
image_path = context.user_data.get('image_path')
if image_path and os.path.exists(image_path):
os.unlink(image_path)
context.user_data.clear()
await query.message.edit_text("Операция отменена.")
elif query.data == BACK_CALLBACK:
context.user_data.clear()
user = update.effective_user
add_user(user.id, user.username)
balance = get_user_balance(user.id)
keyboard = [[InlineKeyboardButton("ПРАВИЛА", callback_data=RULES_CALLBACK)]]
await query.message.reply_text(
f"👋🏻 Привет, Творец!\n\n"
"Рада видеть тебя в SecretRoom\n\n"
"✅ Любая фантазия о которой ты мечтал оживёт в этом боте\n\n"
"Жми «🔮 Оживить фото» и наслаждайся\n\n"
"Стоимость: 20 токен за запрос.\n\n"
f"Ваш баланс: {balance} токенов.",
reply_markup=InlineKeyboardMarkup(keyboard)
)
await query.message.delete()
async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Отменено.")
image_path = context.user_data.get('image_path')
if image_path and os.path.exists(image_path):
os.unlink(image_path)
context.user_data.clear()
return ConversationHandler.END
async def start_generation(update: Update, context: ContextTypes.DEFAULT_TYPE, preset_index: int):
query = update.callback_query
user_id = update.effective_user.id
cost = COMFYUI_COST
balance = get_user_balance(user_id)
if balance < cost:
await query.edit_message_text("❌ Недостаточно токенов.")
context.user_data.clear()
return
deduct_balance(user_id, cost)
await query.edit_message_text("🚀 Начинаю генерацию...")
try:
image_path = context.user_data['image_path']
video_prefix = context.user_data['video_prefix']
selected_prompt = COMFYUI_COMMON_PROMT[preset_index]
os.makedirs(COMFYUI_INPUT_DIR, exist_ok=True)
image_filename = f"user_image_{uuid.uuid4().hex[:12]}.png"
input_image_path = os.path.join(COMFYUI_INPUT_DIR, image_filename)
shutil.copy(image_path, input_image_path)
with open(COMFYUI_WORKFLOW, 'r', encoding='utf-8') as f:
workflow_base = f.read()
modified_workflow = modify_workflow(
workflow_base,
selected_prompt,
image_filename,
context.user_data['width'],
context.user_data['height'],
video_prefix
)
video_path = await run_comfyui_workflow(modified_workflow, input_image_path, video_prefix)
video_path = clean_metadata(video_path)
with open(video_path, 'rb') as video_file:
await query.message.reply_video(video_file, supports_streaming=True)
await query.message.reply_text("✅ Генерация завершена!")
for p in [image_path, input_image_path, video_path]:
if os.path.exists(p):
os.unlink(p)
except Exception as e:
await query.message.reply_text(f"❌ Ошибка генерации: {str(e)}")
update_balance(user_id, cost)
new_balance = get_user_balance(user_id)
await query.message.reply_text(f"Ваш баланс: {new_balance} токенов.")
context.user_data.clear()
def main():
init_db()
app = Application.builder().token(TELEGRAM_TOKEN).build()
conv_handler = ConversationHandler(
entry_points=[MessageHandler(filters.PHOTO & ~filters.COMMAND, handle_photo)],
states={},
fallbacks=[],
)
app.add_handler(CommandHandler("start", start))
app.add_handler(CommandHandler("add", handle_admin_add))
app.add_handler(conv_handler)
app.add_handler(CallbackQueryHandler(handle_callback))
print(f"Бот запущен. Output dir: {COMFYUI_OUTPUT_DIR}")
app.run_polling()
if __name__ == '__main__':
main()
Executable
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
curl -L "https://huggingface.co/NSFW-API/NSFW-Wan-UMT5-XXL/resolve/main/nsfw_wan_umt5-xxl_fp8_scaled.safetensors" \
--output "models/clip/nsfw_wan_umt5-xxl_fp8_scaled.safetensors"
curl -f -L -H "Authorization: Bearer YOUR_API_KEY_FOR_CIVITAI" \
"https://civitai.com/api/download/models/2467166?type=Model&format=GGUF&size=full&fp=fp16" \
--output "models/unet/DasiwaWAN22I2V14BTastysinV8_q5High.gguf"
curl -f -L -H "Authorization: Bearer YOUR_API_KEY_FOR_CIVITAI" \
"https://civitai.com/api/download/models/2467350?type=Model&format=GGUF&size=full&fp=fp16" \
--output "models/unet/DasiwaWAN22I2V14BTastysinV8_q5Low.gguf"
+641
View File
@@ -0,0 +1,641 @@
{
"1": {
"inputs": {
"ckpt_name": "hyphoriaIlluNAI_v001.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Load Checkpoint"
}
},
"4": {
"inputs": {
"text": "asterpiece, best quality, very aesthetic, amazing quality, absurdres, newest, simple background.BREAK.\nfull body,black background.BREAK. \nelf,elf eyars,girl,solo,big breast,middle age woman,sexual body, white square hair, black skirt, black transparent stockings, yellow crop top,without shoes,without sleeves, full body",
"clip": [
"84",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "POSITIVE PROMT"
}
},
"5": {
"inputs": {
"text": "(worst quality, low quality, very displeasing, lowres),(interlocked fingers, badly drawn hands and fingers, anatomically incorrect hands),blurry,watermark,multiple views,comic,censored,jpeg artifacts,patreon logo,patreon username,web address,signature,watermark,text,logo,artist name,safe_neg,unfinished,displeasing,oldest,early,chromatic aberration,signature,artistic error,scan,",
"clip": [
"84",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "NEGATIVE PROMT"
}
},
"6": {
"inputs": {
"width": 592,
"height": 1000,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Empty Latent Image"
}
},
"45": {
"inputs": {
"rgthree_comparer": {
"images": [
{
"name": "A",
"selected": true,
"url": "/api/view?filename=rgthree.compare._temp_uombk_00007_.png&type=temp&subfolder=&rand=0.8818697993189192"
},
{
"name": "B",
"selected": true,
"url": "/api/view?filename=rgthree.compare._temp_uombk_00008_.png&type=temp&subfolder=&rand=0.5067790983571415"
}
]
},
"image_a": [
"79:59",
0
],
"image_b": [
"79:48",
0
]
},
"class_type": "Image Comparer (rgthree)",
"_meta": {
"title": "Image Comparer (rgthree)"
}
},
"50": {
"inputs": {
"rgthree_comparer": {
"images": [
{
"name": "A",
"selected": true,
"url": "/api/view?filename=rgthree.compare._temp_xvppg_00021_.png&type=temp&subfolder=&rand=0.6368199259194705"
},
{
"name": "B",
"selected": true,
"url": "/api/view?filename=rgthree.compare._temp_xvppg_00022_.png&type=temp&subfolder=&rand=0.07174302046978531"
}
]
},
"image_a": [
"79:48",
0
],
"image_b": [
"79:8",
0
]
},
"class_type": "Image Comparer (rgthree)",
"_meta": {
"title": "Image Comparer (rgthree)"
}
},
"84": {
"inputs": {
"PowerLoraLoaderHeaderWidget": {
"type": "PowerLoraLoaderHeaderWidget"
},
"lora_1": {
"on": true,
"lora": "image/r17329_illuu.safetensors",
"strength": 0.39
},
"lora_2": {
"on": true,
"lora": "image/illustrious_masterpieces_v3.safetensors",
"strength": 0.21
},
"lora_3": {
"on": true,
"lora": "image/ma1ma1helmes_b-000014.safetensors",
"strength": 0.65
},
"lora_4": {
"on": false,
"lora": "image/MGE_V6.1_IL_Final_R1.safetensors",
"strength": 0.317578125
},
"lora_5": {
"on": false,
"lora": "image/People'sWorks_v9_Illusv1.0_128dim.safetensors",
"strength": 0.7136718750000002
},
"lora_6": {
"on": true,
"lora": "image/𝐓𝐡𝐞_𝐨𝐧𝐥𝐲_𝐋𝐨𝐑𝐀_𝐲𝐨𝐮_𝐞𝐯𝐞𝐫_𝐧𝐞𝐞𝐝__必要なのはLoRAだけ__by_CHROMEKIDD.safetensors",
"strength": 0.48
},
"➕ Add Lora": "",
"model": [
"1",
0
],
"clip": [
"1",
1
]
},
"class_type": "Power Lora Loader (rgthree)",
"_meta": {
"title": "LORA 1"
}
},
"85": {
"inputs": {
"PowerLoraLoaderHeaderWidget": {
"type": "PowerLoraLoaderHeaderWidget"
},
"lora_1": {
"on": true,
"lora": "image/r17329_illuu.safetensors",
"strength": 0.11
},
"lora_2": {
"on": true,
"lora": "image/illustrious_masterpieces_v3.safetensors",
"strength": 0.08
},
"lora_3": {
"on": true,
"lora": "image/ma1ma1helmes_b-000014.safetensors",
"strength": 0.1
},
"➕ Add Lora": "",
"model": [
"1",
0
],
"clip": [
"1",
1
]
},
"class_type": "Power Lora Loader (rgthree)",
"_meta": {
"title": "LORA 2"
}
},
"86": {
"inputs": {
"images": [
"79:8",
0
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Preview Image"
}
},
"88": {
"inputs": {
"image": "depth_00009_ (3).png"
},
"class_type": "LoadImage",
"_meta": {
"title": "Load Image"
}
},
"79:54": {
"inputs": {
"UNKNOWN": "bbox/hand_yolov8s.pt"
},
"_meta": {}
},
"79:53": {
"inputs": {
"UNKNOWN": "all",
"bbox_detector": [
"79:54",
0
],
"image": [
"79:38",
0
]
},
"_meta": {}
},
"79:34": {
"inputs": {
"UNKNOWN": "all",
"segm_detector": [
"79:36",
1
],
"image": [
"79:57",
0
]
},
"_meta": {}
},
"79:60": {
"inputs": {
"UNKNOWN": "all",
"bbox_detector": [
"79:61",
0
],
"image": [
"79:51",
0
]
},
"_meta": {}
},
"79:59": {
"inputs": {
"UNKNOWN": false,
"image": [
"79:51",
0
],
"segs": [
"79:60",
0
],
"basic_pipe": [
"79:23",
0
]
},
"_meta": {}
},
"79:38": {
"inputs": {
"UNKNOWN": false,
"image": [
"79:57",
0
],
"segs": [
"79:34",
0
],
"basic_pipe": [
"79:10",
0
]
},
"_meta": {}
},
"79:51": {
"inputs": {
"UNKNOWN": false,
"image": [
"79:38",
0
],
"segs": [
"79:53",
0
],
"basic_pipe": [
"79:23",
0
]
},
"_meta": {}
},
"79:61": {
"inputs": {
"UNKNOWN": "bbox/99coins_anime_girl_face_box.pt"
},
"_meta": {}
},
"79:40": {
"inputs": {
"images": [
"79:38",
5
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Preview Image"
}
},
"79:62": {
"inputs": {
"images": [
"79:59",
5
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Preview Image"
}
},
"79:8": {
"inputs": {
"samples": [
"79:3",
0
],
"vae": [
"1",
2
]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE Decode"
}
},
"79:10": {
"inputs": {
"model": [
"85",
0
],
"clip": [
"85",
1
],
"vae": [
"1",
2
],
"positive": [
"4",
0
],
"negative": [
"4",
0
]
},
"_meta": {}
},
"79:48": {
"inputs": {
"samples": [
"79:47",
0
],
"vae": [
"1",
2
]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE Decode"
}
},
"79:57": {
"inputs": {
"upscale_model": [
"79:56",
0
],
"image": [
"79:48",
0
]
},
"class_type": "ImageUpscaleWithModel",
"_meta": {
"title": "Upscale Image (using Model)"
}
},
"79:23": {
"inputs": {
"basic_pipe": [
"79:10",
0
]
},
"_meta": {}
},
"79:39": {
"inputs": {
"filename_prefix": "detailed",
"images": [
"79:59",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "Save Image"
}
},
"79:55": {
"inputs": {
"images": [
"79:51",
5
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Preview Image"
}
},
"79:56": {
"inputs": {
"model_name": "2x-AnimeSharpV4_RCAN.safetensors"
},
"class_type": "UpscaleModelLoader",
"_meta": {
"title": "Load Upscale Model"
}
},
"79:36": {
"inputs": {
"UNKNOWN": "segm/person_yolov8m-seg.pt"
},
"_meta": {}
},
"79:46": {
"inputs": {
"upscale_method": "bicubic",
"scale_by": 1.25,
"samples": [
"79:3",
0
]
},
"class_type": "LatentUpscaleBy",
"_meta": {
"title": "Upscale Latent By"
}
},
"79:47": {
"inputs": {
"seed": 572039885248643,
"steps": 35,
"cfg": 3.1,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 0.47,
"model": [
"85",
0
],
"positive": [
"4",
0
],
"negative": [
"5",
0
],
"latent_image": [
"79:46",
0
]
},
"class_type": "KSampler",
"_meta": {
"title": "KSampler"
}
},
"79:12": {
"inputs": {
"text": "",
"clip": [
"84",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"79:11": {
"inputs": {
"text": "detailed",
"clip": [
"84",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"79:72": {
"inputs": {
"images": [
"79:8",
0
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Preview Image"
}
},
"79:3": {
"inputs": {
"seed": 692784915640704,
"steps": 30,
"cfg": 2.5,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"model": [
"84",
0
],
"positive": [
"79:79",
0
],
"negative": [
"79:79",
1
],
"latent_image": [
"6",
0
]
},
"class_type": "KSampler",
"_meta": {
"title": "KSampler"
}
},
"79:84": {
"inputs": {
"UNKNOWN": "depth_anything_v2_vitl_fp32.safetensors"
},
"_meta": {
"title": "model d a"
}
},
"79:86": {
"inputs": {
"control_net_name": "control-lora-depth-rank256.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Load ControlNet Model"
}
},
"79:83": {
"inputs": {
"da_model": [
"79:84",
0
],
"images": [
"88",
0
]
},
"_meta": {}
},
"79:79": {
"inputs": {
"strength": 1.38,
"start_percent": 0,
"end_percent": 1,
"positive": [
"4",
0
],
"negative": [
"5",
0
],
"control_net": [
"79:86",
0
],
"image": [
"79:83",
0
],
"vae": [
"1",
2
]
},
"class_type": "ControlNetApplyAdvanced",
"_meta": {
"title": "Apply ControlNet"
}
}
}
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:92c2163a0b6a725b28269b0c251b7af1e0f8561f41f6c45a9f6680087b850f25
size 514393972
+42
View File
@@ -0,0 +1,42 @@
# Гайд
> Установка приспособлена только для linux дистрибутивов (arch-based, redhat-based, debian-based)
>
> для корректной работы скрипта down_models необходимо указать api ключ из личного кабинета civitai внутри самого скрипта
>
> любые вопросы -> qaws3623@gmail.com
## Установка ComfyUI
git clone https://github.com/Comfy-Org/ComfyUI.git && cd ComfyUI
python3 -m venv venv && source venv/bin/activate
pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu130
pip install -r requirements.txt && pip install -r manager_requirements.txt
python main.py --enable-manager
## Установка бота + моделей
cd && git clone https://github.com/s13bby/tgbotcomf.git
cd tgbotcomf/ && tar -xf models_and_nodes.tar.xz && mv models/ custom_nodes/ bot.py bot.db down_models.sh video_generate.json bot-requirements.txt ~/ComfyUI/
chmod +x tgbotcomf/scut.sh && mv tgbotcomf/scut.sh ~/
bash ~/ComfyUI/down_models.sh
source ComfyUI/venv/bin/activate && pip install -r bot-requirements.txt
## Установка screen
arch
> sudo pacman -S screen
deb
> sudo apt install screen
fedora
> sudo dnf install screen
## Запуск бота + comfyui
./scut.sh
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
cd ~/ComfyUI && source venv/bin/activate
screen -dmS comfy_bot python bot.py
screen -dmS comfy_main python main.py
echo -e "Бот и ComfyUI запущены в отдельных сессиях screen.\n"
echo -e "Посмотреть, что там происходит, можно будет командами screen -r comfy_bot и screen -r comfy_main\n"
echo -e "Чтобы выйти: ctrl+A, потом D"
+619
View File
@@ -0,0 +1,619 @@
{
"86": {
"inputs": {
"add_noise": "enable",
"noise_seed": [
"155",
0
],
"steps": 4,
"cfg": 1,
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": 0,
"end_at_step": 2,
"return_with_leftover_noise": "enable",
"model": [
"199:104",
0
],
"positive": [
"190",
0
],
"negative": [
"190",
1
],
"latent_image": [
"219",
0
]
},
"class_type": "KSamplerAdvanced",
"_meta": {
"title": "KSampler (Advanced)"
}
},
"87": {
"inputs": {
"samples": [
"221",
0
],
"vae": [
"90",
0
]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE Decode"
}
},
"89": {
"inputs": {
"text": "Colorful tones, overexposed, static, blurred details, subtitles, style, works, paintings, pictures, stillness, overall gray, worst quality, low quality, JPEG compression residue, ugly, incomplete, extra fingers, poorly painted hands, poorly painted face, deformed, disfigured, deformed limbs, finger fusion, still picture, messy background, three legs, many people in the background, walking backwards, mosaic, cartoon collapse, drawing errors, chaotic lines, graffiti sense, CG sense is too strong, plastic texture, AI sense is too strong, stiff movements, puppet-like movements, rigid posture, lack of dynamics, smirk, facial stiffness, sluggish expression, loss of dynamics, lack of animation, low frame rate, torn movements, abnormal afterimages, body caton, weird head-body proportions, blurred eyes, misalignment of facial features, repetitive body parts, missing limbs, collapsed skin, perspective background error, unreasonable light and shadow, scene violation, clothes disappear out of thin air, incoherent clothes, deformed reproductive organs, mutant reproductive organs, excess reproductive organs, mutant penis, deformed penis, excess penis, painted Bad penis, mutant vagina, deformed vagina, extra vagina, poorly painted vagina, poorly painted reproductive organs, women do not have a vagina, men grow a vagina, men do not have a penis, slow-moving penis, slow-moving penis, deformed lips, mutant lips, poorly painted lips, deformed mouth, mutant mouth, poorly painted mouth, extra teeth, missing teeth, asymmetric lips, unnatural lipstick, lipstick smeared blurred, incoherent lips, poorly painted feet, mutant feet, deformed feet, dark lips, dark lipstick, red lipstick, red lips, deformed Face, mutant face, poorly painted face, facial deformation, multiple faces, inconsistent face shape, character identity change, blurred face, flickering face, distorted hands,Mutant hands, excess hands, limb piercing, distorted eyes, mutant eyes, poorly painted eyes, inconsistent eyes, pixelation, serrated, rough edges, serrated edges, artifacts, noise, blurred lines, distorted details, sharp edges, line shaking, out of focus, low resolution, wrong texture, realistic face, real eyelashes, real eyelashes, 3D eyelashes, real face, real people, real people, 3D people.",
"clip": [
"222",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Negative Prompt)"
}
},
"90": {
"inputs": {
"vae_name": "wan_2.1_vae.safetensors"
},
"class_type": "VAELoader",
"_meta": {
"title": "Load VAE"
}
},
"93": {
"inputs": {
"text": "woman take off her clothes, full nudity, full naked, pyssy, boobs, nipples. camera zooms out",
"clip": [
"222",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Positive Prompt)"
}
},
"116": {
"inputs": {
"unet_name": "DasiwaWAN22I2V14BTastysinV8_q5High.gguf"
},
"class_type": "UnetLoaderGGUF",
"_meta": {
"title": "Unet Loader (GGUF) - High"
}
},
"117": {
"inputs": {
"unet_name": "DasiwaWAN22I2V14BTastysinV8_q5Low.gguf"
},
"class_type": "UnetLoaderGGUF",
"_meta": {
"title": "Unet Loader (GGUF) - Low"
}
},
"121": {
"inputs": {
"frame_rate": 10,
"loop_count": 0,
"filename_prefix": "video",
"format": "video/h264-mp4",
"pix_fmt": "yuv420p",
"crf": 8,
"save_metadata": true,
"trim_to_audio": false,
"pingpong": false,
"save_output": false,
"images": [
"87",
0
]
},
"class_type": "VHS_VideoCombine",
"_meta": {
"title": "Video Combine 🎥🅥🅗🅢"
}
},
"144": {
"inputs": {
"PowerLoraLoaderHeaderWidget": {
"type": "PowerLoraLoaderHeaderWidget"
},
"lora_1": {
"on": false,
"lora": "DR34ML4Y_I2V_14B_HIGH_V2.safetensors",
"strength": 0.4
},
"lora_2": {
"on": false,
"lora": "wan2.2-i2v-high-oral-insertion-v1.0.safetensors",
"strength": 1
},
"lora_3": {
"on": false,
"lora": "SmoothXXXAnimation_High.safetensors",
"strength": 1.5
},
"lora_4": {
"on": false,
"lora": "2D_animation_effects_high_noise.safetensors",
"strength": 0.4
},
"lora_5": {
"on": false,
"lora": "NSFW-22-H-e8.safetensors",
"strength": 1
},
"lora_6": {
"on": false,
"lora": "BounceHighWan2_2.safetensors",
"strength": 0.2
},
"➕ Add Lora": "",
"model": [
"116",
0
]
},
"class_type": "Power Lora Loader (rgthree)",
"_meta": {
"title": "LORAS - HIGH NOISE"
}
},
"145": {
"inputs": {
"PowerLoraLoaderHeaderWidget": {
"type": "PowerLoraLoaderHeaderWidget"
},
"lora_1": {
"on": false,
"lora": "DR34ML4Y_I2V_14B_LOW_V2.safetensors",
"strength": 0.4
},
"lora_2": {
"on": false,
"lora": "wan2.2-i2v-low-oral-insertion-v1.0.safetensors",
"strength": 1
},
"lora_3": {
"on": false,
"lora": "SmoothXXXAnimation_Low.safetensors",
"strength": 1.5
},
"lora_4": {
"on": false,
"lora": "2D_animation_effects_low_noise.safetensors",
"strength": 0.4
},
"lora_5": {
"on": false,
"lora": "NSFW-22-L-e8.safetensors",
"strength": 1
},
"lora_6": {
"on": false,
"lora": "BounceLowWan2_2.safetensors",
"strength": 0.2
},
"➕ Add Lora": "",
"model": [
"117",
0
]
},
"class_type": "Power Lora Loader (rgthree)",
"_meta": {
"title": "LORAS - LOW NOISE"
}
},
"146": {
"inputs": {
"anything": [
"217",
0
]
},
"class_type": "easy cleanGpuUsed",
"_meta": {
"title": "Clean VRAM Used"
}
},
"149": {
"inputs": {
"ckpt_name": "rife49.pth",
"clear_cache_after_n_frames": 1,
"multiplier": 2,
"fast_mode": false,
"ensemble": true,
"scale_factor": 1,
"frames": [
"223",
0
]
},
"class_type": "RIFE VFI",
"_meta": {
"title": "Frame Interpolation (RIFE)"
}
},
"155": {
"inputs": {
"seed": -1
},
"class_type": "Seed (rgthree)",
"_meta": {
"title": "Seed (rgthree)"
}
},
"183": {
"inputs": {
"value": 842
},
"class_type": "INTConstant",
"_meta": {
"title": "HEIGHT"
}
},
"184": {
"inputs": {
"value": 474
},
"class_type": "INTConstant",
"_meta": {
"title": "WIDTH"
}
},
"190": {
"inputs": {
"width": [
"193",
2
],
"height": [
"193",
3
],
"length": 41,
"batch_size": 1,
"motion_amplitude": 1.4,
"positive": [
"93",
0
],
"negative": [
"89",
0
],
"vae": [
"90",
0
],
"start_image": [
"193",
0
]
},
"class_type": "PainterI2V",
"_meta": {
"title": "PainterI2V"
}
},
"193": {
"inputs": {
"image": "742cad1b01e30ef47b613ef3df009957.jpg",
"resize": true,
"width": [
"184",
0
],
"height": [
"183",
0
],
"repeat": 1,
"keep_proportion": false,
"divisible_by": 16,
"mask_channel": "alpha",
"background_color": ""
},
"class_type": "LoadAndResizeImage",
"_meta": {
"title": "START IMAGE"
}
},
"210": {
"inputs": {
"model_name": "2x-AnimeSharpV4_RCAN.safetensors"
},
"class_type": "UpscaleModelLoader",
"_meta": {
"title": "Load Upscale Model"
}
},
"214": {
"inputs": {
"frame_rate": 20,
"loop_count": 1,
"filename_prefix": "AnimateDiff",
"format": "video/h264-mp4",
"pix_fmt": "yuv420p",
"crf": 8,
"save_metadata": true,
"trim_to_audio": false,
"pingpong": false,
"save_output": true,
"images": [
"224",
0
]
},
"class_type": "VHS_VideoCombine",
"_meta": {
"title": "FIENAL"
}
},
"217": {
"inputs": {
"add_noise": "disable",
"noise_seed": 666124386785654,
"steps": 4,
"cfg": 1,
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": 2,
"end_at_step": 4,
"return_with_leftover_noise": "disable",
"model": [
"200:103",
0
],
"positive": [
"190",
0
],
"negative": [
"190",
1
],
"latent_image": [
"86",
0
]
},
"class_type": "KSamplerAdvanced",
"_meta": {
"title": "KSampler (Advanced)"
}
},
"219": {
"inputs": {
"anything": [
"190",
2
]
},
"class_type": "easy cleanGpuUsed",
"_meta": {
"title": "Clean VRAM Used"
}
},
"221": {
"inputs": {
"anything": [
"146",
0
]
},
"class_type": "easy clearCacheAll",
"_meta": {
"title": "Clear Cache All"
}
},
"222": {
"inputs": {
"clip_name": "nsfw_wan_umt5-xxl_fp8_scaled.safetensors",
"type": "wan",
"device": "default"
},
"class_type": "CLIPLoader",
"_meta": {
"title": "Load CLIP"
}
},
"223": {
"inputs": {
"upscale_model": [
"210",
0
],
"image": [
"87",
0
]
},
"class_type": "ImageUpscaleWithModel",
"_meta": {
"title": "Upscale Image (using Model)"
}
},
"224": {
"inputs": {
"anything": [
"225",
0
]
},
"class_type": "easy clearCacheAll",
"_meta": {
"title": "Clear Cache All"
}
},
"225": {
"inputs": {
"anything": [
"149",
0
]
},
"class_type": "easy cleanGpuUsed",
"_meta": {
"title": "Clean VRAM Used"
}
},
"200:200": {
"inputs": {
"value": 10
},
"class_type": "PrimitiveFloat",
"_meta": {
"title": "SHIFT"
}
},
"199:204": {
"inputs": {
"value": 10
},
"class_type": "PrimitiveFloat",
"_meta": {
"title": "SHIFT"
}
},
"199:195": {
"inputs": {
"sage_attention": "auto",
"allow_compile": true,
"model": [
"144",
0
]
},
"class_type": "PathchSageAttentionKJ",
"_meta": {
"title": "Patch Sage Attention KJ"
}
},
"200:196": {
"inputs": {
"sage_attention": "auto",
"allow_compile": true,
"model": [
"145",
0
]
},
"class_type": "PathchSageAttentionKJ",
"_meta": {
"title": "Patch Sage Attention KJ"
}
},
"199:197": {
"inputs": {
"enable_fp16_accumulation": true,
"model": [
"199:195",
0
]
},
"class_type": "ModelPatchTorchSettings",
"_meta": {
"title": "Model Patch Torch Settings"
}
},
"200:198": {
"inputs": {
"enable_fp16_accumulation": true,
"model": [
"200:196",
0
]
},
"class_type": "ModelPatchTorchSettings",
"_meta": {
"title": "Model Patch Torch Settings"
}
},
"199:124": {
"inputs": {
"nag_scale": 11,
"nag_alpha": 0.25,
"nag_tau": 2.5,
"input_type": "default",
"model": [
"199:197",
0
],
"conditioning": [
"89",
0
]
},
"class_type": "WanVideoNAG",
"_meta": {
"title": "WanVideoNAG-High"
}
},
"200:127": {
"inputs": {
"nag_scale": 11,
"nag_alpha": 0.25,
"nag_tau": 2.5,
"input_type": "default",
"model": [
"200:198",
0
],
"conditioning": [
"89",
0
]
},
"class_type": "WanVideoNAG",
"_meta": {
"title": "WanVideoNAG-Low"
}
},
"199:104": {
"inputs": {
"shift": [
"199:204",
0
],
"model": [
"199:124",
0
]
},
"class_type": "ModelSamplingSD3",
"_meta": {
"title": "ModelSamplingSD3"
}
},
"200:103": {
"inputs": {
"shift": [
"200:200",
0
],
"model": [
"200:127",
0
]
},
"class_type": "ModelSamplingSD3",
"_meta": {
"title": "ModelSamplingSD3"
}
}
}