-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #231 from BinaryStudioAcademy/task/OV-173-add-azur…
…e-avatar-integration OV-173: add azure avatar integration
- Loading branch information
Showing
53 changed files
with
561 additions
and
59 deletions.
There are no files selected for viewing
89 changes: 89 additions & 0 deletions
89
backend/src/bundles/avatar-videos/avatar-videos.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { type UserGetCurrentResponseDto, ApiPath } from 'shared'; | ||
|
||
import { | ||
type ApiHandlerOptions, | ||
type ApiHandlerResponse, | ||
} from '~/common/controller/controller.js'; | ||
import { BaseController } from '~/common/controller/controller.js'; | ||
import { HttpCode, HTTPMethod } from '~/common/http/http.js'; | ||
import { type Logger } from '~/common/logger/logger.js'; | ||
|
||
import { type AvatarVideoService } from './avatar-videos.service.js'; | ||
import { AvatarVideosApiPath } from './enums/enums.js'; | ||
import { type RenderAvatarVideoRequestDto } from './types/types.js'; | ||
import { renderAvatarVideoValidationSchema } from './validation-schemas/validation-schemas.js'; | ||
|
||
class AvatarVideoController extends BaseController { | ||
private avatarVideoService: AvatarVideoService; | ||
|
||
public constructor(logger: Logger, avatarVideoService: AvatarVideoService) { | ||
super(logger, ApiPath.AVATAR_VIDEO); | ||
|
||
this.avatarVideoService = avatarVideoService; | ||
|
||
this.addRoute({ | ||
path: AvatarVideosApiPath.ROOT, | ||
method: HTTPMethod.POST, | ||
validation: { | ||
body: renderAvatarVideoValidationSchema, | ||
}, | ||
handler: (options) => | ||
this.renderAvatarVideo( | ||
options as ApiHandlerOptions<{ | ||
body: RenderAvatarVideoRequestDto; | ||
}>, | ||
), | ||
}); | ||
} | ||
|
||
/** | ||
* @swagger | ||
* /avatar-video: | ||
* post: | ||
* description: Generate video from text | ||
* security: | ||
* - bearerAuth: [] | ||
* requestBody: | ||
* description: Data for video generation | ||
* required: true | ||
* content: | ||
* application/json: | ||
* schema: | ||
* type: object | ||
* required: [text, voice, avatarName, avatarStyle] | ||
* properties: | ||
* text: | ||
* type: string | ||
* voice: | ||
* type: string | ||
* avatarName: | ||
* type: string | ||
* avatarStyle: | ||
* type: string | ||
* responses: | ||
* 201: | ||
* description: Successful operation | ||
* content: | ||
* application/json: | ||
* schema: | ||
* type: object | ||
* properties: | ||
* id: | ||
* type: string | ||
*/ | ||
private async renderAvatarVideo( | ||
options: ApiHandlerOptions<{ | ||
body: RenderAvatarVideoRequestDto; | ||
}>, | ||
): Promise<ApiHandlerResponse> { | ||
return { | ||
payload: await this.avatarVideoService.renderAvatarVideo({ | ||
...options.body, | ||
userId: (options.user as UserGetCurrentResponseDto).id, | ||
}), | ||
status: HttpCode.CREATED, | ||
}; | ||
} | ||
} | ||
|
||
export { AvatarVideoController }; |
130 changes: 130 additions & 0 deletions
130
backend/src/bundles/avatar-videos/avatar-videos.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { HttpCode, HttpError } from 'shared'; | ||
import { v4 as uuidv4 } from 'uuid'; | ||
|
||
import { type AzureAIService } from '~/common/services/azure-ai/azure-ai.service.js'; | ||
import { type FileService } from '~/common/services/file/file.service.js'; | ||
|
||
import { type VideoService } from '../videos/video.service.js'; | ||
import { REQUEST_DELAY } from './constants/constnats.js'; | ||
import { | ||
GenerateAvatarResponseStatus, | ||
RenderVideoErrorMessage, | ||
} from './enums/enums.js'; | ||
import { getFileName } from './helpers/helpers.js'; | ||
import { | ||
type RenderAvatarResponseDto, | ||
type RenderAvatarVideoRequestDto, | ||
} from './types/types.js'; | ||
|
||
type HandleRenderVideoArguments = { | ||
id: string; | ||
userId: string; | ||
url: string; | ||
}; | ||
|
||
class AvatarVideoService { | ||
private azureAIService: AzureAIService; | ||
private fileService: FileService; | ||
private videoService: VideoService; | ||
|
||
public constructor( | ||
azureAIService: AzureAIService, | ||
fileService: FileService, | ||
videoService: VideoService, | ||
) { | ||
this.azureAIService = azureAIService; | ||
this.fileService = fileService; | ||
this.videoService = videoService; | ||
} | ||
|
||
private async saveAvatarVideo(url: string, id: string): Promise<string> { | ||
const buffer = await this.azureAIService.getAvatarVideoBuffer(url); | ||
|
||
const fileName = getFileName(id); | ||
|
||
await this.fileService.uploadFile(buffer, fileName); | ||
return this.fileService.getCloudFrontFileUrl(fileName); | ||
} | ||
|
||
public async renderAvatarVideo( | ||
payload: RenderAvatarVideoRequestDto & { userId: string }, | ||
): Promise<RenderAvatarResponseDto> { | ||
const { userId, ...avatarConfig } = payload; | ||
const response = await this.azureAIService.renderAvatarVideo({ | ||
id: uuidv4(), | ||
payload: avatarConfig, | ||
}); | ||
|
||
this.checkAvatarProcessing(response.id, userId); | ||
|
||
return response; | ||
} | ||
|
||
private checkAvatarProcessing(id: string, userId: string): void { | ||
const interval = setInterval((): void => { | ||
this.azureAIService | ||
.getAvatarVideo(id) | ||
.then((response) => { | ||
if ( | ||
response.status === | ||
GenerateAvatarResponseStatus.SUCCEEDED | ||
) { | ||
this.handleSuccessfulAvatarGeneration({ | ||
id, | ||
userId, | ||
url: response.outputs.result, | ||
}) | ||
.then(() => { | ||
// TODO: NOTIFY USER | ||
}) | ||
.catch((error) => { | ||
throw new HttpError({ | ||
message: error.message, | ||
status: error.status, | ||
}); | ||
}) | ||
.finally(() => { | ||
clearInterval(interval); | ||
}); | ||
} else if ( | ||
response.status === GenerateAvatarResponseStatus.FAILED | ||
) { | ||
// TODO: NOTIFY USER | ||
clearInterval(interval); | ||
} | ||
}) | ||
.catch((error) => { | ||
clearInterval(interval); | ||
throw new HttpError({ | ||
message: error.message, | ||
status: error.status, | ||
}); | ||
}); | ||
}, REQUEST_DELAY); | ||
} | ||
|
||
private async handleSuccessfulAvatarGeneration({ | ||
id, | ||
url, | ||
userId, | ||
}: HandleRenderVideoArguments): Promise<void> { | ||
const savedUrl = await this.saveAvatarVideo(url, id); | ||
|
||
const videoData = await this.videoService.create({ | ||
name: getFileName(id), | ||
url: savedUrl, | ||
userId, | ||
}); | ||
|
||
if (!videoData) { | ||
throw new HttpError({ | ||
message: RenderVideoErrorMessage.NOT_SAVED, | ||
status: HttpCode.BAD_REQUEST, | ||
}); | ||
} | ||
|
||
await this.azureAIService.removeAvatarVideo(id); | ||
} | ||
} | ||
|
||
export { AvatarVideoService }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { logger } from '~/common/logger/logger.js'; | ||
import { azureAIService, fileService } from '~/common/services/services.js'; | ||
|
||
import { videoService } from '../videos/videos.js'; | ||
import { AvatarVideoController } from './avatar-videos.controller.js'; | ||
import { AvatarVideoService } from './avatar-videos.service.js'; | ||
|
||
const avatarVideoService = new AvatarVideoService( | ||
azureAIService, | ||
fileService, | ||
videoService, | ||
); | ||
|
||
const avatarVideoController = new AvatarVideoController( | ||
logger, | ||
avatarVideoService, | ||
); | ||
|
||
export { avatarVideoController }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { REQUEST_DELAY } from './request-delay.constant.js'; |
3 changes: 3 additions & 0 deletions
3
backend/src/bundles/avatar-videos/constants/request-delay.constant.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
const REQUEST_DELAY = 4000; | ||
|
||
export { REQUEST_DELAY }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { GenerateAvatarResponseStatus } from './generate-avatar-response-status.enum.js'; | ||
export { RenderVideoErrorMessage } from './render-video-error-message.enum.js'; | ||
export { AvatarVideosApiPath } from 'shared'; |
6 changes: 6 additions & 0 deletions
6
backend/src/bundles/avatar-videos/enums/generate-avatar-response-status.enum.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
const GenerateAvatarResponseStatus = { | ||
SUCCEEDED: 'Succeeded', | ||
FAILED: 'Failed', | ||
} as const; | ||
|
||
export { GenerateAvatarResponseStatus }; |
6 changes: 6 additions & 0 deletions
6
backend/src/bundles/avatar-videos/enums/render-video-error-message.enum.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
const RenderVideoErrorMessage = { | ||
NOT_FOUND: 'Video not found', | ||
NOT_SAVED: 'Video was not saved', | ||
} as const; | ||
|
||
export { RenderVideoErrorMessage }; |
5 changes: 5 additions & 0 deletions
5
backend/src/bundles/avatar-videos/helpers/get-file-name.helper.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const getFileName = (id: string): string => { | ||
return `${id}.webm`; | ||
}; | ||
|
||
export { getFileName }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { getFileName } from './get-file-name.helper.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export { | ||
type RenderAvatarResponseDto, | ||
type RenderAvatarVideoRequestDto, | ||
} from 'shared'; |
1 change: 1 addition & 0 deletions
1
backend/src/bundles/avatar-videos/validation-schemas/validation-schemas.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { renderAvatarVideoValidationSchema } from 'shared'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.