Add - Classe Gemini, endpoint de criacao de video

This commit is contained in:
LeoMortari
2025-10-03 00:59:51 -03:00
parent f7857fdcbc
commit 558a625f11
13 changed files with 182 additions and 92 deletions

View File

@@ -1,44 +0,0 @@
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { OllamaService } from './ollama.service';
import { ChatDto } from './dto/chat.dto';
@Controller('ollama')
export class OllamaController {
constructor(private readonly ollamaService: OllamaService) {}
@Get('models')
public async getModels(
@Query('onlyChats') { onlyChats }: { onlyChats: boolean },
) {
return await this.ollamaService.getModels({ onlyChats });
}
@Post('chat')
public async chat(@Body() body: ChatDto) {
const { message, model } = body;
if (!message) {
throw new Error('O atributo message é obrigatório');
}
if (!model) {
const [defaultModel] = await this.ollamaService.getModels({
onlyChats: true,
});
if (!defaultModel) {
throw new Error('Nenhum modelo encontrado');
}
return await this.ollamaService.generateChat({
model: defaultModel.name,
message,
});
}
return await this.ollamaService.generateChat({
model,
message,
});
}
}

View File

@@ -1,9 +1,7 @@
import { Module } from '@nestjs/common';
import { OllamaController } from './ollama.controller';
import { OllamaService } from './ollama.service';
@Module({
controllers: [OllamaController],
providers: [OllamaService],
})
export class OllamaModule {}

View File

@@ -1,34 +1,35 @@
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';
import { Transform } from 'class-transformer';
import {
IsEnum,
IsInt,
IsISO8601,
IsArray,
IsNumber,
IsOptional,
IsString,
IsUrl,
MaxLength,
} from 'class-validator';
import { video_situation } from '@root/generated/prisma';
dayjs.extend(duration);
export class CreateVideoDto {
@IsOptional()
@IsString({ message: 'Id deve ser uma string' })
@MaxLength(244)
id?: string;
@IsOptional()
@IsArray({ message: 'Tags deve ser um array' })
tags?: string[];
@IsUrl()
@MaxLength(244)
url!: string;
@IsOptional()
@IsEnum(video_situation)
situation?: video_situation;
@IsOptional()
@IsString()
@MaxLength(244)
error_message?: string;
@IsOptional()
@IsInt()
clips_quantity?: number;
@IsOptional()
times?: unknown;
@IsArray({ message: 'Categories deve ser um array' })
categories?: string[];
@IsOptional()
@IsString()
@@ -36,24 +37,38 @@ export class CreateVideoDto {
title?: string;
@IsOptional()
@IsString()
@IsUrl()
@MaxLength(244)
filename?: string;
thumbnail?: string;
@IsOptional()
@IsString()
@IsString({ message: 'Videoid deve ser uma string' })
@MaxLength(244)
videoid?: string;
@IsOptional()
@IsISO8601()
datetime_download?: string;
@IsString({ message: 'Duration deve ser uma string' })
@Transform(({ value }: { value: number }) => {
const duration = dayjs.duration(value, 'seconds');
return duration.format('HH:mm:ss');
})
duration?: string;
@IsOptional()
@IsISO8601()
datetime_convert?: string;
@IsString()
@MaxLength(244)
description?: string;
@IsOptional()
@IsISO8601()
datetime_posted?: string;
@IsNumber(
{ allowNaN: false, allowInfinity: false },
{ message: 'Timestamp deve ser um número' },
)
@Transform(({ value }: { value: number }) => {
const duration = dayjs(value * 1000);
return duration.format('DD/MM/YYYY HH:mm:ss');
})
timestamp?: string;
}

View File

@@ -7,27 +7,20 @@ import {
Body,
Delete,
UseGuards,
Post,
} from '@nestjs/common';
import { Prisma, videos, video_situation } from 'generated/prisma';
import { VideosService } from './videos.service';
import { VideoResponseDto } from './dto/video-response.dto';
import { KeycloakAuthGuard } from '../auth/keycloak-auth.guard';
import { Roles } from '../auth/decorator/roles.decorator';
import { ListVideosQueryDto } from './dto/list-videos-query.dto';
import { VideoMetadataDto } from 'src/shared/dto/video-metadata';
import { KeycloakAuthGuard } from '@modules/auth/keycloak-auth.guard';
import { Roles } from '@modules/auth/decorator/roles.decorator';
import { VideoMetadataDto } from '@shared/dto/video-metadata';
type PaginatedResponse<T> = {
content: T[];
pagination: {
page: number;
perPage: number;
total: number;
totalPages: number;
hasNext: boolean;
hasPrev: boolean;
};
};
import { ListVideosQueryDto } from './dto/list-videos-query.dto';
import { VideoResponseDto } from './dto/video-response.dto';
import { VideosService } from './videos.service';
import type { PaginatedResponse } from '@shared/types/pagination';
import { CreateVideoDto } from './dto/create-video-dto';
@Controller('videos')
@UseGuards(KeycloakAuthGuard)
@@ -63,6 +56,12 @@ export class VideosController {
});
}
@Post()
@Roles('user', 'admin')
async create(@Body() body: CreateVideoDto): Promise<void> {
await this.videosService.createNewVideo(body);
}
@Get(':id')
async get(@Param('id') id: string): Promise<videos | null> {
return this.videosService.get(Number(id));

View File

@@ -1,4 +1,6 @@
import axios from 'axios';
import isEmpty from 'lodash/isEmpty';
import { Injectable } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
@@ -9,6 +11,7 @@ import { VideoResponseDto } from './dto/video-response.dto';
import { PaginatedResponse } from '@shared/dto/paginated';
import { ListVideosQueryDto } from './dto/list-videos-query.dto';
import { VideoMetadataDto } from '@shared/dto/video-metadata';
import { CreateVideoDto } from './dto/create-video-dto';
@Injectable()
export class VideosService {
@@ -133,6 +136,20 @@ export class VideosService {
}
}
async createNewVideo(data: CreateVideoDto): Promise<void> {
const { url, videoid } = data;
const searchUrl = await this.prisma.videos.findFirst({
where: { url, videoid },
});
if (!isEmpty(searchUrl)) {
throw new Error(
`Esta video já foi renderizado, e se encontra na situação ${searchUrl.situation}`,
);
}
}
async update(id: number, data: Prisma.videosUpdateInput): Promise<videos> {
return this.prisma.videos.update({
where: { id },