Skip to content
Open
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
5 changes: 3 additions & 2 deletions src/app/api/AIAssistant/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { executeWebSearchAgent } from "./services/webSearchAgent";
import normalizeModelContent from "./normalizeModelContent";
import { withRateLimit } from "~/lib/rate-limit-middleware";
import { RateLimitPresets } from "~/lib/rate-limiter";
import { DEFAULT_MODELS } from "~/lib/models";


export const runtime = 'nodejs';
Expand Down Expand Up @@ -234,7 +235,7 @@ export async function POST(request: Request) {
}

const embeddings = new OpenAIEmbeddings({
model: "text-embedding-ada-002",
model: DEFAULT_MODELS.EMBEDDING,
openAIApiKey: process.env.OPENAI_API_KEY,
});

Expand Down Expand Up @@ -376,7 +377,7 @@ export async function POST(request: Request) {

const chat = new ChatOpenAI({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "gpt-5.2",
modelName: DEFAULT_MODELS.ANALYSIS,
temperature: 0.7, // Increased for more natural, conversational responses
timeout: 600000
});
Expand Down
5 changes: 3 additions & 2 deletions src/app/api/AIAssistant/services/webSearchAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ChatOpenAI } from "@langchain/openai";
import { SystemMessage, HumanMessage } from "@langchain/core/messages";
import { performTavilySearch, type WebSearchResult } from "./tavilySearch";
import { env } from "~/env";
import { DEFAULT_MODELS } from "~/lib/models";

/**
* Web Search Agent using LangChain and LangSmith
Expand Down Expand Up @@ -91,7 +92,7 @@ async function refineSearchQuery(
): Promise<{ refinedQuery: string; reasoning: string }> {
const chat = new ChatOpenAI({
openAIApiKey: env.server.OPENAI_API_KEY,
modelName: "gpt-5-mini",
modelName: DEFAULT_MODELS.LIGHTWEIGHT,
temperature: 0.3,
});

Expand Down Expand Up @@ -180,7 +181,7 @@ async function synthesizeResults(

const chat = new ChatOpenAI({
openAIApiKey: env.server.OPENAI_API_KEY,
modelName: "gpt-5-mini",
modelName: DEFAULT_MODELS.LIGHTWEIGHT,
temperature: 0.2,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
import { z } from "zod";
import { DuckDuckGoSearch } from "@langchain/community/tools/duckduckgo_search";
import type {
PdfChunk,
AnalysisSpecification,
PredictiveAnalysisResult,
import type {
PdfChunk,
AnalysisSpecification,
PredictiveAnalysisResult,
MissingDocumentPrediction,
SearchResult
} from "../types";
Expand All @@ -20,6 +20,7 @@ import { document } from "~/server/db/schema";
import { and, eq, ne } from "drizzle-orm";
import stringSimilarity from 'string-similarity-js';
import { ANALYSIS_BATCH_CONFIG } from "~/lib/constants";
import { DEFAULT_MODELS } from "~/lib/models";

async function withRetry<T>(
operation: () => Promise<T>,
Expand Down Expand Up @@ -149,7 +150,7 @@ export async function callAIAnalysis(

const chat = new ChatOpenAI({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "gpt-5.2",
modelName: DEFAULT_MODELS.ANALYSIS,
temperature: 0.3,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { HumanMessage, SystemMessage } from "@langchain/core/messages";
import { z } from "zod";
import type { PdfChunk, DocumentReference } from "../types";
import { groupContentFromChunks, hasSpecificIdentifier } from "../utils/content";
import { DEFAULT_MODELS } from "~/lib/models";

const ReferenceExtractionSchema = z.object({
references: z.array(z.object({
Expand Down Expand Up @@ -45,7 +46,7 @@ export async function extractReferences(

const chat = new ChatOpenAI({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "gpt-5.2",
modelName: DEFAULT_MODELS.ANALYSIS,
temperature: 0.1,
});

Expand Down
5 changes: 3 additions & 2 deletions src/app/api/predictive-document-analysis/utils/embeddings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { OpenAIEmbeddings } from "@langchain/openai";
import { DEFAULT_MODELS } from "~/lib/models";

const embeddingCache = new Map<string, number[]>();

Expand All @@ -10,7 +11,7 @@ export async function getEmbeddings(text: string): Promise<number[]> {
try {
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "text-embedding-ada-002",
modelName: DEFAULT_MODELS.EMBEDDING,
});

const [embedding] = await embeddings.embedDocuments([text]);
Expand All @@ -30,7 +31,7 @@ export async function batchGetEmbeddings(texts: string[]): Promise<number[][]> {
try {
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "text-embedding-ada-002",
modelName: DEFAULT_MODELS.EMBEDDING,
});

const results = await embeddings.embedDocuments(uniqueTexts);
Expand Down
3 changes: 2 additions & 1 deletion src/app/api/study-agent/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { db } from "../../../../server/db/index";
import { pdfChunks, document, users } from "../../../../server/db/schema";
import { eq, inArray } from "drizzle-orm";
import { DEFAULT_MODELS } from "~/lib/models";

import type { EmotionTag, StudyAgentChatRequest } from "./types";
import {
Expand Down Expand Up @@ -245,7 +246,7 @@ export async function POST(request: Request) {
// Initialize OpenAI and generate response
const chat = new ChatOpenAI({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "gpt-4o-mini",
modelName: DEFAULT_MODELS.LIGHTWEIGHT,
temperature: 0.7,
timeout: 30000,
});
Expand Down
3 changes: 2 additions & 1 deletion src/app/api/study-agent/speech-to-text/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NextResponse } from "next/server";
import { auth } from "@clerk/nextjs/server";
import OpenAI from "openai";
import { File } from "formdata-node";
import { DEFAULT_MODELS } from "~/lib/models";

/**
* Speech-to-Text API using OpenAI Whisper
Expand Down Expand Up @@ -70,7 +71,7 @@ export async function POST(request: Request) {

const transcription = await openai.audio.transcriptions.create({
file: audioFileForOpenAI as unknown as globalThis.File, // Type assertion for OpenAI SDK compatibility
model: "gpt-4o-transcribe",
model: DEFAULT_MODELS.TRANSCRIPTION,
response_format: "text",
});

Expand Down
3 changes: 2 additions & 1 deletion src/app/api/uploadDocument/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { Document } from "langchain/document";
import { processPDFWithOCR } from "../services/ocrService";
import { withRateLimit } from "~/lib/rate-limit-middleware";
import { RateLimitPresets } from "~/lib/rate-limiter";
import { DEFAULT_MODELS } from "~/lib/models";

interface PDFMetadata {
loc?: {
Expand Down Expand Up @@ -158,7 +159,7 @@ export async function POST(request: Request) {
}

const embeddings = new OpenAIEmbeddings({
model: "text-embedding-ada-002",
model: DEFAULT_MODELS.EMBEDDING,
openAIApiKey: process.env.OPENAI_API_KEY,
});

Expand Down
75 changes: 75 additions & 0 deletions src/lib/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Centralized AI Model Configuration
*
* This file contains all OpenAI model identifiers used throughout the application.
* Centralizing these constants makes it easier to:
* - Update model versions across the codebase
* - Maintain consistency in model usage
* - Track which models are used where
*
* @see https://platform.openai.com/docs/models
*/

/**
* Chat completion models for conversational AI tasks
*/
export const CHAT_MODELS = {
/**
* GPT-4o - Most capable model for complex reasoning tasks
* Best for: Document analysis, complex Q&A, structured output generation
*/
GPT_4O: "gpt-4o",

/**
* GPT-4o-mini - Fast and cost-effective for simpler tasks
* Best for: Query refinement, quick classifications, lightweight processing
*/
GPT_4O_MINI: "gpt-4o-mini",
} as const;

/**
* Embedding models for vector search and similarity
*/
export const EMBEDDING_MODELS = {
/**
* Ada 002 - Standard embedding model for text similarity
* Dimensions: 1536
* Best for: Document chunking, semantic search, RAG applications
*/
ADA_002: "text-embedding-ada-002",
} as const;

/**
* Audio transcription models for speech-to-text
*/
export const TRANSCRIPTION_MODELS = {
/**
* GPT-4o Transcribe - High-quality speech-to-text transcription
* Best for: Audio transcription, voice input processing
*/
GPT_4O_TRANSCRIBE: "gpt-4o-transcribe",
} as const;

/**
* Default model selections for different use cases
*/
export const DEFAULT_MODELS = {
/** Default model for document analysis and complex reasoning */
ANALYSIS: CHAT_MODELS.GPT_4O,

/** Default model for lightweight tasks like query refinement */
LIGHTWEIGHT: CHAT_MODELS.GPT_4O_MINI,

/** Default model for text embeddings */
EMBEDDING: EMBEDDING_MODELS.ADA_002,

/** Default model for audio transcription */
TRANSCRIPTION: TRANSCRIPTION_MODELS.GPT_4O_TRANSCRIBE,
} as const;

// Type exports for TypeScript usage
export type ChatModel = (typeof CHAT_MODELS)[keyof typeof CHAT_MODELS];
export type EmbeddingModel =
(typeof EMBEDDING_MODELS)[keyof typeof EMBEDDING_MODELS];
export type TranscriptionModel =
(typeof TRANSCRIPTION_MODELS)[keyof typeof TRANSCRIPTION_MODELS];