Skip to content

Commit 488bff0

Browse files
authored
Merge pull request #1 from dlmarques/develop
MVP 1
2 parents d19c3a7 + 60a51f9 commit 488bff0

File tree

13 files changed

+1191
-10
lines changed

13 files changed

+1191
-10
lines changed

LICENSE

Lines changed: 663 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This project is licensed under the GNU AGPL v3—see LICENSE for details

controllers/model.controller.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import OpenAI from "openai";
2+
require("dotenv").config();
3+
4+
const openai = new OpenAI({
5+
apiKey: process.env.OPEN_AI_API_KEY,
6+
});
7+
8+
export const getModelResponse = (previousTopics?: string[]) => {
9+
let refinedPrompt;
10+
11+
if (previousTopics) {
12+
const joinedPreviousTopics = previousTopics.join(", ");
13+
refinedPrompt = `Explain a programming/computer science concept that has not been previously provided. Previously provided concepts: ${joinedPreviousTopics}. Return only a valid JSON object with the following structure: { 'concept': '', 'definition': '', 'realWorldAnalogy': '', 'examples': [{ 'language': '', 'code': '' }], 'quiz': {'question': '', 'answers': [{'id': '', 'content': ''}], rightAnswer: '' } }, the entire explanation must be between 4 and 5 minutes read, and you have to provide examples in following languages: JavaScript, Python, Java, C#, C++, TypeScript, PHP.Do not include any additional text before or after the JSON. The concept should be unique and not in the previously provided list.`;
14+
} else {
15+
refinedPrompt =
16+
"Explain a programming/computer science concept. Return only a valid JSON object with the following structure: { 'concept': '', 'definition': '', 'realWorldAnalogy': '', 'examples': [{ 'language': '', 'code': '' }], 'quiz': {'question': '', 'answers': [{'id': '', 'content': ''}], rightAnswerId: '' } }, the entire explanation cannot exceed 5 minutes read. Do not include any additional text before or after the JSON. The concept should be unique and not in the previously provided list.";
17+
}
18+
19+
try {
20+
const completion = openai.chat.completions.create({
21+
model: "gpt-4o-mini",
22+
store: true,
23+
messages: [{ role: "user", content: refinedPrompt }],
24+
});
25+
26+
const response = completion.then((result) => {
27+
return result.choices[0].message.content;
28+
});
29+
return response;
30+
} catch (error) {
31+
console.error(error);
32+
return null;
33+
}
34+
};

controllers/topics.controller.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Request, Response } from "express";
2+
import { getModelResponse } from "./model.controller";
3+
import schedule from "node-schedule";
4+
import { getPreviousTopics } from "../utils/getPreviousTopics";
5+
import { insertNewTopic } from "../utils/insertNewTopic";
6+
import { client } from "../utils/dbConnect";
7+
import { Topic } from "../types/Topic";
8+
import { isToday } from "../utils/isToday";
9+
10+
export const requestAndSaveNewTopic = async () => {
11+
const pastTopics = await getPreviousTopics();
12+
13+
const modelResponse = await getModelResponse(pastTopics);
14+
15+
if (modelResponse) {
16+
const parsedResponse = JSON.parse(modelResponse);
17+
18+
const insertTopicResult = await insertNewTopic({
19+
...parsedResponse,
20+
date: new Date(),
21+
});
22+
23+
if (insertTopicResult) {
24+
console.log("New topic generated and inserted sucessfully");
25+
}
26+
} else {
27+
throw new Error("Something went wrong on model requisition");
28+
}
29+
};
30+
31+
schedule.scheduleJob("0 0 * * *", requestAndSaveNewTopic);
32+
33+
export const getTopic = async (req: Request, res: Response) => {
34+
const database = client.db("topics");
35+
36+
const topic = database.collection<Topic>("topic");
37+
38+
const result = topic.find().toArray();
39+
40+
const _result = await result;
41+
42+
const lastTopic = _result.find((topic) => {
43+
if (isToday(topic.date)) return topic;
44+
});
45+
46+
if (lastTopic) {
47+
res.status(200).send({ success: true, content: lastTopic });
48+
} else {
49+
requestAndSaveNewTopic();
50+
}
51+
};

index.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1-
import express, { Express, Request, Response, Application } from "express";
1+
// Copyright (c) 2025 Daniel Marques
2+
// Licensed under the GNU AGPL v3. See LICENSE.
3+
4+
import express, { Application } from "express";
25
import dotenv from "dotenv";
6+
import topicRoutes from "./routes/topics";
7+
import { runDB } from "./utils/dbConnect";
8+
import cors from "cors";
39

4-
//For env File
510
dotenv.config();
611

712
const app: Application = express();
813
const port = process.env.PORT || 8000;
914

10-
/* app.get("/", (req: Request, res: Response) => {
11-
res.send("Welcome to Express & TypeScript Server");
12-
}); */
15+
app.use(
16+
cors({
17+
origin: ["http://localhost:3000"],
18+
methods: ["GET", "POST"],
19+
allowedHeaders: ["Content-Type"],
20+
credentials: true,
21+
})
22+
);
23+
24+
app.use("/topics", topicRoutes);
25+
26+
runDB().catch(console.dir);
1327

1428
app.listen(port, () => {
1529
console.log(`Server is Fire at https://localhost:${port}`);

0 commit comments

Comments
 (0)