feat(puterai): add claude

This commit is contained in:
KernelDeimos
2024-08-20 22:23:27 -04:00
committed by Eric Dubé
parent 9d5963cdf5
commit d009cd0aaf
4 changed files with 141 additions and 1 deletions

View File

@@ -7,6 +7,7 @@
"test": "npx mocha"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.26.1",
"@aws-sdk/client-polly": "^3.622.0",
"@aws-sdk/client-textract": "^3.621.0",
"@heyputer/kv.js": "^0.1.3",

View File

@@ -0,0 +1,109 @@
const { default: Anthropic } = require("@anthropic-ai/sdk");
const BaseService = require("../../services/BaseService");
const { whatis } = require("../../util/langutil");
const { PassThrough } = require("stream");
const { TypedValue } = require("../../services/drivers/meta/Runtime");
const PUTER_PROMPT = `
You are running on an open-source platform called Puter,
as the Claude implementation for a driver interface
called puter-chat-completion.
The following JSON contains system messages from the
user of the driver interface (typically an app on Puter):
`.replace('\n', ' ').trim();
class ClaudeService extends BaseService {
static MODULES = {
Anthropic: require('@anthropic-ai/sdk'),
}
async _init () {
this.anthropic = new Anthropic({
apiKey: this.config.apiKey
});
}
static IMPLEMENTS = {
['puter-chat-completion']: {
async complete ({ messages, stream }) {
const adapted_messages = [];
const system_prompts = [];
let previous_was_user = false;
for ( const message of messages ) {
if ( typeof message.content === 'string' ) {
message.content = {
type: 'text',
text: message.content,
};
}
if ( whatis(message.content) !== 'array' ) {
message.content = [message.content];
}
if ( message.role === 'user' && previous_was_user ) {
const last_msg = adapted_messages[adapted_messages.length-1];
last_msg.content.push(
...(Array.isArray ? message.content : [message.content])
);
continue;
}
if ( message.role === 'system' ) {
system_prompts.push(...message.content);
continue;
}
adapted_messages.push(message);
if ( message.role === 'user' ) {
previous_was_user = true;
}
}
if ( stream ) {
const stream = new PassThrough();
const retval = new TypedValue({
$: 'stream',
content_type: 'application/x-ndjson',
chunked: true,
}, stream);
(async () => {
const completion = await this.anthropic.messages.stream({
model: 'claude-3-5-sonnet-20240620',
max_tokens: 1000,
temperature: 0,
system: PUTER_PROMPT + JSON.stringify(system_prompts),
messages: adapted_messages,
});
for await ( const event of completion ) {
if (
event.type !== 'content_block_delta' ||
event.delta.type !== 'text_delta'
) continue;
const str = JSON.stringify({
text: event.delta.text,
});
stream.write(str + '\n');
}
})();
return retval;
}
const msg = await this.anthropic.messages.create({
model: 'claude-3-5-sonnet-20240620',
max_tokens: 1000,
temperature: 0,
system: PUTER_PROMPT + JSON.stringify(system_prompts),
messages: adapted_messages,
});
return {
message: msg,
finish_reason: 'stop'
};
}
}
}
}
module.exports = {
ClaudeService,
};

View File

@@ -28,6 +28,11 @@ class PuterAIModule extends AdvancedBase {
const { OpenAIImageGenerationService } = require('./OpenAIImageGenerationService');
services.registerService('openai-image-generation', OpenAIImageGenerationService);
}
if ( !! config?.services?.claude ) {
const { ClaudeService } = require('./ClaudeService');
services.registerService('claude', ClaudeService);
}
}
}