107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import { Component, inject, signal } from '@angular/core';
|
|
import {
|
|
FormBuilder,
|
|
FormControl,
|
|
FormGroup,
|
|
ReactiveFormsModule,
|
|
Validators,
|
|
} from '@angular/forms';
|
|
import { SseClient } from 'ngx-sse-client';
|
|
import { Spinner } from '../../shared/components/spinner/spinner';
|
|
|
|
@Component({
|
|
selector: 'app-recipe-upload-page',
|
|
imports: [ReactiveFormsModule, Spinner],
|
|
templateUrl: './recipe-upload-page.html',
|
|
styleUrl: './recipe-upload-page.css',
|
|
})
|
|
export class RecipeUploadPage {
|
|
private readonly sseClient = inject(SseClient);
|
|
private readonly formBuilder = inject(FormBuilder);
|
|
|
|
protected readonly sourceRecipeImage = signal<string | null>(null);
|
|
protected readonly inferenceInProgress = signal(false);
|
|
|
|
protected readonly recipeUploadForm = this.formBuilder.group({
|
|
file: this.formBuilder.control<File | null>(null, [Validators.required]),
|
|
});
|
|
|
|
protected readonly recipeForm = new FormGroup({
|
|
title: new FormControl('', [Validators.required]),
|
|
recipeText: new FormControl('', Validators.required),
|
|
});
|
|
|
|
protected onClear() {
|
|
this.recipeUploadForm.reset();
|
|
this.sourceRecipeImage.set(null);
|
|
}
|
|
|
|
protected onFileChange(event: Event) {
|
|
const fileInput = event.target as HTMLInputElement;
|
|
if (fileInput.files && fileInput.files.length) {
|
|
const file = fileInput.files[0];
|
|
this.recipeUploadForm.controls.file.setValue(file);
|
|
this.recipeUploadForm.controls.file.markAsTouched();
|
|
this.recipeUploadForm.controls.file.updateValueAndValidity();
|
|
|
|
// set source image
|
|
this.sourceRecipeImage.set(URL.createObjectURL(file));
|
|
}
|
|
}
|
|
|
|
protected onFileSubmit() {
|
|
const rawValue = this.recipeUploadForm.getRawValue();
|
|
|
|
this.inferenceInProgress.set(true);
|
|
|
|
// upload form data
|
|
const formData = new FormData();
|
|
formData.append('recipeImageFile', rawValue.file!, rawValue.file!.name);
|
|
this.sseClient
|
|
.stream(
|
|
`http://localhost:8080/inferences/recipe-extract-stream`,
|
|
{
|
|
keepAlive: false,
|
|
reconnectionDelay: 1000,
|
|
responseType: 'event',
|
|
},
|
|
{
|
|
body: formData,
|
|
},
|
|
'PUT',
|
|
)
|
|
.subscribe({
|
|
next: (event) => {
|
|
if (event.type === 'error') {
|
|
const errorEvent = event as ErrorEvent;
|
|
console.error(errorEvent.error, errorEvent.message);
|
|
} else {
|
|
const messageEvent = event as MessageEvent;
|
|
const data: { delta: string } = JSON.parse(messageEvent.data);
|
|
this.recipeForm.patchValue({
|
|
recipeText: this.recipeForm.value.recipeText + data.delta,
|
|
});
|
|
|
|
// must do this so we auto-resize the textarea
|
|
document
|
|
.getElementById('recipe-text')
|
|
?.dispatchEvent(new Event('input', { bubbles: true }));
|
|
}
|
|
},
|
|
complete: () => {
|
|
this.inferenceInProgress.set(false);
|
|
},
|
|
});
|
|
}
|
|
|
|
protected onRecipeSubmit() {
|
|
console.log(this.recipeForm.value);
|
|
}
|
|
|
|
protected onRecipeTextChange(event: Event) {
|
|
const textarea = event.target as HTMLTextAreaElement;
|
|
textarea.style.height = 'auto';
|
|
textarea.style.height = textarea.scrollHeight + 'px';
|
|
}
|
|
}
|