Skip to content

Commit

Permalink
Merge pull request #125 from arnaugomez:feature/CM-147
Browse files Browse the repository at this point in the history
feat: update openai model
  • Loading branch information
arnaugomez authored Sep 28, 2024
2 parents 4a89e14 + f51b132 commit a484150
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { NoteRowModel } from "@/src/notes/domain/models/note-row-model";
import type {
AiNotesGeneratorService,
GenerateAiNotesInputModel,
Expand All @@ -12,48 +13,52 @@ import type {
export class AiNotesGeneratorServiceFakeImpl
implements AiNotesGeneratorService
{
async generate({}: GenerateAiNotesInputModel): Promise<string[][]> {
async generate({}: GenerateAiNotesInputModel): Promise<NoteRowModel[]> {
return [
[
"¿Cómo se define una ecuación de segundo grado?",
"Es una ecuación algebraica cuyo mayor exponente de la incógnita es 2.",
],
[
"¿Cuál es la forma general de una ecuación de segundo grado?",
"ax^2 + bx + c = 0",
],
[
"¿Qué son las raíces de una ecuación de segundo grado?",
"Son los valores de x que satisfacen la ecuación y hacen que sea igual a cero.",
],
[
"¿Qué es el discriminante en una ecuación de segundo grado?",
"Es la expresión b^2 - 4ac que se encuentra dentro de la fórmula cuadrática.",
],
[
"¿Cuántas soluciones puede tener una ecuación de segundo grado?",
"Puede tener 0, 1 o 2 soluciones.",
],
[
"¿Cuál es la fórmula general para hallar las soluciones de una ecuación de segundo grado?",
"x = (-b ± √(b^2 - 4ac)) / 2a",
],
[
"¿Cómo se llama el proceso de encontrar las raíces de una ecuación de segundo grado?",
"Se llama resolver la ecuación.",
],
[
"¿Qué tipo de gráfica representa una ecuación de segundo grado?",
"Representa una parábola.",
],
[
"¿Qué relación existe entre los coeficientes a, b y c de una ecuación de segundo grado y las soluciones?",
"Los coeficientes determinan la naturaleza y cantidad de soluciones, según el discriminante.",
],
[
"¿Qué ocurre si el discriminante es positivo en una ecuación de segundo grado?",
"La ecuación tiene dos soluciones reales y distintas.",
],
{
front: "¿Cómo se define una ecuación de segundo grado?",
back: "Es una ecuación algebraica cuyo mayor exponente de la incógnita es 2.",
},
{
front: "¿Cuál es la forma general de una ecuación de segundo grado?",
back: "ax^2 + bx + c = 0",
},
{
front: "¿Qué son las raíces de una ecuación de segundo grado?",
back: "Son los valores de x que satisfacen la ecuación y hacen que sea igual a cero.",
},
{
front: "¿Qué es el discriminante en una ecuación de segundo grado?",
back: "Es la expresión b^2 - 4ac que se encuentra dentro de la fórmula cuadrática.",
},
{
front: "¿Cuántas soluciones puede tener una ecuación de segundo grado?",
back: "Puede tener 0, 1 o 2 soluciones.",
},
{
front:
"¿Cuál es la fórmula general para hallar las soluciones de una ecuación de segundo grado?",
back: "x = (-b ± √(b^2 - 4ac)) / 2a",
},
{
front:
"¿Cómo se llama el proceso de encontrar las raíces de una ecuación de segundo grado?",
back: "Se llama resolver la ecuación.",
},
{
front: "¿Qué tipo de gráfica representa una ecuación de segundo grado?",
back: "Representa una parábola.",
},
{
front:
"¿Qué relación existe entre los coeficientes a, b y c de una ecuación de segundo grado y las soluciones?",
back: "Los coeficientes determinan la naturaleza y cantidad de soluciones, según el discriminante.",
},
{
front:
"¿Qué ocurre si el discriminante es positivo en una ecuación de segundo grado?",
back: "La ecuación tiene dos soluciones reales y distintas.",
},
];
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { EnvService } from "@/src/common/domain/interfaces/env-service";
import type { ErrorTrackingService } from "@/src/common/domain/interfaces/error-tracking-service";
import type { NoteRowModel } from "@/src/notes/domain/models/note-row-model";
import { OpenAI, OpenAIError, RateLimitError } from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z, ZodError } from "zod";
import {
AiGeneratorEmptyMessageError,
AiGeneratorError,
Expand All @@ -21,6 +24,15 @@ declare module global {
let openaiClient: OpenAI;
}

const ValidationSchema = z.object({
flashcards: z.array(
z.object({
front: z.string(),
back: z.string(),
}),
),
});

/**
* Implementation of AiNotesGeneratorService using the gpt-3.5-turbo-0125
* model. It communicates with the model using the OpenAI SDK, which makes
Expand Down Expand Up @@ -49,7 +61,7 @@ export class AiNotesGeneratorServiceOpenaiImpl
noteTypes,
notesCount,
sourceType,
}: GenerateAiNotesInputModel): Promise<string[][]> {
}: GenerateAiNotesInputModel): Promise<NoteRowModel[]> {
const typesMap = {
[AiGeneratorNoteType.qa]: "a question and the answer",
[AiGeneratorNoteType.definition]:
Expand All @@ -66,7 +78,7 @@ export class AiNotesGeneratorServiceOpenaiImpl
{
role: "system",
content: `You are a flashard generator.
Output a list of flashcards in JSON format. The JSON should be an array of arrays, where each sub-array contains two strings: the question and the answer.
Output a list of flashcards. Each flashcard has a front side (the question) and a back side (the answer).
The flashcards can contain: ${noteTypes.map((type) => typesMap[type]).join(", ")}.
You must generate ${notesCount} flashcards based on the ${textOrTopic} provided by the user.
The language of the flashcards should be the language of the ${textOrTopic} provided by the user.
Expand All @@ -77,51 +89,33 @@ The language of the flashcards should be the language of the ${textOrTopic} prov
content: `Generate ${notesCount} flashcards to help me study this ${textOrTopic}: ${text}`,
},
],
model: "gpt-3.5-turbo-0125",
response_format: { type: "json_object" },
model: "gpt-4o-mini",
response_format: zodResponseFormat(ValidationSchema, "flashcards"),
n: 1,
});
const responseText = completion.choices[0].message.content;
if (!responseText) {

const message = completion.choices[0].message;
const responseText = message.content;
if (message.refusal || !responseText) {
this.errorTrackingService.captureError(message);
throw new AiGeneratorEmptyMessageError();
}

const response = JSON.parse(responseText);
return this.parseResponse(response);
const parsed = ValidationSchema.parse(response);
return parsed.flashcards;
} catch (e) {
if (e instanceof RateLimitError) {
this.errorTrackingService.captureError(e);
throw new AiGeneratorRateLimitError();
} else if (e instanceof OpenAIError) {
this.errorTrackingService.captureError(e);
throw new AiGeneratorError();
} else if (e instanceof ZodError) {
this.errorTrackingService.captureError(e);
throw new AiGeneratorError();
}
throw e;
}
}

/**
* Analyzes the response from the AI, in search of a list of flashcards.
* Because the response from the AI cannot be predicted, this method
* traverses the response object to find the flashcards.
*
* @param response a JSON object with the response from the AI
* @returns an array of flashcards, where each flashcard is an array with two strings: the question and the answer
* @throws `AiGeneratorEmptyMessageError` if the response does not contain the expected data
*/
private parseResponse(response: unknown): string[][] {
if (!response) {
throw new AiGeneratorEmptyMessageError();
}
if (Array.isArray(response)) {
return response;
}
if (typeof response === "object") {
for (const value of Object.values(response)) {
if (Array.isArray(value) && value.length) {
return value;
}
}
}
throw new AiGeneratorEmptyMessageError();
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { NoteRowModel } from "@/src/notes/domain/models/note-row-model";
import type { AiGeneratorNoteType } from "../models/ai-generator-note-type";
import type { AiNotesGeneratorSourceType } from "../models/ai-notes-generator-source-type";

Expand All @@ -14,7 +15,7 @@ export interface AiNotesGeneratorService {
* consisting of two strings: the question (front side of the note) and the
* answer (back side of the note)
*/
generate(input: GenerateAiNotesInputModel): Promise<string[][]>;
generate(input: GenerateAiNotesInputModel): Promise<NoteRowModel[]>;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ export class GenerateAiNotesUseCase {

const generated = await this.aiNotesGeneratorService.generate(input);
await this.rateLimitsRepository.increment(rateLimitKey);
return generated.map(([front, back]) => ({ front, back }));
return generated;
}
}

0 comments on commit a484150

Please sign in to comment.