Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ jobs:
run: npm install
- name: Run build
run: npm run build
env:
NEXT_PUBLIC_BASE_URL: https://cosmic.csui.dev
1 change: 0 additions & 1 deletion app/menfess/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export const metadata: Metadata = {
},
};


const MenfessPage = async () => {
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/menfess`, {
next: { revalidate: 10 }, // Revalidate every 10 seconds
Expand Down
28 changes: 25 additions & 3 deletions components/MenfessPage/send.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { briefFamsData } from "@/modules/fams-data";
import { useMemo } from "react";
import Image from "next/image";
import { toast } from "sonner";
import { detectHate } from "@/lib/detectHate";

const SendMenfess = () => {
const [to, setTo] = useState("");
Expand All @@ -27,6 +28,7 @@ const SendMenfess = () => {
toast.error("Please fill all fields");
return;
}

const menfess = {
to: to,
from: from,
Expand All @@ -39,6 +41,23 @@ const SendMenfess = () => {
}
console.log(to, from, message);
const loader = toast.loading("Sending menfess...");

const status = await detectHate(message);
console.log(status);

if (status === "ERROR") {
toast.error("LLM Error", {
id: loader,
});
}

if (status === "HATEFUL") {
toast.error("Message is indicated to be hateful speech", {
id: loader,
});
return;
}

const res = await fetch("/api/menfess", {
method: "POST",
headers: {
Expand All @@ -48,9 +67,12 @@ const SendMenfess = () => {
});
const data = await res.json();
if (data.success) {
toast.success("Menfess sent successfully", {
id: loader,
});
if (status === "ERROR") {
} else {
toast.success("Menfess sent successfully", {
id: loader,
});
}
setTo("");
setFrom("");
setMessage("");
Expand Down
41 changes: 41 additions & 0 deletions lib/detectHate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use server";

import { generateText } from "ai";
// import { google } from "@ai-sdk/google";
import { createGoogleGenerativeAI } from "@ai-sdk/google";

const google = createGoogleGenerativeAI({
apiKey: process.env.GOOGLE_API_KEY,
});

export async function detectHate(
input: string
): Promise<"HATEFUL" | "NOT_HATEFUL" | "ERROR"> {
try {
const prompt = `
You are a content moderation assistant. Classify the input below as either:

- "HATEFUL" — if it forms any kind of hateful speech or abusive behavior, especially toward an individual whether it's explicitly or implicitly
- "NOT_HATEFUL" — if it does not.

Only respond with "HATEFUL" or "NOT_HATEFUL", nothing else. Detect it either in bahasa indonesia or english

Input:
"""${input}"""
`.trim();

const result = await generateText({
model: google("gemini-2.0-flash"),
prompt,
});

const output = result.text.trim();
const status =
output === "HATEFUL" || output === "NOT_HATEFUL" ? output : "ERROR";

return status;
} catch (e) {
console.error("Moderation error:", e);
return "ERROR";
}
}
19 changes: 9 additions & 10 deletions lib/generated/prisma/edge.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ exports.Prisma = Prisma
exports.$Enums = {}

/**
* Prisma Client JS version: 6.8.2
* Query Engine version: 2060c79ba17c6bb9f5823312b6f6b7f4a845738e
* Prisma Client JS version: 6.10.1
* Query Engine version: 9b628578b3b7cae625e8c927178f15a170e74a9c
*/
Prisma.prismaVersion = {
client: "6.8.2",
engine: "2060c79ba17c6bb9f5823312b6f6b7f4a845738e"
client: "6.10.1",
engine: "9b628578b3b7cae625e8c927178f15a170e74a9c"
}

Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
Expand Down Expand Up @@ -143,7 +143,7 @@ const config = {
"value": "prisma-client-js"
},
"output": {
"value": "D:\\Projects\\WebAngkatanCSUI24\\csui24-web\\lib\\generated\\prisma",
"value": "/home/kims/Projects/csui24-web/lib/generated/prisma",
"fromEnvVar": null
},
"config": {
Expand All @@ -152,7 +152,7 @@ const config = {
"binaryTargets": [
{
"fromEnvVar": null,
"value": "windows",
"value": "debian-openssl-3.0.x",
"native": true
},
{
Expand All @@ -161,21 +161,20 @@ const config = {
}
],
"previewFeatures": [],
"sourceFilePath": "D:\\Projects\\WebAngkatanCSUI24\\csui24-web\\prisma\\schema.prisma",
"sourceFilePath": "/home/kims/Projects/csui24-web/prisma/schema.prisma",
"isCustomOutput": true
},
"relativeEnvPaths": {
"rootEnvPath": null,
"schemaEnvPath": "../../../.env"
},
"relativePath": "../../../prisma",
"clientVersion": "6.8.2",
"engineVersion": "2060c79ba17c6bb9f5823312b6f6b7f4a845738e",
"clientVersion": "6.10.1",
"engineVersion": "9b628578b3b7cae625e8c927178f15a170e74a9c",
"datasourceNames": [
"db"
],
"activeProvider": "postgresql",
"postinstall": false,
"inlineDatasources": {
"db": {
"url": {
Expand Down
8 changes: 4 additions & 4 deletions lib/generated/prisma/index-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ exports.Prisma = Prisma
exports.$Enums = {}

/**
* Prisma Client JS version: 6.8.2
* Query Engine version: 2060c79ba17c6bb9f5823312b6f6b7f4a845738e
* Prisma Client JS version: 6.10.1
* Query Engine version: 9b628578b3b7cae625e8c927178f15a170e74a9c
*/
Prisma.prismaVersion = {
client: "6.8.2",
engine: "2060c79ba17c6bb9f5823312b6f6b7f4a845738e"
client: "6.10.1",
engine: "9b628578b3b7cae625e8c927178f15a170e74a9c"
}

Prisma.PrismaClientKnownRequestError = () => {
Expand Down
4 changes: 2 additions & 2 deletions lib/generated/prisma/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ export namespace Prisma {
export import Exact = $Public.Exact

/**
* Prisma Client JS version: 6.8.2
* Query Engine version: 2060c79ba17c6bb9f5823312b6f6b7f4a845738e
* Prisma Client JS version: 6.10.1
* Query Engine version: 9b628578b3b7cae625e8c927178f15a170e74a9c
*/
export type PrismaVersion = {
client: string
Expand Down
23 changes: 11 additions & 12 deletions lib/generated/prisma/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ exports.Prisma = Prisma
exports.$Enums = {}

/**
* Prisma Client JS version: 6.8.2
* Query Engine version: 2060c79ba17c6bb9f5823312b6f6b7f4a845738e
* Prisma Client JS version: 6.10.1
* Query Engine version: 9b628578b3b7cae625e8c927178f15a170e74a9c
*/
Prisma.prismaVersion = {
client: "6.8.2",
engine: "2060c79ba17c6bb9f5823312b6f6b7f4a845738e"
client: "6.10.1",
engine: "9b628578b3b7cae625e8c927178f15a170e74a9c"
}

Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
Expand Down Expand Up @@ -144,7 +144,7 @@ const config = {
"value": "prisma-client-js"
},
"output": {
"value": "D:\\Projects\\WebAngkatanCSUI24\\csui24-web\\lib\\generated\\prisma",
"value": "/home/kims/Projects/csui24-web/lib/generated/prisma",
"fromEnvVar": null
},
"config": {
Expand All @@ -153,7 +153,7 @@ const config = {
"binaryTargets": [
{
"fromEnvVar": null,
"value": "windows",
"value": "debian-openssl-3.0.x",
"native": true
},
{
Expand All @@ -162,21 +162,20 @@ const config = {
}
],
"previewFeatures": [],
"sourceFilePath": "D:\\Projects\\WebAngkatanCSUI24\\csui24-web\\prisma\\schema.prisma",
"sourceFilePath": "/home/kims/Projects/csui24-web/prisma/schema.prisma",
"isCustomOutput": true
},
"relativeEnvPaths": {
"rootEnvPath": null,
"schemaEnvPath": "../../../.env"
},
"relativePath": "../../../prisma",
"clientVersion": "6.8.2",
"engineVersion": "2060c79ba17c6bb9f5823312b6f6b7f4a845738e",
"clientVersion": "6.10.1",
"engineVersion": "9b628578b3b7cae625e8c927178f15a170e74a9c",
"datasourceNames": [
"db"
],
"activeProvider": "postgresql",
"postinstall": false,
"inlineDatasources": {
"db": {
"url": {
Expand Down Expand Up @@ -225,8 +224,8 @@ exports.PrismaClient = PrismaClient
Object.assign(exports, Prisma)

// file annotations for bundling tools to include these files
path.join(__dirname, "query_engine-windows.dll.node");
path.join(process.cwd(), "lib/generated/prisma/query_engine-windows.dll.node")
path.join(__dirname, "libquery_engine-debian-openssl-3.0.x.so.node");
path.join(process.cwd(), "lib/generated/prisma/libquery_engine-debian-openssl-3.0.x.so.node")

// file annotations for bundling tools to include these files
path.join(__dirname, "libquery_engine-rhel-openssl-3.0.x.so.node");
Expand Down
Binary file not shown.
Empty file modified lib/generated/prisma/libquery_engine-rhel-openssl-3.0.x.so.node
100644 → 100755
Empty file.
18 changes: 12 additions & 6 deletions lib/generated/prisma/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,17 @@
"import": "./runtime/binary.mjs",
"default": "./runtime/binary.mjs"
},
"./runtime/wasm": {
"types": "./runtime/wasm.d.ts",
"require": "./runtime/wasm.js",
"import": "./runtime/wasm.mjs",
"default": "./runtime/wasm.mjs"
"./runtime/wasm-engine-edge": {
"types": "./runtime/wasm-engine-edge.d.ts",
"require": "./runtime/wasm-engine-edge.js",
"import": "./runtime/wasm-engine-edge.mjs",
"default": "./runtime/wasm-engine-edge.mjs"
},
"./runtime/wasm-compiler-edge": {
"types": "./runtime/wasm-compiler-edge.d.ts",
"require": "./runtime/wasm-compiler-edge.js",
"import": "./runtime/wasm-compiler-edge.mjs",
"default": "./runtime/wasm-compiler-edge.mjs"
},
"./runtime/edge": {
"types": "./runtime/edge.d.ts",
Expand Down Expand Up @@ -135,6 +141,6 @@
},
"./*": "./*"
},
"version": "6.8.2",
"version": "6.10.1",
"sideEffects": false
}
8 changes: 4 additions & 4 deletions lib/generated/prisma/wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ exports.Prisma = Prisma
exports.$Enums = {}

/**
* Prisma Client JS version: 6.8.2
* Query Engine version: 2060c79ba17c6bb9f5823312b6f6b7f4a845738e
* Prisma Client JS version: 6.10.1
* Query Engine version: 9b628578b3b7cae625e8c927178f15a170e74a9c
*/
Prisma.prismaVersion = {
client: "6.8.2",
engine: "2060c79ba17c6bb9f5823312b6f6b7f4a845738e"
client: "6.10.1",
engine: "9b628578b3b7cae625e8c927178f15a170e74a9c"
}

Prisma.PrismaClientKnownRequestError = () => {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
"postbuild": "next-sitemap --config next-sitemap.config.mjs"
},
"dependencies": {
"@ai-sdk/google": "^1.2.19",
"@prisma/client": "^6.8.1",
"@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-slot": "^1.2.2",
"@vercel/analytics": "^1.5.0",
"@vercel/speed-insights": "^1.2.0",
"ai": "^4.3.16",
"blurhash-base64": "^0.0.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand Down
24 changes: 23 additions & 1 deletion pages/api/menfess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PrismaClient } from "@/lib/generated/prisma";
import { TwitterApi } from "twitter-api-v2";
import { briefFamsData } from "@/modules/fams-data";
import { globalRateLimit } from "@/lib/rateLimiter";
import { detectHate } from "@/lib/detectHate";

const prisma = new PrismaClient();

Expand Down Expand Up @@ -30,7 +31,9 @@ export default async function handler(
orderBy: {
createdAt: "desc",
},
take: process.env.LIMIT_MENFESS ? parseInt(process.env.LIMIT_MENFESS) : undefined,
take: process.env.LIMIT_MENFESS
? parseInt(process.env.LIMIT_MENFESS)
: undefined,
});
return res.status(200).json({
success: true,
Expand Down Expand Up @@ -132,6 +135,25 @@ export default async function handler(
data: null,
});
}

const status = await detectHate(message);

if (status === "ERROR") {
return res.status(200).json({
success: true,
message: "LLM Error",
data: null,
});
}

if (status === "HATEFUL") {
return res.status(403).json({
success: false,
message: "Message is indicated to be hateful speech",
data: null,
});
}

try {
const newMenfess = await prisma.menfess.create({
data: {
Expand Down
Loading