Skip to content

Commit 17ca506

Browse files
authored
[hotfix/cache-key] Resolve cache key issues for gpt-4 (#3)
1 parent e0e8257 commit 17ca506

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

src/cache.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,28 @@ describe('cache', () => {
5353
result = await getCacheKey(params);
5454
expect(result).toEqual('91b1af0c3f20778905ab588460bcb1d14b4621445f32fd871d7fe23056142923');
5555
});
56+
57+
it('returns a different hash uniquely representing the params when body has different values', async () => {
58+
let params = {
59+
method: 'POST',
60+
path: '/v1/chat/completions',
61+
authHeader: null,
62+
body: '{"model": "gpt-4", "messages": [{"role": "user","content": "Example 1"}]}',
63+
moderation: true,
64+
};
65+
let result = await getCacheKey(params);
66+
expect(result).toEqual('ca1346d5b14a10b852c82502d525ef5d081c5068dc40c1d451e13cfc22417af1');
67+
68+
params = {
69+
method: 'POST',
70+
path: '/v1/chat/completions',
71+
authHeader: null,
72+
body: '{"model": "gpt-4", "messages": [{"role": "user","content": "Example 2"}]}',
73+
moderation: true,
74+
};
75+
result = await getCacheKey(params);
76+
expect(result).toEqual('433436d4185941ab1f0d2158e94c93167d7d154a052f96dda81b0e7fa5560eaa');
77+
});
78+
5679
});
5780
});

src/cache.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,39 @@ import { Redis } from '@upstash/redis/cloudflare';
22
import { Env } from './env';
33
import { getHeadersAsObject, objectHash } from './utils';
44

5+
interface AnyObject {
6+
[key: string]: any;
7+
}
8+
9+
function sortObjectKeys(obj: AnyObject): AnyObject {
10+
const sortedKeys = Object.keys(obj).sort();
11+
const sortedObj: AnyObject = {};
12+
13+
sortedKeys.forEach((key) => {
14+
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
15+
sortedObj[key] = sortObjectKeys(obj[key]);
16+
} else if (Array.isArray(obj[key])) {
17+
sortedObj[key] = obj[key].map((item: any) => {
18+
if (typeof item === 'object' && !Array.isArray(item)) {
19+
return sortObjectKeys(item);
20+
}
21+
return item;
22+
});
23+
} else {
24+
sortedObj[key] = obj[key];
25+
}
26+
});
27+
28+
return sortedObj;
29+
}
30+
531
interface GetCacheKeyProps {
632
method: string;
733
path: string;
834
authHeader: string | null;
935
body: string | null;
1036
}
37+
1138
export const getCacheKey = async (props: GetCacheKeyProps): Promise<string> => {
1239
// https://stackoverflow.com/a/40924449
1340
const propsWithoutUndefined = Object.keys(props).reduce((acc, key) => {
@@ -16,7 +43,23 @@ export const getCacheKey = async (props: GetCacheKeyProps): Promise<string> => {
1643
if (key === 'body' && propValue !== '') {
1744
try {
1845
const body = JSON.parse(propValue);
19-
propValue = JSON.stringify(body, Object.keys(body).sort());
46+
const sortedBody: AnyObject = {};
47+
const sortedKeys = Object.keys(body).sort();
48+
sortedKeys.forEach((key) => {
49+
if (typeof body[key] === 'object' && !Array.isArray(body[key])) {
50+
sortedBody[key] = sortObjectKeys(body[key]);
51+
} else if (Array.isArray(body[key])) {
52+
sortedBody[key] = body[key].map((item: any) => {
53+
if (typeof item === 'object' && !Array.isArray(item)) {
54+
return sortObjectKeys(item);
55+
}
56+
return item;
57+
});
58+
} else {
59+
sortedBody[key] = body[key];
60+
}
61+
});
62+
propValue = JSON.stringify(sortedBody);
2063
} catch (_error) {
2164
propValue = '';
2265
}

0 commit comments

Comments
 (0)