diff --git a/examples/sentiment/src/main.ts b/examples/sentiment/src/main.ts index fec6971e..555db0c1 100644 --- a/examples/sentiment/src/main.ts +++ b/examples/sentiment/src/main.ts @@ -18,5 +18,6 @@ processRequests("😀> ", process.argv[2], async (request) => { console.log(response.message); return; } - console.log(`The sentiment is ${response.data.sentiment}`); + + console.log(`The sentiment is ${response.data.sentiment}. The request used ${response.api?.usage.total_tokens ?? -1} tokens.`); }); diff --git a/src/model.ts b/src/model.ts index dc0dafcb..5c31d20d 100644 --- a/src/model.ts +++ b/src/model.ts @@ -104,9 +104,14 @@ function createAxiosLanguageModel(url: string, config: object, defaultParams: Re temperature: 0, n: 1 }; - const result = await client.post(url, params, { validateStatus: status => true }); + const result = await client.post(url, params, { + validateStatus: (_status) => true + }); + + const { choices, ...apiData } = result.data; + if (result.status === 200) { - return success(result.data.choices[0].message?.content ?? ""); + return success(result.data.choices[0].message?.content ?? "", apiData); } if (!isTransientHttpError(result.status) || retryCount >= retryMaxAttempts) { return error(`REST API error ${result.status}: ${result.statusText}`); diff --git a/src/result.ts b/src/result.ts index 7ec8c078..2659a2e0 100644 --- a/src/result.ts +++ b/src/result.ts @@ -1,25 +1,46 @@ /** * An object representing a successful operation with a result of type `T`. */ -export type Success = { success: true, data: T }; +export type Success = { + success: true; + data: T; + api?: OpenAiInfo; +}; /** * An object representing an operation that failed for the reason given in `message`. */ -export type Error = { success: false, message: string }; +export type Error = { success: false; message: string }; /** * An object representing a successful or failed operation of type `T`. */ export type Result = Success | Error; +/** + * An object containing the information returned by the OpenAI-Api. It contains + * information on the tokens used, the model used, a timestamp, and the specific + * id the prompt has in the backend. + */ +export type OpenAiInfo = { + id: string; + object: string; + created: number; + model: string; + usage: { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; + }; +}; + /** * Returns a `Success` object. * @param data The value for the `data` property of the result. * @returns A `Success` object. */ -export function success(data: T): Success { - return { success: true, data }; +export function success(data: T, info?: OpenAiInfo): Success { + return info ? { success: true, data, api: info } : { success: true, data }; } /** diff --git a/src/typechat.ts b/src/typechat.ts index 3ab774f6..3e5b7555 100644 --- a/src/typechat.ts +++ b/src/typechat.ts @@ -97,7 +97,9 @@ export function createJsonTranslator(model: TypeChatLanguageMo if (!response.success) { return response; } - const responseText = response.data; + + const { api, data: responseText } = response; + const startIndex = responseText.indexOf("{"); const endIndex = responseText.lastIndexOf("}"); if (!(startIndex >= 0 && endIndex > startIndex)) { @@ -106,7 +108,7 @@ export function createJsonTranslator(model: TypeChatLanguageMo const jsonText = responseText.slice(startIndex, endIndex + 1); const validation = validator.validate(jsonText); if (validation.success) { - return validation; + return api ? { ...validation, api } : validation; } if (!attemptRepair) { return error(`JSON validation failed: ${validation.message}\n${jsonText}`);