出图增加sd和Midjourney支持

This commit is contained in:
jingrow 2025-04-26 21:05:54 +08:00
parent 5bb439e2b3
commit f3105cd78b
27 changed files with 1629 additions and 894 deletions

View File

@ -7,7 +7,7 @@ context("Awesome Bar", () => {
beforeEach(() => {
cy.get(".navbar .navbar-home").click();
cy.findByPlaceholderText("Search or type a command (Ctrl + G)").as("awesome_bar");
cy.findByPlaceholderText("Search").as("awesome_bar");
cy.get("@awesome_bar").type("{selectall}");
});

View File

@ -4,7 +4,9 @@
"creation": "2025-04-24 13:00:44.207222",
"engine": "InnoDB",
"field_order": [
"api_tab",
"text_model_tab",
"temperature",
"top_p",
"deepseek_section",
"deepseek_api_url",
"deepseek_api_key",
@ -14,36 +16,43 @@
"chatgpt_api_url",
"chatgpt_api_key",
"chatgpt_api_model",
"参数_tab",
"temperature",
"top_p",
"高级_tab",
"upload_url",
"comfyui_tab",
"flux_section",
"flux_ckpt_name",
"flux_custom_suffix",
"flux_steps",
"flux_cfg",
"column_break_yaxp",
"sd_ckpt_name",
"sd_custom_suffix",
"sd_steps",
"sd_cfg",
"section_break_ukoc",
"server_address",
"ckpt_name",
"sampler_name",
"scheduler",
"denoise",
"column_break_tzse",
"images_per_prompt",
"image_width",
"image_height",
"custom_suffix",
"sampler_name",
"scheduler",
"steps",
"cfg",
"denoise",
"negative_prompt"
"negative_prompt",
"image_model_tab",
"discord_section",
"discord_channel_id",
"discord_user_token",
"midjourney_section",
"midjourney_api_url",
"midjourney_application_id",
"midjourney_data_id",
"midjourney_data_version",
"midjourney_session_id",
"midjourney_options",
"midjourney_suffix",
"others_tab",
"upload_url"
],
"fields": [
{
"fieldname": "参数_tab",
"fieldtype": "Tab Break",
"label": "模型参数"
},
{
"fieldname": "api_tab",
"fieldtype": "Tab Break",
"label": "API"
},
{
"fieldname": "deepseek_section",
"fieldtype": "Section Break",
@ -92,28 +101,23 @@
"fieldtype": "Data",
"label": "DeepSeek API Max Token"
},
{
"fieldname": "高级_tab",
"fieldtype": "Tab Break",
"label": "通用"
},
{
"fieldname": "upload_url",
"fieldtype": "Data",
"label": "图片中转服务器URL"
"label": "Upload URL"
},
{
"default": "0.8",
"fieldname": "temperature",
"fieldtype": "Float",
"label": "temperature",
"label": "Temperature",
"precision": "1"
},
{
"default": "0.9",
"fieldname": "top_p",
"fieldtype": "Float",
"label": "top_p",
"label": "Top_p",
"precision": "1"
},
{
@ -121,46 +125,34 @@
"fieldtype": "Tab Break",
"label": "ComfyUI"
},
{
"default": "fx",
"fieldname": "custom_suffix",
"fieldtype": "Data",
"label": "custom_suffix"
},
{
"fieldname": "server_address",
"fieldtype": "Data",
"label": "server_address"
"label": "Server Address"
},
{
"default": "4",
"fieldname": "images_per_prompt",
"fieldtype": "Int",
"label": "images_per_prompt"
"label": "Images Per Prompt"
},
{
"default": "1024",
"fieldname": "image_width",
"fieldtype": "Int",
"label": "image_width"
"label": "Image Width"
},
{
"default": "1024",
"fieldname": "image_height",
"fieldtype": "Int",
"label": "image_height"
},
{
"default": "flux1-schnell-fp8.safetensors",
"fieldname": "ckpt_name",
"fieldtype": "Data",
"label": "ckpt_name"
"label": "Image Height"
},
{
"default": "euler",
"fieldname": "sampler_name",
"fieldtype": "Data",
"label": "sampler_name"
"label": "Sampler Name"
},
{
"default": "normal",
@ -168,18 +160,6 @@
"fieldtype": "Data",
"label": "scheduler"
},
{
"default": "4",
"fieldname": "steps",
"fieldtype": "Int",
"label": "steps"
},
{
"default": "1",
"fieldname": "cfg",
"fieldtype": "Int",
"label": "cfg"
},
{
"default": "1",
"fieldname": "denoise",
@ -190,14 +170,149 @@
"default": "blur, low quality, low resolution, artifacts, text, watermark, logo, cropped, out of frame, overexposed, underexposed, bad anatomy, deformed body, extra limbs, missing limbs, extra fingers, missing fingers, poor lighting, noisy background, cluttered background, blurry background, pixelated, distorted, unnatural pose, double exposure, incorrect perspective, grainy, dark, bad proportions, out of focus, incorrect clothing fit, unrealistic shadows, weird colors, cartoonish, low detail, jpeg artifacts, unnatural lighting",
"fieldname": "negative_prompt",
"fieldtype": "Small Text",
"label": "negative_prompt"
"label": "Negative Prompt"
},
{
"fieldname": "image_model_tab",
"fieldtype": "Tab Break",
"label": "Image Model"
},
{
"fieldname": "midjourney_api_url",
"fieldtype": "Data",
"label": "Midjourney API URL"
},
{
"fieldname": "midjourney_application_id",
"fieldtype": "Data",
"label": "Midjourney APPLICATION ID"
},
{
"fieldname": "midjourney_data_id",
"fieldtype": "Data",
"label": "Midjourney DATA ID"
},
{
"fieldname": "midjourney_data_version",
"fieldtype": "Data",
"label": "Midjourney DATA VERSION"
},
{
"fieldname": "midjourney_session_id",
"fieldtype": "Data",
"label": "Midjourney SESSION ID"
},
{
"fieldname": "midjourney_section",
"fieldtype": "Section Break",
"label": "Midjourney"
},
{
"fieldname": "text_model_tab",
"fieldtype": "Tab Break",
"label": "Text Model"
},
{
"fieldname": "others_tab",
"fieldtype": "Tab Break",
"label": "Others"
},
{
"fieldname": "discord_channel_id",
"fieldtype": "Data",
"label": "Discord Channel ID"
},
{
"fieldname": "discord_user_token",
"fieldtype": "Data",
"label": "Discord User Token"
},
{
"fieldname": "midjourney_suffix",
"fieldtype": "Data",
"label": "Midjourney Suffix"
},
{
"fieldname": "discord_section",
"fieldtype": "Section Break",
"label": "Discord"
},
{
"fieldname": "midjourney_options",
"fieldtype": "JSON",
"label": "Midjourney Options"
},
{
"default": "flux1-schnell-fp8.safetensors",
"fieldname": "flux_ckpt_name",
"fieldtype": "Data",
"label": "Flux Ckpt Name"
},
{
"fieldname": "flux_section",
"fieldtype": "Section Break",
"label": "Flux"
},
{
"fieldname": "column_break_yaxp",
"fieldtype": "Column Break"
},
{
"default": "flux1-schnell-fp8.safetensors",
"fieldname": "sd_ckpt_name",
"fieldtype": "Data",
"label": "SD Ckpt Name"
},
{
"fieldname": "section_break_ukoc",
"fieldtype": "Section Break"
},
{
"default": "fx",
"fieldname": "flux_custom_suffix",
"fieldtype": "Data",
"label": "Flux Custom Suffix"
},
{
"default": "4",
"fieldname": "flux_steps",
"fieldtype": "Int",
"label": "Flux steps"
},
{
"default": "1",
"fieldname": "flux_cfg",
"fieldtype": "Int",
"label": "Flux CFG"
},
{
"default": "fx",
"fieldname": "sd_custom_suffix",
"fieldtype": "Data",
"label": "SD Custom Suffix"
},
{
"default": "4",
"fieldname": "sd_steps",
"fieldtype": "Int",
"label": "SD steps"
},
{
"default": "1",
"fieldname": "sd_cfg",
"fieldtype": "Int",
"label": "SD CFG"
},
{
"fieldname": "column_break_tzse",
"fieldtype": "Column Break"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-04-26 01:49:21.862323",
"modified": "2025-04-26 19:42:34.713017",
"modified_by": "Administrator",
"module": "AI",
"name": "AI Settings",

View File

@ -14,25 +14,38 @@ class AISettings(Document):
if TYPE_CHECKING:
from jingrow.types import DF
cfg: DF.Int
chatgpt_api_key: DF.Data | None
chatgpt_api_model: DF.Literal["gpt-4o", "gpt-4o-mini"]
chatgpt_api_url: DF.Data | None
ckpt_name: DF.Data | None
custom_suffix: DF.Data | None
deepseek_api_key: DF.Data | None
deepseek_api_max_token: DF.Data | None
deepseek_api_model: DF.Literal["deepseek-chat", "deepseek-reasoner"]
deepseek_api_url: DF.Data | None
denoise: DF.Int
discord_channel_id: DF.Data | None
discord_user_token: DF.Data | None
flux_cfg: DF.Int
flux_ckpt_name: DF.Data | None
flux_custom_suffix: DF.Data | None
flux_steps: DF.Int
image_height: DF.Int
image_width: DF.Int
images_per_prompt: DF.Int
midjourney_api_url: DF.Data | None
midjourney_application_id: DF.Data | None
midjourney_data_id: DF.Data | None
midjourney_data_version: DF.Data | None
midjourney_options: DF.JSON | None
midjourney_session_id: DF.Data | None
midjourney_suffix: DF.Data | None
negative_prompt: DF.SmallText | None
sampler_name: DF.Data | None
scheduler: DF.Data | None
sd_cfg: DF.Int
sd_ckpt_name: DF.Data | None
sd_custom_suffix: DF.Data | None
sd_steps: DF.Int
server_address: DF.Data | None
steps: DF.Int
temperature: DF.Float
top_p: DF.Float
upload_url: DF.Data | None

View File

@ -1,7 +1,7 @@
// Copyright (c) 2025, JINGROW and contributors
// For license information, please see license.txt
// jingrow.ui.form.on("Clothing Model", {
// jingrow.ui.form.on("Fashion Model", {
// refresh(frm) {
// },

View File

@ -4,7 +4,7 @@
"creation": "2024-08-16 01:19:56.495807",
"engine": "InnoDB",
"field_order": [
"绘画_tab",
"\u7ed8\u753b_tab",
"progress",
"section_break_tfxh",
"serial_number",
@ -20,7 +20,7 @@
"reference_image_2",
"reference_image_3",
"reference_image_4",
"详细信息_tab",
"\u8be6\u7ec6\u4fe1\u606f_tab",
"full_name",
"gender",
"age",
@ -45,14 +45,14 @@
],
"fields": [
{
"fieldname": "绘画_tab",
"fieldname": "\u7ed8\u753b_tab",
"fieldtype": "Tab Break",
"label": "绘画"
"label": "\u7ed8\u753b"
},
{
"fieldname": "progress",
"fieldtype": "Data",
"label": "进度",
"label": "\u8fdb\u5ea6",
"precision": "0"
},
{
@ -62,12 +62,12 @@
{
"fieldname": "serial_number",
"fieldtype": "Data",
"label": "编号"
"label": "\u7f16\u53f7"
},
{
"fieldname": "title",
"fieldtype": "Data",
"label": "主题"
"label": "\u4e3b\u9898"
},
{
"fieldname": "prompts",
@ -77,13 +77,13 @@
{
"fieldname": "image_weight",
"fieldtype": "Float",
"label": "参考图片权重",
"label": "\u53c2\u8003\u56fe\u7247\u6743\u91cd",
"precision": "2"
},
{
"fieldname": "image_directory",
"fieldtype": "Data",
"label": "图片保存目录"
"label": "\u56fe\u7247\u4fdd\u5b58\u76ee\u5f55"
},
{
"fieldname": "column_break_jwvz",
@ -92,94 +92,94 @@
{
"fieldname": "status",
"fieldtype": "Select",
"label": "状态",
"options": "待确认\n待描述\n待翻译\n待出图\n待去背景\n待放大图片\n待转换为矢量图\n待添加背景颜色\n任务进行中\n任务未完成\n已确认\n已描述\n已翻译\n已出图\n已去背景\n已放大图片\n已转换为矢量图\n已添加背景颜色\n已存档"
"label": "\u72b6\u6001",
"options": "\u5f85\u786e\u8ba4\n\u5f85\u63cf\u8ff0\n\u5f85\u7ffb\u8bd1\n\u5f85\u51fa\u56fe\n\u5f85\u53bb\u80cc\u666f\n\u5f85\u653e\u5927\u56fe\u7247\n\u5f85\u8f6c\u6362\u4e3a\u77e2\u91cf\u56fe\n\u5f85\u6dfb\u52a0\u80cc\u666f\u989c\u8272\n\u4efb\u52a1\u8fdb\u884c\u4e2d\n\u4efb\u52a1\u672a\u5b8c\u6210\n\u5df2\u786e\u8ba4\n\u5df2\u63cf\u8ff0\n\u5df2\u7ffb\u8bd1\n\u5df2\u51fa\u56fe\n\u5df2\u53bb\u80cc\u666f\n\u5df2\u653e\u5927\u56fe\u7247\n\u5df2\u8f6c\u6362\u4e3a\u77e2\u91cf\u56fe\n\u5df2\u6dfb\u52a0\u80cc\u666f\u989c\u8272\n\u5df2\u5b58\u6863"
},
{
"fieldname": "image_model",
"fieldtype": "Select",
"label": "绘画工具",
"label": "\u7ed8\u753b\u5de5\u5177",
"options": "Flux\nStable Diffusion\nMidjourney"
},
{
"fieldname": "prompts_zh",
"fieldtype": "Text",
"label": "中文提示词"
"label": "\u4e2d\u6587\u63d0\u793a\u8bcd"
},
{
"fieldname": "reference_image_1",
"fieldtype": "Attach Image",
"label": "参考图片1"
"label": "\u53c2\u8003\u56fe\u72471"
},
{
"fieldname": "reference_image_2",
"fieldtype": "Attach Image",
"label": "参考图片2"
"label": "\u53c2\u8003\u56fe\u72472"
},
{
"fieldname": "reference_image_3",
"fieldtype": "Attach Image",
"label": "参考图片3"
"label": "\u53c2\u8003\u56fe\u72473"
},
{
"fieldname": "reference_image_4",
"fieldtype": "Attach Image",
"label": "参考图片4"
"label": "\u53c2\u8003\u56fe\u72474"
},
{
"fieldname": "详细信息_tab",
"fieldname": "\u8be6\u7ec6\u4fe1\u606f_tab",
"fieldtype": "Tab Break",
"label": "详细信息"
"label": "\u8be6\u7ec6\u4fe1\u606f"
},
{
"fieldname": "full_name",
"fieldtype": "Data",
"label": "姓名"
"label": "\u59d3\u540d"
},
{
"fieldname": "gender",
"fieldtype": "Data",
"label": "性别"
"label": "\u6027\u522b"
},
{
"fieldname": "age",
"fieldtype": "Data",
"label": "年龄"
"label": "\u5e74\u9f84"
},
{
"fieldname": "height",
"fieldtype": "Data",
"label": "身高"
"label": "\u8eab\u9ad8"
},
{
"fieldname": "body_shape",
"fieldtype": "Data",
"label": "体型"
"label": "\u4f53\u578b"
},
{
"fieldname": "nationality",
"fieldtype": "Data",
"label": "国籍"
"label": "\u56fd\u7c4d"
},
{
"fieldname": "race",
"fieldtype": "Data",
"label": "人种"
"label": "\u4eba\u79cd"
},
{
"fieldname": "skin_color",
"fieldtype": "Data",
"label": "肤色"
"label": "\u80a4\u8272"
},
{
"fieldname": "posture",
"fieldtype": "Data",
"label": "姿势"
"label": "\u59ff\u52bf"
},
{
"fieldname": "action",
"fieldtype": "Data",
"label": "动作"
"label": "\u52a8\u4f5c"
},
{
"fieldname": "column_break_ujli",
@ -188,52 +188,52 @@
{
"fieldname": "face_features",
"fieldtype": "Data",
"label": "面部特征"
"label": "\u9762\u90e8\u7279\u5f81"
},
{
"fieldname": "hair_style",
"fieldtype": "Data",
"label": "发型和发色"
"label": "\u53d1\u578b\u548c\u53d1\u8272"
},
{
"fieldname": "clothing_type",
"fieldtype": "Data",
"label": "服装类型"
"label": "\u670d\u88c5\u7c7b\u578b"
},
{
"fieldname": "clothing_color_and_pattern",
"fieldtype": "Data",
"label": "服装颜色和图案"
"label": "\u670d\u88c5\u989c\u8272\u548c\u56fe\u6848"
},
{
"fieldname": "clothing_style",
"fieldtype": "Data",
"label": "服装风格"
"label": "\u670d\u88c5\u98ce\u683c"
},
{
"fieldname": "environment",
"fieldtype": "Data",
"label": "环境设置"
"label": "\u73af\u5883\u8bbe\u7f6e"
},
{
"fieldname": "background_elements",
"fieldtype": "Data",
"label": "背景元素"
"label": "\u80cc\u666f\u5143\u7d20"
},
{
"fieldname": "lighting_conditions",
"fieldtype": "Data",
"label": "光照条件"
"label": "\u5149\u7167\u6761\u4ef6"
},
{
"fieldname": "tone_and_atmosphere",
"fieldtype": "Data",
"label": "色调和氛围"
"label": "\u8272\u8c03\u548c\u6c1b\u56f4"
},
{
"fieldname": "angle",
"fieldtype": "Data",
"label": "角度"
"label": "\u89d2\u5ea6"
}
],
"index_web_pages_for_search": 1,
@ -242,7 +242,7 @@
"modified": "2025-04-25 01:00:05.665533",
"modified_by": "Administrator",
"module": "AI",
"name": "Clothing Model",
"name": "Fashion Model",
"owner": "Administrator",
"pagetype": "PageType",
"permissions": [

View File

@ -5,5 +5,5 @@
from jingrow.model.document import Document
class ClothingModel(Document):
class FashionModel(Document):
pass

View File

@ -5,5 +5,5 @@
from jingrow.tests.utils import JingrowTestCase
class TestClothingModel(JingrowTestCase):
class TestFashionModel(JingrowTestCase):
pass

View File

@ -2,6 +2,7 @@
"actions": [],
"allow_rename": 1,
"creation": "2024-08-16 00:11:57.517570",
"description": "图案花型设计",
"engine": "InnoDB",
"field_order": [
"绘画_tab",
@ -118,7 +119,6 @@
"options": "待确认\n已确认\n待描述\n已描述\n待翻译\n已翻译\n待出图\n已出图\n待定稿\n已定稿\n待去背景\n已去背景\n待合成\n已合成\n待试穿\n已试穿\n待放大图片\n已放大图片\n已存档\n任务进行中\n任务未完成"
},
{
"default": "Stable Diffusion",
"fieldname": "image_model",
"fieldtype": "Select",
"label": "绘画工具",
@ -391,7 +391,7 @@
"index_web_pages_for_search": 1,
"links": [],
"make_attachments_public": 1,
"modified": "2025-04-25 00:59:42.668355",
"modified": "2025-04-26 11:26:45.083802",
"modified_by": "Administrator",
"module": "AI",
"name": "Pattern Design",

View File

@ -6,4 +6,62 @@ from jingrow.model.document import Document
class PatternDesign(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from jingrow.types import DF
aesthetic_principles: DF.SmallText | None
background_color: DF.Data | None
category: DF.Data | None
color_palette: DF.SmallText | None
color_theory: DF.Data | None
creativity: DF.SmallText | None
design_direction: DF.SmallText | None
design_language: DF.SmallText | None
elements: DF.Data | None
enable_gradient_effect: DF.Literal["True", "False"]
gradient_blur_intensity: DF.Int
gradient_max_alpha: DF.Int
gradient_repeat_count: DF.Int
gradient_type: DF.Literal["linear", "radial"]
guiding_principle: DF.SmallText | None
image_directory: DF.Data | None
image_model: DF.Literal["Flux", "Stable Diffusion", "Midjourney"]
image_weight: DF.Float
intention: DF.SmallText | None
market_demand: DF.SmallText | None
mood: DF.SmallText | None
progress: DF.Data | None
prompts: DF.Text | None
prompts_zh: DF.Text | None
ptt_design_offset: DF.Data | None
ptt_design_rotation: DF.Int
ptt_design_size_ratio: DF.Float
ptt_enable_color_matching: DF.Literal["True", "False"]
ptt_enable_lighting_effect: DF.Literal["True", "False"]
ptt_enable_monochrome: DF.Literal["True", "False"]
ptt_light_angle: DF.Int
ptt_light_blur: DF.Int
ptt_light_intensity: DF.Float
ptt_light_position: DF.Data | None
ptt_light_shape: DF.Literal["ellipse", "circle", "rect"]
rating: DF.Data | None
rating_reason: DF.SmallText | None
reference_image_1: DF.AttachImage | None
reference_image_2: DF.AttachImage | None
reference_image_3: DF.AttachImage | None
reference_image_4: DF.AttachImage | None
references_and_inspiration: DF.SmallText | None
serial_number: DF.Data | None
status: DF.Literal["\u5f85\u786e\u8ba4", "\u5df2\u786e\u8ba4", "\u5f85\u63cf\u8ff0", "\u5df2\u63cf\u8ff0", "\u5f85\u7ffb\u8bd1", "\u5df2\u7ffb\u8bd1", "\u5f85\u51fa\u56fe", "\u5df2\u51fa\u56fe", "\u5f85\u5b9a\u7a3f", "\u5df2\u5b9a\u7a3f", "\u5f85\u53bb\u80cc\u666f", "\u5df2\u53bb\u80cc\u666f", "\u5f85\u5408\u6210", "\u5df2\u5408\u6210", "\u5f85\u8bd5\u7a7f", "\u5df2\u8bd5\u7a7f", "\u5f85\u653e\u5927\u56fe\u7247", "\u5df2\u653e\u5927\u56fe\u7247", "\u5df2\u5b58\u6863", "\u4efb\u52a1\u8fdb\u884c\u4e2d", "\u4efb\u52a1\u672a\u5b8c\u6210"]
style: DF.Data | None
target_customers: DF.SmallText | None
title: DF.Data | None
tryon_models_dir: DF.Data | None
tshirt_image_path: DF.Data | None
# end: auto-generated types
pass

View File

@ -64,5 +64,24 @@ class ProductDesign(Document):
pg_name=self.name,
pagetype=self.pagetype
)
# 处理Midjourney绘图请求
elif self.status == "待出图" and self.image_model == "Midjourney":
# 调用jingrow_midjourney模块中的处理函数
jingrow.enqueue(
"jingrow.utils.midjourney.process_midjourney_task",
pg_name=self.name,
pagetype=self.pagetype
)
# 处理Stable Diffusion绘图请求
elif self.status == "待出图" and self.image_model == "Stable Diffusion":
# 调用jingrow_midjourney模块中的处理函数
jingrow.enqueue(
"jingrow.utils.comfyui_sd.process_comfyui_sd_task",
pg_name=self.name,
pagetype=self.pagetype
)

View File

@ -1,6 +1,6 @@
{
"charts": [],
"content": "[{\"id\":\"YpGCeLfign\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>快捷方式</b></span>\",\"col\":12}},{\"id\":\"b7abeqw4NZ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"AI 智能体\",\"col\":3}},{\"id\":\"oFB4l28FMU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"EpBz2lplSt\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"AI 设置\",\"col\":3}}]",
"content": "[{\"id\":\"b7abeqw4NZ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"AI 智能体\",\"col\":3}},{\"id\":\"oFB4l28FMU\",\"type\":\"spacer\",\"data\":{\"col\":12}}]",
"creation": "2025-04-26 01:14:38.813348",
"custom_blocks": [],
"for_user": "",
@ -90,7 +90,7 @@
"type": "Link"
}
],
"modified": "2025-04-26 01:25:13.670972",
"modified": "2025-04-26 14:46:50.427171",
"modified_by": "Administrator",
"module": "AI",
"name": "AI",
@ -111,12 +111,6 @@
"pg_view": "List",
"stats_filter": "[]",
"type": "PageType"
},
{
"label": "AI 设置",
"link_to": "AI Settings",
"pg_view": "",
"type": "PageType"
}
],
"title": "AI"

View File

@ -0,0 +1,125 @@
{
"charts": [],
"content": "[{\"id\":\"b7abeqw4NZ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"产品设计\",\"col\":3}},{\"id\":\"WUcF6JXLgA\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"图案花型设计\",\"col\":3}},{\"id\":\"oFB4l28FMU\",\"type\":\"spacer\",\"data\":{\"col\":12}}]",
"creation": "2025-04-26 01:36:47.799178",
"custom_blocks": [],
"for_user": "",
"hide_custom": 0,
"icon": "edit",
"idx": 0,
"indicator_color": "green",
"is_hidden": 0,
"label": "Design",
"links": [
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Activity Log",
"link_count": 0,
"link_to": "Activity Log",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Access Log",
"link_count": 0,
"link_to": "Access Log",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Role Permissions Manager",
"link_count": 0,
"link_to": "permission-manager",
"link_type": "Page",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "User Permissions",
"link_count": 0,
"link_to": "User Permission",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Role Permission for Page and Report",
"link_count": 0,
"link_to": "Role Permission for Page and Report",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "User",
"hidden": 0,
"is_query_report": 1,
"label": "Permitted Documents For User",
"link_count": 0,
"link_to": "Permitted Documents For User",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "PageShare",
"hidden": 0,
"is_query_report": 0,
"label": "Document Share Report",
"link_count": 0,
"link_to": "Document Share Report",
"link_type": "Report",
"onboard": 0,
"report_ref_pagetype": "PageShare",
"type": "Link"
}
],
"modified": "2025-04-26 14:40:31.942559",
"modified_by": "Administrator",
"module": "AI",
"name": "Design",
"number_cards": [],
"owner": "Administrator",
"pagestatus": 0,
"pagetype": "Workspace",
"parent_page": "",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 1.1,
"shortcuts": [
{
"label": "产品设计",
"link_to": "Product Design",
"pg_view": "List",
"stats_filter": "[]",
"type": "PageType"
},
{
"color": "Grey",
"label": "图案花型设计",
"link_to": "Pattern Design",
"pg_view": "List",
"stats_filter": "[]",
"type": "PageType"
}
],
"title": "Design"
}

View File

@ -4,7 +4,6 @@
"autoname": "Prompt",
"creation": "2019-02-28 17:12:18.815830",
"description": "Automatically Assign Documents to Users",
"pagetype": "PageType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
@ -54,7 +53,7 @@
"fieldtype": "Column Break"
},
{
"default": "Automatic Assignment",
"default": "自动分配",
"description": "Example: {{ subject }}",
"fieldname": "description",
"fieldtype": "Small Text",
@ -154,11 +153,12 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-07-16 22:51:35.505575",
"modified": "2025-04-26 12:37:40.250605",
"modified_by": "Administrator",
"module": "Automation",
"name": "Assignment Rule",
"owner": "Administrator",
"pagetype": "PageType",
"permissions": [
{
"create": 1,
@ -173,7 +173,9 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@ -20,9 +20,7 @@ class AssignmentRule(Document):
if TYPE_CHECKING:
from jingrow.automation.pagetype.assignment_rule_day.assignment_rule_day import AssignmentRuleDay
from jingrow.automation.pagetype.assignment_rule_user.assignment_rule_user import (
AssignmentRuleUser,
)
from jingrow.automation.pagetype.assignment_rule_user.assignment_rule_user import AssignmentRuleUser
from jingrow.types import DF
assign_condition: DF.Code
@ -38,7 +36,6 @@ class AssignmentRule(Document):
rule: DF.Literal["Round Robin", "Load Balancing", "Based on Field"]
unassign_condition: DF.Code | None
users: DF.TableMultiSelect[AssignmentRuleUser]
# end: auto-generated types
def validate(self):
self.validate_document_types()

View File

@ -1,6 +1,6 @@
{
"charts": [],
"content": "[{\"id\":\"-P-RG1wVHg\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"sR-UFcO7II\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Import Data\",\"col\":3}},{\"id\":\"IkcVmgWb3z\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"ToDo\",\"col\":3}},{\"id\":\"6wir-jZFRE\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"File\",\"col\":3}},{\"id\":\"45a1jzQkTm\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Assignment Rule\",\"col\":3}},{\"id\":\"LdZrgvxxo7\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"yNSSTIaDWZ\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Documents</b></span>\",\"col\":12}},{\"id\":\"0yceBIfhHM\",\"type\":\"card\",\"data\":{\"card_name\":\"Data\",\"col\":4}},{\"id\":\"42WbBA9rpj\",\"type\":\"card\",\"data\":{\"card_name\":\"Tools\",\"col\":4}},{\"id\":\"wE9n7TIrAc\",\"type\":\"card\",\"data\":{\"card_name\":\"Alerts and Notifications\",\"col\":4}},{\"id\":\"7_U7_xCOos\",\"type\":\"card\",\"data\":{\"card_name\":\"Email\",\"col\":4}},{\"id\":\"3imoh2oqsJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Printing\",\"col\":4}},{\"id\":\"SlYKJZj5r3\",\"type\":\"card\",\"data\":{\"card_name\":\"Automation\",\"col\":4}},{\"id\":\"O7jrc2YQTN\",\"type\":\"card\",\"data\":{\"card_name\":\"Newsletter\",\"col\":4}}]",
"content": "[{\"id\":\"42WbBA9rpj\",\"type\":\"card\",\"data\":{\"card_name\":\"工作\",\"col\":4}},{\"id\":\"0yceBIfhHM\",\"type\":\"card\",\"data\":{\"card_name\":\"Data\",\"col\":4}},{\"id\":\"wE9n7TIrAc\",\"type\":\"card\",\"data\":{\"card_name\":\"Alerts and Notifications\",\"col\":4}},{\"id\":\"7_U7_xCOos\",\"type\":\"card\",\"data\":{\"card_name\":\"Email\",\"col\":4}},{\"id\":\"SlYKJZj5r3\",\"type\":\"card\",\"data\":{\"card_name\":\"Automation\",\"col\":4}},{\"id\":\"O7jrc2YQTN\",\"type\":\"card\",\"data\":{\"card_name\":\"Newsletter\",\"col\":4}}]",
"creation": "2020-03-02 14:53:24.980279",
"custom_blocks": [],
"for_user": "",
@ -51,58 +51,6 @@
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Tools",
"link_count": 4,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "To Do",
"link_count": 0,
"link_to": "ToDo",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Calendar",
"link_count": 0,
"link_to": "Event",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Note",
"link_count": 0,
"link_to": "Note",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Files",
"link_count": 0,
"link_to": "File",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@ -229,55 +177,6 @@
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Printing",
"link_count": 4,
"link_type": "PageType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Print Format Builder",
"link_count": 0,
"link_to": "print-format-builder",
"link_type": "Page",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Print Format Builder (New)",
"link_count": 0,
"link_to": "print-format-builder-beta",
"link_type": "Page",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Print Settings",
"link_count": 0,
"link_to": "Print Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Print Heading",
"link_count": 0,
"link_to": "Print Heading",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@ -316,9 +215,62 @@
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "工作",
"link_count": 4,
"link_type": "PageType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "待办事项",
"link_count": 0,
"link_to": "ToDo",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "日历",
"link_count": 0,
"link_to": "Event",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "备注",
"link_count": 0,
"link_to": "Note",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "文件",
"link_count": 0,
"link_to": "File",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
}
],
"modified": "2025-04-26 01:25:13.810308",
"modified": "2025-04-26 14:48:22.232530",
"modified_by": "Administrator",
"module": "Automation",
"name": "Tools",
@ -332,29 +284,6 @@
"restrict_to_domain": "",
"roles": [],
"sequence_id": 4.0,
"shortcuts": [
{
"color": "Grey",
"label": "Import Data",
"link_to": "Data Import",
"pg_view": "List",
"type": "PageType"
},
{
"label": "ToDo",
"link_to": "ToDo",
"type": "PageType"
},
{
"label": "File",
"link_to": "File",
"type": "PageType"
},
{
"label": "Assignment Rule",
"link_to": "Assignment Rule",
"type": "PageType"
}
],
"shortcuts": [],
"title": "Tools"
}

View File

@ -1,6 +1,6 @@
{
"charts": [],
"content": "[{\"id\":\"5nnLaQeoFa\",\"type\":\"header\",\"data\":{\"text\":\"<span style=\\\"font-size: 18px; letter-spacing: 0.18px;\\\"><b>开始</b><br></span>\",\"col\":12}},{\"id\":\"HXRmktXYHy\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"PageType\",\"col\":3}},{\"id\":\"pYALX3MwBW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customize Form\",\"col\":3}},{\"id\":\"XC78DuYB65\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Report\",\"col\":3}},{\"id\":\"XPm50Ppq3J\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Client Script\",\"col\":3}},{\"id\":\"yoU6nWiT83\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Server Script\",\"col\":3}},{\"id\":\"5UgFESBY0N\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Print Format Builder\",\"col\":3}},{\"id\":\"F--MAje9SF\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"AI 设置\",\"col\":3}},{\"id\":\"0gE0s-S70E\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"System Settings\",\"col\":3}},{\"id\":\"62hseENHbd\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tOCrOgLW1G\",\"type\":\"header\",\"data\":{\"text\":\"<span style=\\\"font-size: 18px; letter-spacing: 0.18px;\\\"><b>构建应用程序的组件</b></span>\",\"col\":12}},{\"id\":\"cJ6CVsa8qW\",\"type\":\"card\",\"data\":{\"card_name\":\"Models\",\"col\":4}},{\"id\":\"MmEJpjEdGR\",\"type\":\"card\",\"data\":{\"card_name\":\"Views\",\"col\":4}},{\"id\":\"2ZdtgxQZqq\",\"type\":\"card\",\"data\":{\"card_name\":\"Customization\",\"col\":4}},{\"id\":\"NPFolijIcb\",\"type\":\"card\",\"data\":{\"card_name\":\"Scripting\",\"col\":4}},{\"id\":\"BIHjudL0T_\",\"type\":\"card\",\"data\":{\"card_name\":\"Modules\",\"col\":4}},{\"id\":\"iK3JQ9RXJE\",\"type\":\"card\",\"data\":{\"card_name\":\"Packages\",\"col\":4}},{\"id\":\"TiO9FCUUeC\",\"type\":\"card\",\"data\":{\"card_name\":\"System Logs\",\"col\":4}}]",
"content": "[{\"id\":\"5nnLaQeoFa\",\"type\":\"header\",\"data\":{\"text\":\"常用\",\"col\":12}},{\"id\":\"F--MAje9SF\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"AI 设置\",\"col\":3}},{\"id\":\"0gE0s-S70E\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"System Settings\",\"col\":3}},{\"id\":\"62hseENHbd\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tOCrOgLW1G\",\"type\":\"header\",\"data\":{\"text\":\"<span style=\\\"font-size: 18px; letter-spacing: 0.18px;\\\"><b>构建</b></span>\",\"col\":12}},{\"id\":\"cJ6CVsa8qW\",\"type\":\"card\",\"data\":{\"card_name\":\"Models\",\"col\":4}},{\"id\":\"NPFolijIcb\",\"type\":\"card\",\"data\":{\"card_name\":\"Scripting\",\"col\":4}},{\"id\":\"MmEJpjEdGR\",\"type\":\"card\",\"data\":{\"card_name\":\"Views\",\"col\":4}},{\"id\":\"BIHjudL0T_\",\"type\":\"card\",\"data\":{\"card_name\":\"Modules\",\"col\":4}},{\"id\":\"2ZdtgxQZqq\",\"type\":\"card\",\"data\":{\"card_name\":\"Customization\",\"col\":4}},{\"id\":\"DYWwT3SZys\",\"type\":\"card\",\"data\":{\"card_name\":\"打印\",\"col\":4}},{\"id\":\"TiO9FCUUeC\",\"type\":\"card\",\"data\":{\"card_name\":\"System Logs\",\"col\":4}},{\"id\":\"-acgT-U5PM\",\"type\":\"card\",\"data\":{\"card_name\":\"集成\",\"col\":4}},{\"id\":\"iK3JQ9RXJE\",\"type\":\"card\",\"data\":{\"card_name\":\"Packages\",\"col\":4}}]",
"creation": "2021-01-02 10:51:16.579957",
"custom_blocks": [],
"for_user": "",
@ -320,9 +320,87 @@
"onboard": 0,
"only_for": "",
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "集成",
"link_count": 1,
"link_type": "PageType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Webhook",
"link_count": 0,
"link_to": "Webhook",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "打印",
"link_count": 5,
"link_type": "PageType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "打印设置",
"link_count": 0,
"link_to": "Print Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "打印标题",
"link_count": 0,
"link_to": "Print Heading",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "打印格式",
"link_count": 0,
"link_to": "Print Format",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "打印样式",
"link_count": 0,
"link_to": "Print Style",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "打印机设置",
"link_count": 0,
"link_to": "Network Printer Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
}
],
"modified": "2025-04-26 01:29:24.317047",
"modified": "2025-04-26 14:45:55.533597",
"modified_by": "Administrator",
"module": "Core",
"name": "System",
@ -344,13 +422,6 @@
"pg_view": "List",
"type": "PageType"
},
{
"color": "Grey",
"label": "Print Format Builder",
"link_to": "print-format-builder",
"pg_view": "List",
"type": "Page"
},
{
"color": "Grey",
"label": "System Settings",
@ -358,38 +429,6 @@
"pg_view": "List",
"type": "PageType",
"url": "https://jingrow.school/courses/jingrow-framework-course?utm_source=in_app"
},
{
"color": "Grey",
"label": "Client Script",
"link_to": "Client Script",
"pg_view": "List",
"type": "PageType"
},
{
"label": "PageType",
"link_to": "PageType",
"pg_view": "",
"type": "PageType"
},
{
"label": "Customize Form",
"link_to": "Customize Form",
"pg_view": "",
"type": "PageType"
},
{
"color": "Grey",
"label": "Server Script",
"link_to": "Server Script",
"pg_view": "List",
"type": "PageType"
},
{
"label": "Report",
"link_to": "Report",
"pg_view": "",
"type": "PageType"
}
],
"title": "System"

View File

@ -1,6 +1,6 @@
{
"charts": [],
"content": "[{\"id\":\"YpGCeLfign\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>快捷方式</b></span>\",\"col\":12}},{\"id\":\"b7abeqw4NZ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"User\",\"col\":3}},{\"id\":\"eghSJPhZRC\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Role\",\"col\":3}},{\"id\":\"uAzl_lT_C0\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Permission Manager\",\"col\":3}},{\"id\":\"EpBz2lplSt\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"User Profile\",\"col\":3}},{\"id\":\"vHWhzaFoAH\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"User Type\",\"col\":3}},{\"id\":\"oFB4l28FMU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"yJNNylguxk\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>报告 &amp; 权限管理</b></span>\",\"col\":12}},{\"id\":\"NMpIkExl3i\",\"type\":\"card\",\"data\":{\"card_name\":\"Users\",\"col\":4}},{\"id\":\"VepG3durKm\",\"type\":\"card\",\"data\":{\"card_name\":\"Logs\",\"col\":4}},{\"id\":\"S9FeWt7xXE\",\"type\":\"card\",\"data\":{\"card_name\":\"Permissions\",\"col\":4}}]",
"content": "[{\"id\":\"NMpIkExl3i\",\"type\":\"card\",\"data\":{\"card_name\":\"Users\",\"col\":4}},{\"id\":\"VepG3durKm\",\"type\":\"card\",\"data\":{\"card_name\":\"Logs\",\"col\":4}},{\"id\":\"S9FeWt7xXE\",\"type\":\"card\",\"data\":{\"card_name\":\"Permissions\",\"col\":4}}]",
"creation": "2020-03-02 15:12:16.754449",
"custom_blocks": [],
"for_user": "",
@ -157,7 +157,7 @@
"type": "Link"
}
],
"modified": "2025-04-26 01:25:13.763462",
"modified": "2025-04-26 14:45:14.453373",
"modified_by": "Administrator",
"module": "Core",
"name": "Users",
@ -171,33 +171,6 @@
"restrict_to_domain": "",
"roles": [],
"sequence_id": 3.0,
"shortcuts": [
{
"label": "User",
"link_to": "User",
"type": "PageType"
},
{
"label": "Role",
"link_to": "Role",
"type": "PageType"
},
{
"label": "Permission Manager",
"link_to": "permission-manager",
"type": "Page"
},
{
"label": "User Profile",
"link_to": "user-profile",
"type": "Page"
},
{
"label": "User Type",
"link_to": "User Type",
"pg_view": "",
"type": "PageType"
}
],
"shortcuts": [],
"title": "Users"
}

View File

@ -460,42 +460,18 @@ get_changelog_feed = "jingrow.desk.pagetype.changelog_feed.changelog_feed.get_fe
export_python_type_annotations = True
standard_navbar_items = [
{
"item_label": "My Profile",
"item_type": "Route",
"route": "/app/user-profile",
"is_standard": 1,
},
{
"item_label": "My Settings",
"item_type": "Action",
"action": "jingrow.ui.toolbar.route_to_user()",
"is_standard": 1,
},
{
"item_label": "Session Defaults",
"item_type": "Action",
"action": "jingrow.ui.toolbar.setup_session_defaults()",
"is_standard": 1,
},
{
"item_label": "Reload",
"item_type": "Action",
"action": "jingrow.ui.toolbar.clear_cache()",
"is_standard": 1,
},
{
"item_label": "View Website",
"item_type": "Action",
"action": "jingrow.ui.toolbar.view_website()",
"is_standard": 1,
},
{
"item_label": "Apps",
"item_type": "Route",
"route": "/apps",
"is_standard": 1,
},
{
"item_label": "Toggle Theme",
"item_type": "Action",
@ -528,12 +504,6 @@ standard_help_items = [
"action": "jingrow.ui.toolbar.show_shortcuts(event)",
"is_standard": 1,
},
{
"item_label": "Jingrow Support",
"item_type": "Route",
"route": "https://framework.jingrow.com/support",
"is_standard": 1,
},
]
# log pagetype cleanups to automatically add in log settings

View File

@ -1,235 +0,0 @@
{
"charts": [],
"content": "[{\"id\":\"NPK_AfSLQ2\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"lDOo58F7ZI\",\"type\":\"card\",\"data\":{\"card_name\":\"Backup\",\"col\":4}},{\"id\":\"ij1pcK8jst\",\"type\":\"card\",\"data\":{\"card_name\":\"Google Services\",\"col\":4}},{\"id\":\"aTlMujEHpN\",\"type\":\"card\",\"data\":{\"card_name\":\"Authentication\",\"col\":4}},{\"id\":\"gY5NXKtXss\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"id\":\"n_CI3GGqW-\",\"type\":\"card\",\"data\":{\"card_name\":\"Push Notifications\",\"col\":4}}]",
"creation": "2020-03-02 15:16:18.714190",
"custom_blocks": [],
"for_user": "",
"hide_custom": 0,
"icon": "integration",
"idx": 0,
"is_hidden": 1,
"label": "Integrations",
"links": [
{
"hidden": 0,
"is_query_report": 0,
"label": "Backup",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Dropbox Settings",
"link_count": 0,
"link_to": "Dropbox Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "S3 Backup Settings",
"link_count": 0,
"link_to": "S3 Backup Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Google Drive",
"link_count": 0,
"link_to": "Google Drive",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Google Services",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Google Settings",
"link_count": 0,
"link_to": "Google Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Google Contacts",
"link_count": 0,
"link_to": "Google Contacts",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Google Calendar",
"link_count": 0,
"link_to": "Google Calendar",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Google Drive",
"link_count": 0,
"link_to": "Google Drive",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Settings",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Webhook",
"link_count": 0,
"link_to": "Webhook",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Slack Webhook URL",
"link_count": 0,
"link_to": "Slack Webhook URL",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "SMS Settings",
"link_count": 0,
"link_to": "SMS Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Authentication",
"link_count": 4,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Social Login Key",
"link_count": 0,
"link_to": "Social Login Key",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "LDAP Settings",
"link_count": 0,
"link_to": "LDAP Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "OAuth Client",
"link_count": 0,
"link_to": "OAuth Client",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "OAuth Provider Settings",
"link_count": 0,
"link_to": "OAuth Provider Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Push Notifications",
"link_count": 1,
"link_type": "PageType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Push Notification Settings",
"link_count": 0,
"link_to": "Push Notification Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
}
],
"modified": "2025-04-26 01:32:25.287635",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Integrations",
"number_cards": [],
"owner": "Administrator",
"pagestatus": 0,
"pagetype": "Workspace",
"parent_page": "",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 5.0,
"shortcuts": [],
"title": "Integrations"
}

View File

@ -1479,6 +1479,9 @@ msgstr "已添加默认日志页面类型:{}"
msgid "Added {0}"
msgstr "已添加 {0}"
msgid "Added"
msgstr "已添加"
#: jingrow/public/js/jingrow/form/link_selector.js:180
#: jingrow/public/js/jingrow/form/link_selector.js:202
msgid "Added {0} ({1})"
@ -15983,7 +15986,7 @@ msgstr "个人资料"
#. Type: Action
#: jingrow/hooks.py
msgid "My Settings"
msgstr "我的设置"
msgstr "个人设置"
#. Option for the 'Database Engine' (Select) field in PageType 'PageType'
#: jingrow/core/pagetype/pagetype/pagetype.json
@ -29271,8 +29274,8 @@ msgstr "您选择全量同步选项,将重新同步服务器上所有已读和
#: jingrow/public/js/jingrow/form/footer/form_timeline.js:415
msgctxt "Form timeline"
msgid "You attached {0}"
msgstr "您已附加{0}"
msgid "You attached"
msgstr "您已附加"
#: jingrow/printing/page/print_format_builder/print_format_builder.js:741
msgid "You can add dynamic properties from the document by using Jinja templating."
@ -32097,3 +32100,84 @@ msgstr "PATH中未找到{}!执行备份需要该组件"
msgid "← Back to upload files"
msgstr "← 返回文件上传"
msgid "List Template"
msgstr "列表页模板"
msgid "Detail Template"
msgstr "详情页模板"
msgid "Design"
msgstr "设计"
msgid "designer"
msgstr "设计师"
msgid "AI Settings"
msgstr "AI 设置"
msgid "AI Agent"
msgstr "AI 智能体"
msgid "Product Design"
msgstr "产品设计"
msgid "Pattern Design"
msgstr "图案花型设计"
msgid "Fashion Model"
msgstr "模特"
#: AI Settings
msgid "DeepSeek API URL"
msgstr "DeepSeek API 地址"
msgid "DeepSeek API Key"
msgstr "DeepSeek API 密钥"
msgid "DeepSeek API Max Token"
msgstr "DeepSeek API Token 最大数量"
msgid "DeepSeek API Model"
msgstr "DeepSeek API 模型"
msgid "ChatGPT API URL"
msgstr "ChatGPT API 地址"
msgid "ChatGPT API Key"
msgstr "ChatGPT API 密钥"
msgid "ChatGPT API Model"
msgstr "ChatGPT API 模型"
msgid "Temperature"
msgstr "Temperature温度"
msgid "Top_p"
msgstr "Top_p累积概率"
msgid "Upload URL"
msgstr "图片中转服务器地址"
msgid "Server Address"
msgstr "服务器地址"
msgid "Ckpt Name"
msgstr "模型名称"
msgid "Images Per Prompt"
msgstr "单次生成图片数量"
msgid "Custom Suffix"
msgstr "图片后缀"
msgid "Negative Prompt"
msgstr "负面提示词"
msgid "Text Model"
msgstr "文本模型"
msgid "Image Model"
msgstr "图片模型"
msgid "Others"
msgstr "其他"

View File

@ -26,7 +26,7 @@
id="navbar-search"
type="text"
class="form-control"
placeholder="{%= __('Search or type a command ({0})', [jingrow.utils.is_mac() ? '⌘ + G' : 'Ctrl + G']) %}"
placeholder="{%= __('Search', [jingrow.utils.is_mac() ? '⌘ + G' : 'Ctrl + G']) %}"
aria-haspopup="true"
>
<span class="search-icon">

View File

@ -4795,6 +4795,4 @@ West Bengal,西孟加拉邦,
Published on,发表于,
Bottom,底部,
Top,最佳,
Design,设计,
AI Agent,AI智能体,
designer,设计师,

1 A4 A4
4795 Published on 发表于
4796 Bottom 底部
4797 Top 最佳
4798
AI Agent AI智能体
designer 设计师

View File

@ -13,13 +13,13 @@ from typing import Dict, List, Any, Optional
import jingrow
# 定义配置变量
server_address = jingrow.db.get_single_value("AI Settings", "server_address") or "comfyui.jingrow.com:8188"
ckpt_name = jingrow.db.get_single_value("AI Settings", "ckpt_name") or "flux1-schnell-fp8.safetensors"
custom_suffix = jingrow.db.get_single_value("AI Settings", "custom_suffix") or "fx"
server_address = jingrow.db.get_single_value("AI Settings", "server_address")
ckpt_name = jingrow.db.get_single_value("AI Settings", "flux_ckpt_name") or "flux1-schnell-fp8.safetensors"
custom_suffix = jingrow.db.get_single_value("AI Settings", "flux_custom_suffix") or "fx"
sampler_name = jingrow.db.get_single_value("AI Settings", "sampler_name") or "euler"
scheduler = jingrow.db.get_single_value("AI Settings", "scheduler") or "normal"
steps = int(jingrow.db.get_single_value("AI Settings", "steps") or 4)
cfg = int(jingrow.db.get_single_value("AI Settings", "cfg") or 1)
steps = int(jingrow.db.get_single_value("AI Settings", "flux_steps") or 4)
cfg = int(jingrow.db.get_single_value("AI Settings", "flux_cfg") or 1)
denoise = float(jingrow.db.get_single_value("AI Settings", "denoise") or 1)
images_per_prompt = int(jingrow.db.get_single_value("AI Settings", "images_per_prompt") or 4)
image_width = int(jingrow.db.get_single_value("AI Settings", "image_width") or 1024)
@ -168,9 +168,6 @@ def upload_image(record_name: str, image_data: bytes, image_filename: str, paget
)
file_pg.save()
jingrow.db.commit()
jingrow.log_error("图片上传成功", f"文件: {image_filename}, 已关联到: {pagetype}/{record_name}")
# 返回文件URL
return file_pg.file_url
@ -214,7 +211,7 @@ def process_comfyui_flux_task(pg_name: str, pagetype: str) -> bool:
return False
# 更新状态为"任务进行中"
if hasattr(pg, "status"):
if hasattr(pg, "status"):
pg.status = "任务进行中"
pg.save()
jingrow.db.commit()
@ -321,4 +318,4 @@ def process_comfyui_flux_task(pg_name: str, pagetype: str) -> bool:
return False
finally:
ws.close()
ws.close()

321
jingrow/utils/comfyui_sd.py Normal file
View File

@ -0,0 +1,321 @@
import json
import base64
import requests
import random
import time
import traceback
import websocket
import uuid
import urllib.request
import urllib3
from typing import Dict, List, Any, Optional
import jingrow
# 定义配置变量
server_address = jingrow.db.get_single_value("AI Settings", "server_address")
ckpt_name = jingrow.db.get_single_value("AI Settings", "sd_ckpt_name") or "sd3_medium_incl_clips_t5xxlfp8.safetensors"
custom_suffix = jingrow.db.get_single_value("AI Settings", "sd_custom_suffix") or "sd"
sampler_name = jingrow.db.get_single_value("AI Settings", "sampler_name") or "euler"
scheduler = jingrow.db.get_single_value("AI Settings", "scheduler") or "normal"
steps = int(jingrow.db.get_single_value("AI Settings", "sd_steps") or 20)
cfg = int(jingrow.db.get_single_value("AI Settings", "sd_cfg") or 8)
denoise = float(jingrow.db.get_single_value("AI Settings", "denoise") or 1)
images_per_prompt = int(jingrow.db.get_single_value("AI Settings", "images_per_prompt") or 4)
image_width = int(jingrow.db.get_single_value("AI Settings", "image_width") or 1024)
image_height = int(jingrow.db.get_single_value("AI Settings", "image_height") or 1024)
negative_prompt = jingrow.db.get_single_value("AI Settings", "negative_prompt") or "blur, low quality, low resolution, watermark, cropped, out of frame, overexposed, underexposed, bad anatomy, deformed body, extra limbs, missing limbs, extra fingers, missing fingers, poor lighting, noisy background, cluttered background, blurry background, pixelated, distorted, unnatural pose, double exposure, incorrect perspective, grainy, dark, bad proportions, out of focus, incorrect clothing fit, unrealistic shadows, weird colors, cartoonish, low detail, jpeg artifacts, unnatural lighting"
# 定义基础工作流 JSON 模板
WORKFLOW_TEMPLATE = """
{
"3": {
"class_type": "KSampler",
"inputs": {
"cfg": %d,
"denoise": %d,
"latent_image": [
"5",
0
],
"model": [
"4",
0
],
"negative": [
"7",
0
],
"positive": [
"6",
0
],
"sampler_name": "%s",
"scheduler": "%s",
"seed": 8566257,
"steps": %d
}
},
"4": {
"class_type": "CheckpointLoaderSimple",
"inputs": {
"ckpt_name": "%s"
}
},
"5": {
"class_type": "EmptyLatentImage",
"inputs": {
"batch_size": 1,
"height": %d,
"width": %d
}
},
"6": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"4",
1
],
"text": "masterpiece best quality girl"
}
},
"7": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"4",
1
],
"text": "%s"
}
},
"8": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"3",
0
],
"vae": [
"4",
2
]
}
},
"save_image_websocket_node": {
"class_type": "SaveImageWebsocket",
"inputs": {
"images": [
"8",
0
]
}
}
}
"""
def queue_prompt(prompt: Dict, server_address: str, client_id: str) -> Dict:
p = {"prompt": prompt, "client_id": client_id}
data = json.dumps(p).encode('utf-8')
req = urllib.request.Request(f"http://{server_address}/prompt", data=data)
response = json.loads(urllib.request.urlopen(req).read())
return response
def get_images(ws: websocket.WebSocket, workflow: Dict, server_address: str, client_id: str) -> Dict:
try:
prompt_response = queue_prompt(workflow, server_address, client_id)
prompt_id = prompt_response['prompt_id']
except KeyError as e:
return {}
output_images = {}
current_node = ""
while True:
out = ws.recv()
if isinstance(out, str):
message = json.loads(out)
if message['type'] == 'executing':
data = message['data']
if data.get('prompt_id') == prompt_id:
if data['node'] is None:
break
else:
current_node = data['node']
else:
if current_node == 'save_image_websocket_node':
images_output = output_images.get(current_node, [])
images_output.append(out[8:])
output_images[current_node] = images_output
return output_images
def upload_image(record_name: str, image_data: bytes, image_filename: str, pagetype: str) -> str:
try:
# 创建文件并关联到记录
file_pg = jingrow.get_pg(
{
"pagetype": "File",
"attached_to_pagetype": pagetype,
"attached_to_name": record_name,
"file_name": image_filename,
"is_private": 0,
"content": image_data
}
)
file_pg.save()
jingrow.db.commit()
# 返回文件URL
return file_pg.file_url
except Exception as e:
jingrow.log_error("上传图片失败", f"记录:{record_name}, 错误:{str(e)}")
traceback.print_exc()
return None
def update_progress(pg_name: str, progress_value: int, pagetype: str) -> None:
try:
pg = jingrow.get_pg(pagetype, pg_name)
if pg and hasattr(pg, "progress"):
pg.progress = progress_value
pg.save()
jingrow.db.commit()
except Exception as e:
jingrow.log_error("更新进度失败", f"记录:{pg_name}, 错误:{str(e)}")
def process_comfyui_sd_task(pg_name: str, pagetype: str) -> bool:
# 创建WebSocket连接
ws = websocket.WebSocket()
client_id = str(uuid.uuid4())
try:
# 获取页面对象
pg = jingrow.get_pg(pagetype, pg_name)
if not pg:
jingrow.log_error("处理文生图任务失败", f"找不到文档: {pagetype} {pg_name}")
return False
# 从页面对象获取提示词
prompts = pg.prompts if hasattr(pg, "prompts") else None
if not prompts:
jingrow.log_error("文生图任务失败", f"没有提供提示词: {pagetype} {pg_name}")
if hasattr(pg, "status"):
pg.status = "任务未完成"
pg.save()
jingrow.db.commit()
return False
# 更新状态为"任务进行中"
if hasattr(pg, "status"):
pg.status = "任务进行中"
pg.save()
jingrow.db.commit()
# 连接WebSocket
ws.connect(f"ws://{server_address}/ws?clientId={client_id}")
# 更新进度为20
if hasattr(pg, "progress"):
update_progress(pg_name, 20, pagetype)
for i in range(images_per_prompt):
# 准备工作流程
workflow = json.loads(WORKFLOW_TEMPLATE % (
cfg,
denoise,
sampler_name,
scheduler,
steps,
ckpt_name,
image_height,
image_width,
negative_prompt
))
# 设置提示词
workflow["6"]["inputs"]["text"] = prompts
# 生成随机种子
seed = random.randint(1, 4294967295)
workflow["3"]["inputs"]["seed"] = seed
# 准备文件名
unique_id = str(uuid.uuid4())[:4]
fields_to_include = ""
if hasattr(pg, "serial_number") and pg.serial_number:
fields_to_include += f"{pg.serial_number}_"
if hasattr(pg, "title") and pg.title:
fields_to_include += f"{pg.title}_"
image_filename = f"{fields_to_include}{pg_name}_{pagetype}_{custom_suffix}_{unique_id}_{i+1}.png"
try:
# 获取生成的图像
images = get_images(ws, workflow, server_address, client_id)
# 上传图像
for node_id, image_list in images.items():
for image_data in image_list:
upload_image(pg_name, image_data, image_filename, pagetype)
# 更新进度
if hasattr(pg, "progress"):
current_progress = 20 + ((i + 1) * 80) // images_per_prompt
update_progress(pg_name, min(current_progress, 100), pagetype)
except Exception as e:
jingrow.log_error("处理提示词时出错", f"{pagetype}:{pg_name}, 错误:{str(e)}")
if hasattr(pg, "status"):
pg.status = "任务未完成"
if hasattr(pg, "progress"):
pg.progress = 0
pg.save()
jingrow.db.commit()
return False
time.sleep(2)
# 确保任务完成后进度为100%
if hasattr(pg, "progress"):
update_progress(pg_name, 100, pagetype)
# 更新状态为"已出图"如果有status字段
if hasattr(pg, "status"):
# 使用get_pg获取最新的文档以避免覆盖progress值
current_pg = jingrow.get_pg(pagetype, pg_name)
current_pg.status = "已出图"
# 确保progress不会被覆盖再次确认进度为100%
if hasattr(current_pg, "progress"):
current_pg.progress = 100
current_pg.save()
jingrow.db.commit()
return True
except Exception as e:
jingrow.log_error("处理文生图任务时发生异常", f"{pagetype}:{pg_name}, 错误:{str(e)}")
# 尝试更新页面对象状态
try:
pg = jingrow.get_pg(pagetype, pg_name)
if pg and hasattr(pg, "status"):
pg.status = "任务未完成"
if hasattr(pg, "progress"):
pg.progress = 0
pg.save()
jingrow.db.commit()
except:
pass
return False
finally:
ws.close()

622
jingrow/utils/midjourney.py Normal file
View File

@ -0,0 +1,622 @@
import json
import sys
import os
import io
import requests
import time
import random
import re
import uuid
import urllib.request
import urllib3
import traceback
from pathlib import Path
from urllib.parse import urlparse
from PIL import Image
import mimetypes
import jingrow
# 从AI Settings获取Midjourney配置
try:
api_url = jingrow.db.get_single_value("AI Settings", "midjourney_api_url")
application_id = jingrow.db.get_single_value("AI Settings", "midjourney_application_id")
data_id = jingrow.db.get_single_value("AI Settings", "midjourney_data_id")
data_version = jingrow.db.get_single_value("AI Settings", "midjourney_data_version")
session_id = jingrow.db.get_single_value("AI Settings", "midjourney_session_id")
midjourney_suffix = jingrow.db.get_single_value("AI Settings", "midjourney_suffix")
upload_url = jingrow.db.get_single_value("AI Settings", "upload_url")
# 获取Midjourney选项配置
midjourney_options_str = jingrow.db.get_single_value("AI Settings", "midjourney_options")
if midjourney_options_str:
try:
midjourney_options = json.loads(midjourney_options_str)
except:
midjourney_options = {"ar": "1:1", "v": "6.1"}
else:
midjourney_options = {"ar": "1:1", "v": "6.1"}
# 代理设置 - 如果需要可以在AI Settings中配置
http_proxy = "http://127.0.0.1:1080"
https_proxy = "http://127.0.0.1:1080"
except Exception as e:
jingrow.log_error("获取Midjourney配置失败", f"错误: {str(e)}")
traceback.print_exc()
# 禁用不安全请求警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class Midjourney:
def __init__(self, channel_id, oauth_token):
self.API_URL = api_url
self.APPLICATION_ID = application_id
self.DATA_ID = data_id
self.DATA_VERSION = data_version
self.SESSION_ID = session_id
self.channel_id = channel_id
self.oauth_token = oauth_token
# 设置代理
self.proxies = {
'http': http_proxy,
'https': https_proxy
}
self.client = requests.Session()
self.client.headers.update({
'Authorization': oauth_token
})
# 为会话设置代理
self.client.proxies.update(self.proxies)
try:
response = self.client.get(f'{self.API_URL}/channels/{self.channel_id}')
data = response.json()
self.guild_id = data['guild_id']
response = self.client.get(f'{self.API_URL}/users/@me')
data = response.json()
self.user_id = data['id']
except Exception as e:
jingrow.log_error("初始化Midjourney客户端失败", f"错误: {str(e)}")
traceback.print_exc()
raise Exception(f"初始化Midjourney客户端失败: {str(e)}")
@staticmethod
def first_where(array, key, value=None):
for item in array:
if callable(key) and key(item):
return item
if isinstance(key, str) and item[key].startswith(value):
return item
return None
# 使用给定的提示词生成图像请求
def imagine(self, prompt):
params = {
'type': 2,
'application_id': self.APPLICATION_ID,
'guild_id': self.guild_id,
'channel_id': self.channel_id,
'session_id': self.SESSION_ID,
'data': {
'version': self.DATA_VERSION,
'id': self.DATA_ID,
'name': 'imagine',
'type': 1,
'options': [{
'type': 3,
'name': 'prompt',
'value': prompt
}],
'application_command': {
'id': self.DATA_ID,
'application_id': self.APPLICATION_ID,
'version': self.DATA_VERSION,
'default_member_permissions': None,
'type': 1,
'nsfw': False,
'name': 'imagine',
'description': 'Create images with Midjourney',
'dm_permission': True,
'options': [{
'type': 3,
'name': 'prompt',
'description': 'The prompt to imagine',
'required': True
}]
},
'attachments': []
}
}
try:
r = self.client.post(f'{self.API_URL}/interactions', json=params)
time.sleep(2)
imagine_message = None
count = 0
while imagine_message is None:
imagine_message = self.get_imagine(prompt, count)
if imagine_message is None:
time.sleep(8)
count += 1
if count > 15:
break
return imagine_message
except Exception as e:
jingrow.log_error("发送Imagine请求失败", f"错误: {str(e)}")
traceback.print_exc()
raise Exception(f"发送Imagine请求失败: {str(e)}")
# 获取生成图像的消息
def get_imagine(self, prompt, count=0):
try:
response = self.client.get(f'{self.API_URL}/channels/{self.channel_id}/messages')
data = response.json()
def criteria(item):
# 定义查找消息的条件
if "http" in prompt:
# Replace all http(s)://... by <URL>
prompt_test = re.sub(r'https?://\S+', '<URL>', prompt)
item_content = re.sub(r'https?://\S+', 'URL>', item['content'])
end_with = "fast"
if "--relax" in prompt:
end_with = "relaxed"
if "--turbo" in prompt:
end_with = "turbo"
return (item_content.startswith(f"**{prompt_test}** - <@{self.user_id}>")
and "%" not in item['content']
and ((item['content'].endswith('(fast)')) or (item['content'].endswith(f'({end_with})'))))
else:
end_with = "fast"
if "--relax" in prompt:
end_with = "relaxed"
if "--turbo" in prompt:
end_with = "turbo"
return (item['content'].startswith(f"**{prompt}** - <@{self.user_id}>")
and "%" not in item['content']
and ((item['content'].endswith('(fast)')) or (item['content'].endswith(f'({end_with})'))))
raw_message = self.first_where(data, criteria)
# 重试 15 次
if raw_message is None and count < 15:
return None
if count == 15:
return {
'id': data[0]['id'],
'prompt': prompt,
'raw_message': data[0]
}
r_final = {
'id': raw_message['id'],
'prompt': prompt,
'raw_message': raw_message
}
return r_final
except Exception as e:
jingrow.log_error("获取通道消息失败", f"错误: {str(e)}")
return None
# 执行图像的放大操作
def upscale(self, message, upscale_index=0):
if 'raw_message' not in message:
raise Exception('Upscale requires a message object obtained from the imagine/getImagine methods.')
if upscale_index < 0 or upscale_index > 3:
raise Exception('Upscale index must be between 0 and 3.')
try:
upscale_hash = None
raw_message = message['raw_message']
if 'components' in raw_message and isinstance(raw_message['components'], list):
upscales = raw_message['components'][0]['components']
upscale_hash = upscales[upscale_index]['custom_id']
else:
jingrow.log_error("获取upscale_hash失败", "消息中没有components字段或格式不正确")
params = {
'type': 3,
'guild_id': self.guild_id,
'channel_id': self.channel_id,
'message_flags': 0,
'message_id': message['id'],
'application_id': self.APPLICATION_ID,
'session_id': self.SESSION_ID,
'data': {
'component_type': 2,
'custom_id': upscale_hash
}
}
self.client.post(f'{self.API_URL}/interactions', json=params)
upscaled_photo_url = None
count = 0
while upscaled_photo_url is None:
upscaled_photo_url = self.get_upscale(message, upscale_index, count)
if upscaled_photo_url is None:
time.sleep(3)
count += 1
if count > 5:
break
return upscaled_photo_url
except Exception as e:
jingrow.log_error("执行放大操作失败", f"错误: {str(e)}")
traceback.print_exc()
raise Exception(f"执行放大操作失败: {str(e)}")
# 获取放大后的图像URL
def get_upscale(self, message, upscale_index=0, count=0):
if 'raw_message' not in message:
raise Exception('Upscale requires a message object obtained from the imagine/getImagine methods.')
if upscale_index < 0 or upscale_index > 3:
raise Exception('Upscale index must be between 0 and 3.')
try:
prompt = message['prompt']
response = self.client.get(f'{self.API_URL}/channels/{self.channel_id}/messages')
messages = response.json()
# Delete --seed from prompt
prompt = re.sub(r"\s--seed\s\d+", "", prompt)
# Delete --relax from prompt
prompt = re.sub(r"\s--relax", "", prompt)
prompt = re.sub(r"\s--turbo", "", prompt)
url = None
prompt_test = re.sub(r'https?://\S+', '<URL>', prompt)
messages[0]['content'] = re.sub(r'https?://\S+', 'URL>', messages[0]['content'])
if messages[0]['content'].startswith(f"**{prompt_test}** - Image"):
url = messages[0]['attachments'][0]['url']
# After 3 tries we return messages[0]['attachments'][0]['url']
if count == 3:
return messages[0]['attachments'][0]['url']
if url is None or url == "":
return None
else:
return url
except Exception as e:
jingrow.log_error("获取放大后的图像URL失败", f"错误: {str(e)}")
return None
# 生成图像并返回生成的消息ID
def generate(self, prompt, options={}, sources={}, upscale_index=-1):
try:
prompt = prompt.strip()
# Force options version to 6.0
if "v" not in options or options['v'] == "":
options['v'] = '6.0'
if "ar" not in options or options['ar'] == "":
options['ar'] = '3:2'
if "seed" not in options or options['seed'] == "":
options['seed'] = random.randint(0, 4294967295)
# Force seed as last parameter in the dict
seed = options.pop('seed')
options['seed'] = seed
parameter = ""
no_value_key = ['relax', 'fast', 'turbo']
for key, value in options.items():
if key in no_value_key:
parameter += f" --{key}"
else:
parameter += f" --{key} {value}"
# Image sources
if 'images' in sources:
prompt = " ".join(sources['images']) + " " + prompt
# Add caracters
if 'caracters' in sources and len(sources['caracters']) > 0:
prompt = prompt + " --cref " + " ".join(sources['caracters'])
# Add styles
if 'styles' in sources and len(sources['styles']) > 0:
prompt = prompt + " --sref " + " ".join(sources['styles'])
# On ajoute une seed pour éviter les doublons
prompt = prompt + parameter
imagine = self.imagine(prompt)
return {
'imagine_message_id': imagine['id'],
'raw_message': imagine['raw_message'],
'seed': seed
}
except Exception as e:
jingrow.log_error("生成图像失败", f"错误: {str(e)}")
traceback.print_exc()
raise Exception(f"生成图像失败: {str(e)}")
# 从提示词中提取参数和来源
def get_parameter_from_prompt(self, prompt):
sources = {}
# Get all sources from prompt
# Get --sref http://xxxx, http://xxxx, http://xxxx
sources['styles'] = []
styles_match = re.search(r'--sref\s+((?:https?://\S+(?:,\s*)?)+)', prompt)
if styles_match:
sources['styles'] = re.findall(r'https?://\S+', styles_match.group(0))
prompt = prompt[:styles_match.start()] + prompt[styles_match.end():]
# Get --cref http://xxxx, http://xxxx, http://xxxx
sources['caracters'] = []
caracters_match = re.search(r'--cref\s+((?:https?://\S+(?:,\s*)?)+)', prompt)
if caracters_match:
sources['caracters'] = re.findall(r'https?://\S+', caracters_match.group(0))
prompt = prompt[:caracters_match.start()] + prompt[caracters_match.end():]
# Get all parameters from prompt
parameters = re.findall(r'--(\w+\s[\w.:]+)', prompt)
# Clean prompt
for parameter in parameters:
prompt = prompt.replace(f'--{parameter}', '')
# Delete multiple spaces
prompt = re.sub(' {2,}', ' ', prompt)
prompt = prompt.strip()
return {parameter.split(' ')[0].replace('--', ''): parameter.split(' ')[1] for parameter in
parameters}, sources, prompt
# 上传图像到图床服务器
def upload_image_to_intermediate_server(image_url, upload_url):
try:
response = requests.get(image_url, verify=False)
image_data = response.content
parsed_url = urlparse(image_url)
file_name = Path(parsed_url.path).name
file_ext = Path(file_name).suffix
# 如果图片是webp格式转换为png格式
if file_ext.lower() == '.webp':
image = Image.open(io.BytesIO(image_data))
png_buffer = io.BytesIO()
image.save(png_buffer, format='PNG')
image_data = png_buffer.getvalue()
file_name = file_name.replace('.webp', '.png')
files = {"file": (file_name, image_data)}
upload_response = requests.post(upload_url, files=files, verify=False)
if upload_response.status_code == 200:
return upload_response.json()["file_url"]
else:
jingrow.log_error("上传图片失败", f"状态码: {upload_response.status_code}, 响应: {upload_response.text[:200]}")
raise Exception(f"上传失败. 状态码: {upload_response.status_code}, {upload_response.text}")
except Exception as e:
jingrow.log_error("上传图像到中间服务器失败", f"错误: {str(e)}, URL: {image_url}")
traceback.print_exc()
raise Exception(f"上传图像到中间服务器失败: {str(e)}")
# 检查图片URL是否有效
def is_valid_image_url(url):
return url and url.strip() and url.lower() != "none"
# 更新进度的辅助函数
def update_progress(pg_name, progress_value, pagetype):
try:
pg = jingrow.get_pg(pagetype, pg_name)
if pg and hasattr(pg, "progress"):
pg.progress = progress_value
pg.save()
jingrow.db.commit()
except Exception as e:
jingrow.log_error("更新进度失败", f"记录: {pg_name}, 错误: {str(e)}")
# 处理Midjourney任务的主函数
def process_midjourney_task(pg_name, pagetype):
try:
# 获取页面对象
pg = jingrow.get_pg(pagetype, pg_name)
if not pg:
jingrow.log_error("处理Midjourney任务失败", f"找不到文档: {pagetype} {pg_name}")
return False
# 获取必要的配置
discord_channel_id = jingrow.db.get_single_value("AI Settings", "discord_channel_id")
discord_user_token = jingrow.db.get_single_value("AI Settings", "discord_user_token")
if not discord_channel_id or not discord_user_token:
jingrow.log_error("处理Midjourney任务失败", "Discord配置不完整")
if hasattr(pg, "status"):
pg.status = "任务未完成"
pg.save()
jingrow.db.commit()
return False
# 从页面对象获取提示词
prompts = pg.prompts if hasattr(pg, "prompts") else None
if not prompts:
jingrow.log_error("Midjourney任务失败", f"没有提供提示词: {pagetype} {pg_name}")
if hasattr(pg, "status"):
pg.status = "任务未完成"
pg.save()
jingrow.db.commit()
return False
# 更新状态为"任务进行中"
if hasattr(pg, "status"):
pg.status = "任务进行中"
pg.save()
jingrow.db.commit()
# 初始化Midjourney客户端
midjourney = Midjourney(discord_channel_id, discord_user_token)
# 更新进度为20%
update_progress(pg_name, 20, pagetype)
# 准备图像URL列表
image_urls = []
# 获取并上传参考图片到中间服务器
if hasattr(pg, "reference_image_1") and is_valid_image_url(pg.reference_image_1):
full_image_url = f"{jingrow.utils.get_url()}{pg.reference_image_1}"
new_image_url = upload_image_to_intermediate_server(full_image_url, upload_url)
image_urls.append(new_image_url)
if hasattr(pg, "reference_image_2") and is_valid_image_url(pg.reference_image_2):
full_image_url = f"{jingrow.utils.get_url()}{pg.reference_image_2}"
new_image_url = upload_image_to_intermediate_server(full_image_url, upload_url)
image_urls.append(new_image_url)
if hasattr(pg, "reference_image_3") and is_valid_image_url(pg.reference_image_3):
full_image_url = f"{jingrow.utils.get_url()}{pg.reference_image_3}"
new_image_url = upload_image_to_intermediate_server(full_image_url, upload_url)
image_urls.append(new_image_url)
if hasattr(pg, "reference_image_4") and is_valid_image_url(pg.reference_image_4):
full_image_url = f"{jingrow.utils.get_url()}{pg.reference_image_4}"
new_image_url = upload_image_to_intermediate_server(full_image_url, upload_url)
image_urls.append(new_image_url)
update_progress(pg_name, 40, pagetype)
# 从配置读取选项而不是硬编码
options = midjourney_options.copy()
# 如果有参考图像,设置图像权重
if image_urls:
prompt = " ".join(image_urls) + " " + prompts
if hasattr(pg, "image_weight") and pg.image_weight is not None and 0 < pg.image_weight <= 3:
options["iw"] = pg.image_weight
else:
prompt = prompts
# 生成图像并返回生成的消息ID
result = midjourney.generate(prompt, options)
imagine_message_id = result['imagine_message_id']
raw_message = result['raw_message']
seed = result['seed']
update_progress(pg_name, 60, pagetype)
# 确保生成的消息包含正确的seed
if f"--seed {seed}" not in raw_message['content']:
jingrow.log_error("Seed不匹配", f"消息内容: {raw_message['content'][:200]}...")
raise Exception("Seed不匹配该消息不属于当前任务。")
# 执行放大操作获取图像
image_urls = []
for i in range(4):
message = {
'id': imagine_message_id,
'prompt': prompt,
'raw_message': raw_message
}
upscaled_photo_url = midjourney.upscale(message, upscale_index=i)
if not upscaled_photo_url:
jingrow.log_error("获取放大图像失败", f"索引: {i}")
raise Exception(f"获取放大图像失败,索引 {i}")
image_urls.append(upscaled_photo_url)
update_progress(pg_name, 80, pagetype)
# 设置代理用于下载Discord图片
proxies = {
'http': http_proxy,
'https': https_proxy
}
# 上传图像到Jingrow
for i, image_url in enumerate(image_urls):
try:
# 使用代理下载Discord图片
response = requests.get(image_url, proxies=proxies, timeout=60)
if response.status_code != 200:
jingrow.log_error("图像下载失败", f"状态码: {response.status_code}")
continue
image_data = io.BytesIO(response.content)
# 生成唯一文件名
unique_id = str(uuid.uuid4())[:4]
fields_to_include = ""
if hasattr(pg, "serial_number") and pg.serial_number:
fields_to_include += f"{pg.serial_number}_"
if hasattr(pg, "title") and pg.title:
fields_to_include += f"{pg.title}_"
image_filename = f"{fields_to_include}{pg_name}_{pagetype}_{midjourney_suffix}_{unique_id}_{seed}_{i+1}.png"
# 创建文件并关联到记录
file_pg = jingrow.get_pg(
{
"pagetype": "File",
"attached_to_pagetype": pagetype,
"attached_to_name": pg_name,
"file_name": image_filename,
"is_private": 0,
"content": image_data.getvalue()
}
)
file_pg.save()
jingrow.db.commit()
except Exception as e:
jingrow.log_error(f"处理图像 {i+1} 失败", f"错误: {str(e)}")
traceback.print_exc()
# 继续处理下一张图像,不中断整个过程
update_progress(pg_name, 100, pagetype)
# 更新状态为"已出图"
current_pg = jingrow.get_pg(pagetype, pg_name)
if hasattr(current_pg, "status"):
current_pg.status = "已出图"
if hasattr(current_pg, "progress"):
current_pg.progress = 100
current_pg.save()
jingrow.db.commit()
return True
except Exception as e:
jingrow.log_error("处理Midjourney任务时发生异常", f"{pagetype}:{pg_name}, 错误: {str(e)}")
traceback.print_exc()
# 尝试更新页面对象状态
try:
pg = jingrow.get_pg(pagetype, pg_name)
if pg and hasattr(pg, "status"):
pg.status = "任务未完成"
if hasattr(pg, "progress"):
pg.progress = 0
pg.save()
jingrow.db.commit()
except Exception as inner_e:
jingrow.log_error("更新状态失败", f"错误: {str(inner_e)}")
return False

View File

@ -1,286 +0,0 @@
{
"charts": [],
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Website\",\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Blog Post\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Blogger\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Web Page\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Web Form\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Website Settings\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Setup\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Blog\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Web Site\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Portal\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Knowledge Base\",\"col\":4}}]",
"creation": "2020-03-02 14:13:51.089373",
"custom_blocks": [],
"for_user": "",
"hide_custom": 0,
"icon": "website",
"idx": 0,
"is_hidden": 1,
"label": "Website",
"links": [
{
"hidden": 0,
"icon": "setting",
"is_query_report": 0,
"label": "Setup",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Website Settings",
"link_count": 0,
"link_to": "Website Settings",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Website Theme",
"link_count": 0,
"link_to": "Website Theme",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Website Script",
"link_count": 0,
"link_to": "Website Script",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "About Us Settings",
"link_count": 0,
"link_to": "About Us Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Contact Us Settings",
"link_count": 0,
"link_to": "Contact Us Settings",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"icon": "",
"is_query_report": 0,
"label": "Blog",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Blog Post",
"link_count": 0,
"link_to": "Blog Post",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Blogger",
"link_count": 0,
"link_to": "Blogger",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Blog Category",
"link_count": 0,
"link_to": "Blog Category",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"icon": "website",
"is_query_report": 0,
"label": "Web Site",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Web Page",
"link_count": 0,
"link_to": "Web Page",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Web Form",
"link_count": 0,
"link_to": "Web Form",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Website Sidebar",
"link_count": 0,
"link_to": "Website Sidebar",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Website Slideshow",
"link_count": 0,
"link_to": "Website Slideshow",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Website Route Meta",
"link_count": 0,
"link_to": "Website Route Meta",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"icon": "website",
"is_query_report": 0,
"label": "Portal",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Portal Settings",
"link_count": 0,
"link_to": "Portal Settings",
"link_type": "PageType",
"onboard": 1,
"type": "Link"
},
{
"hidden": 0,
"icon": "project",
"is_query_report": 0,
"label": "Knowledge Base",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Help Category",
"link_count": 0,
"link_to": "Help Category",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Help Article",
"link_count": 0,
"link_to": "Help Article",
"link_type": "PageType",
"onboard": 0,
"type": "Link"
}
],
"modified": "2025-04-26 01:32:21.821626",
"modified_by": "Administrator",
"module": "Website",
"name": "Website",
"number_cards": [],
"owner": "Administrator",
"pagestatus": 0,
"pagetype": "Workspace",
"parent_page": "",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 2.0,
"shortcuts": [
{
"color": "Green",
"format": "{} Published",
"label": "Blog Post",
"link_to": "Blog Post",
"stats_filter": "{\"published\":\"1\"}",
"type": "PageType"
},
{
"color": "Green",
"format": "{} Active",
"label": "Blogger",
"link_to": "Blogger",
"stats_filter": "{\"disabled\": 0}",
"type": "PageType"
},
{
"color": "Green",
"format": "{} Published",
"label": "Web Page",
"link_to": "Web Page",
"stats_filter": "{ \"published\": 1 }",
"type": "PageType"
},
{
"label": "Web Form",
"link_to": "Web Form",
"type": "PageType"
},
{
"label": "Website Settings",
"link_to": "Website Settings",
"type": "PageType"
}
],
"title": "Website"
}