Comparing version 0.0.9 to 1.0.0
@@ -13,3 +13,4 @@ /// <reference types="node" /> | ||
completeFromModel(fineTunedModel: string, options: CompletionRequest): Promise<Completion>; | ||
completionTextStream(engine: EngineId, options: CompletionRequest): Promise<Readable>; | ||
completeAndStream(engine: EngineId, options: CompletionRequest): Promise<Readable>; | ||
completeFromModelAndStream(fineTunedModel: string, options: CompletionRequest): Promise<Readable>; | ||
contentFilter(content: string, user?: string): Promise<ContentLabel>; | ||
@@ -30,2 +31,3 @@ search(engine: EngineId, options: SearchRequest): Promise<SearchDocument[]>; | ||
private request; | ||
private eventStreamTransformer; | ||
} |
@@ -45,21 +45,13 @@ (function (factory) { | ||
} | ||
async completionTextStream(engine, options) { | ||
async completeAndStream(engine, options) { | ||
const request = await this.requestRaw(`/engines/${engine}/completions`, 'POST', { ...options, stream: true }); | ||
console.warn("Stream completion is an experimental feature, don't use on production"); | ||
const transform = new stream_1.Transform({ | ||
transform: (chunk, _, callback) => { | ||
const body = chunk.slice(6).toString().trim(); | ||
if (body && body[0] !== '[') { | ||
try { | ||
const completion = JSON.parse(body); | ||
return callback(undefined, completion.choices[0].text); | ||
} | ||
catch (e) { | ||
throw new Error(`Faile to parse: "${chunk.toString()}"`); | ||
} | ||
} | ||
callback(); | ||
}, | ||
return request.body.pipe(this.eventStreamTransformer()); | ||
} | ||
async completeFromModelAndStream(fineTunedModel, options) { | ||
const request = await this.requestRaw(`/completions`, 'POST', { | ||
...options, | ||
model: fineTunedModel, | ||
stream: true, | ||
}); | ||
return request.body.pipe(transform); | ||
return request.body.pipe(this.eventStreamTransformer()); | ||
} | ||
@@ -163,6 +155,12 @@ async contentFilter(content, user) { | ||
try { | ||
errorBody = await response.text(); | ||
const { error: { message }, } = await response.json(); | ||
errorBody = message; | ||
} | ||
catch { | ||
errorBody = 'Failed to get body as text'; | ||
try { | ||
errorBody = await response.text(); | ||
} | ||
catch { | ||
errorBody = 'Failed to get body as text'; | ||
} | ||
} | ||
@@ -177,4 +175,22 @@ throw new Error(`OpenAI did not return ok: ${response.status} ~ Error body: ${errorBody}`); | ||
} | ||
eventStreamTransformer() { | ||
const dataHeader = Buffer.from('data: '); | ||
return new stream_1.Transform({ | ||
transform: function (chunk, _, callback) { | ||
if (chunk.length >= dataHeader.length && | ||
dataHeader.compare(chunk, undefined, dataHeader.length) === 0) { | ||
if (this.prevChunk) { | ||
const completion = JSON.parse(this.prevChunk.toString()); | ||
this.push(completion.choices[0].text); | ||
this.prevChunk = undefined; | ||
} | ||
chunk = chunk.slice(dataHeader.length); | ||
} | ||
this.prevChunk = this.prevChunk ? Buffer.concat([this.prevChunk, chunk]) : chunk; | ||
callback(); | ||
}, | ||
}); | ||
} | ||
} | ||
exports.OpenAI = OpenAI; | ||
}); |
{ | ||
"name": "openai", | ||
"version": "0.0.9", | ||
"version": "1.0.0", | ||
"description": "Tiny OpenAI API wrapper", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -74,3 +74,3 @@ # OpenAI | ||
// This API may change at any time | ||
const stream = await openai.completionTextStream('curie', { | ||
const stream = await openai.completeAndStream('curie', { // or completeFromModelAndStream | ||
prompt: 'Q: Hello\nA:', | ||
@@ -77,0 +77,0 @@ user: 'user-123' |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
20410
411
0