xref: /plugin/aichat/Model/Anthropic/ChatModel.php (revision dce0dee5ef27bcbbc5570fc278f3e75f426c19c5)
1*dce0dee5SAndreas Gohr<?php
2*dce0dee5SAndreas Gohr
3*dce0dee5SAndreas Gohrnamespace dokuwiki\plugin\aichat\Model\Anthropic;
4*dce0dee5SAndreas Gohr
5*dce0dee5SAndreas Gohruse dokuwiki\plugin\aichat\Model\AbstractModel;
6*dce0dee5SAndreas Gohruse dokuwiki\plugin\aichat\Model\ChatInterface;
7*dce0dee5SAndreas Gohr
8*dce0dee5SAndreas Gohrclass ChatModel extends AbstractModel implements ChatInterface
9*dce0dee5SAndreas Gohr{
10*dce0dee5SAndreas Gohr    /** @inheritdoc */
11*dce0dee5SAndreas Gohr    public function __construct(string $name, array $config)
12*dce0dee5SAndreas Gohr    {
13*dce0dee5SAndreas Gohr        parent::__construct($name, $config);
14*dce0dee5SAndreas Gohr
15*dce0dee5SAndreas Gohr        $this->http->headers['x-api-key'] = $config['anthropic_key'] ?? '';
16*dce0dee5SAndreas Gohr        $this->http->headers['anthropic-version'] = '2023-06-01';
17*dce0dee5SAndreas Gohr    }
18*dce0dee5SAndreas Gohr
19*dce0dee5SAndreas Gohr    /** @inheritdoc */
20*dce0dee5SAndreas Gohr    public function getAnswer(array $messages): string
21*dce0dee5SAndreas Gohr    {
22*dce0dee5SAndreas Gohr        // convert OpenAI Style to Anthropic style
23*dce0dee5SAndreas Gohr        $system = '';
24*dce0dee5SAndreas Gohr        $chat = [];
25*dce0dee5SAndreas Gohr        foreach ($messages as $message) {
26*dce0dee5SAndreas Gohr            if ($message['role'] === 'system') {
27*dce0dee5SAndreas Gohr                $system .= $message['content'] . "\n";
28*dce0dee5SAndreas Gohr            } else {
29*dce0dee5SAndreas Gohr                $chat[] = $message;
30*dce0dee5SAndreas Gohr            }
31*dce0dee5SAndreas Gohr        }
32*dce0dee5SAndreas Gohr
33*dce0dee5SAndreas Gohr        $data = [
34*dce0dee5SAndreas Gohr            'messages' => $chat,
35*dce0dee5SAndreas Gohr            'model' => $this->getModelName(),
36*dce0dee5SAndreas Gohr            'max_tokens' => $this->getMaxEmbeddingTokenLength(),
37*dce0dee5SAndreas Gohr            'stream' => false,
38*dce0dee5SAndreas Gohr            'temperature' => 0.0,
39*dce0dee5SAndreas Gohr        ];
40*dce0dee5SAndreas Gohr
41*dce0dee5SAndreas Gohr        if ($system) {
42*dce0dee5SAndreas Gohr            $data['system'] = $system;
43*dce0dee5SAndreas Gohr        }
44*dce0dee5SAndreas Gohr
45*dce0dee5SAndreas Gohr        $response = $this->request('messages', $data);
46*dce0dee5SAndreas Gohr
47*dce0dee5SAndreas Gohr        print_r($response);
48*dce0dee5SAndreas Gohr
49*dce0dee5SAndreas Gohr        return $response['content'][0]['text'];
50*dce0dee5SAndreas Gohr    }
51*dce0dee5SAndreas Gohr
52*dce0dee5SAndreas Gohr    /**
53*dce0dee5SAndreas Gohr     * Send a request to the OpenAI API
54*dce0dee5SAndreas Gohr     *
55*dce0dee5SAndreas Gohr     * @param string $endpoint
56*dce0dee5SAndreas Gohr     * @param array $data Payload to send
57*dce0dee5SAndreas Gohr     * @return array API response
58*dce0dee5SAndreas Gohr     * @throws \Exception
59*dce0dee5SAndreas Gohr     */
60*dce0dee5SAndreas Gohr    protected function request($endpoint, $data)
61*dce0dee5SAndreas Gohr    {
62*dce0dee5SAndreas Gohr        $url = 'https://api.anthropic.com/v1/' . $endpoint;
63*dce0dee5SAndreas Gohr        return $this->sendAPIRequest('POST', $url, $data);
64*dce0dee5SAndreas Gohr    }
65*dce0dee5SAndreas Gohr
66*dce0dee5SAndreas Gohr    /** @inheritdoc */
67*dce0dee5SAndreas Gohr    protected function parseAPIResponse($response)
68*dce0dee5SAndreas Gohr    {
69*dce0dee5SAndreas Gohr        if (isset($response['usage'])) {
70*dce0dee5SAndreas Gohr            $this->tokensUsed += $response['usage']['input_tokens'] + $response['usage']['output_tokens'];
71*dce0dee5SAndreas Gohr        }
72*dce0dee5SAndreas Gohr
73*dce0dee5SAndreas Gohr        if (isset($response['error'])) {
74*dce0dee5SAndreas Gohr            throw new \Exception('Anthropic API error: ' . $response['error']['message']);
75*dce0dee5SAndreas Gohr        }
76*dce0dee5SAndreas Gohr
77*dce0dee5SAndreas Gohr        return $response;
78*dce0dee5SAndreas Gohr    }
79*dce0dee5SAndreas Gohr}
80