Skip to content

Commit

Permalink
Merge pull request #1136 from AletheiaFact/create-fact-check-agents
Browse files Browse the repository at this point in the history
Automated Fact-checking Report MVP
  • Loading branch information
thesocialdev authored Apr 11, 2024
2 parents f4070d9 + d66fc31 commit a437721
Show file tree
Hide file tree
Showing 30 changed files with 614 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

# misc
.DS_Store
/**/*/._.DS_Store
.env.local
.env.development.local
.env.test.local
Expand Down
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
yarn lint-staged
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified .yarn/install-state.gz
Binary file not shown.
2 changes: 2 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ services:
port: 3000
cors: '*'
debug: true
websocketUrl: ws://localhost:5001
agentsUrl: http://localhost:8000
#override_public_routes: true
recaptcha_secret: RECAPTCHA_SECRET
recaptcha_sitekey: 6Lc2BtYUAAAAAOUBI-9r1sDJUIfG2nt6C43noOXh
Expand Down
1 change: 1 addition & 0 deletions cypress/e2e/tests/review.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe("Test claim review", () => {
it("should be able to assign a user", () => {
cy.login();
goToClaimReviewPage();
cy.checkRecaptcha();
cy.get(locators.claimReview.BTN_START_CLAIM_REVIEW)
.should("exist")
.click();
Expand Down
32 changes: 32 additions & 0 deletions newrelic_agent.log

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion public/locales/en/claimReviewForm.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,12 @@
"rejectionCommentLabel": "Rejection comment",
"rejectionCommentPlaceholder": "Describe what needs to be changed",
"loginButton": "Login to continue",
"notReviewed": "Not reviewed"
"notReviewed": "Not reviewed",
"addAgentReview": "Add AI review",
"agentInputText": "Fact-check the following claim: {{sentence}}, provide the answer in English.",
"addAgentReviewModalTitle": "Generating fact-checking report",
"agentLoadingThoughts": "Thinking...",
"agentFinishedThoughts": "Finished.",
"agentFinishedReport": "Report generated",
"submitAgentReview": "Submit generated report"
}
9 changes: 8 additions & 1 deletion public/locales/pt/claimReviewForm.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,12 @@
"rejectionCommentLabel": "Comentário de rejeição",
"rejectionCommentPlaceholder": "Descreva o que precisa ser alterado",
"loginButton": "Faça login para continuar",
"notReviewed": "Não revisado"
"notReviewed": "Não revisado",
"addAgentReview": "Adicionar checagem por IA",
"agentInputText": "Faça a checagem da seguinte afirmação: {{sentence}} forneça a resposta em português",
"addAgentReviewModalTitle": "Gerando relatório de checagem",
"agentLoadingThoughts": "Pensando...",
"agentFinishedThoughts": "Finalizado.",
"agentFinishedReport": "Relatório gerado",
"submitAgentReview": "Enviar relatório gerado"
}
2 changes: 2 additions & 0 deletions server/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { NotificationModule } from "./notifications/notifications.module";
import { CommentModule } from "./claim-review-task/comment/comment.module";
import { NameSpaceModule } from "./auth/name-space/name-space.module";
import { NameSpaceGuard } from "./auth/name-space/name-space.guard";
import { AutomatedFactCheckingModule } from "./automated-fact-checking/automated-fact-checking.module";

@Module({})
export class AppModule implements NestModule {
Expand Down Expand Up @@ -107,6 +108,7 @@ export class AppModule implements NestModule {
NotificationModule,
CommentModule,
NameSpaceModule,
AutomatedFactCheckingModule,
];
if (options.feature_flag) {
imports.push(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Body, Controller, Post, Header } from "@nestjs/common";
import { ApiTags } from "@nestjs/swagger";
import { AutomatedFactCheckingService } from "./automated-fact-checking.service";
import { CreateAutomatedFactCheckingDTO } from "./dto/create-automated-fact-checking.dto";

@Controller()
export class AutomatedFactCheckingController {
constructor(
private automatedFactCheckingService: AutomatedFactCheckingService
) {}

@ApiTags("automated-fact-checking")
@Post("api/ai-fact-checking")
@Header("Cache-Control", "no-cache")
async create(@Body() { sentence }: CreateAutomatedFactCheckingDTO) {
return this.automatedFactCheckingService.getResponseFromAgents(
sentence
);
}
}
13 changes: 13 additions & 0 deletions server/automated-fact-checking/automated-fact-checking.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from "@nestjs/common";
import { ClaimReviewTaskModule } from "../claim-review-task/claim-review-task.module";
import { AutomatedFactCheckingService } from "./automated-fact-checking.service";
import { AutomatedFactCheckingController } from "./automated-fact-checking.controller";
import { ConfigModule } from "@nestjs/config";

@Module({
imports: [ClaimReviewTaskModule, ConfigModule],
providers: [AutomatedFactCheckingService],
exports: [AutomatedFactCheckingService],
controllers: [AutomatedFactCheckingController],
})
export class AutomatedFactCheckingModule {}
72 changes: 72 additions & 0 deletions server/automated-fact-checking/automated-fact-checking.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Injectable, Scope } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";

@Injectable({ scope: Scope.REQUEST })
export class AutomatedFactCheckingService {
constructor(private configService: ConfigService) {}

async getResponseFromAgents(sentence: string = ""): Promise<object> {
try {
const url = `${this.configService.get<string>("agentsUrl")}/stream`;
const params = {
input: {
messages: [
{
content: sentence,
type: "human",
role: "human",
},
],
sender: "Supervisor",
},
};

const response = await fetch(url, {
method: "POST",
body: JSON.stringify(params),
headers: {
"Content-Type": "application/json",
},
});

let reader = response.body.getReader();

let streamResponse = "";
let done, value;

while (!done) {
({ done, value } = await reader.read());
streamResponse += new TextDecoder().decode(value, {
stream: true,
});
}

const jsonEvents = streamResponse
.split("\n")
.filter((line) => line.startsWith("data:"))
.map((line) => JSON.parse(line.substring(5)))
.reduce((acc, data) => ({ ...acc, ...data }), {});

jsonEvents.__end__.messages = this.convertMessageContentsToJSON(
jsonEvents.__end__.messages
);
return jsonEvents.__end__;
} catch (error) {
return {
error: "Error in data fetching process",
};
}
}

convertMessageContentsToJSON(messages) {
return messages
.map(({ content }) => {
try {
return JSON.parse(content);
} catch (error) {
return undefined;
}
})
.filter((message) => message !== undefined);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IsString } from "class-validator";

export class CreateAutomatedFactCheckingDTO {
@IsString()
sentence: string;
}
8 changes: 8 additions & 0 deletions server/claim-review-task/claim-review-task.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export class ClaimReviewController {
public async personalityList(@Req() req: Request, @Res() res: Response) {
const parsedUrl = parse(req.url, true);
const enableCollaborativeEditor = this.isEnableCollaborativeEditor();
const enableAgentReview = this.isEnableAgentReview();
const enableEditorAnnotations = this.isEnableEditorAnnotations();

await this.viewService.getNextServer().render(
Expand All @@ -173,6 +174,7 @@ export class ClaimReviewController {
sitekey: this.configService.get<string>("recaptcha_sitekey"),
enableCollaborativeEditor,
enableEditorAnnotations,
enableAgentReview,
websocketUrl: this.configService.get<string>("websocketUrl"),
nameSpace: req.params.namespace,
})
Expand All @@ -187,6 +189,12 @@ export class ClaimReviewController {
: false;
}

private isEnableAgentReview() {
const config = this.configService.get<string>("feature_flag");

return config ? this.unleash.isEnabled("agent_review") : false;
}

private isEnableEditorAnnotations() {
const config = this.configService.get<string>("feature_flag");

Expand Down
16 changes: 14 additions & 2 deletions server/claim/claim.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
Res,
Header,
Optional,
NotFoundException,
UseGuards,
} from "@nestjs/common";
import { ClaimReviewService } from "../claim-review/claim-review.service";
Expand All @@ -35,7 +34,6 @@ import { SentenceService } from "./types/sentence/sentence.service";
import type { BaseRequest } from "../types";
import slugify from "slugify";
import { UnleashService } from "nestjs-unleash";
import { ContentModelEnum } from "../types/enums";
import { SentenceDocument } from "./types/sentence/schemas/sentence.schema";
import { ImageService } from "./types/image/image.service";
import { ImageDocument } from "./types/image/schemas/image.schema";
Expand Down Expand Up @@ -331,6 +329,7 @@ export class ClaimController {
}

const enableCollaborativeEditor = this.isEnableCollaborativeEditor();
const enableAgentReview = this.isEnableAgentReview();
const enableEditorAnnotations = this.isEnableEditorAnnotations();

hideDescriptions[TargetModel.Claim] =
Expand Down Expand Up @@ -361,6 +360,7 @@ export class ClaimController {
hideDescriptions,
enableCollaborativeEditor,
enableEditorAnnotations,
enableAgentReview,
websocketUrl: this.configService.get<string>("websocketUrl"),
nameSpace: req.params.namespace,
})
Expand Down Expand Up @@ -541,6 +541,7 @@ export class ClaimController {
namespace as NameSpaceEnum
);
const enableCollaborativeEditor = this.isEnableCollaborativeEditor();
const enableAgentReview = this.isEnableAgentReview();
const enableEditorAnnotations = this.isEnableEditorAnnotations();

if (claim.personalities.length > 0) {
Expand All @@ -563,6 +564,7 @@ export class ClaimController {
sitekey: this.configService.get<string>("recaptcha_sitekey"),
enableCollaborativeEditor,
enableEditorAnnotations,
enableAgentReview,
websocketUrl: this.configService.get<string>("websocketUrl"),
nameSpace: namespace,
})
Expand All @@ -582,6 +584,7 @@ export class ClaimController {
const parsedUrl = parse(req.url, true);

const enableCollaborativeEditor = this.isEnableCollaborativeEditor();
const enableAgentReview = this.isEnableAgentReview();
const enableEditorAnnotations = this.isEnableEditorAnnotations();

const personality =
Expand Down Expand Up @@ -614,6 +617,7 @@ export class ClaimController {
sitekey: this.configService.get<string>("recaptcha_sitekey"),
enableCollaborativeEditor,
enableEditorAnnotations,
enableAgentReview,
websocketUrl: this.configService.get<string>("websocketUrl"),
hideDescriptions,
nameSpace: namespace,
Expand All @@ -640,6 +644,7 @@ export class ClaimController {
);

const enableCollaborativeEditor = this.isEnableCollaborativeEditor();
const enableAgentReview = this.isEnableAgentReview();
const enableEditorAnnotations = this.isEnableEditorAnnotations();

const claim = await this.claimService.getByPersonalityIdAndClaimSlug(
Expand All @@ -657,6 +662,7 @@ export class ClaimController {
claim,
enableCollaborativeEditor,
enableEditorAnnotations,
enableAgentReview,
websocketUrl: this.configService.get<string>("websocketUrl"),
nameSpace: namespace,
})
Expand Down Expand Up @@ -798,6 +804,12 @@ export class ClaimController {
: false;
}

private isEnableAgentReview() {
const config = this.configService.get<string>("feature_flag");

return config ? this.unleash.isEnabled("agent_review") : false;
}

private isEnableEditorAnnotations() {
const config = this.configService.get<string>("feature_flag");

Expand Down
23 changes: 23 additions & 0 deletions src/api/AutomatedFactCheckingApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import axios from "axios";

const request = axios.create({
withCredentials: true,
baseURL: `/api/ai-fact-checking`,
});

const createClaimReviewTaskUsingAIAgents = (params) => {
return request
.post("/", { ...params })
.then((response) => {
return response.data;
})
.catch((error) => {
console.log(error);
});
};

const AutomatedFactCheckingApi = {
createClaimReviewTaskUsingAIAgents,
};

export default AutomatedFactCheckingApi;
24 changes: 24 additions & 0 deletions src/components/AgentReview/AgentReviewSteps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel";

const AgentReviewStep = ({
label,
stepIconComponent = null,
...props
}: {
label: string;
stepIconComponent?: any;
key: string;
color?: string;
last?: boolean;
completed?: boolean;
}) => {
return (
<Step {...props}>
<StepLabel StepIconComponent={stepIconComponent}>{label}</StepLabel>
</Step>
);
};

export default AgentReviewStep;
Loading

0 comments on commit a437721

Please sign in to comment.