chatgpt-api/test/llms/parse-output.test.ts

302 wiersze
9.4 KiB
TypeScript
Czysty Zwykły widok Historia

import test from 'ava'
import { z } from 'zod'
import {
2023-06-21 18:33:15 +00:00
extractJSONFromString,
parseArrayOutput,
parseBooleanOutput,
parseNumberOutput,
2023-06-20 14:54:53 +00:00
parseObjectOutput,
parseOutput
} from '@/llms/parse-output'
2023-06-21 18:33:15 +00:00
test('extractJSONFromString should extract JSON object from string', (t) => {
let jsonStr = 'Some text {"name":"John Doe"} more text'
let result = extractJSONFromString(jsonStr, 'object')
t.deepEqual(result[0], { name: 'John Doe' })
jsonStr =
'Some text {"name":"John Doe","age":42,"address":{"street":"Main Street","number":42}} more text'
result = extractJSONFromString(jsonStr, 'object')
t.deepEqual(result[0], {
name: 'John Doe',
age: 42,
address: { street: 'Main Street', number: 42 }
})
jsonStr = 'foo {"name":"John Doe","school":"St. John\'s"} bar'
result = extractJSONFromString(jsonStr, 'object')
t.deepEqual(result[0], { name: 'John Doe', school: "St. John's" })
})
test('extractJSONFromString should extract an invalid JSON object from string', (t) => {
let jsonStr = 'Some text {"name":\'John Doe\'} more text'
let result = extractJSONFromString(jsonStr, 'object')
t.deepEqual(result[0], { name: 'John Doe' })
jsonStr = 'Some text {"name":"John Doe","age":42,} more text'
result = extractJSONFromString(jsonStr, 'object')
t.deepEqual(result[0], { name: 'John Doe', age: 42 })
})
test('extractJSONFromString should extract multiple JSON objects from string', (t) => {
let jsonStr = 'Some text {"name":"John Doe"} more text {"name":"Jane Doe"}'
let result = extractJSONFromString(jsonStr, 'object')
t.deepEqual(result[0], { name: 'John Doe' })
t.deepEqual(result[1], { name: 'Jane Doe' })
jsonStr =
'Some text {"name":"John Doe","age":42,"address":{"street":"Main Street","number":42}} more text {"name":"Jane Doe","age":42,"address":{"street":"Main Street","number":42}}'
result = extractJSONFromString(jsonStr, 'object')
t.deepEqual(result[0], {
name: 'John Doe',
age: 42,
address: { street: 'Main Street', number: 42 }
})
t.deepEqual(result[1], {
name: 'Jane Doe',
age: 42,
address: { street: 'Main Street', number: 42 }
})
})
test('extractJSONFromString should extract JSON array from string', (t) => {
let jsonString = 'Some text [1,2,3] more text'
let result = extractJSONFromString(jsonString, 'array')
t.deepEqual(result[0], [1, 2, 3])
jsonString = 'Some text ["foo","bar","\'quoted\'"] more text'
result = extractJSONFromString(jsonString, 'array')
t.deepEqual(result[0], ['foo', 'bar', "'quoted'"])
})
test('extractJSONFromString should extract an invalid JSON array from string', (t) => {
let jsonString = 'Some text [1,2,3,] more text'
let result = extractJSONFromString(jsonString, 'array')
t.deepEqual(result[0], [1, 2, 3])
jsonString = "Some text ['foo','bar'] more text"
result = extractJSONFromString(jsonString, 'array')
t.deepEqual(result[0], ['foo', 'bar'])
})
test('extractJSONFromString should extract multiple JSON arrays from string', (t) => {
const jsonString = 'Some text [1,2,3] more text [4,5,6]'
const result = extractJSONFromString(jsonString, 'array')
t.deepEqual(result[0], [1, 2, 3])
t.deepEqual(result[1], [4, 5, 6])
})
test('extractJSONFromString should return an empty array if no JSON object is found', (t) => {
const jsonString = 'Some text'
const result = extractJSONFromString(jsonString, 'object')
t.deepEqual(result, [])
})
test('extractJSONFromString should return an empty array if no JSON array is found', (t) => {
const jsonString = 'Some text'
const result = extractJSONFromString(jsonString, 'array')
t.deepEqual(result, [])
})
test('parseArrayOutput - handles valid arrays correctly', (t) => {
const output1 = parseArrayOutput('[1,2,3]')
const output2 = parseArrayOutput('["a", "b", "c"]')
const output3 = parseArrayOutput('[{"a": 1}, {"b": 2}]')
t.snapshot(output1, 'should return [1, 2, 3] for "[1,2,3]"')
t.snapshot(output2, 'should return ["a", "b", "c"] for "["a", "b", "c"]')
t.snapshot(
output3,
'should return [{"a": 1}, {"b": 2}] for [{"a": 1}, {"b": 2}]'
)
})
test('parseArrayOutput - handles arrays surrounded by text correctly', (t) => {
const output1 = parseArrayOutput('The array is [1,2,3]')
const output2 = parseArrayOutput('Array: ["a", "b", "c"]. That\'s all!')
const output3 = parseArrayOutput(
'This is the array [{"a": 1}, {"b": 2}] in the text'
)
t.snapshot(output1, 'should return [1, 2, 3] for "The array is [1,2,3]"')
t.snapshot(
output2,
'should return ["a", "b", "c"] for "Array: ["a", "b", "c"]. That\'s all!"'
)
t.snapshot(
output3,
'should return [{"a": 1}, {"b": 2}] for "This is the array [{"a": 1}, {"b": 2}] in the text"'
)
})
test('parseArrayOutput - throws error for invalid arrays', (t) => {
const error = t.throws(
() => {
parseArrayOutput('not a valid array')
},
{ instanceOf: Error }
)
t.snapshot(error?.message)
})
test('parseObjectOutput - handles valid objects correctly', (t) => {
const output1 = parseObjectOutput('{"a":1,"b":2,"c":3}')
const output2 = parseObjectOutput(
'{"name":"John","age":30,"city":"New York"}'
)
t.snapshot(
output1,
'should return {"a":1,"b":2,"c":3} for {"a":1,"b":2,"c":3}'
)
t.snapshot(
output2,
'should return {"name":"John","age":30,"city":"New York"} for {"name":"John","age":30,"city":"New York"}'
)
})
test('parseObjectOutput - handles objects surrounded by text correctly', (t) => {
const output1 = parseObjectOutput('The object is {"a":1,"b":2,"c":3}')
const output2 = parseObjectOutput(
'Object: {"name":"John","age":30,"city":"New York"}. That\'s all!'
)
t.snapshot(
output1,
'should return {"a":1,"b":2,"c":3} for "The object is {"a":1,"b":2,"c":3}"'
)
t.snapshot(
output2,
'should return {"name":"John","age":30,"city":"New York"} for "Object: {"name":"John","age":30,"city":"New York"}. That\'s all!"'
)
})
test('parseObjectOutput - handles JSON array of objects', (t) => {
const output = parseObjectOutput('[{"a":1,"b":2},{"c":3,"d":4}]')
t.snapshot(
output,
'should return first object {"a":1,"b":2} for [{"a":1,"b":2},{"c":3,"d":4}]'
)
})
test('parseObjectOutput - throws error for invalid objects', (t) => {
const error = t.throws(
() => {
parseObjectOutput('not a valid object')
},
{ instanceOf: Error }
)
t.snapshot(error?.message)
})
test('parseBooleanOutput - handles `true` outputs correctly', (t) => {
const output1 = parseBooleanOutput('True')
const output2 = parseBooleanOutput('TRUE')
const output3 = parseBooleanOutput('true.')
t.snapshot(output1, 'should return true for "True"')
t.snapshot(output2, 'should return true for "TRUE"')
t.snapshot(output3, 'should return true for "true."')
})
test('parseBooleanOutput - handles `false` outputs correctly', (t) => {
const output1 = parseBooleanOutput('False')
const output2 = parseBooleanOutput('FALSE')
const output3 = parseBooleanOutput('false!')
t.snapshot(output1, 'should return false for "False"')
t.snapshot(output2, 'should return false for "FALSE"')
t.snapshot(output3, 'should return false for "false!"')
})
test('parseBooleanOutput - throws error for invalid outputs', (t) => {
const error = t.throws(
() => {
parseBooleanOutput('NotBooleanValue')
},
{ instanceOf: Error }
)
t.snapshot(error?.message)
})
test('parseNumberOutput - handles integer outputs correctly', (t) => {
const output1 = parseNumberOutput('42', z.number().int())
const output2 = parseNumberOutput(' -5 ', z.number().int())
t.snapshot(output1, 'should return 42 for "42"')
t.snapshot(output2, 'should return -5 for " -5 "')
})
test('parseNumberOutput - handles float outputs correctly', (t) => {
const output1 = parseNumberOutput('42.42', z.number())
const output2 = parseNumberOutput(' -5.5 ', z.number())
t.snapshot(output1, 'should return 42.42 for "42.42"')
t.snapshot(output2, 'should return -5.5 for " -5.5 "')
})
test('parseNumberOutput - throws error for invalid outputs', (t) => {
const error = t.throws(
() => {
parseNumberOutput('NotANumber', z.number())
},
{ instanceOf: Error }
)
t.snapshot(error?.message)
})
2023-06-20 14:54:53 +00:00
test('parseOutput - handles arrays correctly', (t) => {
const arraySchema = z.array(z.number())
const output = '[1, 2, 3]'
const result = parseOutput(output, arraySchema)
t.snapshot(result, 'should parse and return [1, 2, 3] for "[1, 2, 3]"')
})
test('parseOutput - handles objects correctly', (t) => {
const objectSchema = z.object({ a: z.number(), b: z.string() })
const output = '{"a": 1, "b": "two"}'
const result = parseOutput(output, objectSchema)
t.snapshot(
result,
'should parse and return {"a": 1, "b": "two"} for "{"a": 1, "b": "two"}"'
)
})
test('parseOutput - handles booleans correctly', (t) => {
const booleanSchema = z.boolean()
const output = 'True'
const result = parseOutput(output, booleanSchema)
t.snapshot(result, 'should parse and return true for "True"')
})
test('parseOutput - handles numbers correctly', (t) => {
const numberSchema = z.number()
const output = '123.45'
const result = parseOutput(output, numberSchema)
t.snapshot(result, 'should parse and return 123.45 for "123.45"')
})
test('parseOutput - throws error for invalid data', (t) => {
const numberSchema = z.number()
const output = 'not a number'
const error = t.throws(
() => {
parseOutput(output, numberSchema)
},
{ instanceOf: Error }
)
t.snapshot(error?.message)
})