kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: switch zod-to-ts to zod-to-json-schema
rodzic
cce996ca39
commit
8a3c89ccc1
|
@ -65,7 +65,6 @@
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"zod": "^3.21.4",
|
"zod": "^3.21.4",
|
||||||
"zod-to-json-schema": "^3.21.2",
|
"zod-to-json-schema": "^3.21.2",
|
||||||
"zod-to-ts": "^1.1.4",
|
|
||||||
"zod-validation-error": "^1.3.0"
|
"zod-validation-error": "^1.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -86,9 +86,6 @@ dependencies:
|
||||||
zod-to-json-schema:
|
zod-to-json-schema:
|
||||||
specifier: ^3.21.2
|
specifier: ^3.21.2
|
||||||
version: 3.21.2(zod@3.21.4)
|
version: 3.21.2(zod@3.21.4)
|
||||||
zod-to-ts:
|
|
||||||
specifier: ^1.1.4
|
|
||||||
version: 1.1.4(typescript@5.1.3)(zod@3.21.4)
|
|
||||||
zod-validation-error:
|
zod-validation-error:
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
version: 1.3.0(zod@3.21.4)
|
version: 1.3.0(zod@3.21.4)
|
||||||
|
@ -4448,6 +4445,7 @@ packages:
|
||||||
resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==}
|
resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/uglify-js@3.17.4:
|
/uglify-js@3.17.4:
|
||||||
resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
|
resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
|
||||||
|
@ -4645,16 +4643,6 @@ packages:
|
||||||
zod: 3.21.4
|
zod: 3.21.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/zod-to-ts@1.1.4(typescript@5.1.3)(zod@3.21.4):
|
|
||||||
resolution: {integrity: sha512-jsCg+pTNxLAdJOfW4ul+SpechdGYEJPPnssSbqWdR2LSIkotT22k+UvqPb1nEHwe/YbEcbUOlZUfGM0npgR+Jg==}
|
|
||||||
peerDependencies:
|
|
||||||
typescript: ^4.9.4 || ^5.0.2
|
|
||||||
zod: ^3
|
|
||||||
dependencies:
|
|
||||||
typescript: 5.1.3
|
|
||||||
zod: 3.21.4
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/zod-validation-error@1.3.0(zod@3.21.4):
|
/zod-validation-error@1.3.0(zod@3.21.4):
|
||||||
resolution: {integrity: sha512-4WoQnuWnj06kwKR4A+cykRxFmy+CTvwMQO5ogTXLiVx1AuvYYmMjixh7sbkSsQTr1Fvtss6d5kVz8PGeMPUQjQ==}
|
resolution: {integrity: sha512-4WoQnuWnj06kwKR4A+cykRxFmy+CTvwMQO5ogTXLiVx1AuvYYmMjixh7sbkSsQTr1Fvtss6d5kVz8PGeMPUQjQ==}
|
||||||
engines: {node: '>=16.0.0'}
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { JSONRepairError, jsonrepair } from 'jsonrepair'
|
||||||
import { dedent } from 'ts-dedent'
|
import { dedent } from 'ts-dedent'
|
||||||
import { type SetRequired } from 'type-fest'
|
import { type SetRequired } from 'type-fest'
|
||||||
import { ZodType, z } from 'zod'
|
import { ZodType, z } from 'zod'
|
||||||
import { printNode, zodToTs } from 'zod-to-ts'
|
import { zodToJsonSchema } from 'zod-to-json-schema'
|
||||||
|
|
||||||
import * as errors from '@/errors'
|
import * as errors from '@/errors'
|
||||||
import * as types from '@/types'
|
import * as types from '@/types'
|
||||||
|
@ -275,22 +275,12 @@ export abstract class BaseChatCompletion<
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace zod-to-ts with zod-to-json-schema?
|
const schema = zodToJsonSchema(outputSchema) as types.Jsonifiable
|
||||||
const { node } = zodToTs(outputSchema)
|
const schemaStr = stringifyForModel(schema, [
|
||||||
|
'default',
|
||||||
if (node.kind === 152) {
|
'additionalProperties',
|
||||||
// Handle raw strings differently:
|
'$schema'
|
||||||
return dedent`Output a raw string only, without any additional text.`
|
])
|
||||||
}
|
|
||||||
|
|
||||||
const tsTypeString = printNode(node, {
|
|
||||||
removeComments: false,
|
|
||||||
// TODO: this doesn't seem to actually work, so we're doing it manually below
|
|
||||||
omitTrailingSemicolon: true,
|
|
||||||
noEmitHelpers: true
|
|
||||||
})
|
|
||||||
.replace(/^ {4}/gm, ' ')
|
|
||||||
.replace(/;$/gm, '')
|
|
||||||
let label: string
|
let label: string
|
||||||
if (outputSchema instanceof z.ZodArray) {
|
if (outputSchema instanceof z.ZodArray) {
|
||||||
label = 'JSON array (minified)'
|
label = 'JSON array (minified)'
|
||||||
|
@ -306,9 +296,9 @@ export abstract class BaseChatCompletion<
|
||||||
label = 'JSON value'
|
label = 'JSON value'
|
||||||
}
|
}
|
||||||
|
|
||||||
return dedent`Do not output code. Output a single ${label} in the following TypeScript format:
|
return dedent`Do not output code. Output a single ${label} according to the following JSON Schema:
|
||||||
\`\`\`ts
|
\`\`\`json
|
||||||
${tsTypeString}
|
${schemaStr}
|
||||||
\`\`\``
|
\`\`\``
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
src/utils.ts
14
src/utils.ts
|
@ -1,5 +1,6 @@
|
||||||
import { customAlphabet, urlAlphabet } from 'nanoid'
|
import { customAlphabet, urlAlphabet } from 'nanoid'
|
||||||
import type { ThrottledFunction } from 'p-throttle'
|
import type { ThrottledFunction } from 'p-throttle'
|
||||||
|
import { JsonValue } from 'type-fest'
|
||||||
|
|
||||||
import * as types from './types'
|
import * as types from './types'
|
||||||
|
|
||||||
|
@ -132,7 +133,10 @@ export function chunkMultipleStrings(
|
||||||
* @param json - JSON value to stringify
|
* @param json - JSON value to stringify
|
||||||
* @returns stringified value with all double quotes around object keys removed
|
* @returns stringified value with all double quotes around object keys removed
|
||||||
*/
|
*/
|
||||||
export function stringifyForModel(json: types.Jsonifiable): string {
|
export function stringifyForModel(
|
||||||
|
json: types.Jsonifiable,
|
||||||
|
omit: string[] = []
|
||||||
|
): string {
|
||||||
const UNIQUE_PREFIX = defaultIDGeneratorFn()
|
const UNIQUE_PREFIX = defaultIDGeneratorFn()
|
||||||
return (
|
return (
|
||||||
JSON.stringify(json, replacer)
|
JSON.stringify(json, replacer)
|
||||||
|
@ -143,7 +147,11 @@ export function stringifyForModel(json: types.Jsonifiable): string {
|
||||||
/**
|
/**
|
||||||
* Replacer function prefixing all keys with a unique identifier.
|
* Replacer function prefixing all keys with a unique identifier.
|
||||||
*/
|
*/
|
||||||
function replacer(_: string, value: any) {
|
function replacer(key: string, value: JsonValue) {
|
||||||
|
if (omit.includes(key)) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
if (value && typeof value === 'object') {
|
if (value && typeof value === 'object') {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value
|
return value
|
||||||
|
@ -152,7 +160,7 @@ export function stringifyForModel(json: types.Jsonifiable): string {
|
||||||
const replacement = {}
|
const replacement = {}
|
||||||
|
|
||||||
for (const k in value) {
|
for (const k in value) {
|
||||||
if (Object.hasOwnProperty.call(value, k)) {
|
if (Object.hasOwnProperty.call(value, k) && !omit.includes(k)) {
|
||||||
replacement[UNIQUE_PREFIX + k] = value[k]
|
replacement[UNIQUE_PREFIX + k] = value[k]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue