mirror of
https://github.com/HeyPuter/puter.git
synced 2025-01-23 06:00:21 +08:00
feat(puterai): add claude
This commit is contained in:
parent
9d5963cdf5
commit
d009cd0aaf
27
package-lock.json
generated
27
package-lock.json
generated
@ -263,6 +263,30 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/sdk": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.26.1.tgz",
|
||||
"integrity": "sha512-HeMJP1bDFfQPQS3XTJAmfXkFBdZ88wvfkE05+vsoA9zGn5dHqEaHOPsqkazf/i0gXYg2XlLxxZrf6rUAarSqzw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/node-fetch": "^2.6.4",
|
||||
"abort-controller": "^3.0.0",
|
||||
"agentkeepalive": "^4.2.1",
|
||||
"form-data-encoder": "1.7.2",
|
||||
"formdata-node": "^4.3.2",
|
||||
"node-fetch": "^2.6.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/sdk/node_modules/@types/node": {
|
||||
"version": "18.19.45",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.45.tgz",
|
||||
"integrity": "sha512-VZxPKNNhjKmaC1SUYowuXSRSMGyQGmQjvvA1xE4QZ0xce2kLtEhPDS+kqpCPBZYgqblCLQ2DAjSzmgCM5auvhA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@aws-crypto/sha256-browser": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz",
|
||||
@ -16561,9 +16585,10 @@
|
||||
},
|
||||
"src/backend": {
|
||||
"name": "@heyputer/backend",
|
||||
"version": "2.1.0",
|
||||
"version": "2.4.1",
|
||||
"license": "AGPL-3.0-only",
|
||||
"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",
|
||||
|
@ -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",
|
||||
|
109
src/backend/src/modules/puterai/ClaudeService.js
Normal file
109
src/backend/src/modules/puterai/ClaudeService.js
Normal 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,
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user