Skip to content

Commit

Permalink
Feat: Display LoRAs when browsing styles
Browse files Browse the repository at this point in the history
  • Loading branch information
RikudouSage committed Mar 28, 2024
1 parent 22bbb51 commit d84859d
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h2>{{ 'app.prompt_style.choose' | transloco }}</h2>
<app-box [collapsible]="true" [title]="category">
@for (style of stylesByCategory()[category]; track style.name) {
<div class="prompt-style">
<div class="card mb-1" [class.collapsed]="collapsed()[style.name] ?? true">
<div class="card mb-1" [class.collapsed]="collapsed()[style.name] ?? true" (click)="loadLoraNames(style)">
<div class="card-header cursor-pointer" (click)="toggleCollapsed(style)">
<div class="prompt-style-name">{{ style.name }}</div>
<div class="prompt-style-model">{{ 'app.generate.model' | transloco }}: {{ style.model }}</div>
Expand All @@ -26,6 +26,18 @@ <h2>{{ 'app.prompt_style.choose' | transloco }}</h2>
<app-prompt-style-text [originalPrompt]="originalNegativePrompt() ?? ''" [stylePrompt]="style.prompt" [negative]="true" />
<br>

@if (style.loras?.length) {
<strong>{{'app.generate.lora_list' | transloco}}</strong>:
@if (loraNames()[style.name]?.length) {
<ul>
@for (lora of loraNames()[style.name]!; track lora) {
<li>{{lora}}</li>
}
</ul>
}
<br>
}

<button class="btn btn-primary mt-1" (click)="useStyle(style)">{{'app.prompt_style.use' | transloco}}</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import {TranslocoPipe} from "@ngneat/transloco";
import {BoxComponent} from "../box/box.component";
import {PromptStyleTextComponent} from "../prompt-style-text/prompt-style-text.component";
import {ModalService} from "../../services/modal.service";
import {LoraNamePipe} from "../../pipes/lora-name.pipe";
import {AsyncPipe} from "@angular/common";
import {CivitAiService} from "../../services/civit-ai.service";
import {catchError, map, Observable, of, tap} from "rxjs";
import {CivitAiModel} from "../../types/civit-ai/civit-ai-model";
import {TranslatorService} from "../../services/translator.service";

@Component({
selector: 'app-prompt-style-modal',
Expand All @@ -15,12 +21,16 @@ import {ModalService} from "../../services/modal.service";
LoaderComponent,
TranslocoPipe,
BoxComponent,
PromptStyleTextComponent
PromptStyleTextComponent,
LoraNamePipe,
AsyncPipe
],
templateUrl: './prompt-style-modal.component.html',
styleUrl: './prompt-style-modal.component.scss'
})
export class PromptStyleModalComponent implements OnInit {
private loraNameCache: Record<string, CivitAiModel> = {};

public originalPrompt = input.required<string>();
public originalNegativePrompt = input.required<string | null>();

Expand All @@ -41,11 +51,15 @@ export class PromptStyleModalComponent implements OnInit {
public collapsed = signal<{[style:string]: boolean | undefined}>({});
public loading = signal(true);

public loraNames = signal<Record<string, string[] | undefined>>({});

public styleChosen = output<EnrichedPromptStyle>();

constructor(
private readonly repoData: HordeRepoDataService,
private readonly modalService: ModalService,
private readonly civitAi: CivitAiService,
private readonly translator: TranslatorService,
) {
}

Expand All @@ -65,4 +79,36 @@ export class PromptStyleModalComponent implements OnInit {
this.styleChosen.emit(style);
await this.modalService.close();
}

public async loadLoraNames(style: EnrichedPromptStyle) {
const promises: Promise<string>[] = [];
for (const lora of (style.loras ?? [])) {
let observable: Observable<CivitAiModel>;
const cacheKey = lora.name + String(lora.is_version ?? false);
if (this.loraNameCache[cacheKey]) {
observable = of(this.loraNameCache[cacheKey]);
} else {
if (lora.is_version) {
observable = this.civitAi.getLoraByVersion(Number(lora.name));
} else {
observable = this.civitAi.getLoraDetail(Number(lora.name));
}
observable = observable.pipe(
tap (lora => this.loraNameCache[cacheKey] = lora),
);
}

promises.push(toPromise(observable.pipe(
map (lora => lora.name),
catchError(() => this.translator.get('app.lora.unknown')),
)));
}

const result = await Promise.all(promises);
this.loraNames.update(loraNames => {
loraNames[style.name] = result;

return {...loraNames};
});
}
}
3 changes: 2 additions & 1 deletion src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,5 +210,6 @@
"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.generate.style_name": "Style name"
"app.generate.style_name": "Style name",
"app.lora.unknown": "Unknown LoRA (failed to fetch from CivitAI)"
}

0 comments on commit d84859d

Please sign in to comment.