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": ">=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": {
|
"node_modules/@aws-crypto/sha256-browser": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz",
|
||||||
@ -16561,9 +16585,10 @@
|
|||||||
},
|
},
|
||||||
"src/backend": {
|
"src/backend": {
|
||||||
"name": "@heyputer/backend",
|
"name": "@heyputer/backend",
|
||||||
"version": "2.1.0",
|
"version": "2.4.1",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@anthropic-ai/sdk": "^0.26.1",
|
||||||
"@aws-sdk/client-polly": "^3.622.0",
|
"@aws-sdk/client-polly": "^3.622.0",
|
||||||
"@aws-sdk/client-textract": "^3.621.0",
|
"@aws-sdk/client-textract": "^3.621.0",
|
||||||
"@heyputer/kv.js": "^0.1.3",
|
"@heyputer/kv.js": "^0.1.3",
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"test": "npx mocha"
|
"test": "npx mocha"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@anthropic-ai/sdk": "^0.26.1",
|
||||||
"@aws-sdk/client-polly": "^3.622.0",
|
"@aws-sdk/client-polly": "^3.622.0",
|
||||||
"@aws-sdk/client-textract": "^3.621.0",
|
"@aws-sdk/client-textract": "^3.621.0",
|
||||||
"@heyputer/kv.js": "^0.1.3",
|
"@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');
|
const { OpenAIImageGenerationService } = require('./OpenAIImageGenerationService');
|
||||||
services.registerService('openai-image-generation', 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