Skip to content

Commit

Permalink
Image and file parameters in shared prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
neoxelox committed Dec 17, 2024
1 parent 1510e91 commit e53d442
Show file tree
Hide file tree
Showing 27 changed files with 517 additions and 488 deletions.
2 changes: 1 addition & 1 deletion .tmuxinator.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: latitude-llm
windows:
- web: cd .
- workspace: cd .
- apps: pnpm dev --filter='./apps/*'
- packages: pnpm dev --filter='./packages/*'
- docker: docker compose up --menu=false
Expand Down
5 changes: 4 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"@latitude-data/constants": "workspace:*",
"@latitude-data/core": "workspace:*",
"@latitude-data/env": "workspace:^",
"promptl-ai": "^0.3.3",
"@latitude-data/sdk": "workspace:*",
"@latitude-data/web-ui": "workspace:*",
"@lucia-auth/adapter-drizzle": "^1.0.7",
Expand All @@ -31,12 +30,14 @@
"@sentry/utils": "^8.30.0",
"@sindresorhus/slugify": "^2.2.1",
"@t3-oss/env-nextjs": "^0.10.1",
"@types/ip": "^1.1.3",
"ai": "^4.0.18",
"bullmq": "^5.8.5",
"date-fns": "^3.6.0",
"drizzle-orm": "^0.33.0",
"import-in-the-middle": "^1.11.2",
"ioredis": "^5.4.1",
"ip": "^2.0.1",
"jose": "^5.8.0",
"js-cookie": "^3.0.5",
"lodash-es": "^4.17.21",
Expand All @@ -50,6 +51,8 @@
"oslo": "1.2.0",
"pdfjs-dist": "^4.9.155",
"posthog-js": "^1.161.6",
"promptl-ai": "^0.3.3",
"rate-limiter-flexible": "^5.0.3",
"react": "19.0.0-rc-5d19e1c8-20240923",
"react-dom": "19.0.0-rc-5d19e1c8-20240923",
"socket.io-react-hook": "^2.4.5",
Expand Down
16 changes: 14 additions & 2 deletions apps/web/src/actions/files/upload.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
'use server'

import { getUnsafeIp } from '$/helpers/ip'
import { MAX_SIZE, MAX_UPLOAD_SIZE_IN_MB } from '@latitude-data/core/browser'
import { uploadFile } from '@latitude-data/core/services/files/upload'
import { createHash } from 'crypto'
import { headers } from 'next/headers'
import { z } from 'zod'

import { authProcedure } from '../procedures'
import { maybeAuthProcedure, withRateLimit } from '../procedures'

export const uploadFileAction = authProcedure
export const uploadFileAction = (
await withRateLimit(maybeAuthProcedure, {
limit: 10,
period: 60,
})
)
.createServerAction()
.input(
z.object({
Expand All @@ -16,8 +24,12 @@ export const uploadFileAction = authProcedure
}),
)
.handler(async ({ input, ctx }) => {
const ip = getUnsafeIp(await headers()) || 'unknown'
const fingerprint = createHash('sha1').update(ip).digest('hex')

const result = await uploadFile({
file: input.file,
prefix: ctx.workspace ? undefined : fingerprint,
workspace: ctx.workspace,
})

Expand Down
70 changes: 67 additions & 3 deletions apps/web/src/actions/procedures/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { UnauthorizedError } from '@latitude-data/core/lib/errors'
import { getUnsafeIp } from '$/helpers/ip'
import { getCurrentUserOrError } from '$/services/auth/getCurrentUser'
import { cache } from '@latitude-data/core/cache'
import {
RateLimitError,
UnauthorizedError,
} from '@latitude-data/core/lib/errors'
import {
DocumentVersionsRepository,
ProjectsRepository,
} from '@latitude-data/core/repositories'
import * as Sentry from '@sentry/nextjs'
import { getCurrentUserOrError } from '$/services/auth/getCurrentUser'
import { ReplyError } from 'ioredis'
import { headers } from 'next/headers'
import { RateLimiterRedis, RateLimiterRes } from 'rate-limiter-flexible'
import { z } from 'zod'
import { createServerActionProcedure } from 'zsa'
import { createServerActionProcedure, TAnyCompleteProcedure } from 'zsa'

const DEFAULT_RATE_LIMIT_POINTS = 1000
const DEFAULT_RATE_LIMIT_DURATION = 60

export const errorHandlingProcedure = createServerActionProcedure()
.onError(async (error) => {
Expand All @@ -26,6 +37,22 @@ export const errorHandlingProcedure = createServerActionProcedure()
})
.handler((ctx) => ({ ...ctx }))

export const maybeAuthProcedure = createServerActionProcedure(
errorHandlingProcedure,
).handler(async () => {
try {
const data = await getCurrentUserOrError()

return {
session: data.session!,
workspace: data.workspace,
user: data.user,
}
} catch (error) {
return {}
}
})

export const authProcedure = createServerActionProcedure(
errorHandlingProcedure,
).handler(async () => {
Expand Down Expand Up @@ -76,3 +103,40 @@ export const withAdmin = createServerActionProcedure(authProcedure).handler(
return ctx
},
)

export async function withRateLimit<T extends TAnyCompleteProcedure>(
procedure: T,
{
limit = DEFAULT_RATE_LIMIT_POINTS,
period = DEFAULT_RATE_LIMIT_DURATION,
}: {
limit?: number
period?: number
},
): Promise<T> {
const rateLimiter = new RateLimiterRedis({
storeClient: await cache(),
points: limit,
duration: period,
})

return createServerActionProcedure(procedure).handler(
async ({ ctx, ...rest }) => {
const key = ctx.user?.id || getUnsafeIp(await headers()) || 'unknown'

try {
await rateLimiter.consume(key)
} catch (error) {
if (error instanceof RateLimiterRes) {
throw new RateLimitError('Too many requests')
}

if (!(error instanceof ReplyError)) {
throw error
}
}

return { ...ctx, ...rest }
},
) as T
}
Loading

0 comments on commit e53d442

Please sign in to comment.