Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add descriptions for individual fields #20

Merged
merged 4 commits into from Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -36,6 +36,7 @@
"autosize": "^6.0.1",
"express": "^4.18.2",
"lodash": "^4.17.21",
"ngx-tippy-wrapper": "^6.3.0",
"ngx-toastr": "^18.0.0",
"ngx-transloco-markup": "^5.1.0",
"rxjs": "~7.8.0",
Expand Down
Expand Up @@ -2,4 +2,5 @@
<input class="toggle-checkbox" type="checkbox" id="input{{random()}}" [checked]="value()" (change)="value.set(input.checked)" #input>
<div class="toggle-switch"></div>
<span class="toggle-label">{{description()}}</span>
<ng-content />
</label>
Expand Up @@ -48,4 +48,5 @@
margin-left: 5px;
position: relative;
top: 2px;
margin-right: 4px;
}
1 change: 1 addition & 0 deletions src/app/components/tooltip/tooltip.component.html
@@ -0,0 +1 @@
<fa-icon [icon]="icon()" [ngxTippy]="text()" />
3 changes: 3 additions & 0 deletions src/app/components/tooltip/tooltip.component.scss
@@ -0,0 +1,3 @@
fa-icon {
cursor: help;
}
19 changes: 19 additions & 0 deletions src/app/components/tooltip/tooltip.component.ts
@@ -0,0 +1,19 @@
import {Component, input, signal} from '@angular/core';
import {faCircleInfo} from "@fortawesome/free-solid-svg-icons";
import {FaIconComponent} from "@fortawesome/angular-fontawesome";
import {NgxTippyModule} from "ngx-tippy-wrapper";

@Component({
selector: 'app-tooltip',
standalone: true,
imports: [
FaIconComponent,
NgxTippyModule
],
templateUrl: './tooltip.component.html',
styleUrl: './tooltip.component.scss'
})
export class TooltipComponent {
public text = input.required<string>();
public icon = signal(faCircleInfo);
}
66 changes: 40 additions & 26 deletions src/app/pages/generate-image/generate-image.component.html
Expand Up @@ -5,7 +5,7 @@
<div class="row">
<div class="col-md-5">
<div class="form-group">
<label for="inputPrompt">{{ 'app.generate.prompt' | transloco }}</label>
<label for="inputPrompt">{{ 'app.generate.prompt' | transloco }} <app-tooltip [text]="'app.generate.help.prompt' | transloco" /></label>
<textarea required type="text" class="form-control" formControlName="prompt" id="inputPrompt" auto-grow></textarea>
<div class="flex">
<button type="button" class="btn mr-05" (click)="openModal(styleModal)">{{'app.generate.use_style' | transloco}}</button>
Expand All @@ -22,16 +22,16 @@
<app-effective-value [value]="modifiedOptions()?.prompt" [original]="form.value.prompt" />
</div>
<div class="form-group">
<label for="inputNegativePrompt">{{ 'app.generate.negative_prompt' | transloco }}</label>
<label for="inputNegativePrompt">{{ 'app.generate.negative_prompt' | transloco }} <app-tooltip [text]="'app.generate.help.negative_prompt' | transloco" /></label>
<textarea type="text" class="form-control" formControlName="negativePrompt" id="inputNegativePrompt" auto-grow></textarea>
<app-effective-value [value]="modifiedOptions()?.negativePrompt" [original]="form.value.negativePrompt" />
</div>
<div class="form-group">
<label for="inputSeed">{{'app.generate.seed' | transloco}}</label>
<label for="inputSeed">{{'app.generate.seed' | transloco}} <app-tooltip [text]="'app.generate.help.seed' | transloco" /></label>
<input type="text" class="form-control" formControlName="seed" id="inputSeed" autocomplete="off" />
</div>
<div class="form-group">
<label for="inputSampler">{{ 'app.generate.sampler' | transloco }}</label>
<label for="inputSampler">{{ 'app.generate.sampler' | transloco }} <app-tooltip [text]="'app.generate.help.sampler' | transloco" /></label>
<select id="inputSampler" formControlName="sampler" required tom-select [maxItems]="1">
@for (enumCase of Sampler | keyvalue; track enumCase.key) {
<option [value]="enumCase.value">{{ enumCase.value }}</option>
Expand All @@ -40,7 +40,7 @@
<app-effective-value [value]="modifiedOptions()?.sampler" [original]="form.value.sampler" />
</div>
<div class="form-group">
<label for="inputModel">{{ 'app.generate.model' | transloco }}</label>
<label for="inputModel">{{ 'app.generate.model' | transloco }} <app-tooltip [text]="'app.generate.help.model' | transloco" /></label>
<select id="inputModel" formControlName="model" required tom-select [maxItems]="1" [maxOptions]="null">
@for (item of groupedModels() | keyvalue; track item.key) {
<optgroup [label]="item.key">
Expand Down Expand Up @@ -106,7 +106,7 @@
}
</div>
<div class="form-group">
<label>{{'app.generate.lora_list' | transloco}}</label>
<label>{{'app.generate.lora_list' | transloco}} <app-tooltip [text]="'app.generate.help.lora_list' | transloco" /></label>
<button [disabled]="(form.value.loraList?.length ?? 0) >= 5" class="btn" type="button"
(click)="openModal(addLoraModal)">{{'app.generate.add_loras' | transloco}}</button>
<ng-template #addLoraModal>
Expand Down Expand Up @@ -136,7 +136,7 @@
}
</div>
<div class="form-group">
<label for="inputFaceFixers">{{'app.generate.face_fixers' | transloco}}</label>
<label for="inputFaceFixers">{{'app.generate.face_fixers' | transloco}} <app-tooltip [text]="'app.generate.help.face_fixers' | transloco" /></label>
<select id="inputFaceFixers" multiple tom-select formControlName="faceFixers">
@for (enumCase of PostProcessor | keyvalue; track enumCase.key) {
@if (enumCase.value | isFaceFixer) {
Expand All @@ -148,12 +148,12 @@
@if (form.value.faceFixers?.length) {
<div class="form-group">
<!--suppress XmlInvalidId -->
<label for="inputFaceFixerStrength">{{ 'app.generate.face_fixer_strength' | transloco }}</label>
<label for="inputFaceFixerStrength">{{ 'app.generate.face_fixer_strength' | transloco }} <app-tooltip [text]="'app.generate.help.face_fixer_strength' | transloco" /></label>
<app-slider-with-value [min]="0" [max]="1" [step]="0.01" formControlName="faceFixerStrength" inputId="inputFaceFixerStrength" />
</div>
}
<div class="form-group">
<label for="inputUpscaler">{{'app.generate.upscaler' | transloco}}</label>
<label for="inputUpscaler">{{'app.generate.upscaler' | transloco}} <app-tooltip [text]="'app.generate.help.upscaler' | transloco" /></label>
<select id="inputUpscaler" tom-select formControlName="upscaler" [maxItems]="1">
<option [value]="null">{{'app.select.empty_option' | transloco}}</option>
@for (enumCase of PostProcessor | keyvalue; track enumCase.key) {
Expand All @@ -164,7 +164,7 @@
</select>
</div>
<div class="form-group">
<label for="inputPostProcessors">{{'app.generate.post_processors' | transloco}}</label>
<label for="inputPostProcessors">{{'app.generate.post_processors' | transloco}} <app-tooltip [text]="'app.generate.help.post_processors' | transloco" /></label>
<select id="inputPostProcessors" multiple tom-select formControlName="genericPostProcessors">
@for (enumCase of PostProcessor | keyvalue; track enumCase.key) {
@if (!(enumCase.value | isFaceFixer) && !(enumCase.value | isUpscaler)) {
Expand All @@ -174,63 +174,77 @@
</select>
</div>
<div class="form-group">
<label for="inputWidth">{{ 'app.generate.width' | transloco }}</label>
<label for="inputWidth">{{ 'app.generate.width' | transloco }} <app-tooltip [text]="'app.generate.help.width' | transloco" /></label>
<input type="number" min="64" max="3072" step="64" formControlName="width" id="inputWidth"
class="form-control"/>
<app-effective-value [value]="modifiedOptions()?.width" [original]="form.value.width" />
</div>
<div class="form-group">
<label for="inputHeight">{{ 'app.generate.height' | transloco }}</label>
<label for="inputHeight">{{ 'app.generate.height' | transloco }} <app-tooltip [text]="'app.generate.help.height' | transloco" /></label>
<input type="number" min="64" max="3072" step="64" formControlName="height" id="inputHeight"
class="form-control"/>
<app-effective-value [value]="modifiedOptions()?.height" [original]="form.value.height" />
</div>
<div class="form-group">
<!-- <div class="form-group">-->
<!--suppress XmlInvalidId -->
<label for="inputDenoisingStrength">{{ 'app.generate.denoising_strength' | transloco }})</label>
<app-slider-with-value [min]="0.01" [max]="1" [step]="0.01" formControlName="denoisingStrength" inputId="inputDenoisingStrength" />
</div>
<!-- <label for="inputDenoisingStrength">{{ 'app.generate.denoising_strength' | transloco }} <app-tooltip [text]="'app.generate.help.denoising_strength' | transloco" /></label>-->
<!-- <app-slider-with-value [min]="0.01" [max]="1" [step]="0.01" formControlName="denoisingStrength" inputId="inputDenoisingStrength" />-->
<!-- </div>-->
<div class="form-group">
<!--suppress XmlInvalidId -->
<label for="inputCfgScale">{{ 'app.generate.cfg_scale' | transloco }}</label>
<label for="inputCfgScale">{{ 'app.generate.cfg_scale' | transloco }} <app-tooltip [text]="'app.generate.help.cfg_scale' | transloco" /></label>
<app-slider-with-value [min]="0" [max]="100" [step]="0.5" formControlName="cfgScale" inputId="inputCfgScale" />
<app-effective-value [value]="modifiedOptions()?.cfgScale" [original]="form.value.cfgScale" />
</div>
<div class="form-group">
<!--suppress XmlInvalidId -->
<label for="inputSteps">{{ 'app.generate.steps' | transloco }}</label>
<label for="inputSteps">{{ 'app.generate.steps' | transloco }} <app-tooltip [text]="'app.generate.help.steps' | transloco" /></label>
<app-slider-with-value [min]="1" [max]="500" [step]="1" formControlName="steps" inputId="inputSteps" />
<app-effective-value [value]="modifiedOptions()?.steps" [original]="form.value.steps" />
</div>
<div class="form-group">
<!--suppress XmlInvalidId -->
<label for="inputClipSkip">{{ 'app.generate.clip_skip' | transloco }}</label>
<label for="inputClipSkip">{{ 'app.generate.clip_skip' | transloco }} <app-tooltip [text]="'app.generate.help.clip_skip' | transloco" /></label>
<app-slider-with-value [min]="1" [max]="12" [step]="1" formControlName="clipSkip" inputId="inputClipSkip" />
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<app-toggle-checkbox [description]="'app.generate.karras' | transloco" formControlName="karras" />
<app-toggle-checkbox [description]="'app.generate.karras' | transloco" formControlName="karras">
<app-tooltip [text]="'app.generate.help.karras' | transloco" />
</app-toggle-checkbox>
</div>
<div class="form-group">
<app-toggle-checkbox [description]="'app.generate.hires_fix' | transloco" formControlName="hiresFix" />
<app-toggle-checkbox [description]="'app.generate.hires_fix' | transloco" formControlName="hiresFix">
<app-tooltip [text]="'app.generate.help.hires_fix' | transloco" />
</app-toggle-checkbox>
</div>
<div class="form-group">
<app-toggle-checkbox [description]="'app.generate.nsfw' | transloco" formControlName="nsfw" />
<app-toggle-checkbox [description]="'app.generate.nsfw' | transloco" formControlName="nsfw">
<app-tooltip [text]="'app.generate.help.nsfw' | transloco" />
</app-toggle-checkbox>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<app-toggle-checkbox [description]="'app.generate.slow_workers' | transloco" formControlName="slowWorkers" />
<app-toggle-checkbox [description]="'app.generate.slow_workers' | transloco" formControlName="slowWorkers">
<app-tooltip [text]="'app.generate.help.slow_workers' | transloco" />
</app-toggle-checkbox>
</div>
<div class="form-group">
<app-toggle-checkbox [description]="'app.generate.censor_nsfw' | transloco" formControlName="censorNsfw" />
<app-toggle-checkbox [description]="'app.generate.censor_nsfw' | transloco" formControlName="censorNsfw">
<app-tooltip [text]="'app.generate.help.censor_nsfw' | transloco" />
</app-toggle-checkbox>
</div>
<div class="form-group">
<app-toggle-checkbox [description]="'app.generate.trusted_workers' | transloco" formControlName="trustedWorkers" />
<app-toggle-checkbox [description]="'app.generate.trusted_workers' | transloco" formControlName="trustedWorkers">
<app-tooltip [text]="'app.generate.help.trusted_workers' | transloco" />
</app-toggle-checkbox>
</div>
<div class="form-group">
<app-toggle-checkbox [description]="'app.generate.allow_downgrade' | transloco" formControlName="allowDowngrade" />
<app-toggle-checkbox [description]="'app.generate.allow_downgrade' | transloco" formControlName="allowDowngrade">
<app-tooltip [text]="'app.generate.help.allow_downgrade' | transloco" />
</app-toggle-checkbox>
</div>
</div>
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/app/pages/generate-image/generate-image.component.ts
Expand Up @@ -63,6 +63,7 @@ import _ from 'lodash';
import {BaselineModel} from "../../types/sd-repo/baseline-model";
import {AutoGrowDirective} from "../../directives/auto-grow.directive";
import {SliderWithValueComponent} from "../../components/slider-with-value/slider-with-value.component";
import {TooltipComponent} from "../../components/tooltip/tooltip.component";

interface Result {
width: number;
Expand Down Expand Up @@ -105,7 +106,8 @@ interface Result {
IsFaceFixerPipe,
IsUpscalerPipe,
AutoGrowDirective,
SliderWithValueComponent
SliderWithValueComponent,
TooltipComponent
],
templateUrl: './generate-image.component.html',
styleUrl: './generate-image.component.scss'
Expand Down
24 changes: 23 additions & 1 deletion src/assets/i18n/en.json
Expand Up @@ -209,5 +209,27 @@
"app.generate.no_commercial": "This model does not allow commercial use, please make sure you only use it in a non-commercial way.",
"app.worker.pause": "Pause worker",
"app.worker.resume": "Resume worker",
"app.lora.broken": "The CivitAI api is currently broken and you can only see the latest version of a LoRa. This needs to be fixed on CivitAI's side and there's nothing we can do."
"app.lora.broken": "The CivitAI api is currently broken and you can only see the latest version of a LoRa. This needs to be fixed on CivitAI's side and there's nothing we can do.",
"app.generate.help.prompt": "{{app.generate.prompt}} is where you describe what you want in the picture. Depending on the model it could be one or multiple sentences or, more commonly with Stable Diffusion, a comma separated list of keywords.",
"app.generate.help.negative_prompt": "Here you can (optionally) describe what you don't want the image to contain. The format is the same as for the {{app.generate.prompt}}. A good starting point is checking the {{app.generate.model}}'s homepage for any instructions by the author.",
"app.generate.help.seed": "The Seed is like a unique ID for your image. If you repeat all the parameters (including the same {{app.generate.seed}}), the AI will generate the same image every time. If you don’t provide a seed, the AI will use a random one, assuring that the image generated will always be unique, even if every other parameter remains the same.",
"app.generate.help.sampler": "Consider the {{app.generate.sampler}} as the engine that powers image generation. It's the technical tool that uses your given instructions to create the image. Different samplers follow different strategies to make this happen. There isn't a one-size-fits-all guide to choosing a sampler, so it's best to experiment and find one that works best for you.",
"app.generate.help.model": "The {{app.generate.model}} essentially shapes what the final image will look like. Each model has been trained with different images, which means they all interpret prompts differently and produce unique results. For the best outcomes, feel free to experiment with various models.",
"app.generate.help.lora_list": "{{app.generate.lora_list}} allow you to tweak the image with capabilities or concepts the base model itself might not have.",
"app.generate.help.face_fixers": "{{app.generate.face_fixers}} are specialized post processors that aim to fix deformed faces in generated images. Only useful if you're generating images of people.",
"app.generate.help.face_fixer_strength": "The strength of the above post processors. Play with the value until you're happy.",
"app.generate.help.upscaler": "A post processor that makes the image a higher resolution by upscaling it.",
"app.generate.help.post_processors": "All other generic post processors that modify the image after it has been generated.",
"app.generate.help.width": "The target width of the image, must be divisible by 64.",
"app.generate.help.height": "The target height of the image, must be divisible by 64.",
"app.generate.help.cfg_scale": "{{app.generate.cfg_scale}} controls how closely the AI follows your prompt. Lower values mean the AI is more creative, while higher values mean it will try to follow your prompt more closely.",
"app.generate.help.steps": "{{app.generate.steps}} controls how many steps the AI takes to generate your image. In each step the image is generated according to your prompt while taking the image from the previous step into account. In simple terms, after each step it tries to improve the previous image to match your prompt more closely. Note that it can also go overboard and make the image worse. Around 20-30 steps is usually the lower threshold for a good image while going above 60 rarely makes sense.",
"app.generate.help.clip_skip": "{{app.generate.clip_skip}} controls how the AI interprets your prompt. In the background your text is converted to a numerical representation that the AI then works with. This parameters allows you to skip some layers, essentially making the prompt different from the point of view of the AI.",
"app.generate.help.karras": "{{app.generate.karras}} improves the sampler with a different noise generating function. I can't think of a simple explanation, sorry. Basically there's no reason to turn it off.",
"app.generate.help.nsfw": "If you check this, only workers that allow NSFW content will be able to pick up your request.",
"app.generate.help.slow_workers": "Toggle whether you want to include slow workers in your request. Costs more kudos if you don't.",
"app.generate.help.censor_nsfw": "Whether you want to censor NSFW images. Sometimes even SFW prompts may lead to NSFW results, this will attempt to censor them.",
"app.generate.help.trusted_workers": "When enabled, only users that are trusted can process your request. Generally not needed.",
"app.generate.help.allow_downgrade": "When enabled, your request can be downgraded to fit within the available criteria if you don't have enough kudos.",
"app.generate.help.hires_fix": "HiRes fix works by generating your image at a lower resolution and then upscaling it."
}
1 change: 1 addition & 0 deletions src/styles.scss
@@ -1,5 +1,6 @@
@import 'ngx-toastr/toastr';
@import 'tom-select/dist/scss/tom-select.default.scss';
@import "tippy.js/dist/tippy.css";

@import "scss/colors";

Expand Down