Skip to content

Commit a51ccb9

Browse files
16397 llm proxy custom providers (#7)
1 parent 800d46f commit a51ccb9

66 files changed

Lines changed: 2839 additions & 382 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
release_notes.md
22
target
33
.DS_STORE
4-
.vscode/launch.json
4+
.vscode/launch.json
5+
.env

CHANGELOG.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,60 @@
1+
## 1.39.0 - 2024-11-15
2+
### Added
3+
- Added encryption integration
4+
5+
### Changed
6+
- Removed support for Redis TLS config
7+
8+
9+
## 1.38.0 - 2024-11-09
10+
### Added
11+
- Added support for `claude-3-5-haiku`
12+
- Added support for Redis TLS config
13+
- Added support for `gpt-4o-2024-08-06`
14+
15+
## 1.37.0 - 2024-10-23
16+
### Added
17+
- Added request level timeout with HTTP header `x-request-timeout`
18+
19+
## 1.36.5 - 2024-10-16
20+
### Changed
21+
- Updated `gpt-4o` pricing according to OpenAI updates
22+
23+
## 1.36.4 - 2024-10-15
24+
### Added
25+
- Added support for `gpt-4o-mini` in routes
26+
27+
## 1.36.3 - 2024-09-16
28+
### Added
29+
- Added support for OpenAI o1 models
30+
31+
## 1.36.2 - 2024-09-13
32+
### Fixed
33+
- Fixed compatibility issues between Anthropic SDK and AWS Bedrock
34+
35+
## 1.36.1 - 2024-09-10
36+
### Fixed
37+
- Fixed provider selection issue when a key is associated with multiple providers
38+
39+
## 1.36.0 - 2024-09-09
40+
### Added
41+
- Added Amazon Bedrock integration for Claude models
42+
43+
## 1.35.2 - 2024-08-10
44+
### Changed
45+
- Changed aggregated table column data types from `INT` to `BIGINT`
46+
47+
## 1.35.1 - 2024-08-10
48+
### Changed
49+
- Changed cache TTL from `1h` to `24h` for keys and provider settings
50+
51+
## 1.35.0 - 2024-08-10
52+
### Added
53+
- Added cost tracking for `gpt-4o-2024-08-06`
54+
55+
### Changed
56+
- Changed default read time out for PostgreSQL
57+
158
## 1.34.0 - 2024-07-29
259
### Added
360
- Added cost tracking for `gpt-4o-mini`

Dockerfile.dev

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
FROM golang:1.22.1 AS build
1+
FROM golang:1.23.2 AS build
22
ENV CGO_ENABLED=0
33
ENV GOOS=linux
44

55
WORKDIR /go/src/github.com/bricks-cloud/bricksllm/
66
COPY . /go/src/github.com/bricks-cloud/bricksllm/
77
RUN go build -ldflags="-s -w" -o ./bin/bricksllm ./cmd/bricksllm/main.go
88

9-
FROM alpine:3.17
9+
FROM alpine:3.20
1010
RUN apk --no-cache add ca-certificates
1111
WORKDIR /usr/bin
1212
COPY --from=build /go/src/github.com/bricks-cloud/bricksllm/bin /go/bin

Dockerfile.prod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
FROM golang:1.22.1 AS build
1+
FROM golang:1.23.2 AS build
22
ENV CGO_ENABLED=0
33
ENV GOOS=linux
44

55
WORKDIR /go/src/github.com/bricks-cloud/bricksllm/
66
COPY . /go/src/github.com/bricks-cloud/bricksllm/
77
RUN go build -ldflags="-s -w" -o ./bin/bricksllm ./cmd/bricksllm/main.go
88

9-
FROM alpine:3.17
9+
FROM alpine:3.20
1010
RUN apk --no-cache add ca-certificates
1111
WORKDIR /usr/bin
1212
COPY --from=build /go/src/github.com/bricks-cloud/bricksllm/bin /go/bin

cmd/bricksllm/main.go

Lines changed: 41 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
auth "github.com/bricks-cloud/bricksllm/internal/authenticator"
1313
"github.com/bricks-cloud/bricksllm/internal/cache"
1414
"github.com/bricks-cloud/bricksllm/internal/config"
15+
"github.com/bricks-cloud/bricksllm/internal/encryptor"
1516
"github.com/bricks-cloud/bricksllm/internal/logger/zap"
1617
"github.com/bricks-cloud/bricksllm/internal/manager"
1718
"github.com/bricks-cloud/bricksllm/internal/message"
@@ -173,137 +174,112 @@ func main() {
173174
}
174175
rMemStore.Listen()
175176

176-
rateLimitRedisCache := redis.NewClient(&redis.Options{
177-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
178-
Password: cfg.RedisPassword,
179-
DB: 0,
180-
})
177+
defaultRedisOption := func(cfg *config.Config, dbIndex int) *redis.Options {
178+
179+
options := &redis.Options{
180+
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
181+
Password: cfg.RedisPassword,
182+
DB: cfg.RedisDBStartIndex + dbIndex,
183+
}
184+
185+
return options
186+
}
187+
188+
rateLimitRedisCache := redis.NewClient(defaultRedisOption(cfg, 0))
181189
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
182190
defer cancel()
183191
if err := rateLimitRedisCache.Ping(ctx).Err(); err != nil {
184192
log.Sugar().Fatalf("error connecting to rate limit redis cache: %v", err)
185193
}
186194

187-
costLimitRedisCache := redis.NewClient(&redis.Options{
188-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
189-
Password: cfg.RedisPassword,
190-
DB: 1,
191-
})
195+
costLimitRedisCache := redis.NewClient(defaultRedisOption(cfg, 1))
192196

193197
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
194198
defer cancel()
195199
if err := costLimitRedisCache.Ping(ctx).Err(); err != nil {
196200
log.Sugar().Fatalf("error connecting to cost limit redis cache: %v", err)
197201
}
198202

199-
costRedisStorage := redis.NewClient(&redis.Options{
200-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
201-
Password: cfg.RedisPassword,
202-
DB: 2,
203-
})
203+
costRedisStorage := redis.NewClient(defaultRedisOption(cfg, 2))
204204

205205
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
206206
defer cancel()
207207
if err := costRedisStorage.Ping(ctx).Err(); err != nil {
208208
log.Sugar().Fatalf("error connecting to cost limit redis storage: %v", err)
209209
}
210210

211-
apiRedisCache := redis.NewClient(&redis.Options{
212-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
213-
Password: cfg.RedisPassword,
214-
DB: 3,
215-
})
211+
apiRedisCache := redis.NewClient(defaultRedisOption(cfg, 3))
216212

217213
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
218214
defer cancel()
219215
if err := apiRedisCache.Ping(ctx).Err(); err != nil {
220216
log.Sugar().Fatalf("error connecting to api redis cache: %v", err)
221217
}
222218

223-
accessRedisCache := redis.NewClient(&redis.Options{
224-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
225-
Password: cfg.RedisPassword,
226-
DB: 4,
227-
})
219+
accessRedisCache := redis.NewClient(defaultRedisOption(cfg, 4))
228220

229221
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
230222
defer cancel()
231223
if err := accessRedisCache.Ping(ctx).Err(); err != nil {
232224
log.Sugar().Fatalf("error connecting to api redis cache: %v", err)
233225
}
234226

235-
userRateLimitRedisCache := redis.NewClient(&redis.Options{
236-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
237-
Password: cfg.RedisPassword,
238-
DB: 5,
239-
})
227+
userRateLimitRedisCache := redis.NewClient(defaultRedisOption(cfg, 5))
240228

241229
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
242230
defer cancel()
243231
if err := userRateLimitRedisCache.Ping(ctx).Err(); err != nil {
244232
log.Sugar().Fatalf("error connecting to user rate limit redis cache: %v", err)
245233
}
246234

247-
userCostLimitRedisCache := redis.NewClient(&redis.Options{
248-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
249-
Password: cfg.RedisPassword,
250-
DB: 6,
251-
})
235+
userCostLimitRedisCache := redis.NewClient(defaultRedisOption(cfg, 6))
252236

253237
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
254238
defer cancel()
255239
if err := userCostLimitRedisCache.Ping(ctx).Err(); err != nil {
256240
log.Sugar().Fatalf("error connecting to user cost limit redis cache: %v", err)
257241
}
258242

259-
userCostRedisStorage := redis.NewClient(&redis.Options{
260-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
261-
Password: cfg.RedisPassword,
262-
DB: 7,
263-
})
243+
userCostRedisStorage := redis.NewClient(defaultRedisOption(cfg, 7))
264244

265245
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
266246
defer cancel()
267247
if err := userCostRedisStorage.Ping(ctx).Err(); err != nil {
268248
log.Sugar().Fatalf("error connecting to user cost redis cache: %v", err)
269249
}
270250

271-
userAccessRedisCache := redis.NewClient(&redis.Options{
272-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
273-
Password: cfg.RedisPassword,
274-
DB: 8,
275-
})
251+
userAccessRedisCache := redis.NewClient(defaultRedisOption(cfg, 8))
276252

277253
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
278254
defer cancel()
279255
if err := userAccessRedisCache.Ping(ctx).Err(); err != nil {
280256
log.Sugar().Fatalf("error connecting to user access redis storage: %v", err)
281257
}
282258

283-
providerSettingsRedisCache := redis.NewClient(&redis.Options{
284-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
285-
Password: cfg.RedisPassword,
286-
DB: 9,
287-
})
259+
providerSettingsRedisCache := redis.NewClient(defaultRedisOption(cfg, 9))
288260

289261
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
290262
defer cancel()
291263
if err := providerSettingsRedisCache.Ping(ctx).Err(); err != nil {
292264
log.Sugar().Fatalf("error connecting to provider settings redis storage: %v", err)
293265
}
294266

295-
keysRedisCache := redis.NewClient(&redis.Options{
296-
Addr: fmt.Sprintf("%s:%s", cfg.RedisHosts, cfg.RedisPort),
297-
Password: cfg.RedisPassword,
298-
DB: 10,
299-
})
267+
keysRedisCache := redis.NewClient(defaultRedisOption(cfg, 10))
300268

301269
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
302270
defer cancel()
303271
if err := keysRedisCache.Ping(ctx).Err(); err != nil {
304272
log.Sugar().Fatalf("error connecting to keys redis storage: %v", err)
305273
}
306274

275+
requestsLimitRedisStorage := redis.NewClient(defaultRedisOption(cfg, 11))
276+
277+
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
278+
defer cancel()
279+
if err := requestsLimitRedisStorage.Ping(ctx).Err(); err != nil {
280+
log.Sugar().Fatalf("error connecting to requests limit redis storage: %v", err)
281+
}
282+
307283
rateLimitCache := redisStorage.NewCache(rateLimitRedisCache, cfg.RedisWriteTimeout, cfg.RedisReadTimeout)
308284
costLimitCache := redisStorage.NewCache(costLimitRedisCache, cfg.RedisWriteTimeout, cfg.RedisReadTimeout)
309285
costStorage := redisStorage.NewStore(costRedisStorage, cfg.RedisWriteTimeout, cfg.RedisReadTimeout)
@@ -317,12 +293,17 @@ func main() {
317293

318294
psCache := redisStorage.NewProviderSettingsCache(providerSettingsRedisCache, cfg.RedisWriteTimeout, cfg.RedisReadTimeout)
319295
keysCache := redisStorage.NewKeysCache(keysRedisCache, cfg.RedisWriteTimeout, cfg.RedisReadTimeout)
296+
requestsLimitStorage := redisStorage.NewStore(requestsLimitRedisStorage, cfg.RedisWriteTimeout, cfg.RedisReadTimeout)
320297

321-
v := validator.NewValidator(costLimitCache, rateLimitCache, costStorage)
298+
encryptor, err := encryptor.NewEncryptor(cfg.DecryptionEndpoint, cfg.EncryptionEndpoint, cfg.EnableEncrytion, cfg.EncryptionTimeout, cfg.Audience)
299+
if cfg.EnableEncrytion && err != nil {
300+
log.Sugar().Fatalf("error creating encryption client: %v", err)
301+
}
302+
v := validator.NewValidator(costLimitCache, rateLimitCache, costStorage, requestsLimitStorage)
322303

323-
m := manager.NewManager(store, costLimitCache, rateLimitCache, accessCache, keysCache)
304+
m := manager.NewManager(store, costLimitCache, rateLimitCache, accessCache, keysCache, requestsLimitStorage)
324305
krm := manager.NewReportingManager(costStorage, store, store, v)
325-
psm := manager.NewProviderSettingsManager(store, psCache)
306+
psm := manager.NewProviderSettingsManager(store, psCache, encryptor)
326307
cpm := manager.NewCustomProvidersManager(store, cpMemStore)
327308
rm := manager.NewRouteManager(store, store, rMemStore, psm)
328309
pm := manager.NewPolicyManager(store, rMemStore)
@@ -357,9 +338,9 @@ func main() {
357338

358339
uv := validator.NewUserValidator(userCostLimitCache, userRateLimitCache, userCostStorage)
359340

360-
rec := recorder.NewRecorder(costStorage, userCostStorage, costLimitCache, userCostLimitCache, ce, store)
341+
rec := recorder.NewRecorder(costStorage, userCostStorage, costLimitCache, userCostLimitCache, ce, store, requestsLimitStorage)
361342
rlm := manager.NewRateLimitManager(rateLimitCache, userRateLimitCache)
362-
a := auth.NewAuthenticator(psm, m, rm, store)
343+
a := auth.NewAuthenticator(psm, m, rm, store, encryptor)
363344

364345
c := cache.NewCache(apiCache)
365346

docker-compose.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
version: '3.8'
21
services:
32
redis:
43
image: redis:6.2-alpine
54
restart: always
65
ports:
76
- '6379:6379'
87
command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
9-
volumes:
8+
volumes:
109
- redis:/data
1110
postgresql:
1211
image: postgres:14.1-alpine
@@ -16,10 +15,10 @@ services:
1615
- POSTGRES_PASSWORD=postgres
1716
ports:
1817
- '5432:5432'
19-
volumes:
18+
volumes:
2019
- postgresql:/var/lib/postgresql/data
2120
# bricksllm:
22-
# depends_on:
21+
# depends_on:
2322
# - redis
2423
# - postgresql
2524
# image: luyuanxin1995/bricksllm
@@ -38,4 +37,4 @@ volumes:
3837
redis:
3938
driver: local
4039
postgresql:
41-
driver: local
40+
driver: local

docs/admin.yaml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,8 +1423,6 @@ components:
14231423
type: object
14241424
description: API Credentials associated with different providers.
14251425
example: { "apikey": "MY_OPENAI_API_KEY" }
1426-
required:
1427-
- apikey
14281426
properties:
14291427
apikey:
14301428
type: string
@@ -1438,6 +1436,18 @@ components:
14381436
type: string
14391437
example: MY_AZURE_OPENAI_RESOURCE_NAME
14401438
description: Required for Azure OpenAI integrations.
1439+
awsAccessKeyId:
1440+
type: string
1441+
example: MY_AWS_ACCESS_KEY_ID
1442+
description: Required for Bedrock Anthropic integrations.
1443+
awsSecretAccessKey:
1444+
type: string
1445+
example: MY_AWS_SECRET_ACCESS_KEY
1446+
description: Required for Bedrock Anthropic integrations.
1447+
awsRegion:
1448+
type: string
1449+
example: MY_AWS_REGION
1450+
description: Required for Bedrock Anthropic integrations.
14411451

14421452
ReportingEventsRequest:
14431453
type: object

0 commit comments

Comments
 (0)