Add new components for AI and tutorials, update routing, and enhance file upload functionality

This commit is contained in:
liosha84
2025-08-04 10:38:46 +03:00
parent 18c6906637
commit 483d029952
206 changed files with 2362 additions and 1199 deletions
@@ -0,0 +1 @@
<router-outlet></router-outlet>
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AiMainComponent } from './ai-main.component';
describe('AiMainComponent', () => {
let component: AiMainComponent;
let fixture: ComponentFixture<AiMainComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AiMainComponent]
})
.compileComponents();
fixture = TestBed.createComponent(AiMainComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import {RouterOutlet} from '@angular/router';
@Component({
selector: 'app-ai-main.component',
imports: [
RouterOutlet
],
templateUrl: './ai-main.component.html',
styleUrl: './ai-main.component.scss'
})
export class AiMainComponent {
}
@@ -0,0 +1 @@
<p>ai-welcome.component works!</p>
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AiWelcomeComponent } from './ai-welcome.component';
describe('AiWelcomeComponent', () => {
let component: AiWelcomeComponent;
let fixture: ComponentFixture<AiWelcomeComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AiWelcomeComponent]
})
.compileComponents();
fixture = TestBed.createComponent(AiWelcomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-ai-welcome.component',
imports: [],
templateUrl: './ai-welcome.component.html',
styleUrl: './ai-welcome.component.scss'
})
export class AiWelcomeComponent {
}
@@ -0,0 +1,21 @@
import {NgModule} from '@angular/core';
import {moderatorRouting} from '../moderator-module/moderator.routing';
import {ModeratorComponent} from '../moderator-module/moderator.component/moderator.component';
import {CommonModule} from '@angular/common';
import {AiWelcomeComponent} from './ai-welcome.component/ai-welcome.component';
import {AiMainComponent} from './ai-main.component/ai-main.component';
import {aiRouting} from './ai.routing';
import {MatDialogModule} from "@angular/material/dialog";
@NgModule({
declarations: [],
imports: [
aiRouting,
AiMainComponent,
CommonModule,
MatDialogModule
]
})
export class AiModule { }
@@ -0,0 +1,22 @@
import {RouterModule, Routes} from '@angular/router';
import {AiMainComponent} from './ai-main.component/ai-main.component';
const AI_ROUTES: Routes = [
{
path: '',
component: AiMainComponent,
children: [
{
path: 'ai-welcome',
loadComponent: () => import('../ai-module/ai-welcome.component/ai-welcome.component').then((c) => c.AiWelcomeComponent),
},
{
path: 'generate-image',
loadComponent: () => import('../ai-module/generate-image.component/generate-image.component').then((c) => c.GenerateImageComponent)
}
]
}
];
export const aiRouting = RouterModule.forChild(AI_ROUTES);
@@ -0,0 +1,49 @@
<div class="generate-image-view">
<mat-card appearance="outlined">
<mat-card-header>
<mat-card-title>Generate image</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-form-field class="example-full-width">
<mat-label>Query</mat-label>
<input matInput required
[(ngModel)]="query">
</mat-form-field>
</mat-card-content>
<mat-card-actions>
@if (spinnerService.visibility | async) {
<mat-spinner [diameter]="25" ></mat-spinner>
} @else {
<button matButton (click)="generateImage()" >Generate</button>
}
</mat-card-actions>
</mat-card>
@for (image of images; track image) {
<mat-card>
<mat-card-header>
<div class="image-container">
<img src="{{image.url}}"
alt="" width="100%" height="100%">
<mat-toolbar class="image-toolbar">
<mat-toolbar-row>
<span class="menu-spacer"></span>
<!-- <button matMiniFab matTooltip="Dawnload image" aria-label="Download" (click)="downloadImage(image.url)">
<mat-icon>download</mat-icon>
</button>-->
@if (isLoggedIn) {
<button matMiniFab matTooltip="Save to server" aria-label="Save" (click)="save(image.url)" >
<mat-icon>upload_file</mat-icon>
</button>
}
</mat-toolbar-row>
</mat-toolbar>
</div>
</mat-card-header>
<mat-card-content>
</mat-card-content>
</mat-card>
}
</div>
@@ -0,0 +1,42 @@
.generate-image-view {
margin-right: 12px;
padding: 20px 22px 18px 22px;
margin-top: 81px;
margin-left: 12px;
background-color: #e7edf3c2;
backdrop-filter: blur(8px);
}
.image-container{
width: 100%;
height: 100%;
}
.image-container .image-toolbar
{
background-color: rgba(153,153,153,0);
color: white;
position: absolute;
left : 50%;
top: 5%;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
padding: 0px 2px;
border: none;
border-radius: 5px;
}
.image-container .menu-spacer {
flex: 1 1 auto;
}
.image-container .image-file-name {
padding-left: 10px;
}
.mat-mdc-mini-fab{
margin: 5px;
}
.example-full-width {
width: 100%;
}
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GenerateImageComponent } from './generate-image.component';
describe('GenerateImageComponent', () => {
let component: GenerateImageComponent;
let fixture: ComponentFixture<GenerateImageComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [GenerateImageComponent]
})
.compileComponents();
fixture = TestBed.createComponent(GenerateImageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,126 @@
import {Component, CUSTOM_ELEMENTS_SCHEMA, Inject, inject, Renderer2} from '@angular/core';
import {AsyncPipe, DOCUMENT, NgOptimizedImage} from "@angular/common";
import {FormsModule} from "@angular/forms";
import {MatButton, MatMiniFabButton} from "@angular/material/button";
import {
MatCard,
MatCardActions,
MatCardContent,
MatCardHeader,
MatCardImage,
MatCardXlImage
} from "@angular/material/card";
import {MatFormField, MatInput, MatLabel} from "@angular/material/input";
import {Image} from '../../../models/image';
import {ZhipuaiImageService} from '../zhipuai-image.service';
import {SpinnerService} from '../../../services/spinner.service';
import {MatProgressSpinner} from '@angular/material/progress-spinner';
import {FileUploadService} from '../../../services/file-upload-api.service';
import {Observable, Subscription} from 'rxjs';
import {HttpClient, HttpResponse} from '@angular/common/http';
import {MatToolbar, MatToolbarRow} from '@angular/material/toolbar';
import {MatIcon} from '@angular/material/icon';
import {MatTooltip} from '@angular/material/tooltip';
import {AuthService} from '../../../services/auth.service';
import {TokenStorageService} from '../../../services/token-storage.service';
import {FileInfo} from '../../../models/file-info';
import {UserApiService} from '../../user-module/user-api.service';
import {MatProgressBar} from '@angular/material/progress-bar';
@Component({
selector: 'app-generate-image.component',
imports: [
AsyncPipe,
FormsModule,
MatButton,
MatCard,
MatCardActions,
MatCardContent,
MatCardHeader,
MatFormField,
MatInput,
MatLabel,
MatProgressSpinner,
NgOptimizedImage,
MatCardXlImage,
MatCardImage,
MatToolbarRow,
MatToolbar,
MatIcon,
MatMiniFabButton,
MatTooltip,
MatProgressBar
],
templateUrl: './generate-image.component.html',
styleUrl: './generate-image.component.scss',
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class GenerateImageComponent {
isSpinnerVisible = false;
query : string = '';
images: Image[] = [];
image: Image = {
url: ''
};
currentFile?: File;
message = '';
isLoggedIn = false;
private storageService: TokenStorageService = inject(TokenStorageService);
constructor(
private zhipuaiImageService: ZhipuaiImageService,
public spinnerService: SpinnerService,
private uploadService: FileUploadService,
private userApiService:UserApiService,
) {
this.isLoggedIn = this.storageService.isLoggedIn();
}
generateImage(){
this.zhipuaiImageService.generate(this.query).subscribe(
data => {
this.image = data;
this.images.unshift(this.image);
// this.output.file = data.;
console.log(data);
},
error => {
console.log(error);
}
)
}
save(url: string | undefined) {
let requestUrl:string = url?url:"";
console.log(requestUrl);
this.userApiService.saveZhipuaiImage(requestUrl).subscribe(data =>{
console.log(data);
},error =>{
console.log(error);
});
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { ZhipuaiImageService } from './zhipuai-image.service';
describe('ZhipuaiImageService', () => {
let service: ZhipuaiImageService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ZhipuaiImageService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,26 @@
import { Injectable } from '@angular/core';
import {Observable} from 'rxjs';
import {Tutorial} from '../../models/tutorial.model';
import {HttpClient} from '@angular/common/http';
import {Image} from '../../models/image';
import {SpinnerService} from '../../services/spinner.service';
import {GlobalConstants} from '../../global-constants';
@Injectable({
providedIn: 'root'
})
export class ZhipuaiImageService {
baseUrl : string = `${GlobalConstants.API_URL}/public/zhipuai`;
constructor(private http: HttpClient,public spinnerService: SpinnerService) {
}
generate(query: String): Observable<Image> {
return this.http.get(`${(this.baseUrl)}/image/${query}`);
}
}