Skip to content

Commit ba1cf2a

Browse files
authored
Merge pull request #34 from topcoder-platform/pm-1793
feat(PM-1793): Create AI workflow api implementation
2 parents 5178c02 + 8915092 commit ba1cf2a

File tree

5 files changed

+137
-0
lines changed

5 files changed

+137
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Controller, Post, Body } from '@nestjs/common';
2+
import {
3+
ApiBearerAuth,
4+
ApiTags,
5+
ApiOperation,
6+
ApiResponse,
7+
} from '@nestjs/swagger';
8+
import { AiWorkflowService } from './ai-workflow.service';
9+
import { CreateAiWorkflowDto } from '../../dto/aiWorkflow.dto';
10+
import { Scopes } from 'src/shared/decorators/scopes.decorator';
11+
import { UserRole } from 'src/shared/enums/userRole.enum';
12+
import { Scope } from 'src/shared/enums/scopes.enum';
13+
import { Roles } from 'src/shared/guards/tokenRoles.guard';
14+
15+
@ApiTags('ai_workflow')
16+
@ApiBearerAuth()
17+
@Controller('/workflows')
18+
export class AiWorkflowController {
19+
constructor(private readonly aiWorkflowService: AiWorkflowService) {}
20+
21+
@Post()
22+
@Roles(UserRole.Admin)
23+
@Scopes(Scope.CreateWorkflow)
24+
@ApiOperation({ summary: 'Create a new AI workflow' })
25+
@ApiResponse({
26+
status: 201,
27+
description: 'The AI workflow has been successfully created.',
28+
})
29+
@ApiResponse({ status: 403, description: 'Forbidden.' })
30+
async create(@Body() createAiWorkflowDto: CreateAiWorkflowDto) {
31+
return this.aiWorkflowService.createWithValidation(createAiWorkflowDto);
32+
}
33+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Injectable, BadRequestException } from '@nestjs/common';
2+
import { PrismaService } from '../../shared/modules/global/prisma.service';
3+
import { CreateAiWorkflowDto } from '../../dto/aiWorkflow.dto';
4+
import { ScorecardStatus } from 'src/dto/scorecard.dto';
5+
6+
@Injectable()
7+
export class AiWorkflowService {
8+
constructor(private readonly prisma: PrismaService) {}
9+
10+
async scorecardExists(scorecardId: string): Promise<boolean> {
11+
const count = await this.prisma.scorecard.count({
12+
where: { id: scorecardId, status: ScorecardStatus.ACTIVE },
13+
});
14+
return count > 0;
15+
}
16+
17+
async llmModelExists(llmId: string): Promise<boolean> {
18+
const count = await this.prisma.llmModel.count({
19+
where: { id: llmId },
20+
});
21+
return count > 0;
22+
}
23+
24+
async createWithValidation(createAiWorkflowDto: CreateAiWorkflowDto) {
25+
const { scorecardId, llmId, name, description, defUrl, gitId, gitOwner } =
26+
createAiWorkflowDto;
27+
28+
const scorecardExists = await this.scorecardExists(scorecardId);
29+
if (!scorecardExists) {
30+
throw new BadRequestException(
31+
`Scorecard with id ${scorecardId} does not exist or is not active.`,
32+
);
33+
}
34+
35+
const llmExists = await this.llmModelExists(llmId);
36+
if (!llmExists) {
37+
throw new BadRequestException(
38+
`LLM model with id ${llmId} does not exist.`,
39+
);
40+
}
41+
42+
return this.prisma.aiWorkflow.create({
43+
data: {
44+
defUrl,
45+
description,
46+
gitId,
47+
gitOwner,
48+
name,
49+
scorecardId,
50+
llmId,
51+
// TODO: This has to be removed once the prisma middleware is implemented
52+
createdBy: '',
53+
updatedAt: '',
54+
updatedBy: '',
55+
},
56+
});
57+
}
58+
}

src/api/api.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { WebhookController } from './webhook/webhook.controller';
2525
import { WebhookService } from './webhook/webhook.service';
2626
import { GiteaWebhookAuthGuard } from '../shared/guards/gitea-webhook-auth.guard';
2727
import { ScoreCardService } from './scorecard/scorecard.service';
28+
import { AiWorkflowService } from './ai-workflow/ai-workflow.service';
29+
import { AiWorkflowController } from './ai-workflow/ai-workflow.controller';
2830

2931
@Module({
3032
imports: [HttpModule, GlobalProvidersModule, FileUploadModule],
@@ -42,6 +44,7 @@ import { ScoreCardService } from './scorecard/scorecard.service';
4244
ReviewApplicationController,
4345
ReviewHistoryController,
4446
WebhookController,
47+
AiWorkflowController,
4548
],
4649
providers: [
4750
ReviewOpportunityService,
@@ -53,6 +56,7 @@ import { ScoreCardService } from './scorecard/scorecard.service';
5356
ScoreCardService,
5457
SubmissionService,
5558
ReviewSummationService,
59+
AiWorkflowService,
5660
],
5761
})
5862
export class ApiModule {}

src/dto/aiWorkflow.dto.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { IsString, IsNotEmpty } from 'class-validator';
3+
4+
export class CreateAiWorkflowDto {
5+
@ApiProperty()
6+
@IsString()
7+
@IsNotEmpty()
8+
name: string;
9+
10+
@ApiProperty()
11+
@IsString()
12+
@IsNotEmpty()
13+
llmId: string;
14+
15+
@ApiProperty()
16+
@IsString()
17+
@IsNotEmpty()
18+
description: string;
19+
20+
@ApiProperty()
21+
@IsString()
22+
@IsNotEmpty()
23+
defUrl: string;
24+
25+
@ApiProperty()
26+
@IsString()
27+
@IsNotEmpty()
28+
gitId: string;
29+
30+
@ApiProperty()
31+
@IsString()
32+
@IsNotEmpty()
33+
gitOwner: string;
34+
35+
@ApiProperty()
36+
@IsString()
37+
@IsNotEmpty()
38+
scorecardId: string;
39+
}

src/shared/enums/scopes.enum.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export enum Scope {
6363
UpdateSubmission = 'update:submission',
6464
DeleteSubmission = 'delete:submission',
6565
AllSubmission = 'all:submission',
66+
67+
// AI workflow scopes
68+
CreateWorkflow = 'create:workflow',
6669
}
6770

6871
/**

0 commit comments

Comments
 (0)