Skip to content

Commit

Permalink
Merge pull request #1236 from AletheiaFact/create-daily-report-document
Browse files Browse the repository at this point in the history
Send Unsolicited Latest Reviews in Daily Report
  • Loading branch information
thesocialdev authored Jun 3, 2024
2 parents d2a179f + 1a13e17 commit c209932
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 125 deletions.
2 changes: 2 additions & 0 deletions server/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { NameSpaceGuard } from "./auth/name-space/name-space.guard";
import { AutomatedFactCheckingModule } from "./automated-fact-checking/automated-fact-checking.module";
import { CopilotChatModule } from "./copilot/copilot-chat.module";
import { UnattributedModule } from "./claim/types/unattributed/unattributed.module";
import { DailyReportModule } from "./daily-report/daily-report.module";

@Module({})
export class AppModule implements NestModule {
Expand Down Expand Up @@ -113,6 +114,7 @@ export class AppModule implements NestModule {
AutomatedFactCheckingModule,
CopilotChatModule,
UnattributedModule,
DailyReportModule,
];
if (options.feature_flag) {
imports.push(
Expand Down
31 changes: 18 additions & 13 deletions server/claim-review/claim-review.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,24 +85,29 @@ export class ClaimReviewService {
);
}

async listDailyReviews(
/**
* FIXME: Claim review should have namespace on it to avoid filtering claim by namespaces
*/
async listDailyClaimReviews({
page,
pageSize,
order,
query,
nameSpace,
latest = false
) {
const today = new Date();
today.setHours(0, 0, 0, 0);

const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);

query.date = {
$gte: today,
$lt: tomorrow,
};
latest = false,
}) {
if (!query.date) {
const today = new Date();
today.setHours(0, 0, 0, 0);

const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);

query.date = {
$gte: today,
$lt: tomorrow,
};
}
const pipeline = this.ClaimReviewModel.find(query)
.sort(latest ? { date: -1 } : { _id: order === "asc" ? 1 : -1 })
.populate({
Expand Down
64 changes: 64 additions & 0 deletions server/daily-report/daily-report.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Controller, Param, Post, UseGuards } from "@nestjs/common";
import {
AdminUserAbility,
CheckAbilities,
} from "../auth/ability/ability.decorator";
import { AbilitiesGuard } from "../auth/ability/abilities.guard";
import { DailyReportService } from "../daily-report/daily-report.service";
import { ClaimReviewService } from "../claim-review/claim-review.service";
import { NotificationService } from "../notifications/notifications.service";

@Controller()
export class DailyReportController {
constructor(
private readonly dailyReportService: DailyReportService,
private claimReviewService: ClaimReviewService,
private notificationService: NotificationService
) {}

@Post("api/daily-report/topic/:topic/send/:nameSpace")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
async sendDailyReport(
@Param("topic") topic,
@Param("nameSpace") nameSpace
) {
const queryParams: any = { isHidden: false, isDeleted: false };
const [lastDailyReportSent] =
await this.dailyReportService.getLastDailyReportSent();

if (lastDailyReportSent) {
queryParams.date = { $gt: lastDailyReportSent?.date };
}

const dailyClaimReviews =
await this.claimReviewService.listDailyClaimReviews({
page: 0,
pageSize: 30,
order: "asc",
nameSpace,
query: queryParams,
});

if (dailyClaimReviews.length > 0) {
const reportIds = dailyClaimReviews.map(({ report }) => report._id);
await this.dailyReportService.create({
reports: reportIds,
date: new Date(),
});
}

const dailyReport = await this.dailyReportService.generateDailyReport(
dailyClaimReviews,
nameSpace
);

this.notificationService.sendDailyReviewsEmail(topic, dailyReport);

if (dailyClaimReviews.length < 1) {
throw new Error("No daily reports today");
}

return dailyClaimReviews;
}
}
32 changes: 32 additions & 0 deletions server/daily-report/daily-report.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Module } from "@nestjs/common";
import { DailyReport, DailyReportSchema } from "./schemas/daily-report.schema";
import { DailyReportService } from "./daily-report.service";
import { MongooseModule } from "@nestjs/mongoose";
import { AbilityModule } from "../auth/ability/ability.module";
import { SummarizationModule } from "../summarization/summarization.module";
import { ClaimReviewModule } from "../claim-review/claim-review.module";
import { NotificationModule } from "../notifications/notifications.module";
import { DailyReportController } from "./daily-report.controller";
import { ConfigModule } from "@nestjs/config";

export const DailyReportModel = MongooseModule.forFeature([
{
name: DailyReport.name,
schema: DailyReportSchema,
},
]);

@Module({
imports: [
DailyReportModel,
ClaimReviewModule,
SummarizationModule,
AbilityModule,
NotificationModule,
ConfigModule,
],
providers: [DailyReportService],
controllers: [DailyReportController],
exports: [DailyReportService],
})
export class DailyReportModule {}
46 changes: 46 additions & 0 deletions server/daily-report/daily-report.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Injectable, Scope, Logger } from "@nestjs/common";
import { Model } from "mongoose";
import {
DailyReport,
DailyReportDocument,
} from "./schemas/daily-report.schema";
import { InjectModel } from "@nestjs/mongoose";
import { SummarizationService } from "../summarization/summarization.service";

@Injectable({ scope: Scope.REQUEST })
export class DailyReportService {
private readonly logger = new Logger("SummarizationLogger");
constructor(
@InjectModel(DailyReport.name)
private DailyReportModel: Model<DailyReportDocument>,
private summarizationService: SummarizationService
) {}

async create(dailyReportBody: DailyReport): Promise<DailyReport> {
return new this.DailyReportModel(dailyReportBody).save();
}

async getLastDailyReportSent(): Promise<DailyReport[]> {
return await this.DailyReportModel.find({}).sort({ date: -1 }).limit(1);
}

async generateDailyReport(
dailyClaimReviews,
nameSpace?: string
): Promise<string> {
try {
const summarizedReviews =
await this.summarizationService.getSummarizedReviews(
dailyClaimReviews
);

return this.summarizationService.generateHTMLReport(
summarizedReviews,
nameSpace
);
} catch (error) {
this.logger.error("Error generating daily report:", error);
throw new Error("Failed to generate daily report");
}
}
}
24 changes: 24 additions & 0 deletions server/daily-report/schemas/daily-report.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as mongoose from "mongoose";
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Report } from "../../report/schemas/report.schema";

export type DailyReportDocument = DailyReport & mongoose.Document;

@Schema({ toObject: { virtuals: true }, toJSON: { virtuals: true } })
export class DailyReport {
@Prop({
type: [
{
type: mongoose.Types.ObjectId,
required: true,
ref: "Report",
},
],
})
reports: Report[];

@Prop({ required: true })
date: Date;
}

export const DailyReportSchema = SchemaFactory.createForClass(DailyReport);
20 changes: 1 addition & 19 deletions server/notifications/notification.controller.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,15 @@
import { Body, Controller, Get, Param, Post, UseGuards } from "@nestjs/common";
import { Body, Controller, Get, Param, Post } from "@nestjs/common";
import { NotificationService } from "./notifications.service";
import { ApiTags } from "@nestjs/swagger";
import { ConfigService } from "@nestjs/config";
import { SummarizationService } from "../summarization/summarization.service";
import {
AdminUserAbility,
CheckAbilities,
} from "../auth/ability/ability.decorator";
import { AbilitiesGuard } from "../auth/ability/abilities.guard";

@Controller()
export class NotificationController {
constructor(
private readonly notificationService: NotificationService,
private summarizationService: SummarizationService,
private configService: ConfigService
) {}

@Post("api/notification/topic-subscription/:key/send/:nameSpace")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
async sendDailyReport(@Param("key") key, @Param("nameSpace") nameSpace) {
const dailyReport = await this.summarizationService.generateDailyReport(
nameSpace
);

return this.notificationService.sendDailyReviewsEmail(key, dailyReport);
}

@ApiTags("notifications")
@Post("api/notification")
sendNotification(@Body() body) {
Expand Down
12 changes: 1 addition & 11 deletions server/notifications/notifications.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,9 @@ import { ConfigModule } from "@nestjs/config";
import { NotificationService } from "./notifications.service";
import { NovuProvider } from "./novu.provider";
import { NotificationController } from "./notification.controller";
import { ClaimReviewModule } from "../claim-review/claim-review.module";
import { SummarizationModule } from "../summarization/summarization.module";
import { EmailModule } from "../email/email.module";
import { AbilityModule } from "../auth/ability/ability.module";

@Module({
imports: [
ConfigModule,
ClaimReviewModule,
SummarizationModule,
EmailModule,
AbilityModule,
],
imports: [ConfigModule],
exports: [NotificationService],
providers: [NotificationService, NovuProvider],
controllers: [NotificationController],
Expand Down
22 changes: 0 additions & 22 deletions server/summarization/summarization.controller.ts

This file was deleted.

2 changes: 0 additions & 2 deletions server/summarization/summarization.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Module } from "@nestjs/common";
import { SummarizationChainService } from "./summarization-chain.service";
import { SummarizationService } from "./summarization.service";
import { SummarizationController } from "./summarization.controller";
import { ClaimReviewModule } from "../claim-review/claim-review.module";
import { AbilityModule } from "../auth/ability/ability.module";
import { ConfigModule } from "@nestjs/config";
Expand All @@ -10,6 +9,5 @@ import { ConfigModule } from "@nestjs/config";
imports: [ClaimReviewModule, AbilityModule, ConfigModule],
providers: [SummarizationChainService, SummarizationService],
exports: [SummarizationService],
controllers: [SummarizationController],
})
export class SummarizationModule {}
44 changes: 2 additions & 42 deletions server/summarization/summarization.service.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,16 @@
import { Injectable, Logger } from "@nestjs/common";
import { SummarizationChainService } from "./summarization-chain.service";
import { ClaimReviewService } from "../claim-review/claim-review.service";
import { ConfigService } from "@nestjs/config";

@Injectable()
export class SummarizationService {
private readonly logger = new Logger("SummarizationLogger");
constructor(
private chainService: SummarizationChainService,
private claimReviewService: ClaimReviewService,
private configService: ConfigService
) {}

async generateDailyReport(nameSpace?: string): Promise<string> {
const query = {
page: 0,
pageSize: 10,
order: "asc",
isHidden: false,
latest: false,
isDailyRange: true,
nameSpace: nameSpace,
};

try {
const dailyClaimReviews =
await this.claimReviewService.listDailyReviews(
query.page,
query.pageSize,
query.order,
{ isHidden: query.isHidden, isDeleted: false },
query.nameSpace,
query.latest
);

const summarizedReviews = await this.getSummarizedReviews(
dailyClaimReviews
);

return this.generateHTMLReport(summarizedReviews, nameSpace);
} catch (error) {
this.logger.error("Error generating daily report:", error);
throw new Error("Failed to generate daily report");
}
}

private async getSummarizedReviews(
dailyClaimReviews: any[]
): Promise<any[]> {
async getSummarizedReviews(dailyClaimReviews: any[]): Promise<any[]> {
try {
return await Promise.all(
dailyClaimReviews.map(async (claimReview) => {
Expand All @@ -67,10 +30,7 @@ export class SummarizationService {
}
}

private generateHTMLReport(
summarizedReviews: any[],
nameSpace: string
): string {
generateHTMLReport(summarizedReviews: any[], nameSpace: string): string {
const classificationTranslations = {
"not-fact": "Não é fato",
trustworthy: "Confiável",
Expand Down
Loading

0 comments on commit c209932

Please sign in to comment.