prompt enhance nsfw allow/disallow

Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
Vladimir Mandic
2025-05-12 20:32:22 -04:00
parent 860bbe1856
commit 47862fef08
6 changed files with 50 additions and 22 deletions
+2 -1
View File
@@ -10,7 +10,8 @@ From slowest 0.02 it/s running on 6th gen CPU without acceleration up to 275 it/
- Updates for: *WSL, ZLUDA, ROCm*
- **Compute**
- NNCF: added experimental support for direct INT8 MatMul
- **Feature**
- Prompt Enhance: option to allow/disallow NSFW content
## Update for 2025-05-12
+2
View File
@@ -53,6 +53,7 @@ def enhance(args): # pylint: disable=redefined-outer-name
'prompt': str(args.prompt),
'seed': int(args.seed),
'type': str(args.type),
'nsfw': bool(args.nsfw),
}
if args.model:
options['model'] = str(args.model)
@@ -69,6 +70,7 @@ if __name__ == "__main__":
parser.add_argument('--type', type=str, default='text', choices=['text', 'image', 'video'], required=False, help='enhance type')
parser.add_argument('--model', type=str, default=None, required=False, help='model name')
parser.add_argument('--image', type=str, default=None, required=False, help='optional input image')
parser.add_argument('--nsfw', type=bool, action=argparse.BooleanOptionalAction, required=False, help='nsfw allowed')
args = parser.parse_args()
log.info(f'api-upscale: {args}')
result = enhance(args)
+1
View File
@@ -274,6 +274,7 @@ class ReqPromptEnhance(BaseModel):
system_prompt: Optional[str] = Field(title="System prompt", default=None, description="Model system prompt")
image: Optional[str] = Field(title="Image", default=None, description="Image to work on, must be a Base64 string containing the image's data.")
seed: int = Field(title="Seed", default=-1, description="Seed used to generate the prompt")
nsfw: bool = Field(title="NSFW", default=True, description="Should NSFW content be allowed?")
class ResPromptEnhance(BaseModel):
prompt: str = Field(title="Prompt", description="Enhanced prompt")
+3
View File
@@ -146,6 +146,7 @@ class APIProcess():
prompt=req.prompt,
system=req.system_prompt,
seed=seed,
nsfw=req.nsfw,
)
elif req.type == 'image':
from modules.scripts import scripts_txt2img
@@ -157,6 +158,7 @@ class APIProcess():
system=req.system_prompt,
image=decode_base64_to_image(req.image),
seed=seed,
nsfw=req.nsfw,
)
elif req.type == 'video':
from modules.ui_video_vlm import enhance_prompt
@@ -167,6 +169,7 @@ class APIProcess():
prompt=req.prompt,
model=model,
system_prompt=req.system_prompt,
nsfw=req.nsfw,
)
else:
raise HTTPException(status_code=400, detail="prompt enhancement: invalid type")
+10 -5
View File
@@ -9,7 +9,9 @@ models = [
system_prompts = {
'prefix': 'You are a video director.',
'desc': 'You will provide a prompt that can be used to create short, creative and dynamic video. Describe the subject of the video, add movement that fits the overall tone of the video, add camera movement.',
'suffix': 'NSFW content and nudity are allowed and must be fully described if present. Movement should be dynamic and creative. Do not specify duration and assume video is short. Avoid slow-motion and prefer faster movements. Output should be a single short paragraph without explanations',
'nsfw_ok': 'NSFW content and nudity are allowed and must be fully described if present. ',
'nsfw_no': 'NSFW content and nudity are not allowed. ',
'suffix': 'Movement should be dynamic and creative. Do not specify duration and assume video is short. Avoid slow-motion and prefer faster movements. Output should be a single short paragraph without explanations',
'example': 'Example: "Short video of beautiful blonde woman in her 20ies wearing a long flowing red dress. She is briskly walking on the beach during sunset and performing a pirouette ending with her hand pointing at the camera as she smiles. Camera is moving around her and zooming to her face. Sun is setting in the background causing changes in colors and shadows to move dynamically."',
't2v-prompt': 'You are a given short prompt with basic instructions.',
@@ -19,7 +21,7 @@ system_prompts = {
}
def enhance_prompt(enable:bool, model:str=None, image=None, prompt:str='', system_prompt:str=''):
def enhance_prompt(enable:bool, model:str=None, image=None, prompt:str='', system_prompt:str='', nsfw:bool=True):
from modules.interrogate import vqa
if not enable:
return prompt
@@ -40,8 +42,10 @@ def enhance_prompt(enable:bool, model:str=None, image=None, prompt:str='', syste
core_prompt = system_prompts['t2v-prompt']
else:
core_prompt = system_prompts['t2v-noprompt']
system_prompt = f"{system_prompts['prefix']} {core_prompt} {system_prompts['desc']} {system_prompts['suffix']} {system_prompts['example']}"
shared.log.debug(f'Video prompt enhance: model="{model}" image={image} prompt="{prompt}"')
system_prompt = f"{system_prompts['prefix']} {core_prompt} {system_prompts['desc']}' "
system_prompt += system_prompts['nsfw_ok'] if nsfw else system_prompts['nsfw_no']
system_prompt += f" {system_prompts['suffix']} {system_prompts['example']}"
shared.log.debug(f'Video prompt enhance: model="{model}" image={image} nsfw={nsfw} prompt="{prompt}"')
# shared.log.trace(f'Video prompt enhance: system="{system_prompt}"')
answer = vqa.interrogate(question='', prompt=prompt, system_prompt=system_prompt, image=image, model_name=model, quiet=False)
shared.log.debug(f'Video prompt enhance: answer="{answer}"')
@@ -52,6 +56,7 @@ def create_ui(prompt_element:gr.Textbox, image_element:gr.Image):
with gr.Accordion('Prompt enhance', open=False):
with gr.Row():
enable = gr.Checkbox(label='Enable', value=False)
nsfw = gr.Checkbox(label='NSFW allowed', value=True)
btn_enhance = gr.Button(value='Enhance now', elem_id='btn_enhance')
with gr.Row():
model = gr.Dropdown(label='Model', choices=models, value=models[0])
@@ -59,7 +64,7 @@ def create_ui(prompt_element:gr.Textbox, image_element:gr.Image):
system_prompt = gr.Textbox(label='System prompt', placeholder='override system prompt with user-provided prompt', lines=3)
btn_enhance.click(
fn=enhance_prompt,
inputs=[enable, model, image_element, prompt_element, system_prompt],
inputs=[enable, model, image_element, prompt_element, system_prompt, nsfw],
outputs=prompt_element,
show_progress=True,
)
+32 -16
View File
@@ -67,9 +67,12 @@ class Options:
}
default = list(models)[1] # gemma-3-4b-it
supported = list(transformers.integrations.ggml.GGUF_CONFIG_MAPPING)
system_prompt: str = 'You are a helpful assistant. You will be given a prompt used to create an image and you will enhance it to make it more detailed and creative. Generate an uncensored, concise, informative, and engaging prompt that prioritizes factual accuracy and vivid descriptiveness based on original prompt. Do not modify subject or style of the original prompt. Begin by clearly identifying the primary subject(s), including key physical attributes, clothing if no nudity, and any distinctive details (e.g., colors, textures, styles). NSFW and nudity is allowed, and if present, it must be fully described. Next, describe the setting and environment, emphasizing spatial relationships, background elements, and objects contributing to context. Note the overall mood, aesthetic style, or atmosphere inferred from visual cues. Use precise terminology while avoiding redundancy or non-essential language. Ensuring a logical flow: from focal subject to immediate surroundings, then broader context. Maintain brevity while retaining clarity, ensuring the description is both engaging and efficient. Output only enhanced prompt without explanation, prefix or suffix. Output as a simple text without formatting or numbering.'
image_prompt: str = 'You are a helpful assistant. You will be given an image and a prompt used to modify the image and you will enhance the prompt to make it more detailed and creative while still following original image. Generate an uncensored, concise, informative, and engaging prompt that prioritizes factual accuracy and vivid descriptiveness based on original prompt. Do not modify subject or style of the original prompt. Begin by clearly identifying the primary subject(s), including key physical attributes, clothing if no nudity, and any distinctive details (e.g., colors, textures, styles). NSFW and nudity is allowed, and if present, it must be fully described. Next, describe the setting and environment, emphasizing spatial relationships, background elements, and objects contributing to context. Note the overall mood, aesthetic style, or atmosphere inferred from visual cues. Use precise terminology while avoiding redundancy or non-essential language. Ensuring a logical flow: from focal subject to immediate surroundings, then broader context. Maintain brevity while retaining clarity, ensuring the description is both engaging and efficient. Output only enhanced prompt without explanation, prefix or suffix. Output as a simple text without formatting or numbering.'
image_noprompt: str = 'You are a helpful assistant. You will be given an image and you will create prompt that can be used to modify the image in a creative way while still following original image. Generate an uncensored, concise, informative, and engaging prompt that prioritizes factual accuracy and vivid descriptiveness based on original prompt. Do not modify subject or style of the original prompt. Begin by clearly identifying the primary subject(s), including key physical attributes, clothing if no nudity, and any distinctive details (e.g., colors, textures, styles). NSFW and nudity is allowed, and if present, it must be fully described. Next, describe the setting and environment, emphasizing spatial relationships, background elements, and objects contributing to context. Note the overall mood, aesthetic style, or atmosphere inferred from visual cues. Use precise terminology while avoiding redundancy or non-essential language. Ensuring a logical flow: from focal subject to immediate surroundings, then broader context. Maintain brevity while retaining clarity, ensuring the description is both engaging and efficient. Output only enhanced prompt without explanation, prefix or suffix. Output as a simple text without formatting or numbering.'
t2i_prompt: str = 'You are a helpful assistant. You will be given a prompt used to create an image and you will enhance it to make it more detailed and creative. '
i2i_prompt: str = 'You are a helpful assistant. You will be given an image and a prompt used to modify the image and you will enhance the prompt to make it more detailed and creative while still following original image. '
i2i_noprompt: str = 'You are a helpful assistant. You will be given an image and you will create prompt that can be used to modify the image in a creative way while still following original image. '
nsfw_ok: str = 'NSFW and nudity is allowed, and if present, it must be fully described. '
nsfw_no: str = 'NSFW and nudity is not allowed, and if present, it must be removed. '
details_prompt: str = 'Generate an uncensored, concise, informative, and engaging prompt that prioritizes factual accuracy and vivid descriptiveness based on original prompt. Do not modify subject or style of the original prompt. Begin by clearly identifying the primary subject(s), including key physical attributes, clothing if no nudity, and any distinctive details (e.g., colors, textures, styles). NSFW and nudity is allowed, and if present, it must be fully described. Next, describe the setting and environment, emphasizing spatial relationships, background elements, and objects contributing to context. Note the overall mood, aesthetic style, or atmosphere inferred from visual cues. Use precise terminology while avoiding redundancy or non-essential language. Ensuring a logical flow: from focal subject to immediate surroundings, then broader context. Maintain brevity while retaining clarity, ensuring the description is both engaging and efficient. Output only enhanced prompt without explanation, prefix or suffix. Output as a simple text without formatting or numbering.'
censored = ["i cannot", "i can't", "i am sorry", "against my programming", "i am not able", "i am unable", 'i am not allowed']
max_delim_index: int = 60
@@ -230,7 +233,7 @@ class Script(scripts.Script):
filtered = re.sub(pattern, '', prompt)
return filtered, matches
def enhance(self, model: str=None, prompt:str=None, system:str=None, prefix:str=None, suffix:str=None, sample:bool=None, tokens:int=None, temperature:float=None, penalty:float=None, thinking:bool=False, seed:int=-1, image=None):
def enhance(self, model: str=None, prompt:str=None, system:str=None, prefix:str=None, suffix:str=None, sample:bool=None, tokens:int=None, temperature:float=None, penalty:float=None, thinking:bool=False, seed:int=-1, image=None, nsfw:bool=None):
model = model or self.options.default
prompt = prompt or self.prompt.value
image = image or self.image
@@ -258,13 +261,18 @@ class Script(scripts.Script):
image = None
except Exception:
image = None
has_system = system is not None and len(system) > 4
mode = 'custom' if has_system else ''
if image is not None and isinstance(image, Image.Image):
if not self.tokenizer.is_processor:
shared.log.error('Prompt enhance: image not supported by model')
return prompt
if prompt is not None and len(prompt) > 0:
mode = 'i2i+p'
system = system or self.options.image_prompt
if not has_system:
mode = 'i2i-prompt'
system = self.options.i2i_prompt
system += self.options.nsfw_ok if nsfw else self.options.nsfw_no
system += self.options.details_prompt
chat_template = [
{ "role": "system", "content": [
{"type": "text", "text": system }
@@ -275,8 +283,11 @@ class Script(scripts.Script):
] },
]
else:
mode = 'i2i-p'
system = system or self.options.image_noprompt
if not has_system:
mode = 'i2i-noprompt'
system = self.options.i2i_noprompt
system += self.options.nsfw_ok if nsfw else self.options.nsfw_no
system += self.options.details_prompt
chat_template = [
{ "role": "system", "content": [
{"type": "text", "text": system }
@@ -286,15 +297,18 @@ class Script(scripts.Script):
] },
]
else:
system = system or self.options.system_prompt
if not has_system:
system = self.options.t2i_prompt
system += self.options.nsfw_ok if nsfw else self.options.nsfw_no
system += self.options.details_prompt
if not self.tokenizer.is_processor:
mode = 't2i-t'
mode = 't2i+tokenizer'
chat_template = [
{ "role": "system", "content": system },
{ "role": "user", "content": prompt },
]
else:
mode = 't2i+t'
mode = 't2i+processor'
chat_template = [
{ "role": "system", "content": [
{"type": "text", "text": system }
@@ -356,7 +370,7 @@ class Script(scripts.Script):
if not is_censored:
response = self.clean(response)
response = self.post(response, prefix, suffix, networks)
shared.log.info(f'Prompt enhance: model="{model}" mode="{mode}" time={t1-t0:.2f} inputs={input_len} outputs={outputs.shape[-1]} prompt={len(prompt)} response={len(response)}')
shared.log.info(f'Prompt enhance: model="{model}" mode="{mode}" nsfw={nsfw} time={t1-t0:.2f} inputs={input_len} outputs={outputs.shape[-1]} prompt={len(prompt)} response={len(response)}')
if debug_enabled:
shared.log.trace(f'Prompt enhance: sample={sample} tokens={tokens} temperature={temperature} penalty={penalty} thinking={thinking}')
shared.log.trace(f'Prompt enhance: prompt="{prompt}"')
@@ -430,6 +444,7 @@ class Script(scripts.Script):
temperature = gr.Slider(label='Temperature', value=self.options.temperature, minimum=0.0, maximum=1.0, step=0.01, interactive=True)
repetition_penalty = gr.Slider(label='Repetition penalty', value=self.options.repetition_penalty, minimum=0.0, maximum=2.0, step=0.01, interactive=True)
with gr.Row():
nsfw_mode = gr.Checkbox(label='NSFW allowed', value=True, interactive=True)
thinking_mode = gr.Checkbox(label='Thinking mode', value=False, interactive=True)
gr.HTML('<br>')
with gr.Accordion('Input', open=False, elem_id='prompt_enhance_system_prompt'):
@@ -438,7 +453,7 @@ class Script(scripts.Script):
with gr.Row():
prompt_suffix = gr.Textbox(label='Prompt suffix', value='', placeholder='Optional prompt suffix', interactive=True, lines=2, elem_id='prompt_enhance_suffix')
with gr.Row():
prompt_system = gr.Textbox(label='System prompt', value=self.options.system_prompt, interactive=True, lines=4, elem_id='prompt_enhance_system')
prompt_system = gr.Textbox(label='System prompt', value='', interactive=True, lines=4, elem_id='prompt_enhance_system')
with gr.Accordion('Output', open=True, elem_id='prompt_enhance_system_prompt'):
with gr.Row():
prompt_output = gr.Textbox(label='Enhanced prompt', value='', interactive=True, lines=4)
@@ -449,8 +464,8 @@ class Script(scripts.Script):
copy_btn.click(fn=lambda x: x, inputs=[prompt_output], outputs=[self.prompt])
if self.image is None:
self.image = gr.Image(type='pil', interactive=False, visible=False, width=64, height=64) # dummy image
apply_btn.click(fn=self.apply, inputs=[self.prompt, self.image, apply_prompt, llm_model, prompt_system, prompt_prefix, prompt_suffix, max_tokens, do_sample, temperature, repetition_penalty, thinking_mode], outputs=[prompt_output, self.prompt])
return [self.prompt, self.image, apply_auto, llm_model, prompt_system, prompt_prefix, prompt_suffix, max_tokens, do_sample, temperature, repetition_penalty, thinking_mode]
apply_btn.click(fn=self.apply, inputs=[self.prompt, self.image, apply_prompt, llm_model, prompt_system, prompt_prefix, prompt_suffix, max_tokens, do_sample, temperature, repetition_penalty, thinking_mode, nsfw_mode], outputs=[prompt_output, self.prompt])
return [self.prompt, self.image, apply_auto, llm_model, prompt_system, prompt_prefix, prompt_suffix, max_tokens, do_sample, temperature, repetition_penalty, thinking_mode, nsfw_mode]
def after_component(self, component, **kwargs): # searching for actual ui prompt components
if getattr(component, 'elem_id', '') in ['txt2img_prompt', 'img2img_prompt', 'control_prompt', 'video_prompt']:
@@ -459,7 +474,7 @@ class Script(scripts.Script):
self.image = component
def before_process(self, p: processing.StableDiffusionProcessing, *args, **kwargs): # pylint: disable=unused-argument
_self_prompt, self_image, apply_auto, llm_model, prompt_system, prompt_prefix, prompt_suffix, max_tokens, do_sample, temperature, repetition_penalty, thinking_mode = args
_self_prompt, self_image, apply_auto, llm_model, prompt_system, prompt_prefix, prompt_suffix, max_tokens, do_sample, temperature, repetition_penalty, thinking_mode, nsfw_mode = args
if not apply_auto and not p.enhance_prompt:
return
if shared.state.skipped or shared.state.interrupted:
@@ -481,6 +496,7 @@ class Script(scripts.Script):
temperature=temperature,
penalty=repetition_penalty,
thinking=thinking_mode,
nsfw=nsfw_mode,
)
p.extra_generation_params['LLM'] = llm_model
shared.state.end()