Unverified Commit 5c258e21 authored by takatost's avatar takatost Committed by GitHub

feat: add Anthropic claude-3 models support (#2684)

parent 6a6133c1
...@@ -21,7 +21,7 @@ class AnthropicProvider(ModelProvider): ...@@ -21,7 +21,7 @@ class AnthropicProvider(ModelProvider):
# Use `claude-instant-1` model for validate, # Use `claude-instant-1` model for validate,
model_instance.validate_credentials( model_instance.validate_credentials(
model='claude-instant-1', model='claude-instant-1.2',
credentials=credentials credentials=credentials
) )
except CredentialsValidateFailedError as ex: except CredentialsValidateFailedError as ex:
......
...@@ -2,8 +2,8 @@ provider: anthropic ...@@ -2,8 +2,8 @@ provider: anthropic
label: label:
en_US: Anthropic en_US: Anthropic
description: description:
en_US: Anthropic’s powerful models, such as Claude 2 and Claude Instant. en_US: Anthropic’s powerful models, such as Claude 3.
zh_Hans: Anthropic 的强大模型,例如 Claude 2 和 Claude Instant zh_Hans: Anthropic 的强大模型,例如 Claude 3
icon_small: icon_small:
en_US: icon_s_en.svg en_US: icon_s_en.svg
icon_large: icon_large:
......
- claude-3-opus-20240229
- claude-3-sonnet-20240229
- claude-2.1
- claude-instant-1.2
- claude-2
- claude-instant-1
...@@ -34,3 +34,4 @@ pricing: ...@@ -34,3 +34,4 @@ pricing:
output: '24.00' output: '24.00'
unit: '0.000001' unit: '0.000001'
currency: USD currency: USD
deprecated: true
model: claude-3-opus-20240229
label:
en_US: claude-3-opus-20240229
model_type: llm
features:
- agent-thought
- vision
model_properties:
mode: chat
context_size: 200000
parameter_rules:
- name: temperature
use_template: temperature
- name: top_p
use_template: top_p
- name: top_k
label:
zh_Hans: 取样数量
en_US: Top k
type: int
help:
zh_Hans: 仅从每个后续标记的前 K 个选项中采样。
en_US: Only sample from the top K options for each subsequent token.
required: false
- name: max_tokens
use_template: max_tokens
required: true
default: 4096
min: 1
max: 4096
- name: response_format
use_template: response_format
pricing:
input: '15.00'
output: '75.00'
unit: '0.000001'
currency: USD
model: claude-3-sonnet-20240229
label:
en_US: claude-3-sonnet-20240229
model_type: llm
features:
- agent-thought
- vision
model_properties:
mode: chat
context_size: 200000
parameter_rules:
- name: temperature
use_template: temperature
- name: top_p
use_template: top_p
- name: top_k
label:
zh_Hans: 取样数量
en_US: Top k
type: int
help:
zh_Hans: 仅从每个后续标记的前 K 个选项中采样。
en_US: Only sample from the top K options for each subsequent token.
required: false
- name: max_tokens
use_template: max_tokens
required: true
default: 4096
min: 1
max: 4096
- name: response_format
use_template: response_format
pricing:
input: '3.00'
output: '15.00'
unit: '0.000001'
currency: USD
model: claude-instant-1.2
label:
en_US: claude-instant-1.2
model_type: llm
features: [ ]
model_properties:
mode: chat
context_size: 100000
parameter_rules:
- name: temperature
use_template: temperature
- name: top_p
use_template: top_p
- name: top_k
label:
zh_Hans: 取样数量
en_US: Top k
type: int
help:
zh_Hans: 仅从每个后续标记的前 K 个选项中采样。
en_US: Only sample from the top K options for each subsequent token.
required: false
- name: max_tokens
use_template: max_tokens
required: true
default: 4096
min: 1
max: 4096
- name: response_format
use_template: response_format
pricing:
input: '1.63'
output: '5.51'
unit: '0.000001'
currency: USD
...@@ -33,3 +33,4 @@ pricing: ...@@ -33,3 +33,4 @@ pricing:
output: '5.51' output: '5.51'
unit: '0.000001' unit: '0.000001'
currency: USD currency: USD
deprecated: true
...@@ -35,7 +35,7 @@ docx2txt==0.8 ...@@ -35,7 +35,7 @@ docx2txt==0.8
pypdfium2==4.16.0 pypdfium2==4.16.0
resend~=0.7.0 resend~=0.7.0
pyjwt~=2.8.0 pyjwt~=2.8.0
anthropic~=0.7.7 anthropic~=0.17.0
newspaper3k==0.2.8 newspaper3k==0.2.8
google-api-python-client==2.90.0 google-api-python-client==2.90.0
wikipedia==1.4.0 wikipedia==1.4.0
......
import os import os
from time import sleep from time import sleep
from typing import Any, Generator, List, Literal, Union from typing import Any, Literal, Union, Iterable
from anthropic.resources import Messages
from anthropic.types.message_delta_event import Delta
import anthropic import anthropic
import pytest import pytest
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from anthropic import Anthropic from anthropic import Anthropic, Stream
from anthropic._types import NOT_GIVEN, Body, Headers, NotGiven, Query from anthropic.types import MessageParam, Message, MessageStreamEvent, \
from anthropic.resources.completions import Completions ContentBlock, MessageStartEvent, Usage, TextDelta, MessageDeltaEvent, MessageStopEvent, ContentBlockDeltaEvent, \
from anthropic.types import Completion, completion_create_params MessageDeltaUsage
MOCK = os.getenv('MOCK_SWITCH', 'false') == 'true' MOCK = os.getenv('MOCK_SWITCH', 'false') == 'true'
class MockAnthropicClass(object): class MockAnthropicClass(object):
@staticmethod @staticmethod
def mocked_anthropic_chat_create_sync(model: str) -> Completion: def mocked_anthropic_chat_create_sync(model: str) -> Message:
return Completion( return Message(
completion='hello, I\'m a chatbot from anthropic', id='msg-123',
type='message',
role='assistant',
content=[ContentBlock(text='hello, I\'m a chatbot from anthropic', type='text')],
model=model, model=model,
stop_reason='stop_sequence' stop_reason='stop_sequence',
usage=Usage(
input_tokens=1,
output_tokens=1
)
) )
@staticmethod @staticmethod
def mocked_anthropic_chat_create_stream(model: str) -> Generator[Completion, None, None]: def mocked_anthropic_chat_create_stream(model: str) -> Stream[MessageStreamEvent]:
full_response_text = "hello, I'm a chatbot from anthropic" full_response_text = "hello, I'm a chatbot from anthropic"
for i in range(0, len(full_response_text) + 1): yield MessageStartEvent(
sleep(0.1) type='message_start',
if i == len(full_response_text): message=Message(
yield Completion( id='msg-123',
completion='', content=[],
model=model, role='assistant',
stop_reason='stop_sequence' model=model,
) stop_reason=None,
else: type='message',
yield Completion( usage=Usage(
completion=full_response_text[i], input_tokens=1,
model=model, output_tokens=1
stop_reason=''
) )
)
)
index = 0
for i in range(0, len(full_response_text)):
sleep(0.1)
yield ContentBlockDeltaEvent(
type='content_block_delta',
delta=TextDelta(text=full_response_text[i], type='text_delta'),
index=index
)
index += 1
yield MessageDeltaEvent(
type='message_delta',
delta=Delta(
stop_reason='stop_sequence'
),
usage=MessageDeltaUsage(
output_tokens=1
)
)
yield MessageStopEvent(type='message_stop')
def mocked_anthropic(self: Completions, *, def mocked_anthropic(self: Messages, *,
max_tokens_to_sample: int, max_tokens: int,
model: Union[str, Literal["claude-2.1", "claude-instant-1"]], messages: Iterable[MessageParam],
prompt: str, model: str,
stream: Literal[True], stream: Literal[True],
**kwargs: Any **kwargs: Any
) -> Union[Completion, Generator[Completion, None, None]]: ) -> Union[Message, Stream[MessageStreamEvent]]:
if len(self._client.api_key) < 18: if len(self._client.api_key) < 18:
raise anthropic.AuthenticationError('Invalid API key') raise anthropic.AuthenticationError('Invalid API key')
...@@ -55,12 +90,13 @@ class MockAnthropicClass(object): ...@@ -55,12 +90,13 @@ class MockAnthropicClass(object):
else: else:
return MockAnthropicClass.mocked_anthropic_chat_create_sync(model=model) return MockAnthropicClass.mocked_anthropic_chat_create_sync(model=model)
@pytest.fixture @pytest.fixture
def setup_anthropic_mock(request, monkeypatch: MonkeyPatch): def setup_anthropic_mock(request, monkeypatch: MonkeyPatch):
if MOCK: if MOCK:
monkeypatch.setattr(Completions, 'create', MockAnthropicClass.mocked_anthropic) monkeypatch.setattr(Messages, 'create', MockAnthropicClass.mocked_anthropic)
yield yield
if MOCK: if MOCK:
monkeypatch.undo() monkeypatch.undo()
\ No newline at end of file
...@@ -15,14 +15,14 @@ def test_validate_credentials(setup_anthropic_mock): ...@@ -15,14 +15,14 @@ def test_validate_credentials(setup_anthropic_mock):
with pytest.raises(CredentialsValidateFailedError): with pytest.raises(CredentialsValidateFailedError):
model.validate_credentials( model.validate_credentials(
model='claude-instant-1', model='claude-instant-1.2',
credentials={ credentials={
'anthropic_api_key': 'invalid_key' 'anthropic_api_key': 'invalid_key'
} }
) )
model.validate_credentials( model.validate_credentials(
model='claude-instant-1', model='claude-instant-1.2',
credentials={ credentials={
'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY') 'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY')
} }
...@@ -33,7 +33,7 @@ def test_invoke_model(setup_anthropic_mock): ...@@ -33,7 +33,7 @@ def test_invoke_model(setup_anthropic_mock):
model = AnthropicLargeLanguageModel() model = AnthropicLargeLanguageModel()
response = model.invoke( response = model.invoke(
model='claude-instant-1', model='claude-instant-1.2',
credentials={ credentials={
'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY'), 'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY'),
'anthropic_api_url': os.environ.get('ANTHROPIC_API_URL') 'anthropic_api_url': os.environ.get('ANTHROPIC_API_URL')
...@@ -49,7 +49,7 @@ def test_invoke_model(setup_anthropic_mock): ...@@ -49,7 +49,7 @@ def test_invoke_model(setup_anthropic_mock):
model_parameters={ model_parameters={
'temperature': 0.0, 'temperature': 0.0,
'top_p': 1.0, 'top_p': 1.0,
'max_tokens_to_sample': 10 'max_tokens': 10
}, },
stop=['How'], stop=['How'],
stream=False, stream=False,
...@@ -64,7 +64,7 @@ def test_invoke_stream_model(setup_anthropic_mock): ...@@ -64,7 +64,7 @@ def test_invoke_stream_model(setup_anthropic_mock):
model = AnthropicLargeLanguageModel() model = AnthropicLargeLanguageModel()
response = model.invoke( response = model.invoke(
model='claude-instant-1', model='claude-instant-1.2',
credentials={ credentials={
'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY') 'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY')
}, },
...@@ -78,7 +78,7 @@ def test_invoke_stream_model(setup_anthropic_mock): ...@@ -78,7 +78,7 @@ def test_invoke_stream_model(setup_anthropic_mock):
], ],
model_parameters={ model_parameters={
'temperature': 0.0, 'temperature': 0.0,
'max_tokens_to_sample': 100 'max_tokens': 100
}, },
stream=True, stream=True,
user="abc-123" user="abc-123"
...@@ -97,7 +97,7 @@ def test_get_num_tokens(): ...@@ -97,7 +97,7 @@ def test_get_num_tokens():
model = AnthropicLargeLanguageModel() model = AnthropicLargeLanguageModel()
num_tokens = model.get_num_tokens( num_tokens = model.get_num_tokens(
model='claude-instant-1', model='claude-instant-1.2',
credentials={ credentials={
'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY') 'anthropic_api_key': os.environ.get('ANTHROPIC_API_KEY')
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment