Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
anthropic support
Browse files Browse the repository at this point in the history
  • Loading branch information
patcher9 committed Mar 8, 2024
1 parent 7063141 commit 1d995a6
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 45 deletions.
19 changes: 3 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"author": "Doku Labs",
"license": "ISC",
"dependencies": {
"@anthropic-ai/tokenizer": "^0.0.4",
"stream": "^0.0.2"
},
"devDependencies": {
Expand Down
159 changes: 132 additions & 27 deletions src/anthropic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {sendData} from './helpers.js';
import {countTokens} from '@anthropic-ai/tokenizer';
import { Readable } from 'stream';

/**
* Initializes Anthropic functionality with performance tracking.
Expand Down Expand Up @@ -31,33 +31,138 @@ import {countTokens} from '@anthropic-ai/tokenizer';
* }
*/
export default function initAnthropic({ llm, dokuUrl, apiKey, environment, applicationName, skipResp }) {
const originalCompletionsCreate = llm.completions.create;
const originalMessagesCreate = llm.messages.create;

// Define wrapped method
llm.completions.create = async function(params) {
const start = performance.now();
const response = await originalCompletionsCreate.apply(this, params);
const end = performance.now();
const duration = (end - start) / 1000;

const data = {
llmReqId: response.id,
environment: environment,
applicationName: applicationName,
sourceLanguage: 'Javascript',
endpoint: 'anthropic.completions',
skipResp: skipResp,
completionTokens: countTokens(response.completion),
promptTokens: countTokens(prompt),
requestDuration: duration,
model: params.model,
prompt: params.prompt,
finishReason: response.stop_reason,
response: response.completion,
};

await sendData(data, dokuUrl, apiKey);

return response;
llm.messages.create = async function(params) {
let streaming = params.stream || false;
if (streaming) {
// Call original method
const start = performance.now();
const originalResponseStream = await originalMessagesCreate.call(this, params);

// Create a pass-through stream
const passThroughStream = new Readable({
read() {},
objectMode: true // Set to true because the chunks are objects
});

let dataResponse = '';
var responseId = '';
var promptTokens = 0;
var completionTokens = 0;

// Immediately-invoked async function to handle streaming
(async () => {
for await (const chunk of originalResponseStream) {
if (chunk.type === 'message_start') {
responseId = chunk.message.id;
promptTokens = chunk.message.usage.input_tokens;
passThroughStream.push(chunk); // Push chunk to the pass-through stream
}
else if (chunk.type === 'content_block_delta') {
dataResponse += chunk.delta.text;
passThroughStream.push(chunk); // Push chunk to the pass-through stream
}
else if (chunk.type === 'message_delta') {
completionTokens = chunk.usage.output_tokens;
passThroughStream.push(chunk); // Push chunk to the pass-through stream
}
}
passThroughStream.push(null); // Signal end of the pass-through stream

// Process response data after stream has ended
const end = performance.now();
const duration = (end - start) / 1000;

let formattedMessages = [];
for (let message of params.messages) {
let role = message.role;
let content = message.content;

if (Array.isArray(content)) {
let contentStr = content.map(item => {
if (item.type) {
return `${item.type}: ${item.text || item.image_url}`;
} else {
return `text: ${item.text}`;
}
}).join(", ");
formattedMessages.push(`${role}: ${contentStr}`);
} else {
formattedMessages.push(`${role}: ${content}`);
}
}
let prompt = formattedMessages.join("\n");

// Prepare the data object for Doku
const data = {
llmReqId: responseId,
environment: environment,
applicationName: applicationName,
sourceLanguage: 'Javascript',
endpoint: 'anthropic.messages',
skipResp: skipResp,
requestDuration: duration,
model: params.model,
prompt: prompt,
response: dataResponse,
promptTokens: promptTokens,
completionTokens: completionTokens,
};
data.totalTokens = data.promptTokens + data.completionTokens;

await sendData(data, dokuUrl, apiKey);
})();

// Return the pass-through stream to the original caller
return passThroughStream;
}
else{
const start = performance.now();
const response = await originalMessagesCreate.call(this, params);
const end = performance.now();
const duration = (end - start) / 1000;
let formattedMessages = [];
for (let message of params.messages) {
let role = message.role;
let content = message.content;

if (Array.isArray(content)) {
let contentStr = content.map(item => {
if (item.type) {
return `${item.type}: ${item.text || item.image_url}`;
} else {
return `text: ${item.text}`;
}
}).join(", ");
formattedMessages.push(`${role}: ${contentStr}`);
} else {
formattedMessages.push(`${role}: ${content}`);
}
}
let prompt = formattedMessages.join("\n");

const data = {
llmReqId: response.id,
environment: environment,
applicationName: applicationName,
sourceLanguage: 'Javascript',
endpoint: 'anthropic.messages',
skipResp: skipResp,
completionTokens: response.usage.input_tokens,
promptTokens: response.usage.output_tokens,
requestDuration: duration,
model: params.model,
prompt: prompt,
finishReason: response.stop_reason,
response: response.content[0].text,
};
data.totalTokens = data.promptTokens + data.completionTokens;

await sendData(data, dokuUrl, apiKey);

return response;
}
};
}
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function init({ llm, dokuUrl, apiKey, environment="default", applicationName="de
initOpenAI({ llm, dokuUrl, apiKey, environment, applicationName, skipResp });
} else if (llm.generate && typeof llm.rerank === 'function') {
initCohere({ llm, dokuUrl, apiKey, environment, applicationName, skipResp });
} else if (typeof llm.summarize=== 'function') {
} else if (llm.messages && typeof llm.messages.create === 'function') {
initAnthropic({ llm, dokuUrl, apiKey, environment, applicationName, skipResp });
}
}
Expand Down

0 comments on commit 1d995a6

Please sign in to comment.