Skip to content

Commit

Permalink
feat(api): add gpt response caching
Browse files Browse the repository at this point in the history
  • Loading branch information
duongdev committed Jul 16, 2024
1 parent db149c1 commit c615b89
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "CachedGptResponse" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"query" TEXT NOT NULL,
"response" TEXT NOT NULL,

CONSTRAINT "CachedGptResponse_pkey" PRIMARY KEY ("id")
);
9 changes: 9 additions & 0 deletions apps/api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,12 @@ enum CategoryType {
INCOME
EXPENSE
}

model CachedGptResponse {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
query String
response String
}
24 changes: 24 additions & 0 deletions apps/api/v1/services/ai-cache.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import prisma from '../../lib/prisma'

export async function findAiCacheByQuery({
query,
}: {
query: string
}) {
return await prisma.cachedGptResponse.findFirst({
where: { query },
orderBy: { updatedAt: 'desc' },
})
}

export async function createAiCache({
query,
response,
}: {
query: string
response: string
}) {
return await prisma.cachedGptResponse.create({
data: { query, response },
})
}
27 changes: 25 additions & 2 deletions apps/api/v1/services/ai.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { CategoryType } from '@prisma/client'
import { OpenAI } from 'openai'
import { getLogger } from '../../lib/log'
import { createAiCache, findAiCacheByQuery } from './ai-cache.service'
import { hashFile } from './file.service'

const ASSISTANT_ID = process.env.OPENAI_ASSISTANT_ID!

Expand Down Expand Up @@ -54,6 +56,23 @@ export async function generateTransactionDataFromFile({
}[]
}) {
const log = getLogger(`ai.service:${generateTransactionDataFromFile.name}`)
const additionalInstructions = `note must be in ${noteLanguage} language but do not translate names. Categories: ${JSON.stringify(categories?.map((cat) => ({ id: cat.id, name: cat.name, icon: cat.icon, type: cat.type })) || [])}`

// If cached, return cached response
const fileHash = await hashFile(inputFile)
const cacheQuery = `transaction_file:${JSON.stringify({
fileHash,
additionalInstructions,
})}`

log.debug('Checking cache for query: %s', cacheQuery)

const cachedResponse = await findAiCacheByQuery({ query: cacheQuery })

if (cachedResponse) {
log.info('Found cached response for query: %s', cacheQuery)
return JSON.parse(cachedResponse.response)
}

const file = await uploadVisionFile({ file: inputFile })

Expand All @@ -71,8 +90,6 @@ export async function generateTransactionDataFromFile({
log.info('Created thread with uploaded file. Thread ID: %s', thread.id)
log.debug('Created thread with uploaded file. Thread details: %o', thread)

const additionalInstructions = `note must be in ${noteLanguage} language but do not translate names. Categories: ${JSON.stringify(categories?.map((cat) => ({ id: cat.id, name: cat.name, icon: cat.icon, type: cat.type })) || [])}`

log.debug(
'Running assistant on thread.\nAssistant ID: %s\nAdditional instructions: %s',
ASSISTANT_ID,
Expand Down Expand Up @@ -106,6 +123,12 @@ export async function generateTransactionDataFromFile({

cleanup()

// save to cache
createAiCache({
query: cacheQuery,
response: JSON.stringify(aiTransactionData),
})

return aiTransactionData
}

Expand Down
15 changes: 15 additions & 0 deletions apps/api/v1/services/file.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createHash } from 'crypto'
import { getLogger } from '../../lib/log'

export async function hashFile(file: File) {
const log = getLogger(`file.service:${hashFile.name}`)

log.debug('Hashing file. File size: %d', file.size)

const buffer = Buffer.from(await file.arrayBuffer())
const hash = createHash('sha256').update(buffer).digest('hex')

log.info('Hashed file. Hash: %s', hash)

return hash
}

0 comments on commit c615b89

Please sign in to comment.