微信公众号应用开发,支持微信公众号,下发指令生图,和网页版
This commit is contained in:
@@ -16,3 +16,5 @@ unpackage/dist/dev/
|
||||
*.pyc
|
||||
config/baidu.json
|
||||
ckpts/*
|
||||
config/lamWeChat.db
|
||||
config/weChat.yaml
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
wechat:
|
||||
appid: wxa50ed345b253964d #公众号appid
|
||||
secret: 327ac9ba06d214d2fcfe2e9ed0520684 #公众号秘钥
|
||||
serverAddress: http://139.9.53.208/ #服务器地址 微信公众配置地址的前缀
|
||||
freeSize: 3 #免费使用次数
|
||||
isEnterprise: true #是否为企业微信
|
||||
adminNo: b0pOVFM2dnRsZkdLeWl2Zlk2bG9MTFNjUTNGUQ== #管理员微信编号启动会后可发送我的编号获取
|
||||
adminWeChat: yanlang123456 #管理员微信号
|
||||
access_token: '' #不用填系统用于保存临时值
|
||||
access_token_expires_at: 0 #默认0
|
||||
commands: #功能列表
|
||||
图生视频:
|
||||
filename: img2video.json #功能流程图json文件
|
||||
params: #参数列表
|
||||
image: #参数名称(几个固定参数名称必须如下:图片:image 随机种子:seed 正向提示词:prompt 反向提示词:negative)
|
||||
isRequired: true #是否必填
|
||||
keys: #参数对应json中对应的key
|
||||
- '38'
|
||||
- inputs
|
||||
- image_path
|
||||
zhName: 图片 #参数中文名称
|
||||
motion_bucket:
|
||||
default: 127
|
||||
isRequired: true
|
||||
keys:
|
||||
- '12'
|
||||
- inputs
|
||||
- motion_bucket_id
|
||||
max: 200
|
||||
min: 0
|
||||
type: number
|
||||
zhName: 运动量
|
||||
seed:
|
||||
default: -1
|
||||
isRequired: true
|
||||
keys:
|
||||
- '3'
|
||||
- inputs
|
||||
- seed
|
||||
type: text
|
||||
zhName: 随机种子
|
||||
replyText: 请发送您的图片发送“ok”开始任务,如:“ok” #指令说明回复
|
||||
文生图:
|
||||
filename: text2img.json
|
||||
params:
|
||||
ckpt:
|
||||
isRequired: false
|
||||
keys:
|
||||
- '4'
|
||||
- inputs
|
||||
- ckpt_name
|
||||
options: #选项参数
|
||||
冷却混合料SD1.5: chilloutmix_NiPrunedFp32Fix.safetensors #中文名称:英文名称
|
||||
卡通动画片SD1.5: yamer_Cartoon_xenoArcadiaCD.safetensors
|
||||
无法控制的SDXL: juggernautXL_version6Rundiffusion.safetensors
|
||||
梦想塑造者SD1.5: dreamshaper_8.safetensors
|
||||
zhName: 基础模型
|
||||
height:
|
||||
default: 512 #默认值
|
||||
isRequired: false
|
||||
keys:
|
||||
- '14'
|
||||
- inputs
|
||||
- height
|
||||
max: 1024 #最大值
|
||||
min: 512 #最小值
|
||||
type: number #类型(输入型参数目前只支持 number/text)
|
||||
zhName: 高度
|
||||
lora:
|
||||
isRequired: false
|
||||
keys:
|
||||
- '10'
|
||||
- inputs
|
||||
- lora_name
|
||||
options:
|
||||
SD1.5-LCM加速: lcm-lora-sdv1-5.safetensors
|
||||
SDXL-LCM加速: lcm-lora-sdxl.safetensors
|
||||
zhName: LoRA
|
||||
negative:
|
||||
isRequired: false
|
||||
keys:
|
||||
- '7'
|
||||
- inputs
|
||||
- text
|
||||
zhName: 反向提示词
|
||||
prompt:
|
||||
isRequired: true
|
||||
keys:
|
||||
- '20'
|
||||
- inputs
|
||||
- text_trans
|
||||
zhName: 正向提示词
|
||||
seed:
|
||||
default: -1
|
||||
isRequired: true
|
||||
keys:
|
||||
- '3'
|
||||
- inputs
|
||||
- seed
|
||||
type: text
|
||||
zhName: 随机种子
|
||||
width:
|
||||
default: 512
|
||||
isRequired: false
|
||||
keys:
|
||||
- '14'
|
||||
- inputs
|
||||
- width
|
||||
max: 1024
|
||||
min: 512
|
||||
type: number
|
||||
zhName: 宽度
|
||||
replyText: 请发送您的中文或英文提示词用“ok”结束,如:“一只小狗ok”
|
||||
query_commands: #查询指令(固定)
|
||||
- 查询排队情况
|
||||
- 我的编号
|
||||
@@ -0,0 +1,142 @@
|
||||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": 801899397770458,
|
||||
"steps": 4,
|
||||
"cfg": 1,
|
||||
"sampler_name": "lcm",
|
||||
"scheduler": "karras",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"14",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"12",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"12",
|
||||
1
|
||||
],
|
||||
"latent_image": [
|
||||
"12",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"15",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"width": [
|
||||
"30",
|
||||
0
|
||||
],
|
||||
"height": [
|
||||
"30",
|
||||
1
|
||||
],
|
||||
"video_frames": 25,
|
||||
"motion_bucket_id": 127,
|
||||
"fps": 6,
|
||||
"augmentation_level": 0,
|
||||
"clip_vision": [
|
||||
"15",
|
||||
1
|
||||
],
|
||||
"init_image": [
|
||||
"38",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"15",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "SVD_img2vid_Conditioning"
|
||||
},
|
||||
"14": {
|
||||
"inputs": {
|
||||
"min_cfg": 1,
|
||||
"model": [
|
||||
"33",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VideoLinearCFGGuidance"
|
||||
},
|
||||
"15": {
|
||||
"inputs": {
|
||||
"ckpt_name": "AnimateLCM-SVD-xt-1-1_fp16_comfy.safetensors"
|
||||
},
|
||||
"class_type": "ImageOnlyCheckpointLoader"
|
||||
},
|
||||
"25": {
|
||||
"inputs": {
|
||||
"frame_rate": 8,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "AnimateDiff",
|
||||
"format": "video/h265-mp4",
|
||||
"pingpong": false,
|
||||
"save_image": true,
|
||||
"Sync playback": null,
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VHS_VideoCombine"
|
||||
},
|
||||
"30": {
|
||||
"inputs": {
|
||||
"image": [
|
||||
"31",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "Get image size"
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"upscale_method": "nearest-exact",
|
||||
"scale_by": 0.7000000000000001,
|
||||
"image": [
|
||||
"38",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ImageScaleBy"
|
||||
},
|
||||
"33": {
|
||||
"inputs": {
|
||||
"lora_name": "lcm-lora-sdv1-5.safetensors",
|
||||
"strength_model": 1,
|
||||
"model": [
|
||||
"15",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoraLoaderModelOnly"
|
||||
},
|
||||
"38": {
|
||||
"inputs": {
|
||||
"image_path": "http://127.0.0.1:8188/view?filename=ComfyUI_00402_.png&type=input&subfolder=&rand=0.9232966295130483",
|
||||
"RGBA": "false",
|
||||
"filename_text_extension": "true"
|
||||
},
|
||||
"class_type": "LamLoadPathImage"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": 1068764177227380,
|
||||
"steps": 5,
|
||||
"cfg": 1,
|
||||
"sampler_name": "lcm",
|
||||
"scheduler": "normal",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"10",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"7",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"5",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"4": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaper_8.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"5": {
|
||||
"inputs": {
|
||||
"width": [
|
||||
"14",
|
||||
0
|
||||
],
|
||||
"height": [
|
||||
"14",
|
||||
1
|
||||
],
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"20",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"10",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"text": "undefined",
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"4",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"lora_name": "lcm-lora-sdv1-5.safetensors",
|
||||
"strength_model": 1,
|
||||
"strength_clip": 1,
|
||||
"model": [
|
||||
"4",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "LoraLoader"
|
||||
},
|
||||
"14": {
|
||||
"inputs": {
|
||||
"aspect_ratio": "1152×896 ∣ 9:7",
|
||||
"width": 512,
|
||||
"height": 512
|
||||
},
|
||||
"class_type": "AspectRatio"
|
||||
},
|
||||
"20": {
|
||||
"inputs": {
|
||||
"text_trans": "一只小狗"
|
||||
},
|
||||
"class_type": "ZhPromptTranslator"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 243 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 155 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -292,6 +292,7 @@ app.registerExtension({
|
||||
if(cat_values.join(',')!=Object.keys(pb_cache[prompt_type.value]).join(',')){
|
||||
cat_values=Object.keys(pb_cache[prompt_type.value])
|
||||
cat_value=''
|
||||
category.value=cat_values[0]
|
||||
}
|
||||
return cat_values;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
|
||||
|
||||
Date.prototype.format = function (format) {
|
||||
var args = {
|
||||
"M+": this.getMonth() + 1,
|
||||
"d+": this.getDate(),
|
||||
"h+": this.getHours(),
|
||||
"m+": this.getMinutes(),
|
||||
"s+": this.getSeconds(),
|
||||
"q+": Math.floor((this.getMonth() + 3) / 3), //quarter
|
||||
"S": this.getMilliseconds()
|
||||
};
|
||||
if (/(y+)/.test(format))
|
||||
format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
for (var i in args) {
|
||||
var n = args[i];
|
||||
if (new RegExp("(" + i + ")").test(format))
|
||||
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? n : ("00" + n).substr(("" + n).length));
|
||||
}
|
||||
return format;
|
||||
};
|
||||
|
||||
|
||||
//生成指定长度的随机数字字符
|
||||
function randomString(length) {
|
||||
const str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
let result = '';
|
||||
for(let i = 0; i<length; i++)
|
||||
{
|
||||
let id = Math.floor(Math.random() * str.length);
|
||||
result += str[id];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取当前时间
|
||||
function NowTime() {
|
||||
var time = new Date();
|
||||
var year = time.getFullYear();// 获取年
|
||||
var month = time.getMonth() + 1;// 或者月
|
||||
var day = time.getDate();// 或者天
|
||||
var hour = time.getHours();// 获取小时
|
||||
var minu = time.getMinutes();// 获取分钟
|
||||
var second = time.getSeconds();// 或者秒
|
||||
var data = year + "-";
|
||||
if (month < 10) {
|
||||
data += "0";
|
||||
}
|
||||
data += month + "-";
|
||||
if (day < 10) {
|
||||
data += "0"
|
||||
}
|
||||
data += day + " ";
|
||||
if (hour < 10) {
|
||||
data += "0"
|
||||
}
|
||||
data += hour + ":";
|
||||
if (minu < 10) {
|
||||
data += "0"
|
||||
}
|
||||
data += minu + ":";
|
||||
if (second < 10) {
|
||||
data += "0"
|
||||
}
|
||||
data += second;
|
||||
return data;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+809
@@ -0,0 +1,809 @@
|
||||
<!DOCTYPE>
|
||||
<!--解决idea thymeleaf 表达式模板报红波浪线-->
|
||||
<!--suppress ALL -->
|
||||
<html xmlns:th="http://www.thymeleaf.org" lang="en">
|
||||
|
||||
<head>
|
||||
<title>欢迎{{openId}}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<!-- jquery在线版本 -->
|
||||
<script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
|
||||
<script src="../extensions/ComfyUI_Lam/static/js/qn-rtplayer-web.js"></script>
|
||||
<!--引入样式-->
|
||||
<link rel="stylesheet" href="../extensions/ComfyUI_Lam/static/css/app.css" />
|
||||
<style>
|
||||
:where(.css-3m4nqy).ant-select-single .ant-select-selector .ant-select-selection-search {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
inset-inline-start: 11px px;
|
||||
inset-inline-end: 11px;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy).ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding: 0 11px;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy).ant-select:not(.ant-select-customize-input) .ant-select-selector {
|
||||
position: relative;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #d9d9d9;
|
||||
transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy).ant-select-single .ant-select-selector {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-size: 14px;
|
||||
line-height: 1.5714285714285714;
|
||||
list-style: none;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
display: flex;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy)[class^="ant-select"] [class^="ant-select"],
|
||||
:where(.css-3m4nqy)[class*=" ant-select"] [class^="ant-select"],
|
||||
:where(.css-3m4nqy)[class^="ant-select"] [class*=" ant-select"],
|
||||
:where(.css-3m4nqy)[class*=" ant-select"] [class*=" ant-select"] {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy).ant-select-dropdown .ant-select-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
min-height: 32px;
|
||||
padding: 5px 12px;
|
||||
color: rgba(250, 250, 250, 0.88);
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 1.5714285714285714;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s ease;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy)[class^="ant-input"] [class^="ant-input"],
|
||||
:where(.css-3m4nqy)[class*=" ant-input"] [class^="ant-input"],
|
||||
:where(.css-3m4nqy)[class^="ant-input"] [class*=" ant-input"],
|
||||
:where(.css-3m4nqy)[class*=" ant-input"] [class*=" ant-input"] {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy).ant-input-number .ant-input-number-input {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
padding: 0 11px;
|
||||
text-align: start;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
outline: 0;
|
||||
transition: all 0.2s linear;
|
||||
appearance: textfield;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-size: inherit;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy).ant-select .ant-select-arrow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
vertical-align: -0.125em;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
inset-inline-start: auto;
|
||||
inset-inline-end: 11px;
|
||||
height: 12px;
|
||||
margin-top: -6px;
|
||||
font-size: 12px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy)[class^="ant-select"] [class^="ant-select"],
|
||||
:where(.css-3m4nqy)[class*=" ant-select"] [class^="ant-select"],
|
||||
:where(.css-3m4nqy)[class^="ant-select"] [class*=" ant-select"],
|
||||
:where(.css-3m4nqy)[class*=" ant-select"] [class*=" ant-select"] {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:where(.css-3m4nqy).ant-popover {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-size: 14px;
|
||||
line-height: 1.5714285714285714;
|
||||
list-style: none;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1030;
|
||||
font-weight: normal;
|
||||
white-space: normal;
|
||||
text-align: start;
|
||||
cursor: auto;
|
||||
user-select: text;
|
||||
--antd-arrow-background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app" data-v-app="">
|
||||
<section class="aigc-layout">
|
||||
<div class="aigc-head">
|
||||
<div style="color: aliceblue;font-size: x-large;">降维AI|创作平台</div>
|
||||
<div class="aigc-head__left-block"></div>
|
||||
<div class="aigc-head__right-block">
|
||||
<div style="color: aliceblue;" id="contact_administrator"
|
||||
class="aigc-head__right-block--qun aigc-head__right-block--commonbtn aigc-head__right-block--hover">
|
||||
联系管理员 </div><!---->
|
||||
<div class="aigc-head__right-block--avatarbox"><img class="aigc-head__right-block--avatar"
|
||||
src="https://himg.bdimg.com/sys/portraith/item/public.1.e8294af1.YF07P1v3sOMXm56wbOMh9w">
|
||||
</div><!---->
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div><!---->
|
||||
<div class="ant-popover pop-com soci css-3m4nqy ant-popover-placement-bottomRight"
|
||||
style="left: 968px; top: 43px; transform-origin: 203px 0px;display: none;" id="contact_administrator_popover">
|
||||
<div class="ant-popover-content">
|
||||
<div class="ant-popover-arrow"><span class="ant-popover-arrow-content"></span></div>
|
||||
<div class="ant-popover-inner" role="tooltip"><!---->
|
||||
<div class="ant-popover-inner-content">
|
||||
<div class="add-soci">
|
||||
<div class="add-text">扫码添加管理员微信</div><img class="qr-code"
|
||||
src="/lam/getImage?type=wechat&&name=admin_qr_code.jpg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-ada5c28e="" class="aigc-tab" style="--688ac256: 0px;" id="comand_div_id">
|
||||
<!-- 功能菜单 -->
|
||||
</div>
|
||||
<section data-v-d1097eb1="" class="aigc-main">
|
||||
<div data-v-d1097eb1="" class="aigc-main__left-content">
|
||||
<div data-v-d1097eb1="" class="aigc-main__left-content--top-wrap">
|
||||
<div data-v-d1097eb1="" class="aigc-main__left-content--top-left" id="upload_image_div_id"
|
||||
style="display: none;">
|
||||
<div data-v-23e1e235="" data-v-d1097eb1="" class="aigc-upload step_1"><!---->
|
||||
<span data-v-23e1e235="" class="ant-upload-wrapper aigc-upload__ant-upload css-3m4nqy"
|
||||
id="upload_image_btn_parent_id">
|
||||
<div class="ant-upload ant-upload-drag aigc-upload__ant-upload css-3m4nqy"
|
||||
style="padding-top: 150px;" id="upload_image_btn_id"><span
|
||||
class="ant-upload ant-upload-btn" role="button" tabindex="0">
|
||||
<input type="file" accept="" id="upload_image_input_id"
|
||||
style="display: none;">
|
||||
<div data-v-23e1e235="" class="aigc-upload__not-upload"
|
||||
onclick="clickUpload()">
|
||||
<div data-v-23e1e235="" style="color: aliceblue;"
|
||||
class="aigc-upload__icon-coll--guide-btn">上传图片
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div><!---->
|
||||
<div class="aigc-loading aigc-main__left-content--loading"
|
||||
id="upload_image_loading_id" style="display: none;">
|
||||
<div data-v-e4fb7b31="" class="aigc-loading__mask">
|
||||
<div data-v-e4fb7b31="" role="progressbar"
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-24 css-3m4nqy">
|
||||
<div class="ant-progress-inner"
|
||||
style="width: 24px; height: 24px; font-size: 9.6px;"><svg
|
||||
class="ant-progress-circle" viewBox="0 0 100 100"><!---->
|
||||
<path d="M 50,50 m 0,-46 a 46,46 0 1 1 0,92 a 46,46 0 1 1 0,-92"
|
||||
stroke="#d8d8d8" stroke-linecap="round" stroke-width="8"
|
||||
fill-opacity="0" class="ant-progress-circle-trail"
|
||||
style="stroke: rgb(216, 216, 216); stroke-dasharray: 289.027px, 289.027px; stroke-dashoffset: 0px; transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s ease 0s, stroke-width 0.06s ease 0.3s, opacity 0.3s ease 0s;">
|
||||
</path>
|
||||
</svg><!---->
|
||||
</div>
|
||||
</div><!---->
|
||||
<div data-v-e4fb7b31="" class="aigc-loading__describe">上传中</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<section data-v-e19f253b="" data-v-23e1e235="" class="aigc-preview"
|
||||
id="upload_image_preview_parend_id" style="display: none;">
|
||||
<div data-v-e19f253b="" onclick="clickUpload()" class="aigc-preview__img"
|
||||
id="upload_image_preview_id"
|
||||
style="background-image: url("http://127.0.0.1:8189/view?filename=ComfyUI_00819_.png&type=input&subfolder=&rand=0.9293840121020174");">
|
||||
<!----><!----><!---->
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d1097eb1="" class="aigc-main__left-content--top-right step_5 step_7">
|
||||
<div data-v-d1097eb1="" class="aigc-main__left-content--nodata" id="no_add_task_div">
|
||||
<p data-v-d1097eb1="">生成预览区</p>
|
||||
</div><!---->
|
||||
<div data-v-e4fb7b31="" data-v-d1097eb1=""
|
||||
class="aigc-loading aigc-main__left-content--loading" style="display: none;" id="yes_add_task_div">
|
||||
<div data-v-e4fb7b31="" class="aigc-loading__mask">
|
||||
<div data-v-e4fb7b31="" role="progressbar"
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-24 css-3m4nqy">
|
||||
<div class="ant-progress-inner"
|
||||
style="width: 24px; height: 24px; font-size: 9.6px;"><svg
|
||||
class="ant-progress-circle" viewBox="0 0 100 100"><!---->
|
||||
<path d="M 50,50 m 0,-46 a 46,46 0 1 1 0,92 a 46,46 0 1 1 0,-92"
|
||||
stroke="#d8d8d8" stroke-linecap="round" stroke-width="8"
|
||||
fill-opacity="0" class="ant-progress-circle-trail"
|
||||
style="stroke: rgb(216, 216, 216); stroke-dasharray: 289.027px, 289.027px; stroke-dashoffset: 0px; transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s ease 0s, stroke-width 0.06s ease 0.3s, opacity 0.3s ease 0s;">
|
||||
</path>
|
||||
</svg><!---->
|
||||
</div>
|
||||
</div><!---->
|
||||
<div data-v-e4fb7b31="" class="aigc-loading__describe">效果绘制中</div>
|
||||
</div>
|
||||
</div>
|
||||
<section data-v-e19f253b="" data-v-d1097eb1="" class="aigc-preview" style="display: none;" id="wcomplete_add_task_div">
|
||||
<div data-v-e19f253b="" onclick="openViewNow(this)" class="aigc-preview__img" id="wcomplete_add_task_img_div"
|
||||
style="background-image: url("https://pcsdata.baidu.com/thumbnail/6a9bc2ee8fb8cf53f0d23d6fa4b31143?fid=3878105166-16051585-1026667930322733&time=1713502800&rt=pr&sign=FDTAER-yUdy3dSFZ0SVxtzShv1zcMqd-oTE9DBFqjwgK6eAiBoZIZhTdKU0%3D&expires=48h&chkv=0&chkbd=0&chkpc=&dp-logid=235267649399325916&dp-callid=0&size=c1600_u1600&quality=100&vuk=&ft=video&imgtimes=1713505888030");">
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d1097eb1="" class="aigc-main__left-content--bottom-wrap step_2_empty">
|
||||
<div data-v-622eff0c="" data-v-d1097eb1="" class="aigc-container">
|
||||
<div data-v-622eff0c="" class="aigc-container__formula">
|
||||
<div data-v-622eff0c="" class="aigc-container__tabs-box">
|
||||
<div data-v-622eff0c="" class="aigc-container__sub-tab active-sub-tab">历史记录</div>
|
||||
</div>
|
||||
<div data-v-622eff0c="" class="aigc-container__recomm-fml" id="historys_div_id">
|
||||
|
||||
</div><!---->
|
||||
</div><!----><!----><!----><!---->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d1097eb1="" class="aigc-main__right-params">
|
||||
<div data-v-fe0dcf7c="" data-v-d1097eb1="" class="aigc-layright step_3" id="rightBoxRef">
|
||||
<div data-v-fe0dcf7c="" class="aigc-layright__top">
|
||||
<div data-v-d25ec045="" data-v-fe0dcf7c="" class="aigc-top">
|
||||
<div id="select_container_div">
|
||||
|
||||
</div>
|
||||
<div class="aigc-prompt" id="prompt-container" style="display: none;">
|
||||
<div class="aigc-prompt__head">
|
||||
<div class="aigc-prompt__head--text">正向提示词</div>
|
||||
<div class="aigc-prompt__head--clear"
|
||||
onclick="$('#prompt').html('');userParams['prompt']='';$('#prompt').attr('placeholder',$('#prompt').html().length>0?'':'输入中文或英文提示词');"> 清除 </div>
|
||||
</div>
|
||||
<div class="aigc-prompt__base--textarea">
|
||||
<div class="textarea" id="prompt" contenteditable="true"
|
||||
oninput="userParams['prompt']=$(event.target).html();$(event.target).attr('placeholder',$(event.target).html().length>0?'':'输入中文或英文提示词');"
|
||||
placeholder="输入中文或英文提示词" style="height: 130px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aigc-prompt" id="negative-container" style="display: none;">
|
||||
<div class="aigc-prompt__head">
|
||||
<div class="aigc-prompt__head--text">反向提示词</div>
|
||||
<div class="aigc-prompt__head--clear"
|
||||
onclick="$('#negative').html('');userParams['negative']='';$('#negative').attr('placeholder',$('#negative').html().length>0?'':'输入中文或英文提示词');"> 清除
|
||||
</div>
|
||||
</div>
|
||||
<div class="aigc-prompt__base--textarea">
|
||||
<div class="textarea" id="negative" contenteditable="true"
|
||||
oninput="userParams['negative']=$(event.target).html();$(event.target).attr('placeholder',$(event.target).html().length>0?'':'输入中文或英文提示词');"
|
||||
placeholder="输入中文或英文提示词" style="height: 130px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-fe0dcf7c="" class="aigc-layright__bottom" id="other_params_parent_div"
|
||||
style="display: none;">
|
||||
<div data-v-fea6429a="" data-v-fe0dcf7c="" class="aigc-advanced">
|
||||
<div data-v-fea6429a="" class="aigc-advanced__mid--text"
|
||||
style="font-weight: bold;"> 其他参数 </div>
|
||||
<div data-v-fea6429a="" class="aigc-advanced__midexpend"
|
||||
id="other_params_div_id">
|
||||
<div data-v-fea6429a="" class="aigc-advanced__midexpend--process"> 生成步数 <div
|
||||
data-v-fea6429a=""
|
||||
class="ant-input-number aigc-advanced__midexpend--input css-3m4nqy">
|
||||
<div class="ant-input-number-input-wrap"><input autocomplete="off"
|
||||
role="spinbutton" aria-valuenow="30" step="1" type="number"
|
||||
value="30" class="ant-input-number-input"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-fea6429a="" class="aigc-advanced__midexpend--process"> 提示词引导系数
|
||||
<div data-v-fea6429a=""
|
||||
class="ant-input-number aigc-advanced__midexpend--inputshort css-3m4nqy"
|
||||
style="margin-left: 16px;">
|
||||
<div class="ant-input-number-input-wrap"><input autocomplete="off"
|
||||
role="spinbutton" aria-valuemin="1" aria-valuemax="20"
|
||||
aria-valuenow="7" step="1" type="number" value="0"
|
||||
class="ant-input-number-input"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-fea6429a="" style="white-space: nowrap;"
|
||||
class="aigc-advanced__midexpend--process"> 随机种子
|
||||
<input data-v-fea6429a="" type="text"
|
||||
class="ant-input css-3m4nqy aigc-advanced__midexpend--input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div data-v-d1097eb1="" class="aigc-main__btn-box step_4">
|
||||
<div data-v-d1097eb1="" class="aigc-main__btn-box--merge" id="add_task_btn_id" onclick="addTask(this)"><!---->
|
||||
<div data-v-d1097eb1="" class="text"><span data-v-d1097eb1="" class="upper">立即生成</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!---->
|
||||
<div data-v-51fd3d7a="" data-v-d1097eb1="" class="modal" style="display:none;" id="pop_frame_div_parent_id">
|
||||
<div data-v-51fd3d7a="" class="content-wrap">
|
||||
<img data-v-51fd3d7a="" class="cross-icon" id="pop_frame_div_id" onclick="$('#pop_frame_div_parent_id').hide()"
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGkSURBVHgB7dptbcNADMZxQyiEQCqEMBiEjcHGYGMSCIUQCIHgXaRY8rSmeff5zs9fivrtbP1UVY0SIoQQQgghhBBCCAWJmd/T1aXrO10NOSvtdEvX17TjG1mWBn7y33pPSOMu0066D7IqDRv4fy6QZnDGBrIqDXvw87IivcAZe5BVadid5+tzIC3gjN3JsjSw9YK0AqelHHlAcoujFsyG5B5HyoFUDI5kiVQcjmSBVCyOdCVS8TjSFUjV4EhnIlWHI52BVC2OdASpehxpD1IYHGkLUjgcaQ1SWBxpBVIfFkdaQIqNI21EailiK5Faihov/yCPDwcaitgKHKkPh7QBJx7SDpw4SCtwWnb0tMQ03vAPORwS77h9CIPEB+6tqkc6gqPOqBPpDBx1Vl1IZ+KoM+tAugJHnV020pU4akaZSBY4alZZSJY4amYZSDlw1GzfSDlx1A4+kTzgqF18IXnCUTv5QUrDfjzhqL1eIXVkFT9/kTwrjtptDsn0RfLOI440g2T6DdK/QYMnHGlCkh3Hz4asm6Bu5Dj2euuBEEIIIYQQitwvJD8kAp6CtMQAAAAASUVORK5CYII=">
|
||||
<div data-v-d1097eb1="" class="title" id="pop_frame_div_title_id"></div>
|
||||
<div data-v-d1097eb1="" class="desc" id="pop_frame_div_desc_id">
|
||||
</div>
|
||||
<div data-v-51fd3d7a="" class="bottom-box" id="pop_frame_div_btn_id">
|
||||
<div data-v-51fd3d7a="" class="cancel-btn btn" id="pop_frame_div_btn_cancel_id">取消</div>
|
||||
<div data-v-51fd3d7a="" class="confirm-btn btn" id="pop_frame_div_btn_ok_id">确认</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section><!---->
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
<script src="../extensions/ComfyUI_Lam/static/js/app.js"></script>
|
||||
<script>
|
||||
var openId = '{{openId}}';
|
||||
var websocket = null;
|
||||
|
||||
// 判断当前浏览器是否支持WebSocket, springboot是项目名
|
||||
if ('WebSocket' in window) {
|
||||
var host = window.location.host;
|
||||
websocket = new WebSocket("ws://" + host + '/ws?clientId=' + openId);
|
||||
} else {
|
||||
console.error("不支持WebSocket");
|
||||
}
|
||||
|
||||
// 连接发生错误的回调方法
|
||||
websocket.onerror = function (e) {
|
||||
console.error("WebSocket连接发生错误");
|
||||
};
|
||||
|
||||
// 连接成功建立的回调方法
|
||||
websocket.onopen = function () {
|
||||
// 获取所有在线用户
|
||||
console.log("WebSocket连接成功");
|
||||
//var username = randomString(10);
|
||||
//sendIssue({ "userName": username, "comType": "login" });
|
||||
//$("#talks").html(username);
|
||||
}
|
||||
|
||||
// 接收到消息的回调方法
|
||||
websocket.onmessage = async function (event) {
|
||||
if (event.data == null || event.data == "" || event.data instanceof Blob) {
|
||||
return;
|
||||
}
|
||||
var messageJson = eval("(" + event.data + ")");
|
||||
if(messageJson['type']=='executing'){
|
||||
$("#add_task_btn_id").removeClass("disabled");
|
||||
getHistorys()
|
||||
}
|
||||
console.log(new Date().format("yyyy-MM-dd hh:mm:ss"), messageJson);
|
||||
|
||||
}
|
||||
|
||||
// 连接关闭的回调方法
|
||||
websocket.onclose = function () {
|
||||
// alert("WebSocket连接关闭");
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
function sendIssue(msg) {
|
||||
websocket.send(JSON.stringify(msg));
|
||||
}
|
||||
var userParams = {}
|
||||
var comands = {}
|
||||
$(function () {
|
||||
$('#contact_administrator').mouseenter(function(event) {
|
||||
var mouseX = event.pageX; // 鼠标相对于页面的X坐标
|
||||
var mouseY = event.pageY; // 鼠标相对于页面的Y坐标
|
||||
mouseX=mouseX-$('#contact_administrator_popover').width()
|
||||
$('#contact_administrator_popover').css({
|
||||
'top': mouseY + 'px',
|
||||
'left': mouseX + 'px'
|
||||
});
|
||||
$('#contact_administrator_popover').show()
|
||||
}).mouseleave(function() {
|
||||
// 鼠标离开时的操作
|
||||
$('#contact_administrator_popover').hide()
|
||||
});
|
||||
$.get('/wechatauth/getCommands', {}, function (res) {
|
||||
comands = res;
|
||||
$("#comand_div_id").html('')
|
||||
for (var key of Object.keys(res)) {
|
||||
$("#comand_div_id").append('<div id="'+btoa(encodeURIComponent(key))+'" data-v-ada5c28e="" class="aigc-tab__item " onclick="setComand(\'' + key + '\')"><span data-v-ada5c28e="">' + key + '</span></div>')
|
||||
}
|
||||
if (Object.keys(res).length > 0) {
|
||||
$("#comand_div_id").children().eq(0).click()
|
||||
}
|
||||
})
|
||||
getHistorys()
|
||||
})
|
||||
var historyObj={}
|
||||
function getHistorys(){
|
||||
$.get('/wechatauth/getHistorys', {'openId':openId}, function (res) {
|
||||
console.log(res)
|
||||
var historyHtml='';
|
||||
for(var i = 0; i < res.length; i++){
|
||||
var command=JSON.parse(res[i][2])
|
||||
if (res[i][4] == 'waiting'){
|
||||
setComand(command['command'],command)
|
||||
continue
|
||||
}
|
||||
var outputs=JSON.parse(res[i][7])
|
||||
|
||||
historyObj[command['prompt_id']]=command
|
||||
for(var node_id of Object.keys(outputs)){
|
||||
node_output = outputs[node_id]
|
||||
if(Object.keys(node_output).indexOf("images") >= 0){
|
||||
for(var j = 0; j < node_output.images.length; j++){
|
||||
var img=node_output.images[j]
|
||||
var url = '/view?filename=' + img.filename + '&type=' + img.type + '&subfolder='+ img.subfolder
|
||||
historyHtml+=`<div data-v-ae8b2cf0="" data-v-622eff0c="" onclick="openView('image','`+url+`','`+command['prompt_id']+`')"
|
||||
class="item-box step_2 aigc-container__fml-item"><img data-v-ae8b2cf0=""
|
||||
class="cover-img"
|
||||
src="`+url+`">
|
||||
<div data-v-ae8b2cf0="" class="bottom">
|
||||
<div data-v-ae8b2cf0="" title="`+command['command']+`" class="title">`+command['command']+`</div>
|
||||
</div>
|
||||
</div>`
|
||||
if(userParams['prompt_id']==command['prompt_id']){
|
||||
$("#no_add_task_div").hide()
|
||||
$("#yes_add_task_div").hide()
|
||||
$("#wcomplete_add_task_img_div").css("background-image", "url(" + url + ")")
|
||||
$("#wcomplete_add_task_img_div").html('');
|
||||
$("#wcomplete_add_task_img_div").attr('url',url);
|
||||
$("#wcomplete_add_task_img_div").attr('type','image');
|
||||
$("#wcomplete_add_task_div").show()
|
||||
}
|
||||
}
|
||||
}else if(Object.keys(node_output).indexOf("gifs") >= 0){
|
||||
for(var j = 0; j < node_output.gifs.length; j++){
|
||||
var video=node_output.gifs[j]
|
||||
var url = '/view?filename=' + video.filename + '&type=' + video.type + '&subfolder='+ video.subfolder
|
||||
var imgUrl='/lam/getImage?type=wechat&&name=video_play.jpeg'
|
||||
var backgroundImg=''
|
||||
if(Object.keys(command).indexOf('image')>=0){
|
||||
if(command['image'].indexOf('view?filename')>=0){
|
||||
backgroundImg='/view?'+command['image'].split('?')[1]
|
||||
}
|
||||
}
|
||||
if(userParams['prompt_id']==command['prompt_id']){
|
||||
$("#no_add_task_div").hide()
|
||||
$("#yes_add_task_div").hide()
|
||||
//修改背景图片
|
||||
$("#wcomplete_add_task_img_div").css("background-image", "url(" + backgroundImg + ")")
|
||||
$("#wcomplete_add_task_img_div").html('<img src="'+imgUrl+'" style="width: auto;height: 100%;">')
|
||||
$("#wcomplete_add_task_img_div").attr('url',url);
|
||||
$("#wcomplete_add_task_img_div").attr('type','video');
|
||||
$("#wcomplete_add_task_div").show()
|
||||
}
|
||||
historyHtml+=`<div data-v-ae8b2cf0="" data-v-622eff0c="" style="background-image: url("`+backgroundImg+`");background-size: cover;background-position: center;"
|
||||
class="item-box step_2 aigc-container__fml-item" onclick="openView('video','`+url+`','`+command['prompt_id']+`')" ><img data-v-ae8b2cf0=""
|
||||
class="cover-img" data-video="`+url+`"
|
||||
src="`+imgUrl+`">
|
||||
<div data-v-ae8b2cf0="" class="bottom">
|
||||
<div data-v-ae8b2cf0="" title="`+command['command']+`" class="title">`+command['command']+`</div>
|
||||
</div>
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$("#historys_div_id").html(historyHtml);
|
||||
})
|
||||
}
|
||||
function setComand(name,comand) {
|
||||
userParams = comand?comand:{ 'openId': openId }
|
||||
userParams['command'] = name
|
||||
$("#"+btoa(encodeURIComponent(name))).addClass("active").siblings().removeClass("active")
|
||||
if ("prompt" in comands[name].params) {
|
||||
if(comand &&'prompt' in comand){
|
||||
$("#prompt").html(comand['prompt'])
|
||||
}else{
|
||||
userParams['prompt'] = ''
|
||||
}
|
||||
$('#prompt').attr('placeholder',$('#prompt').html().length>0?'':'输入中文或英文提示词');
|
||||
$("#prompt-container").show()
|
||||
} else {
|
||||
$("#prompt-container").hide()
|
||||
}
|
||||
if ("negative" in comands[name].params) {
|
||||
if(comand &&'negative' in comand){
|
||||
$("#negative").html(comand['negative'])
|
||||
}else{
|
||||
userParams['negative'] = ''
|
||||
}
|
||||
$('#negative').attr('placeholder',$('#negative').html().length>0?'':'输入中文或英文提示词');
|
||||
$("#negative-container").show()
|
||||
} else {
|
||||
$("#negative-container").hide()
|
||||
}
|
||||
if ('image' in comands[name].params) {
|
||||
if(comand &&'image' in comand){
|
||||
if(comand['image'].indexOf('view?filename')>=0){
|
||||
url='/view?'+comand['image'].split('?')[1]
|
||||
$("#upload_image_btn_parent_id").hide()
|
||||
$("#upload_image_preview_parend_id").show()
|
||||
//修改div的背景图片
|
||||
$("#upload_image_preview_id").css("background-image", "url(" + url + ")")
|
||||
var host = window.location.host;
|
||||
imageUrl = 'http://' + host + url
|
||||
userParams['image'] = imageUrl
|
||||
}else{
|
||||
userParams['image'] = ''
|
||||
}
|
||||
}else{
|
||||
userParams['image'] = ''
|
||||
}
|
||||
$("#upload_image_div_id").show()
|
||||
} else {
|
||||
$("#upload_image_div_id").hide()
|
||||
}
|
||||
var comandHtml = ''
|
||||
var otherHtml = ''
|
||||
console.log(comands[name].params)
|
||||
var paichuKeys = ['prompt', 'negative', 'image']
|
||||
for (var key of Object.keys(comands[name].params)) {
|
||||
if (paichuKeys.indexOf(key) >= 0) {
|
||||
continue
|
||||
}
|
||||
if ('options' in comands[name].params[key]) {
|
||||
var selName=''
|
||||
if(comand && key in comand){
|
||||
selName= Object.keys(comands[name].params[key]["options"]).find(opName => comands[name].params[key]["options"][opName] == comand[key]);
|
||||
}else{
|
||||
selName= Object.keys(comands[name].params[key]["options"])[0]
|
||||
userParams[key] = comands[name].params[key]['options'][selName]
|
||||
}
|
||||
comandHtml += `<div data-v-d25ec045="" class="aigc-top__base">
|
||||
<div data-v-d25ec045="" class="aigc-top__base--text" style="font-weight: bold;">
|
||||
`+ comands[name].params[key]['zhName'] + ` </div>
|
||||
<div data-v-d25ec045=""
|
||||
class="ant-select css-3m4nqy aigc-top__base--select ant-select-single ant-select-show-arrow"
|
||||
style="width: 100%;"><!---->
|
||||
<div class="ant-select-selector" onclick="$('#params_`+ key + `_options').toggle()">
|
||||
<span class="ant-select-selection-search" style="position: unset;" id="params_`+ key + `" >
|
||||
`+ selName + `
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div><!---->
|
||||
<div class="ant-select-dropdown css-3m4nqy ant-select-dropdown-placement-bottomLeft"
|
||||
style="min-width: 268px; width: 268px; left: 0px; top: 36px;display: none;" id="params_`+ key + `_options">
|
||||
<div>
|
||||
<div class="rc-virtual-list" style="position: relative;">
|
||||
<div class="rc-virtual-list-holder"
|
||||
style="max-height: 256px; overflow-y: hidden; overflow-anchor: none;">
|
||||
<div><div class="rc-virtual-list-holder-inner"
|
||||
style="display: flex; flex-direction: column;">`
|
||||
|
||||
for (var option of Object.keys(comands[name].params[key]["options"])) {
|
||||
classStr = comands[name].params[key]["options"][option] == userParams[key] ? 'ant-select-item-option-selected' : ''
|
||||
comandHtml += `<div aria-selected="true"
|
||||
class="ant-select-item ant-select-item-option `+ classStr + `" onclick="setOption(this,'` + comands[name].params[key]['options'][option] + `','` + key + `','` + option + `')">
|
||||
<div class="ant-select-item-option-content">
|
||||
<div data-v-d25ec045="">`+ option + `</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
comandHtml += ` </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
} else if ('type' in comands[name].params[key]) {
|
||||
if (comands[name].params[key]['type'] == 'number') {
|
||||
if(!comand||!(key in comand)){
|
||||
userParams[key] = comands[name].params[key]['default']
|
||||
}
|
||||
otherHtml += `
|
||||
<div data-v-fea6429a="" class="aigc-advanced__midexpend--process">`+ comands[name].params[key]['zhName'] + `<div
|
||||
data-v-fea6429a=""
|
||||
class="ant-input-number aigc-advanced__midexpend--input css-3m4nqy">
|
||||
<div class="ant-input-number-input-wrap">
|
||||
<input autocomplete="off" oninput="userParams['`+ key + `']=event.target.value"
|
||||
role="spinbutton" step="1" type="number" aria-valuemin="`+ comands[name].params[key]['min'] + `" aria-valuemax="` + comands[name].params[key]['max'] + `"
|
||||
value="`+ userParams[key] + `" class="ant-input-number-input"></div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
} else {
|
||||
if(!comand||!(key in comand)){
|
||||
userParams[key] = comands[name].params[key]['default']
|
||||
}
|
||||
otherHtml += `
|
||||
<div data-v-fea6429a="" style="white-space: nowrap;" class="aigc-advanced__midexpend--process"> `+ comands[name].params[key]['zhName'] + `
|
||||
<input data-v-fea6429a="" type="text" value="`+ userParams[key] + `"
|
||||
oninput="userParams['`+ key + `']=event.target.value" class="ant-input css-3m4nqy aigc-advanced__midexpend--input">
|
||||
</div>
|
||||
`
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$("#select_container_div").html(comandHtml)
|
||||
if (otherHtml != '') {
|
||||
$("#other_params_div_id").html(otherHtml)
|
||||
$("#other_params_parent_div").show();
|
||||
} else {
|
||||
$("#other_params_parent_div").hide()
|
||||
}
|
||||
|
||||
//console.log(comands[name].params)
|
||||
}
|
||||
function setOption(thi,val, key, option) {
|
||||
userParams[key] = val
|
||||
$("#params_" + key).html(option)
|
||||
$(thi).addClass("ant-select-item-option-selected").siblings().removeClass("ant-select-item-option-selected")
|
||||
$("#params_" + key + "_options").hide()
|
||||
}
|
||||
function clickUpload() {
|
||||
const myFile = $("#upload_image_input_id")
|
||||
// 触发
|
||||
myFile.click()
|
||||
// 监听change事件
|
||||
myFile[0].addEventListener('change', function (e) {
|
||||
var filesList = document.querySelector('#upload_image_input_id').files;
|
||||
if (filesList.length == 0) { //如果取消上传,则上传文件的长度为0
|
||||
console.log("没有上传任何文件");
|
||||
return;
|
||||
} else {
|
||||
//判断div是否显示
|
||||
$("#upload_image_btn_parent_id").show()
|
||||
$("#upload_image_btn_id").hide()
|
||||
$("#upload_image_loading_id").show()
|
||||
//如果有文件上传,这在这里面进行
|
||||
uploadImage(filesList[0])
|
||||
}
|
||||
});
|
||||
}
|
||||
function uploadImage(image) {
|
||||
//上传文件
|
||||
let formData = new FormData();
|
||||
formData.append("image", image, image.name);
|
||||
formData.append("overwrite", "true");
|
||||
formData.append("type", "input");
|
||||
|
||||
//发起jquery ajax请求
|
||||
$.ajax({
|
||||
method: 'post',
|
||||
url: '/upload/image',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (res) {
|
||||
$("#upload_image_btn_parent_id").hide()
|
||||
$("#upload_image_preview_parend_id").show()
|
||||
//修改div的背景图片
|
||||
var url = '/view?filename=' + res.name + '&type=' + res.type + '&subfolder='
|
||||
$("#upload_image_preview_id").css("background-image", "url(" + url + ")")
|
||||
var host = window.location.host;
|
||||
imageUrl = 'http://' + host + url
|
||||
userParams['image'] = imageUrl
|
||||
console.log(imageUrl);
|
||||
}
|
||||
})
|
||||
}
|
||||
function openViewNow(thi){
|
||||
var url=$(thi).attr('url')
|
||||
var type=$(thi).attr('type')
|
||||
var options={'url':url}
|
||||
alertWindow(type,options)
|
||||
}
|
||||
function openView(type,url,prompt_id){
|
||||
var options={'url':url,'okName':'应用参数'}
|
||||
alertWindow(type,options,function(){
|
||||
if(prompt_id){
|
||||
setComand(historyObj[prompt_id]['command'],historyObj[prompt_id])
|
||||
//getHistorys()
|
||||
}
|
||||
})
|
||||
}
|
||||
function alertWindow(type,options,okFun,cancelFun){
|
||||
$("#pop_frame_div_title_id").html('')
|
||||
$("#pop_frame_div_desc_id").html('')
|
||||
if(type=='image'){
|
||||
$("#pop_frame_div_desc_id").html('<img src="'+options.url+'" style="width:100%;height:100%;">')
|
||||
}else if(type=='video'){
|
||||
$("#pop_frame_div_desc_id").html('<video src="'+options.url+'" style="width:100%;height:100%;" controls="controls"></video>')
|
||||
}else if(type=='confirm'){
|
||||
$("#pop_frame_div_title_id").html(options.title)
|
||||
$("#pop_frame_div_desc_id").html(options.desc)
|
||||
}
|
||||
if('okName' in options){
|
||||
$("#pop_frame_div_btn_ok_id").html(options.okName)
|
||||
$("#pop_frame_div_btn_ok_id").show();
|
||||
$("#pop_frame_div_btn_ok_id").click(function(){
|
||||
$("#pop_frame_div_parent_id").hide();
|
||||
if(okFun){
|
||||
okFun();
|
||||
}
|
||||
})
|
||||
}else{
|
||||
$("#pop_frame_div_btn_ok_id").hide();
|
||||
}
|
||||
if('cancelName' in options){
|
||||
$("#pop_frame_div_btn_cancel_id").html(options.cancelName)
|
||||
$("#pop_frame_div_btn_cancel_id").show();
|
||||
$("#pop_frame_div_btn_cancel_id").click(function(){
|
||||
$("#pop_frame_div_parent_id").hide();
|
||||
if(cancelFun){
|
||||
cancelFun();
|
||||
}
|
||||
})
|
||||
}else{
|
||||
$("#pop_frame_div_btn_cancel_id").hide();
|
||||
}
|
||||
$("#pop_frame_div_parent_id").show();
|
||||
}
|
||||
function addTask(thi){ //提交任务
|
||||
$(thi).addClass('disable');
|
||||
let formData = new FormData();
|
||||
for (const key in userParams) {
|
||||
if (Object.hasOwnProperty.call(userParams, key)) {
|
||||
const element = userParams[key];
|
||||
if(element){
|
||||
formData.append(key, element)
|
||||
}
|
||||
}
|
||||
}
|
||||
$.ajax({
|
||||
method: 'post',
|
||||
url: '/wechatauth/addTask',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (res) {
|
||||
console.log(res)
|
||||
if(res.success){
|
||||
userParams['prompt_id']=res.prompt_id
|
||||
$("#no_add_task_div").hide()
|
||||
$("#wcomplete_add_task_div").hide()
|
||||
$("#yes_add_task_div").show()
|
||||
}else{
|
||||
alertWindow('confirm',{'title':'提示','desc':res.msg,'okName':'确定'})
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,89 @@
|
||||
from PIL import Image, ImageFilter, ImageEnhance, ImageOps, ImageDraw, ImageChops, ImageFont
|
||||
import folder_paths
|
||||
import os
|
||||
import numpy as np
|
||||
import torch
|
||||
import random
|
||||
import requests
|
||||
import io
|
||||
|
||||
class LamLoadPathImage:
|
||||
|
||||
def __init__(self):
|
||||
self.input_dir = folder_paths.input_directory
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image_path": ("STRING", {"default": './ComfyUI/input/example.png', "multiline": False}),
|
||||
"RGBA": (["false","true"],),
|
||||
},
|
||||
"optional": {
|
||||
"filename_text_extension": (["true", "false"],),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE", "MASK", "STRING")
|
||||
RETURN_NAMES = ("image", "mask", "filename_text")
|
||||
FUNCTION = "load_image"
|
||||
|
||||
CATEGORY = "lam"
|
||||
|
||||
def load_image(self, image_path, RGBA='false', filename_text_extension="true"):
|
||||
|
||||
RGBA = (RGBA == 'true')
|
||||
|
||||
if image_path.startswith('http'):
|
||||
from io import BytesIO
|
||||
i = self.download_image(image_path)
|
||||
else:
|
||||
try:
|
||||
i = Image.open(image_path)
|
||||
except OSError:
|
||||
print(f"The image `{image_path.strip()}` specified doesn't exist!")
|
||||
i = Image.new(mode='RGB', size=(512, 512), color=(0, 0, 0))
|
||||
if not i:
|
||||
return
|
||||
|
||||
image = i
|
||||
if not RGBA:
|
||||
image = image.convert('RGB')
|
||||
image = np.array(image).astype(np.float32) / 255.0
|
||||
image = torch.from_numpy(image)[None,]
|
||||
|
||||
if 'A' in i.getbands():
|
||||
mask = np.array(i.getchannel('A')).astype(np.float32) / 255.0
|
||||
mask = 1. - torch.from_numpy(mask)
|
||||
else:
|
||||
mask = torch.zeros((64, 64), dtype=torch.float32, device="cpu")
|
||||
|
||||
if filename_text_extension == "true":
|
||||
filename = os.path.basename(image_path)
|
||||
else:
|
||||
filename = os.path.splitext(os.path.basename(image_path))[0]
|
||||
|
||||
return (image, mask, filename)
|
||||
|
||||
def download_image(self, url):
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
img = Image.open(io.BytesIO(response.content))
|
||||
return img
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
print(f"HTTP Error: ({url}): {errh}")
|
||||
except requests.exceptions.ConnectionError as errc:
|
||||
print(f"Connection Error: ({url}): {errc}")
|
||||
except requests.exceptions.Timeout as errt:
|
||||
print(f"Timeout Error: ({url}): {errt}")
|
||||
except requests.exceptions.RequestException as err:
|
||||
print(f"Request Exception: ({url}): {err}")
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"LamLoadPathImage": LamLoadPathImage
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"LamLoadPathImage": "加载网络图片或本地图片"
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
from server import PromptServer
|
||||
from aiohttp import web
|
||||
import os
|
||||
import json
|
||||
from .src.wechat.WechatAuthUtils import *
|
||||
from .src.wechat.DataBaseUtil import DataBaseUtil
|
||||
import xml.etree.ElementTree as ET
|
||||
import time
|
||||
import logging
|
||||
import queue
|
||||
import random
|
||||
import types
|
||||
import execution
|
||||
import uuid
|
||||
import folder_paths
|
||||
def send_sync(self, event, data, sid=None): #继承父类的send_sync方法
|
||||
if sid and hasattr(self, "user_command") and sid in getattr(self,'user_command'):
|
||||
if event == "executing" and data['node'] is None and data['prompt_id'] == self.user_command[sid]['prompt_id']:
|
||||
history=self.prompt_queue.get_history(prompt_id=data['prompt_id'])[data['prompt_id']]
|
||||
#print("历史记录======:",history)
|
||||
if Config().wechat['isEnterprise'] and ('isWeb' not in self.user_command[sid] or self.user_command[sid]['isWeb']==False):
|
||||
imagePaths=[]
|
||||
videoPaths=[]
|
||||
for node_id in history['outputs']:
|
||||
node_output = history['outputs'][node_id]
|
||||
if 'images' in node_output:
|
||||
for image in node_output['images']:
|
||||
basePath=''
|
||||
if 'output' == image['type']:
|
||||
basePath=folder_paths.get_output_directory()
|
||||
elif 'temp' == image['type']:
|
||||
basePath=folder_paths.get_temp_directory()
|
||||
elif 'input' == image['type']:
|
||||
basePath=folder_paths.get_input_directory()
|
||||
|
||||
if image['subfolder']:
|
||||
basePath=os.path.join(basePath,image['subfolder'])
|
||||
|
||||
imagePaths.append(os.path.join(basePath,image['filename']))
|
||||
if 'gifs' in node_output:
|
||||
for image in node_output['gifs']:
|
||||
basePath=''
|
||||
if 'output' in image['type']:
|
||||
basePath=folder_paths.get_output_directory()
|
||||
elif 'temp' in image['type']:
|
||||
basePath=folder_paths.get_temp_directory()
|
||||
elif 'input' in image['type']:
|
||||
basePath=folder_paths.get_input_directory()
|
||||
|
||||
if image['subfolder']:
|
||||
basePath=os.path.join(basePath,image['subfolder'])
|
||||
|
||||
if 'format' in image:
|
||||
if image['format'].startswith('video'):
|
||||
videoPaths.append(os.path.join(basePath,image['filename']))
|
||||
continue
|
||||
|
||||
imagePaths.append(os.path.join(basePath,image['filename']))
|
||||
|
||||
logging.info("imagePaths: " + str(imagePaths)+" videoPaths: " + str(videoPaths))
|
||||
for imagePath in imagePaths:
|
||||
mediaId=getMediaId(imagePath,'image')
|
||||
sendServiceImageMessge(mediaId,sid)
|
||||
for videoPath in videoPaths:
|
||||
mediaId=getMediaId(videoPath,'video')
|
||||
sendServiceVideoMessge(mediaId,'AI生成','AI生成视频',sid)
|
||||
self.user_command[sid]['status']='wcomplete'
|
||||
now = time.localtime()
|
||||
end_time = time.strftime("%Y-%m-%d %H:%M:%S", now)
|
||||
db=DataBaseUtil()
|
||||
db.update_data('wcomplete', end_time, json.dumps(history['outputs']),data['prompt_id'])
|
||||
db.close_con()
|
||||
|
||||
self.loop.call_soon_threadsafe(
|
||||
self.messages.put_nowait, (event, data, sid))
|
||||
def update_dict(dictionary, keys, value):
|
||||
if len(keys) == 1:
|
||||
dictionary[keys[0]] = value
|
||||
else:
|
||||
key = keys.pop(0)
|
||||
if isinstance(dictionary[key], dict):
|
||||
update_dict(dictionary[key], keys, value)
|
||||
elif isinstance(dictionary[key], list):
|
||||
for item in dictionary[key]:
|
||||
update_dict(item, keys[:], value)
|
||||
else:
|
||||
raise ValueError("Invalid data structure")
|
||||
def setPost(self,FromUserName):
|
||||
params=self.user_command[FromUserName]
|
||||
logging.info(str(params))
|
||||
basePath=folder_paths.folder_names_and_paths['custom_nodes'][0][0]
|
||||
comand=Config().wechat['commands'][params['command']]
|
||||
filePath = os.path.join(basePath,'ComfyUI_Lam','config','workflow',comand['filename'])
|
||||
if os.path.exists(filePath)==False:
|
||||
logging.warning("文件不存在:"+filePath)
|
||||
return None
|
||||
f = open(filePath,'r', encoding='utf-8')
|
||||
json_data = json.load(f)
|
||||
f.close()
|
||||
for key in comand['params']:
|
||||
keys=comand['params'][key]['keys'][:]
|
||||
if key in params:
|
||||
update_dict(json_data,keys,params[key])
|
||||
|
||||
json_data={"prompt":json_data,"client_id":params['openId']}
|
||||
logging.info(json_data)
|
||||
json_data = self.trigger_on_prompt(json_data)
|
||||
if "number" in json_data:
|
||||
number = float(json_data['number'])
|
||||
else:
|
||||
number = self.number
|
||||
if "front" in json_data:
|
||||
if json_data['front']:
|
||||
number = -number
|
||||
|
||||
self.number += 1
|
||||
|
||||
if "prompt" in json_data:
|
||||
prompt = json_data["prompt"]
|
||||
valid = execution.validate_prompt(prompt)
|
||||
extra_data = {}
|
||||
if "extra_data" in json_data:
|
||||
extra_data = json_data["extra_data"]
|
||||
|
||||
if "client_id" in json_data:
|
||||
extra_data["client_id"] = json_data["client_id"]
|
||||
if valid[0]:
|
||||
prompt_id = str(uuid.uuid4())
|
||||
outputs_to_execute = valid[2]
|
||||
self.prompt_queue.put((number, prompt_id, prompt, extra_data, outputs_to_execute))
|
||||
now = time.localtime()
|
||||
start_time = time.strftime("%Y-%m-%d %H:%M:%S", now)
|
||||
self.user_command[FromUserName]['status']='waiting' #prepare:准备 waiting:待执行 wcomplete完成
|
||||
self.user_command[FromUserName]['prompt_id']=prompt_id
|
||||
db=DataBaseUtil()
|
||||
db.insert_data( params['openId'], json.dumps(params), prompt_id,'waiting',start_time, '', '')
|
||||
db.close_con()
|
||||
return prompt_id
|
||||
else:
|
||||
logging.warning("invalid prompt: {}".format(valid[1]))
|
||||
return None
|
||||
|
||||
def getTaskRanking(self,FromUserName):
|
||||
if 'prompt_id' not in self.user_command[FromUserName]:
|
||||
return '您还没有排队,请先发送您的指令'
|
||||
prompt_id=self.user_command[FromUserName]['prompt_id']
|
||||
current_queue = self.prompt_queue.get_current_queue()
|
||||
print(current_queue)
|
||||
for i in range(len(current_queue[0])):
|
||||
if current_queue[0][i][1] == prompt_id:
|
||||
return '您的任务正在执行。'
|
||||
for i in range(len(current_queue[1])):
|
||||
if current_queue[1][i][1] == prompt_id:
|
||||
return '当前排队人数:'+str(len(current_queue[1]))+'人,您当前的位置在'+current_queue[1][i][0]+'号。'
|
||||
return '您还没有排队,请先发送您的指令'
|
||||
|
||||
@PromptServer.instance.routes.get("/wechatauth/getHistorys")
|
||||
async def getHistorys(request):
|
||||
if "openId" in request.rel_url.query:
|
||||
openId=request.rel_url.query['openId']
|
||||
db=DataBaseUtil()
|
||||
datas=db.get_many_data(openId)
|
||||
db.close_con()
|
||||
return web.Response(text=json.dumps(datas), content_type='application/json')
|
||||
else:
|
||||
return web.Response(status=404)
|
||||
|
||||
@PromptServer.instance.routes.post("/wechatauth/addTask")
|
||||
async def addTask(request):
|
||||
post = await request.post()
|
||||
print(post.keys())
|
||||
command = post.get("command")
|
||||
if command == None:
|
||||
msg = '指令不能为空!'
|
||||
data={'msg':msg,'success':False}
|
||||
return web.Response(text=json.dumps(data), content_type='application/json')
|
||||
|
||||
openId = post.get("openId")
|
||||
if openId == None:
|
||||
msg = '用户编码不能为空!'
|
||||
data={'msg':msg,'success':False}
|
||||
return web.Response(text=json.dumps(data), content_type='application/json')
|
||||
|
||||
if hasattr(PromptServer.instance,'user_command') and openId in PromptServer.instance.user_command and PromptServer.instance.user_command[openId]['status']=='waiting':
|
||||
msg = '您已经在队列中,请勿重复提交!'
|
||||
data={'msg':msg,'success':False}
|
||||
return web.Response(text=json.dumps(data), content_type='application/json')
|
||||
|
||||
adminNo=base64_decode(Config().wechat['adminNo'])
|
||||
if adminNo!=openId:
|
||||
db=DataBaseUtil()
|
||||
data=db.get_user_frequency(openId)
|
||||
if data[0]==None:
|
||||
db.user_recharge(openId,Config().wechat['freeSize'])
|
||||
data=db.get_user_frequency(openId)
|
||||
countd=db.get_user_task_count(openId)
|
||||
db.close_con()
|
||||
if countd[0] >=data[0]:
|
||||
msg='非常抱歉,您的免费使用次数已用完,如需继续使用,请扫描右上角二维码,联系管理员。'
|
||||
data={'msg':msg,'success':False}
|
||||
return web.Response(text=json.dumps(data), content_type='application/json')
|
||||
|
||||
params=Config().wechat['commands'][command]['params']
|
||||
paramName=''
|
||||
userData={'openId':openId,'command':command,'status':'prepare','isWeb':True}
|
||||
for param in params:
|
||||
val=post.get(param)
|
||||
if params[param]['isRequired'] and val==None:
|
||||
paramName= params[param]['zhName']
|
||||
break
|
||||
if val:
|
||||
userData[param]=val
|
||||
|
||||
if paramName:
|
||||
msg = '参数"'+paramName+'"不能为空!'
|
||||
data={'msg':msg,'success':False}
|
||||
return web.Response(text=json.dumps(data), content_type='application/json')
|
||||
|
||||
if 'seed' in userData:
|
||||
if userData['seed'].isdigit()==False or int(userData['seed'])==-1:
|
||||
userData['seed']=''.join(random.sample('123456789012345678901234567890',14))
|
||||
|
||||
if hasattr(PromptServer.instance,"user_command")==False:
|
||||
setattr(PromptServer.instance,"user_command",{})
|
||||
|
||||
PromptServer.instance.user_command[openId]=userData
|
||||
resp=setPost(PromptServer.instance,openId)
|
||||
if resp!=None:
|
||||
data={'msg':'任务已加入队列请等待...','prompt_id':resp,'success':True}
|
||||
return web.Response(text=json.dumps(data), content_type='application/json')
|
||||
|
||||
@PromptServer.instance.routes.get("/wechatauth/getCommands")
|
||||
async def getCommands(request):
|
||||
commands=Config().wechat['commands']
|
||||
return web.Response(text=json.dumps(commands), content_type='application/json')
|
||||
|
||||
@PromptServer.instance.routes.get("/wechatauth/app")
|
||||
async def app(request):
|
||||
if "openId" in request.rel_url.query:
|
||||
openId=request.rel_url.query['openId']
|
||||
openId=base64_decode(openId)
|
||||
basePath = folder_paths.folder_names_and_paths['custom_nodes'][0][0]
|
||||
htmlPtah = os.path.join(basePath, 'ComfyUI_Lam', 'pages','app.html')
|
||||
# 打开文件
|
||||
with open(htmlPtah, 'r', encoding='utf-8') as file:
|
||||
# 读取文件内容
|
||||
html_content = file.read()
|
||||
|
||||
html_content = html_content.replace('{{openId}}', openId)
|
||||
return web.Response(text=html_content, content_type='text/html')
|
||||
#return web.FileResponse(htmlPtah)
|
||||
else:
|
||||
return web.Response(status=404)
|
||||
|
||||
@PromptServer.instance.routes.get("/wechatauth/handleMessage")
|
||||
async def handleMessageGet(request):
|
||||
if "echostr" in request.rel_url.query:
|
||||
echostr=request.rel_url.query['echostr']
|
||||
return web.Response(text=echostr)
|
||||
else:
|
||||
return web.Response(text="121212")
|
||||
|
||||
@PromptServer.instance.routes.post("/wechatauth/handleMessage")
|
||||
async def handleMessagePost(request):
|
||||
# 读取请求体数据
|
||||
body = await request.read()
|
||||
# 将字节转换为字符串
|
||||
data_str = body.decode('utf-8')
|
||||
data = ET.fromstring(data_str)
|
||||
ToUserName = data.find('ToUserName').text
|
||||
FromUserName = data.find('FromUserName').text
|
||||
MsgType = data.find('MsgType').text
|
||||
logging.info(data_str)
|
||||
CreateTime = int(time.time())
|
||||
if hasattr(PromptServer.instance,"user_command")==False:
|
||||
setattr(PromptServer.instance,"user_command",{})
|
||||
|
||||
#判断是否为准备状态
|
||||
isPrepare=FromUserName in PromptServer.instance.user_command and PromptServer.instance.user_command[FromUserName]['status']=='prepare'
|
||||
isWaiting=FromUserName in PromptServer.instance.user_command and PromptServer.instance.user_command[FromUserName]['status']=='waiting'
|
||||
# 如果发送的是消息请求,
|
||||
if MsgType == 'text': #语音屏蔽or MsgType == 'voice'
|
||||
try:
|
||||
MsgId = data.find("MsgId").text
|
||||
if MsgType == 'text':
|
||||
Content = data.find('Content').text # 文本消息内容
|
||||
elif MsgType == 'voice':
|
||||
Content = data.find('Recognition').text # 语音识别结果,UTF8编码
|
||||
# 调用回复函数判断接受的信息,然后返回对应的内容
|
||||
reply_content,otherName=receive_msg(Content,isPrepare,isWaiting)
|
||||
logging.info("reply_content:"+reply_content+',otherName:'+str(otherName))
|
||||
if reply_content=='menu' and otherName:
|
||||
if Config().wechat['isEnterprise']:
|
||||
sendServiceMenuMessage('您可以执行以下操作:','欢迎再次光临',otherName, FromUserName)
|
||||
else:
|
||||
msgStr='您可以执行以下操作指令:\n '
|
||||
for i in range(len(otherName)):
|
||||
msgStr+=otherName[i]['content']+'\n'
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, msg)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
|
||||
elif reply_content=='command' and otherName:
|
||||
adminNo=base64_decode(Config().wechat['adminNo'])
|
||||
msg=''
|
||||
isAdopt=True
|
||||
if adminNo!=FromUserName:
|
||||
db=DataBaseUtil()
|
||||
data=db.get_user_frequency(FromUserName)
|
||||
if data[0]==None:
|
||||
db.user_recharge(FromUserName,Config().wechat['freeSize'])
|
||||
data=db.get_user_frequency(FromUserName)
|
||||
countd=db.get_user_task_count(FromUserName)
|
||||
db.close_con()
|
||||
if countd[0] >=data[0]:
|
||||
isAdopt=False
|
||||
msg='非常抱歉,您的免费使用次数已用完,如需继续使用,请联系管理员。微信号:\n'+Config().wechat['adminWeChat']
|
||||
|
||||
if isAdopt:
|
||||
#添加指令的代码
|
||||
PromptServer.instance.user_command[FromUserName]={'openId':FromUserName,'status':'prepare','command':otherName,'seed':''.join(random.sample('123456789012345678901234567890',14))}
|
||||
msg,comlist=getCommandMsg(Config().wechat['commands'][otherName],Config().wechat['isEnterprise'])
|
||||
if comlist:
|
||||
sendServiceMenuMessage(msg,Config().wechat['commands'][otherName]['replyText'],comlist, FromUserName)
|
||||
return web.Response(status=200)
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, msg)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
elif reply_content=='query' and otherName:
|
||||
if otherName=='查询排队情况':
|
||||
msg=''
|
||||
if isWaiting:
|
||||
msg=getTaskRanking(PromptServer.instance,FromUserName)
|
||||
else:
|
||||
msg='您还没有排队,请先发送您的指令'
|
||||
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, msg)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
elif otherName == '我的编号':
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, base64_encode(FromUserName))
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
elif reply_content=='ok':
|
||||
if otherName and len(otherName)>0:
|
||||
PromptServer.instance.user_command[FromUserName]['prompt']=PromptServer.instance.user_command[FromUserName]['prompt']+otherName if 'prompt' in PromptServer.instance.user_command[FromUserName] else otherName
|
||||
params=Config().wechat['commands'][PromptServer.instance.user_command[FromUserName]['command']]['params']
|
||||
paramName=''
|
||||
for param in params:
|
||||
if params[param]['isRequired'] and param not in PromptServer.instance.user_command[FromUserName]:
|
||||
paramName= params[param]['zhName']
|
||||
break
|
||||
if paramName!='':
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, '任务缺乏参数“'+paramName+'”请补充后再提交')
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
resp=setPost(PromptServer.instance,FromUserName)
|
||||
if resp!=None:
|
||||
serverAddress=Config().wechat['serverAddress']+'wechatauth/app?openId='+base64_encode(FromUserName)
|
||||
imgUrl='http://mmbiz.qpic.cn/sz_mmbiz_jpg/EpicUicwgk0IGpbYZicuGSXUBaIFWbuDZmBbmDO9PleONOz3FJ3eANEmRicD0eR7mF6PCkxSPxVicbDclQldFKDlHRA/0'
|
||||
out = reply_news(FromUserName, ToUserName, CreateTime, '任务加入队列提醒','任务已加入队列请等待。或可点击访问详情,使用更多功能!',imgUrl,serverAddress)
|
||||
#out = reply_text(FromUserName, ToUserName, CreateTime, '任务已加入队列请等待,详情请访问:\n'+serverAddress)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
elif reply_content=='recharge' and otherName:
|
||||
adminNo=base64_decode(Config().wechat['adminNo'])
|
||||
msg=''
|
||||
if adminNo==FromUserName:
|
||||
data=otherName.split('加')
|
||||
openId=base64_decode(data[0])
|
||||
tount=int(data[1])
|
||||
if openId and tount>0:
|
||||
db=DataBaseUtil()
|
||||
fdata=db.get_user_frequency(openId)
|
||||
if fdata[0] and fdata[0]>0:
|
||||
db.user_recharge(openId,tount)
|
||||
msg='次数加入成功'
|
||||
else:
|
||||
msg='用户不存在'
|
||||
|
||||
db.close_con()
|
||||
else:
|
||||
msg='用户编码错误'
|
||||
else:
|
||||
msg='无效的指令'
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, msg)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
elif isPrepare:
|
||||
msg=''
|
||||
if reply_content and otherName!=None:
|
||||
commandName=PromptServer.instance.user_command[FromUserName]['command']
|
||||
if reply_content in Config().wechat['commands'][commandName]['params']:
|
||||
if 'options' in Config().wechat['commands'][commandName]['params'][reply_content]:
|
||||
PromptServer.instance.user_command[FromUserName][reply_content]=Config().wechat['commands'][commandName]['params'][reply_content]['options'][otherName]
|
||||
else:
|
||||
PromptServer.instance.user_command[FromUserName][reply_content]=otherName
|
||||
msg='已填选'+Config().wechat['commands'][commandName]['params'][reply_content]['zhName']+':'+otherName
|
||||
else:
|
||||
PromptServer.instance.user_command[FromUserName]['prompt']=PromptServer.instance.user_command[FromUserName]['prompt']+reply_content if 'prompt' in PromptServer.instance.user_command[FromUserName] else reply_content
|
||||
msg='已填入提示词:'+reply_content
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, msg)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
else:
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, reply_content)
|
||||
logging.info(out)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
except Exception as e:
|
||||
logging.error('消息处理异常:'+str(e))
|
||||
elif MsgType == 'image': #图片
|
||||
if isPrepare:
|
||||
PicUrl=data.find('PicUrl').text
|
||||
PromptServer.instance.user_command[FromUserName]['image']=PicUrl
|
||||
else:
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, '请先选择指令')
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
elif MsgType == 'event': #事件
|
||||
try:
|
||||
Event = data.find('Event').text
|
||||
Event_key = data.find('EventKey').text
|
||||
CreateTime = int(time.time())
|
||||
# 判断事件,并返回内容
|
||||
reply_content = receive_event(Event,Event_key)
|
||||
if reply_content:
|
||||
out = reply_text(FromUserName, ToUserName, CreateTime, reply_content)
|
||||
return web.Response(text=out, content_type='application/xml')
|
||||
except Exception as e:
|
||||
logging.error('事件处理异常:'+str(e))
|
||||
return web.Response(status=200)
|
||||
|
||||
PromptServer.instance.send_sync=types.MethodType(send_sync,PromptServer.instance)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {}
|
||||
@@ -24,8 +24,8 @@ if not os.path.exists(dir):
|
||||
|
||||
# Directory node save settings
|
||||
CHUNK_SIZE = 1024
|
||||
dir_painter_node = os.path.dirname(__file__)
|
||||
extension_path = os.path.join(os.path.abspath(dir_painter_node))
|
||||
basePath = folder_paths.folder_names_and_paths['custom_nodes'][0][0]
|
||||
extension_path = os.path.join(basePath, 'ComfyUI_Lam', 'config')
|
||||
file_settings_path = os.path.join(extension_path,"settings_nodes.json")
|
||||
|
||||
# Function create file json file
|
||||
@@ -379,9 +379,13 @@ class openPoseEditorPlus:
|
||||
|
||||
image_path = folder_paths.get_annotated_filepath(image)
|
||||
|
||||
i = Image.open(image_path)
|
||||
i = ImageOps.exif_transpose(i)
|
||||
painterImage = i.convert("RGB")
|
||||
if os.path.exists(image_path):
|
||||
i = Image.open(image_path)
|
||||
i = ImageOps.exif_transpose(i)
|
||||
painterImage = i.convert("RGB")
|
||||
else:
|
||||
painterImage = np.zeros(shape=(height, width, 3), dtype=np.uint8)
|
||||
|
||||
painterImage = np.array(painterImage).astype(np.float32) / 255.0
|
||||
painterImage = torch.from_numpy(painterImage)[None,]
|
||||
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import os
|
||||
import sqlite3
|
||||
import folder_paths
|
||||
import time
|
||||
class DataBaseUtil():
|
||||
"""
|
||||
简单sqlite数据库工具类
|
||||
编写这个类主要是为了封装sqlite,继承此类复用方法
|
||||
"""
|
||||
|
||||
def __init__(self, dbName="lamWeChat.db"):
|
||||
"""
|
||||
初始化连接——使用完需关闭连接
|
||||
:param dbName: 连接库的名字,注意,以'.db'结尾
|
||||
"""
|
||||
basePath = folder_paths.folder_names_and_paths['custom_nodes'][0][0]
|
||||
self.db_path = os.path.join(basePath, 'ComfyUI_Lam', 'config', dbName)
|
||||
isNew=os.path.exists(self.db_path)
|
||||
# 连接数据库
|
||||
self._conn = sqlite3.connect(self.db_path)
|
||||
# 创建游标
|
||||
self._cur = self._conn.cursor()
|
||||
if isNew==False:
|
||||
# 创建数据表 用户任务表
|
||||
users_tb_sql ='''
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
openId TEXT NOT NULL,
|
||||
command TEXT NOT NULL,
|
||||
prompt_id TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
start_time TEXT NOT NULL,
|
||||
end_time TEXT,
|
||||
outputs TEXT
|
||||
)
|
||||
'''
|
||||
self.create_tabel(users_tb_sql)
|
||||
# 用户充值记录表
|
||||
user_recharge_sql ='''
|
||||
CREATE TABLE IF NOT EXISTS user_recharge (
|
||||
id INTEGER PRIMARY KEY,
|
||||
openId TEXT NOT NULL,
|
||||
frequency INTEGER NOT NULL,
|
||||
recharge_time TEXT NOT NULL
|
||||
)
|
||||
'''
|
||||
self.create_tabel(user_recharge_sql)
|
||||
|
||||
|
||||
|
||||
def close_con(self):
|
||||
"""关闭连接对象——主动调用
|
||||
:return:
|
||||
"""
|
||||
self._cur.close()
|
||||
self._conn.close()
|
||||
# 创建数据表
|
||||
def create_tabel(self, sql: str):
|
||||
"""
|
||||
创建表
|
||||
:param sql: create sql语句
|
||||
:return: True表示创建表成功
|
||||
"""
|
||||
try:
|
||||
self._cur.execute(sql)
|
||||
self._conn.commit()
|
||||
print("[create table success]")
|
||||
return True
|
||||
except Exception as e:
|
||||
print("[create table error]", e)
|
||||
# 删除数据表
|
||||
def drop_table(self, sql: str):
|
||||
"""
|
||||
删除表
|
||||
:param sql: drop sql语句
|
||||
:return: True表示删除成功
|
||||
"""
|
||||
try:
|
||||
self._cur.execute(sql)
|
||||
self._conn.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
print("[drop table error]", e)
|
||||
return False
|
||||
# 插入或更新表数据,一次插入或更新一条数据
|
||||
def operate_one(self, sql: str, value: tuple):
|
||||
"""
|
||||
插入或更新单条表记录
|
||||
:param sql: insert语句或update语句
|
||||
:param value: 插入或更新的值,形如()
|
||||
:return: True表示插入或更新成功
|
||||
"""
|
||||
try:
|
||||
self._cur.execute(sql, value)
|
||||
self._conn.commit()
|
||||
if 'INSERT' in sql.upper():
|
||||
print("[insert one record success]")
|
||||
if 'UPDATE' in sql.upper():
|
||||
print("[update one record success]")
|
||||
return True
|
||||
except Exception as e:
|
||||
print("[insert/update one record error]", e)
|
||||
self._conn.rollback()
|
||||
return False
|
||||
# 插入或更新表数据,一次插入或更新多条数据
|
||||
def operate_many(self, sql: str, value: list):
|
||||
"""
|
||||
插入或更新多条表记录
|
||||
:param sql: insert语句或update语句
|
||||
:param value: 插入或更新的字段的具体值,列表形式为list:[(),()]
|
||||
:return: True表示插入或更新成功
|
||||
"""
|
||||
try:
|
||||
# 调用executemany()方法
|
||||
self._cur.executemany(sql, value)
|
||||
self._conn.commit()
|
||||
if 'INSERT' in sql.upper():
|
||||
print("[insert many records success]")
|
||||
if 'UPDATE' in sql.upper():
|
||||
print("[update many records success]")
|
||||
return True
|
||||
except Exception as e:
|
||||
print("[insert/update many records error]", e)
|
||||
self._conn.rollback()
|
||||
return False
|
||||
# 删除表数据
|
||||
def delete_record(self, sql: str):
|
||||
"""
|
||||
删除表记录
|
||||
:param sql: 删除记录SQL语句
|
||||
:return: True表示删除成功
|
||||
"""
|
||||
try:
|
||||
if 'DELETE' in sql.upper():
|
||||
self._cur.execute(sql)
|
||||
self._conn.commit()
|
||||
#print("[detele record success]")
|
||||
return True
|
||||
else:
|
||||
print("[sql is not delete]")
|
||||
return False
|
||||
except Exception as e:
|
||||
print("[detele record error]", e)
|
||||
return False
|
||||
# 查询一条数据
|
||||
def query_one(self, sql: str, params=None):
|
||||
"""
|
||||
查询单条数据
|
||||
:param sql: select语句
|
||||
:param params: 查询参数,形如()
|
||||
:return: 语句查询单条结果
|
||||
"""
|
||||
try:
|
||||
if params:
|
||||
self._cur.execute(sql, params)
|
||||
else:
|
||||
self._cur.execute(sql)
|
||||
# 调用fetchone()方法
|
||||
r = self._cur.fetchone()
|
||||
#print("[select one record success]")
|
||||
return r
|
||||
except Exception as e:
|
||||
print("[select one record error]", e)
|
||||
# 查询多条数据
|
||||
def query_many(self, sql: str, params=None):
|
||||
"""
|
||||
查询多条数据
|
||||
:param sql: select语句
|
||||
:param params: 查询参数,形如()
|
||||
:return: 语句查询多条结果
|
||||
"""
|
||||
try:
|
||||
if params:
|
||||
self._cur.execute(sql, params)
|
||||
else:
|
||||
self._cur.execute(sql)
|
||||
# 调用fetchall()方法
|
||||
r = self._cur.fetchall()
|
||||
#print("[select many records success]")
|
||||
return r
|
||||
except Exception as e:
|
||||
print("[select many records error]", e)
|
||||
def insert_data(self, openId, command, prompt_id,status,start_time, end_time, outputs):
|
||||
self.operate_one("INSERT INTO users (openId, command,prompt_id,status, start_time, end_time, outputs) VALUES (?, ?,?, ?, ?, ?,?)", (
|
||||
openId, command, prompt_id,status,start_time, end_time, outputs))
|
||||
|
||||
def get_data(self, openId,prompt_id):
|
||||
return self.query_one("SELECT * FROM users WHERE openId = ? and prompt_id=? ", (openId,prompt_id))
|
||||
|
||||
def update_data(self, status, end_time, outputs,prompt_id):
|
||||
self.operate_one("UPDATE users SET status=?,end_time = ?, outputs = ? WHERE prompt_id = ?",
|
||||
(status, end_time, outputs, prompt_id))
|
||||
|
||||
def get_many_data(self, openId):
|
||||
return self.query_many("SELECT * FROM users WHERE openId=? ", (openId,))
|
||||
|
||||
def user_recharge(self,openId,frequency):
|
||||
now = time.localtime()
|
||||
recharge_time = time.strftime("%Y-%m-%d %H:%M:%S", now)
|
||||
self.operate_one("INSERT INTO user_recharge (openId,frequency,recharge_time) VALUES (?, ?,?)", (openId, frequency, recharge_time))
|
||||
|
||||
def get_user_frequency(self,openId):
|
||||
return self.query_one("SELECT sum(frequency) FROM user_recharge WHERE openId=? ", (openId,))
|
||||
|
||||
def get_user_task_count(self,openId):
|
||||
return self.query_one("SELECT count(*) FROM users WHERE openId=? ", (openId,))
|
||||
|
||||
|
||||
#db=DataBaseUtil()
|
||||
#db.delete_record('DELETE FROM users where command="图生视频"')
|
||||
#data=db.get_user_task_count('oJNTS6vtlfGKyivfY6loLLScQ3FQ')
|
||||
#data=db.get_data('oJNTS6vtlfGKyivfY6loLLScQ3FQ','02b73c61-6f18-4432-837a-dd64d9424ed7')
|
||||
#print(data)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
import requests
|
||||
import hashlib
|
||||
import io
|
||||
import cv2
|
||||
import json
|
||||
from .config import Config
|
||||
import time
|
||||
import logging
|
||||
# APPID = 'wx1c2b19f7af1d6241'
|
||||
# SECRET = '915d587b5ae4e148e100429e11ca4d60'
|
||||
#APPID = 'wxa50ed345b253964d'
|
||||
#SECRET = "327ac9ba06d214d2fcfe2e9ed0520684"
|
||||
# APPID = 'wx2693b75459c2f339'
|
||||
# SECRET = 'f5e8741764bbb0a8b8b2d7d26a17ea62'
|
||||
import base64
|
||||
|
||||
|
||||
def base64_encode(text):
|
||||
encoded_text = base64.b64encode(text.encode('utf-8')).decode('utf-8')
|
||||
return encoded_text
|
||||
|
||||
|
||||
def base64_decode(encoded_text):
|
||||
decoded_text = base64.b64decode(encoded_text).decode('utf-8')
|
||||
return decoded_text
|
||||
|
||||
|
||||
"""这是一个处理客户发送信息的文件"""
|
||||
|
||||
|
||||
def reply_text(FromUserName, ToUserName, CreateTime, Content):
|
||||
"""回复文本消息模板"""
|
||||
textTpl = """<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content></xml>"""
|
||||
out = textTpl % (FromUserName, ToUserName, CreateTime, 'text', Content)
|
||||
return out
|
||||
|
||||
|
||||
"""图片文消息"""
|
||||
|
||||
|
||||
def reply_news(FromUserName, ToUserName, CreateTime, Title, Description, PicUrl, Url):
|
||||
textTpl = """
|
||||
<xml>
|
||||
<ToUserName><![CDATA[%s]]></ToUserName>
|
||||
<FromUserName><![CDATA[%s]]></FromUserName>
|
||||
<CreateTime>%s</CreateTime>
|
||||
<MsgType><![CDATA[news]]></MsgType>
|
||||
<ArticleCount>1</ArticleCount>
|
||||
<Articles>
|
||||
<item>
|
||||
<Title><![CDATA[%s]]></Title>
|
||||
<Description><![CDATA[%s]]></Description>
|
||||
<PicUrl><![CDATA[%s]]></PicUrl>
|
||||
<Url><![CDATA[%s]]></Url>
|
||||
</item>
|
||||
</Articles>
|
||||
</xml>
|
||||
"""
|
||||
out = textTpl % (FromUserName, ToUserName, CreateTime,
|
||||
Title, Description, PicUrl, Url)
|
||||
return out
|
||||
|
||||
|
||||
def getCommandMsg(command, isEnterprise):
|
||||
keyNames = ['image', 'seed', 'prompt', 'negative']
|
||||
if isEnterprise:
|
||||
comList = []
|
||||
names = []
|
||||
otherParamsStr=''
|
||||
index = 0
|
||||
for key in command['params']:
|
||||
if key in keyNames:
|
||||
continue
|
||||
|
||||
requiredText='(必填)' if command['params'][key]['isRequired'] else '(选填)'
|
||||
if 'options' in command['params'][key]:
|
||||
names.append(command['params'][key]['zhName']+requiredText)
|
||||
for option in command['params'][key]['options']:
|
||||
comList.append({"id": index, "content": key+':'+option})
|
||||
index += 1
|
||||
else:
|
||||
otherParamsStr+='\n参数“'+command['params'][key]['zhName']+requiredText+'”指令=》'+key+':'+str(command['params'][key]['default'])
|
||||
|
||||
|
||||
if len(names) > 0 and len(comList) > 0:
|
||||
return '您可以选择以下指令来选择('+','.join(names)+')'+otherParamsStr, comList
|
||||
else:
|
||||
if len(otherParamsStr)>0:
|
||||
return '您可以输入以下指令:'+otherParamsStr+'\n'+command['replyText'], None
|
||||
return command['replyText'], None
|
||||
else:
|
||||
names = []
|
||||
comList = []
|
||||
otherParamsStr=''
|
||||
for key in command['params']:
|
||||
if key in keyNames:
|
||||
continue
|
||||
|
||||
requiredText='(必填)' if command['params'][key]['isRequired'] else '(选填)'
|
||||
if 'options' in command['params'][key]:
|
||||
names.append(command['params'][key]['zhName']+requiredText)
|
||||
for option in command['params'][key]['options']:
|
||||
comList.append(key+':'+option)
|
||||
else:
|
||||
otherParamsStr+='\n参数“'+command['params'][key]['zhName']+requiredText+'”命令=》'+key+':'+str(command['params'][key]['default'])
|
||||
return '您可以执行以下命令:\n'+'\n'.join(comList)+'\n,选择》'+','.join(names)+otherParamsStr+'\n'+command['replyText'], None
|
||||
|
||||
|
||||
def receive_msg(msg, isPrepare=False, isWaiting=False):
|
||||
# 这是一个将疑问改成成熟句子的函数,例如:你好吗 公众号回复:你好
|
||||
commands = Config().wechat['commands']
|
||||
isEnterprise = Config().wechat['isEnterprise']
|
||||
query_commands = Config().wechat['query_commands']
|
||||
if msg == u'帮助':
|
||||
comList = []
|
||||
index = 0
|
||||
for key in commands:
|
||||
comList.append({"id": index, "content": key})
|
||||
index += 1
|
||||
for key in query_commands:
|
||||
comList.append({"id": index, "content": key})
|
||||
index += 1
|
||||
if isEnterprise == False:
|
||||
comNames = [x['content'] for x in comList]
|
||||
return '您可以执行以下操作:\n'+'\n'.join(comNames), None
|
||||
return 'menu', comList
|
||||
elif isWaiting == False and msg in commands:
|
||||
return 'command', msg
|
||||
elif msg in query_commands:
|
||||
return 'query', msg
|
||||
elif isPrepare:
|
||||
if msg.find(':') != -1:
|
||||
return tuple(msg.split(':'))
|
||||
elif (msg.lower().endswith(u'ok') or msg.lower() == 'ok'):
|
||||
return 'ok', msg[:-2]
|
||||
else:
|
||||
return msg, None
|
||||
elif msg.find('加') != -1 and len(msg.split('加')) == 2:
|
||||
return 'recharge', msg
|
||||
elif isWaiting:
|
||||
return '任务已加入队列请等待...', None
|
||||
else:
|
||||
return "您可以发送“帮助”查看使用说明", None
|
||||
|
||||
|
||||
def receive_event(event, key):
|
||||
# 如果是关注公众号事件
|
||||
if event == 'subscribe':
|
||||
return "感谢关注!您可以发送“帮助”查看使用说明"
|
||||
# 如果是点击菜单拉取消息事件
|
||||
elif event == 'CLICK':
|
||||
# 接下来就是根据你点击不同的菜单拉去不同的消息啦
|
||||
# 我为了省事,不进行判断啦,如果需要判断请根据 key进行判断
|
||||
return "你点击了菜单"+key
|
||||
# 如果是点击菜单跳转Url事件,不做任何处理因为微信客户端会自行处理
|
||||
elif event == 'VIEW':
|
||||
return None
|
||||
|
||||
|
||||
def getAccessToken():
|
||||
if Config().wechat['access_token_expires_at'] <= 0 or time.time() >= Config().wechat['access_token_expires_at']:
|
||||
APPID = Config().wechat['appid']
|
||||
SECRET = Config().wechat['secret']
|
||||
token_url = f'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={SECRET}'
|
||||
resResult = requests.get(token_url)
|
||||
data = resResult.json()
|
||||
if 'access_token' in data:
|
||||
access_token = data['access_token']
|
||||
Config().wechat['access_token'] = access_token
|
||||
Config().wechat['access_token_expires_at'] = time.time(
|
||||
)+data['expires_in']-60
|
||||
Config().save_config()
|
||||
return access_token
|
||||
else:
|
||||
logging.info(token_url)
|
||||
logging.error('获取access_token失败'+str(data))
|
||||
|
||||
else:
|
||||
return Config().wechat['access_token']
|
||||
|
||||
|
||||
def sendServiceImageMessge(media_id, touser): # 发送图片
|
||||
message = {
|
||||
"touser": touser,
|
||||
"msgtype": 'image',
|
||||
"image": {
|
||||
"media_id": media_id,
|
||||
}
|
||||
}
|
||||
return sendServiceMessage(message)
|
||||
|
||||
|
||||
def sendServiceVideoMessge(media_id, title, desc, touser): # 发送视频
|
||||
message = {
|
||||
"touser": touser,
|
||||
"msgtype": "video",
|
||||
"video": {
|
||||
"media_id": media_id,
|
||||
"title": title,
|
||||
"description": desc,
|
||||
}
|
||||
}
|
||||
return sendServiceMessage(message)
|
||||
|
||||
|
||||
# 发送菜单 menu_list = [{"id":"1","content":"菜单1"},{"id":"2","content":"菜单2"}]
|
||||
def sendServiceMenuMessage(head_content, tail_content, menu_list, touser):
|
||||
message = {
|
||||
"touser": touser,
|
||||
"msgtype": "msgmenu",
|
||||
"msgmenu": {
|
||||
"head_content": head_content,
|
||||
"list": menu_list,
|
||||
"tail_content": tail_content
|
||||
}
|
||||
}
|
||||
return sendServiceMessage(message)
|
||||
|
||||
|
||||
def sendServiceMessage(message):
|
||||
access_token = getAccessToken()
|
||||
url = f'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={access_token}'
|
||||
data = json.dumps(message, ensure_ascii=False).encode('utf-8')
|
||||
resResult = requests.post(url, data=data)
|
||||
data = resResult.json()
|
||||
if data['errcode'] == 0:
|
||||
return True
|
||||
else:
|
||||
logging.error('发送消息失败'+str(data))
|
||||
return False
|
||||
|
||||
|
||||
def sendServiceTyping(touser): # 下发正在输入状态
|
||||
accessToken = getAccessToken()
|
||||
url = f'https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token={accessToken}'
|
||||
message = {"touser": touser, "command": "Typing"}
|
||||
data = json.dumps(message, ensure_ascii=False).encode('utf-8')
|
||||
resResult = requests.post(url, data=data)
|
||||
data = resResult.json()
|
||||
if data['errcode'] == 0:
|
||||
return True
|
||||
else:
|
||||
logging.error('正在输入状态失败'+str(data))
|
||||
return False
|
||||
|
||||
|
||||
# 上传临时/永久素材
|
||||
# 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
|
||||
def getMediaId(image_path, type, isTemporary=True):
|
||||
access_token = getAccessToken()
|
||||
if(isTemporary):
|
||||
url = f"https://api.weixin.qq.com/cgi-bin/media/upload?access_token={access_token}&type={type}"
|
||||
else:
|
||||
url = f"https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={access_token}&type={type}"
|
||||
|
||||
files = {'media': open(image_path, 'rb')}
|
||||
resResult = requests.post(url, files=files)
|
||||
data = resResult.json()
|
||||
if 'media_id' in data:
|
||||
return data['media_id']
|
||||
else:
|
||||
logging.error('素材上传失败'+str(data))
|
||||
return None
|
||||
@@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import functools
|
||||
import yaml
|
||||
import folder_paths
|
||||
|
||||
def singleton(cls):
|
||||
"""
|
||||
将一个类作为单例
|
||||
来自 https://wiki.python.org/moin/PythonDecoratorLibrary#Singleton
|
||||
"""
|
||||
|
||||
cls.__new_original__ = cls.__new__
|
||||
|
||||
@functools.wraps(cls.__new__)
|
||||
def singleton_new(cls, *args, **kw):
|
||||
it = cls.__dict__.get('__it__')
|
||||
if it is not None:
|
||||
return it
|
||||
|
||||
cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
|
||||
it.__init_original__(*args, **kw)
|
||||
return it
|
||||
|
||||
cls.__new__ = singleton_new
|
||||
cls.__init_original__ = cls.__init__
|
||||
cls.__init__ = object.__init__
|
||||
|
||||
return cls
|
||||
|
||||
@singleton
|
||||
class Config(object):
|
||||
def __init__(self) -> None:
|
||||
basePath=folder_paths.folder_names_and_paths['custom_nodes'][0][0]
|
||||
self.pwd = os.path.join(basePath,'ComfyUI_Lam','config')
|
||||
self.reload()
|
||||
|
||||
def _load_config(self) -> dict:
|
||||
try:
|
||||
with open(f"{self.pwd}/weChat.yaml", "rb") as fp:
|
||||
yconfig = yaml.safe_load(fp)
|
||||
except FileNotFoundError:
|
||||
shutil.copyfile(f"{self.pwd}/weChat.yaml.template", f"{self.pwd}/weChat.yaml")
|
||||
with open(f"{self.pwd}/weChat.yaml", "rb") as fp:
|
||||
yconfig = yaml.safe_load(fp)
|
||||
|
||||
return yconfig
|
||||
|
||||
def save_config(self):
|
||||
yconfig = self._load_config()
|
||||
yconfig["wechat"] = self.wechat
|
||||
with open(f"{self.pwd}/weChat.yaml", 'w', encoding='utf-8') as file:
|
||||
yaml.dump(yconfig, file,sort_keys=False,default_flow_style=False,allow_unicode=True, encoding='utf-8')
|
||||
|
||||
def reload(self) -> None:
|
||||
yconfig = self._load_config()
|
||||
self.wechat = yconfig.get("wechat", {})
|
||||
#self.comfyui = yconfig.get("comfyui", {})
|
||||
#self.EMAIL= yconfig.get("email", {})
|
||||
#self.OPENAI= yconfig.get("openai", {})
|
||||
#self.GLM4= yconfig.get("glm4", {})
|
||||
#self.COMFY_UI=yconfig.get("comfyUI", {})
|
||||
|
||||
Reference in New Issue
Block a user