langfun 0.0.2.dev20240429__py3-none-any.whl → 0.1.2.dev202501140804__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langfun/__init__.py +20 -2
- langfun/core/__init__.py +16 -5
- langfun/core/agentic/__init__.py +30 -0
- langfun/core/agentic/action.py +854 -0
- langfun/core/agentic/action_eval.py +150 -0
- langfun/core/agentic/action_eval_test.py +109 -0
- langfun/core/agentic/action_test.py +136 -0
- langfun/core/coding/python/__init__.py +5 -11
- langfun/core/coding/python/correction.py +37 -21
- langfun/core/coding/python/correction_test.py +29 -3
- langfun/core/coding/python/execution.py +40 -216
- langfun/core/coding/python/execution_test.py +29 -89
- langfun/core/coding/python/generation.py +21 -11
- langfun/core/coding/python/generation_test.py +2 -2
- langfun/core/coding/python/parsing.py +108 -193
- langfun/core/coding/python/parsing_test.py +2 -105
- langfun/core/component.py +63 -2
- langfun/core/component_test.py +53 -0
- langfun/core/concurrent.py +414 -117
- langfun/core/concurrent_test.py +111 -24
- langfun/core/console.py +18 -5
- langfun/core/console_test.py +17 -0
- langfun/core/eval/__init__.py +16 -1
- langfun/core/eval/base.py +622 -174
- langfun/core/eval/base_test.py +200 -54
- langfun/core/eval/matching.py +63 -76
- langfun/core/eval/matching_test.py +17 -8
- langfun/core/eval/patching.py +130 -0
- langfun/core/eval/patching_test.py +170 -0
- langfun/core/eval/scoring.py +26 -26
- langfun/core/eval/scoring_test.py +19 -2
- langfun/core/eval/v2/__init__.py +42 -0
- langfun/core/eval/v2/checkpointing.py +380 -0
- langfun/core/eval/v2/checkpointing_test.py +228 -0
- langfun/core/eval/v2/eval_test_helper.py +136 -0
- langfun/core/eval/v2/evaluation.py +725 -0
- langfun/core/eval/v2/evaluation_test.py +180 -0
- langfun/core/eval/v2/example.py +305 -0
- langfun/core/eval/v2/example_test.py +128 -0
- langfun/core/eval/v2/experiment.py +1048 -0
- langfun/core/eval/v2/experiment_test.py +433 -0
- langfun/core/eval/v2/metric_values.py +156 -0
- langfun/core/eval/v2/metric_values_test.py +80 -0
- langfun/core/eval/v2/metrics.py +357 -0
- langfun/core/eval/v2/metrics_test.py +203 -0
- langfun/core/eval/v2/progress.py +348 -0
- langfun/core/eval/v2/progress_test.py +82 -0
- langfun/core/eval/v2/progress_tracking.py +210 -0
- langfun/core/eval/v2/progress_tracking_test.py +66 -0
- langfun/core/eval/v2/reporting.py +270 -0
- langfun/core/eval/v2/reporting_test.py +158 -0
- langfun/core/eval/v2/runners.py +488 -0
- langfun/core/eval/v2/runners_test.py +334 -0
- langfun/core/langfunc.py +4 -17
- langfun/core/langfunc_test.py +22 -6
- langfun/core/language_model.py +577 -39
- langfun/core/language_model_test.py +470 -56
- langfun/core/llms/__init__.py +87 -16
- langfun/core/llms/anthropic.py +312 -87
- langfun/core/llms/anthropic_test.py +71 -3
- langfun/core/llms/cache/base.py +21 -2
- langfun/core/llms/cache/in_memory.py +13 -0
- langfun/core/llms/cache/in_memory_test.py +53 -2
- langfun/core/llms/compositional.py +101 -0
- langfun/core/llms/compositional_test.py +73 -0
- langfun/core/llms/deepseek.py +117 -0
- langfun/core/llms/deepseek_test.py +61 -0
- langfun/core/llms/fake.py +11 -7
- langfun/core/llms/fake_test.py +14 -0
- langfun/core/llms/gemini.py +507 -0
- langfun/core/llms/gemini_test.py +195 -0
- langfun/core/llms/google_genai.py +62 -218
- langfun/core/llms/google_genai_test.py +9 -202
- langfun/core/llms/groq.py +160 -144
- langfun/core/llms/groq_test.py +31 -137
- langfun/core/llms/llama_cpp.py +15 -42
- langfun/core/llms/llama_cpp_test.py +4 -30
- langfun/core/llms/openai.py +395 -203
- langfun/core/llms/openai_compatible.py +179 -0
- langfun/core/llms/openai_compatible_test.py +495 -0
- langfun/core/llms/openai_test.py +30 -395
- langfun/core/llms/rest.py +113 -0
- langfun/core/llms/rest_test.py +111 -0
- langfun/core/llms/vertexai.py +192 -0
- langfun/core/llms/vertexai_test.py +52 -0
- langfun/core/logging.py +284 -0
- langfun/core/logging_test.py +125 -0
- langfun/core/message.py +319 -9
- langfun/core/message_test.py +190 -13
- langfun/core/modalities/__init__.py +6 -2
- langfun/core/modalities/audio.py +30 -0
- langfun/core/modalities/audio_test.py +63 -0
- langfun/core/modalities/image.py +39 -20
- langfun/core/modalities/image_test.py +52 -9
- langfun/core/modalities/mime.py +206 -29
- langfun/core/modalities/mime_test.py +90 -9
- langfun/core/modalities/ms_office.py +117 -0
- langfun/core/modalities/ms_office_test.py +389 -0
- langfun/core/modalities/pdf.py +22 -0
- langfun/core/modalities/pdf_test.py +57 -0
- langfun/core/modalities/video.py +9 -26
- langfun/core/modalities/video_test.py +3 -3
- langfun/core/modality.py +26 -3
- langfun/core/modality_test.py +2 -2
- langfun/core/sampling.py +11 -11
- langfun/core/structured/__init__.py +12 -16
- langfun/core/structured/completion.py +32 -5
- langfun/core/structured/completion_test.py +7 -6
- langfun/core/structured/description.py +2 -2
- langfun/core/structured/description_test.py +3 -3
- langfun/core/structured/function_generation.py +60 -27
- langfun/core/structured/function_generation_test.py +72 -2
- langfun/core/structured/mapping.py +97 -47
- langfun/core/structured/mapping_test.py +90 -2
- langfun/core/structured/parsing.py +33 -21
- langfun/core/structured/parsing_test.py +53 -9
- langfun/core/structured/querying.py +746 -0
- langfun/core/structured/{prompting_test.py → querying_test.py} +469 -51
- langfun/core/structured/schema.py +204 -97
- langfun/core/structured/schema_generation.py +1 -1
- langfun/core/structured/schema_test.py +130 -29
- langfun/core/structured/scoring.py +125 -19
- langfun/core/structured/scoring_test.py +30 -0
- langfun/core/structured/tokenization.py +64 -0
- langfun/core/structured/tokenization_test.py +48 -0
- langfun/core/template.py +115 -1
- langfun/core/template_test.py +71 -1
- langfun/core/templates/conversation.py +9 -0
- langfun/core/templates/conversation_test.py +4 -3
- langfun/core/templates/selfplay_test.py +10 -2
- langfun-0.1.2.dev202501140804.dist-info/METADATA +225 -0
- langfun-0.1.2.dev202501140804.dist-info/RECORD +153 -0
- {langfun-0.0.2.dev20240429.dist-info → langfun-0.1.2.dev202501140804.dist-info}/WHEEL +1 -1
- langfun/core/coding/python/errors.py +0 -108
- langfun/core/coding/python/errors_test.py +0 -99
- langfun/core/coding/python/permissions.py +0 -90
- langfun/core/coding/python/permissions_test.py +0 -86
- langfun/core/structured/prompting.py +0 -238
- langfun/core/text_formatting.py +0 -162
- langfun/core/text_formatting_test.py +0 -47
- langfun-0.0.2.dev20240429.dist-info/METADATA +0 -100
- langfun-0.0.2.dev20240429.dist-info/RECORD +0 -108
- {langfun-0.0.2.dev20240429.dist-info → langfun-0.1.2.dev202501140804.dist-info}/LICENSE +0 -0
- {langfun-0.0.2.dev20240429.dist-info → langfun-0.1.2.dev202501140804.dist-info}/top_level.txt +0 -0
langfun/core/llms/__init__.py
CHANGED
@@ -24,35 +24,88 @@ from langfun.core.llms.fake import StaticMapping
|
|
24
24
|
from langfun.core.llms.fake import StaticResponse
|
25
25
|
from langfun.core.llms.fake import StaticSequence
|
26
26
|
|
27
|
+
# Compositional models.
|
28
|
+
from langfun.core.llms.compositional import RandomChoice
|
29
|
+
|
30
|
+
# REST-based models.
|
31
|
+
from langfun.core.llms.rest import REST
|
32
|
+
|
27
33
|
# Gemini models.
|
28
34
|
from langfun.core.llms.google_genai import GenAI
|
29
|
-
from langfun.core.llms.google_genai import
|
30
|
-
from langfun.core.llms.google_genai import
|
31
|
-
from langfun.core.llms.google_genai import
|
32
|
-
from langfun.core.llms.google_genai import
|
35
|
+
from langfun.core.llms.google_genai import GeminiFlash2_0ThinkingExp_20241219
|
36
|
+
from langfun.core.llms.google_genai import GeminiFlash2_0Exp
|
37
|
+
from langfun.core.llms.google_genai import GeminiExp_20241206
|
38
|
+
from langfun.core.llms.google_genai import GeminiExp_20241114
|
39
|
+
from langfun.core.llms.google_genai import GeminiPro1_5
|
40
|
+
from langfun.core.llms.google_genai import GeminiPro1_5_002
|
41
|
+
from langfun.core.llms.google_genai import GeminiPro1_5_001
|
42
|
+
from langfun.core.llms.google_genai import GeminiFlash1_5
|
43
|
+
from langfun.core.llms.google_genai import GeminiFlash1_5_002
|
44
|
+
from langfun.core.llms.google_genai import GeminiFlash1_5_001
|
45
|
+
from langfun.core.llms.google_genai import GeminiPro1
|
46
|
+
|
47
|
+
from langfun.core.llms.vertexai import VertexAI
|
48
|
+
from langfun.core.llms.vertexai import VertexAIGeminiFlash2_0ThinkingExp_20241219
|
49
|
+
from langfun.core.llms.vertexai import VertexAIGeminiFlash2_0Exp
|
50
|
+
from langfun.core.llms.vertexai import VertexAIGeminiExp_20241206
|
51
|
+
from langfun.core.llms.vertexai import VertexAIGeminiExp_20241114
|
52
|
+
from langfun.core.llms.vertexai import VertexAIGeminiPro1_5
|
53
|
+
from langfun.core.llms.vertexai import VertexAIGeminiPro1_5_002
|
54
|
+
from langfun.core.llms.vertexai import VertexAIGeminiPro1_5_001
|
55
|
+
from langfun.core.llms.vertexai import VertexAIGeminiFlash1_5
|
56
|
+
from langfun.core.llms.vertexai import VertexAIGeminiFlash1_5_002
|
57
|
+
from langfun.core.llms.vertexai import VertexAIGeminiFlash1_5_001
|
58
|
+
from langfun.core.llms.vertexai import VertexAIGeminiPro1
|
59
|
+
|
60
|
+
# Base for OpenAI-compatible models.
|
61
|
+
from langfun.core.llms.openai_compatible import OpenAICompatible
|
33
62
|
|
34
63
|
# OpenAI models.
|
35
64
|
from langfun.core.llms.openai import OpenAI
|
36
65
|
|
66
|
+
from langfun.core.llms.openai import GptO1
|
67
|
+
from langfun.core.llms.openai import GptO1Preview
|
68
|
+
from langfun.core.llms.openai import GptO1Preview_20240912
|
69
|
+
from langfun.core.llms.openai import GptO1Mini
|
70
|
+
from langfun.core.llms.openai import GptO1Mini_20240912
|
71
|
+
|
72
|
+
from langfun.core.llms.openai import Gpt4oMini
|
73
|
+
from langfun.core.llms.openai import Gpt4oMini_20240718
|
74
|
+
from langfun.core.llms.openai import Gpt4o
|
75
|
+
from langfun.core.llms.openai import Gpt4o_20241120
|
76
|
+
from langfun.core.llms.openai import Gpt4o_20240806
|
77
|
+
from langfun.core.llms.openai import Gpt4o_20240513
|
78
|
+
|
37
79
|
from langfun.core.llms.openai import Gpt4Turbo
|
38
80
|
from langfun.core.llms.openai import Gpt4Turbo_20240409
|
39
81
|
from langfun.core.llms.openai import Gpt4TurboPreview
|
40
|
-
from langfun.core.llms.openai import
|
41
|
-
from langfun.core.llms.openai import
|
82
|
+
from langfun.core.llms.openai import Gpt4TurboPreview_20240125
|
83
|
+
from langfun.core.llms.openai import Gpt4TurboPreview_20231106
|
42
84
|
from langfun.core.llms.openai import Gpt4VisionPreview
|
43
|
-
from langfun.core.llms.openai import
|
85
|
+
from langfun.core.llms.openai import Gpt4VisionPreview_20231106
|
44
86
|
from langfun.core.llms.openai import Gpt4
|
45
|
-
from langfun.core.llms.openai import
|
87
|
+
from langfun.core.llms.openai import Gpt4_20230613
|
88
|
+
|
46
89
|
from langfun.core.llms.openai import Gpt4_32K
|
47
|
-
from langfun.core.llms.openai import
|
90
|
+
from langfun.core.llms.openai import Gpt4_32K_20230613
|
48
91
|
|
49
92
|
from langfun.core.llms.openai import Gpt35Turbo
|
50
|
-
from langfun.core.llms.openai import
|
51
|
-
from langfun.core.llms.openai import
|
52
|
-
from langfun.core.llms.openai import
|
93
|
+
from langfun.core.llms.openai import Gpt35Turbo_20240125
|
94
|
+
from langfun.core.llms.openai import Gpt35Turbo_20231106
|
95
|
+
from langfun.core.llms.openai import Gpt35Turbo_20230613
|
53
96
|
from langfun.core.llms.openai import Gpt35Turbo16K
|
54
|
-
from langfun.core.llms.openai import
|
55
|
-
|
97
|
+
from langfun.core.llms.openai import Gpt35Turbo16K_20230613
|
98
|
+
|
99
|
+
# For backward compatibility.
|
100
|
+
Gpt4TurboPreview_0125 = Gpt4TurboPreview_20240125
|
101
|
+
Gpt4TurboPreview_1106 = Gpt4TurboPreview_20231106
|
102
|
+
Gpt4VisionPreview_1106 = Gpt4VisionPreview_20231106
|
103
|
+
Gpt4_0613 = Gpt4_20230613
|
104
|
+
Gpt4_32K_0613 = Gpt4_32K_20230613
|
105
|
+
Gpt35Turbo_0125 = Gpt35Turbo_20240125
|
106
|
+
Gpt35Turbo_1106 = Gpt35Turbo_20231106
|
107
|
+
Gpt35Turbo_0613 = Gpt35Turbo_20230613
|
108
|
+
Gpt35Turbo16K_0613 = Gpt35Turbo16K_20230613
|
56
109
|
|
57
110
|
from langfun.core.llms.openai import Gpt35
|
58
111
|
|
@@ -62,21 +115,39 @@ from langfun.core.llms.openai import Gpt3Babbage
|
|
62
115
|
from langfun.core.llms.openai import Gpt3Ada
|
63
116
|
|
64
117
|
from langfun.core.llms.anthropic import Anthropic
|
118
|
+
from langfun.core.llms.anthropic import Claude35Sonnet
|
119
|
+
from langfun.core.llms.anthropic import Claude35Sonnet20241022
|
120
|
+
from langfun.core.llms.anthropic import Claude35Sonnet20240620
|
65
121
|
from langfun.core.llms.anthropic import Claude3Opus
|
66
122
|
from langfun.core.llms.anthropic import Claude3Sonnet
|
67
123
|
from langfun.core.llms.anthropic import Claude3Haiku
|
124
|
+
from langfun.core.llms.anthropic import VertexAIAnthropic
|
125
|
+
from langfun.core.llms.anthropic import VertexAIClaude3_5_Sonnet_20241022
|
126
|
+
from langfun.core.llms.anthropic import VertexAIClaude3_5_Sonnet_20240620
|
127
|
+
from langfun.core.llms.anthropic import VertexAIClaude3_5_Haiku_20241022
|
128
|
+
from langfun.core.llms.anthropic import VertexAIClaude3_Opus_20240229
|
68
129
|
|
69
130
|
from langfun.core.llms.groq import Groq
|
131
|
+
from langfun.core.llms.groq import GroqLlama3_2_3B
|
132
|
+
from langfun.core.llms.groq import GroqLlama3_2_1B
|
133
|
+
from langfun.core.llms.groq import GroqLlama3_1_70B
|
134
|
+
from langfun.core.llms.groq import GroqLlama3_1_8B
|
70
135
|
from langfun.core.llms.groq import GroqLlama3_70B
|
71
136
|
from langfun.core.llms.groq import GroqLlama3_8B
|
72
137
|
from langfun.core.llms.groq import GroqLlama2_70B
|
73
138
|
from langfun.core.llms.groq import GroqMistral_8x7B
|
74
|
-
from langfun.core.llms.groq import
|
75
|
-
|
139
|
+
from langfun.core.llms.groq import GroqGemma2_9B_IT
|
140
|
+
from langfun.core.llms.groq import GroqGemma_7B_IT
|
141
|
+
from langfun.core.llms.groq import GroqWhisper_Large_v3
|
142
|
+
from langfun.core.llms.groq import GroqWhisper_Large_v3Turbo
|
76
143
|
|
77
144
|
# LLaMA C++ models.
|
78
145
|
from langfun.core.llms.llama_cpp import LlamaCppRemote
|
79
146
|
|
147
|
+
# DeepSeek models.
|
148
|
+
from langfun.core.llms.deepseek import DeepSeek
|
149
|
+
from langfun.core.llms.deepseek import DeepSeekChat
|
150
|
+
|
80
151
|
# Placeholder for Google-internal imports.
|
81
152
|
|
82
153
|
# Include cache as sub-module.
|
langfun/core/llms/anthropic.py
CHANGED
@@ -16,12 +16,26 @@
|
|
16
16
|
import base64
|
17
17
|
import functools
|
18
18
|
import os
|
19
|
-
from typing import Annotated, Any
|
19
|
+
from typing import Annotated, Any, Literal
|
20
20
|
|
21
21
|
import langfun.core as lf
|
22
22
|
from langfun.core import modalities as lf_modalities
|
23
|
+
from langfun.core.llms import rest
|
23
24
|
import pyglove as pg
|
24
|
-
|
25
|
+
|
26
|
+
|
27
|
+
try:
|
28
|
+
# pylint: disable=g-import-not-at-top
|
29
|
+
from google import auth as google_auth
|
30
|
+
from google.auth import credentials as credentials_lib
|
31
|
+
from google.auth.transport import requests as auth_requests
|
32
|
+
Credentials = credentials_lib.Credentials
|
33
|
+
# pylint: enable=g-import-not-at-top
|
34
|
+
except ImportError:
|
35
|
+
google_auth = None
|
36
|
+
auth_requests = None
|
37
|
+
credentials_lib = None
|
38
|
+
Credentials = Any # pylint: disable=invalid-name
|
25
39
|
|
26
40
|
|
27
41
|
SUPPORTED_MODELS_AND_SETTINGS = {
|
@@ -29,33 +43,106 @@ SUPPORTED_MODELS_AND_SETTINGS = {
|
|
29
43
|
# Rate limits from https://docs.anthropic.com/claude/reference/rate-limits
|
30
44
|
# RPM/TPM for Claude-2.1, Claude-2.0, and Claude-Instant-1.2 estimated
|
31
45
|
# as RPM/TPM of the largest-available model (Claude-3-Opus).
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
'claude-
|
36
|
-
|
37
|
-
|
46
|
+
# Price in US dollars at https://www.anthropic.com/pricing
|
47
|
+
# as of 2024-10-10.
|
48
|
+
# Anthropic models hosted on VertexAI.
|
49
|
+
'claude-3-5-sonnet-v2@20241022': pg.Dict(
|
50
|
+
max_tokens=8192,
|
51
|
+
rpm=1000,
|
52
|
+
tpm=100000,
|
53
|
+
cost_per_1k_input_tokens=0.003,
|
54
|
+
cost_per_1k_output_tokens=0.015,
|
55
|
+
),
|
56
|
+
'claude-3-5-sonnet@20240620': pg.Dict(
|
57
|
+
max_tokens=8192,
|
58
|
+
rpm=1000,
|
59
|
+
tpm=100000,
|
60
|
+
cost_per_1k_input_tokens=0.003,
|
61
|
+
cost_per_1k_output_tokens=0.015,
|
62
|
+
),
|
63
|
+
'claude-3-5-haiku@20241022': pg.Dict(
|
64
|
+
max_tokens=8192,
|
65
|
+
rpm=1000,
|
66
|
+
tpm=100000,
|
67
|
+
cost_per_1k_input_tokens=0.001,
|
68
|
+
cost_per_1k_output_tokens=0.005,
|
69
|
+
),
|
70
|
+
'claude-3-opus@20240229': pg.Dict(
|
71
|
+
max_tokens=4096,
|
72
|
+
rpm=4000,
|
73
|
+
tpm=400000,
|
74
|
+
cost_per_1k_input_tokens=0.015,
|
75
|
+
cost_per_1k_output_tokens=0.075,
|
76
|
+
),
|
77
|
+
# Anthropic hosted models.
|
78
|
+
'claude-3-5-sonnet-20241022': pg.Dict(
|
79
|
+
max_tokens=8192,
|
80
|
+
rpm=4000,
|
81
|
+
tpm=400000,
|
82
|
+
cost_per_1k_input_tokens=0.003,
|
83
|
+
cost_per_1k_output_tokens=0.015,
|
84
|
+
),
|
85
|
+
'claude-3-5-sonnet-20240620': pg.Dict(
|
86
|
+
max_tokens=8192,
|
87
|
+
rpm=4000,
|
88
|
+
tpm=400000,
|
89
|
+
cost_per_1k_input_tokens=0.003,
|
90
|
+
cost_per_1k_output_tokens=0.015,
|
91
|
+
),
|
92
|
+
'claude-3-5-haiku-20241022': pg.Dict(
|
93
|
+
max_tokens=8192,
|
94
|
+
rpm=4000,
|
95
|
+
tpm=400000,
|
96
|
+
cost_per_1k_input_tokens=0.001,
|
97
|
+
cost_per_1k_output_tokens=0.005,
|
98
|
+
),
|
99
|
+
'claude-3-opus-20240229': pg.Dict(
|
100
|
+
max_tokens=4096,
|
101
|
+
rpm=4000,
|
102
|
+
tpm=400000,
|
103
|
+
cost_per_1k_input_tokens=0.015,
|
104
|
+
cost_per_1k_output_tokens=0.075,
|
105
|
+
),
|
106
|
+
'claude-3-sonnet-20240229': pg.Dict(
|
107
|
+
max_tokens=4096,
|
108
|
+
rpm=4000,
|
109
|
+
tpm=400000,
|
110
|
+
cost_per_1k_input_tokens=0.003,
|
111
|
+
cost_per_1k_output_tokens=0.015,
|
112
|
+
),
|
113
|
+
'claude-3-haiku-20240307': pg.Dict(
|
114
|
+
max_tokens=4096,
|
115
|
+
rpm=4000,
|
116
|
+
tpm=400000,
|
117
|
+
cost_per_1k_input_tokens=0.00025,
|
118
|
+
cost_per_1k_output_tokens=0.00125,
|
119
|
+
),
|
120
|
+
'claude-2.1': pg.Dict(
|
121
|
+
max_tokens=4096,
|
122
|
+
rpm=4000,
|
123
|
+
tpm=400000,
|
124
|
+
cost_per_1k_input_tokens=0.008,
|
125
|
+
cost_per_1k_output_tokens=0.024,
|
126
|
+
),
|
127
|
+
'claude-2.0': pg.Dict(
|
128
|
+
max_tokens=4096,
|
129
|
+
rpm=4000,
|
130
|
+
tpm=400000,
|
131
|
+
cost_per_1k_input_tokens=0.008,
|
132
|
+
cost_per_1k_output_tokens=0.024,
|
133
|
+
),
|
134
|
+
'claude-instant-1.2': pg.Dict(
|
135
|
+
max_tokens=4096,
|
136
|
+
rpm=4000,
|
137
|
+
tpm=400000,
|
138
|
+
cost_per_1k_input_tokens=0.0008,
|
139
|
+
cost_per_1k_output_tokens=0.0024,
|
140
|
+
),
|
38
141
|
}
|
39
142
|
|
40
143
|
|
41
|
-
class AnthropicError(Exception): # pylint: disable=g-bad-exception-name
|
42
|
-
"""Base class for Anthropic errors."""
|
43
|
-
|
44
|
-
|
45
|
-
class RateLimitError(AnthropicError):
|
46
|
-
"""Error for rate limit reached."""
|
47
|
-
|
48
|
-
|
49
|
-
class OverloadedError(AnthropicError):
|
50
|
-
"""Anthropic's server is temporarily overloaded."""
|
51
|
-
|
52
|
-
|
53
|
-
_ANTHROPIC_MESSAGE_API_ENDPOINT = 'https://api.anthropic.com/v1/messages'
|
54
|
-
_ANTHROPIC_API_VERSION = '2023-06-01'
|
55
|
-
|
56
|
-
|
57
144
|
@lf.use_init_args(['model'])
|
58
|
-
class Anthropic(
|
145
|
+
class Anthropic(rest.REST):
|
59
146
|
"""Anthropic LLMs (Claude) through REST APIs.
|
60
147
|
|
61
148
|
See https://docs.anthropic.com/claude/reference/messages_post
|
@@ -80,14 +167,18 @@ class Anthropic(lf.LanguageModel):
|
|
80
167
|
),
|
81
168
|
] = None
|
82
169
|
|
170
|
+
api_endpoint: str = 'https://api.anthropic.com/v1/messages'
|
171
|
+
|
172
|
+
api_version: Annotated[
|
173
|
+
str,
|
174
|
+
'Anthropic API version.'
|
175
|
+
] = '2023-06-01'
|
176
|
+
|
83
177
|
def _on_bound(self):
|
84
178
|
super()._on_bound()
|
85
179
|
self._api_key = None
|
86
|
-
self.__dict__.pop('_api_initialized', None)
|
87
|
-
self.__dict__.pop('_session', None)
|
88
180
|
|
89
|
-
|
90
|
-
def _api_initialized(self):
|
181
|
+
def _initialize(self):
|
91
182
|
api_key = self.api_key or os.environ.get('ANTHROPIC_API_KEY', None)
|
92
183
|
if not api_key:
|
93
184
|
raise ValueError(
|
@@ -95,18 +186,16 @@ class Anthropic(lf.LanguageModel):
|
|
95
186
|
'variable `ANTHROPIC_API_KEY` with your Anthropic API key.'
|
96
187
|
)
|
97
188
|
self._api_key = api_key
|
98
|
-
return True
|
99
189
|
|
100
|
-
@
|
101
|
-
def
|
102
|
-
|
103
|
-
s = requests.Session()
|
104
|
-
s.headers.update({
|
190
|
+
@property
|
191
|
+
def headers(self) -> dict[str, Any]:
|
192
|
+
return {
|
105
193
|
'x-api-key': self._api_key,
|
106
|
-
'anthropic-version':
|
194
|
+
'anthropic-version': self.api_version,
|
107
195
|
'content-type': 'application/json',
|
108
|
-
|
109
|
-
|
196
|
+
# TODO(yifenglu): Remove beta flag once the feature is fully supported.
|
197
|
+
'anthropic-beta': 'pdfs-2024-09-25',
|
198
|
+
}
|
110
199
|
|
111
200
|
@property
|
112
201
|
def model_id(self) -> str:
|
@@ -121,13 +210,43 @@ class Anthropic(lf.LanguageModel):
|
|
121
210
|
requests_per_min=rpm, tokens_per_min=tpm
|
122
211
|
)
|
123
212
|
|
124
|
-
def
|
125
|
-
|
126
|
-
|
127
|
-
|
213
|
+
def estimate_cost(
|
214
|
+
self,
|
215
|
+
num_input_tokens: int,
|
216
|
+
num_output_tokens: int
|
217
|
+
) -> float | None:
|
218
|
+
"""Estimate the cost based on usage."""
|
219
|
+
cost_per_1k_input_tokens = SUPPORTED_MODELS_AND_SETTINGS[self.model].get(
|
220
|
+
'cost_per_1k_input_tokens', None
|
221
|
+
)
|
222
|
+
cost_per_1k_output_tokens = SUPPORTED_MODELS_AND_SETTINGS[self.model].get(
|
223
|
+
'cost_per_1k_output_tokens', None
|
128
224
|
)
|
225
|
+
if cost_per_1k_output_tokens is None or cost_per_1k_input_tokens is None:
|
226
|
+
return None
|
227
|
+
return (
|
228
|
+
cost_per_1k_input_tokens * num_input_tokens
|
229
|
+
+ cost_per_1k_output_tokens * num_output_tokens
|
230
|
+
) / 1000
|
231
|
+
|
232
|
+
def request(
|
233
|
+
self,
|
234
|
+
prompt: lf.Message,
|
235
|
+
sampling_options: lf.LMSamplingOptions
|
236
|
+
) -> dict[str, Any]:
|
237
|
+
"""Returns the JSON input for a message."""
|
238
|
+
request = dict()
|
239
|
+
request.update(self._request_args(sampling_options))
|
240
|
+
request.update(
|
241
|
+
dict(
|
242
|
+
messages=[
|
243
|
+
dict(role='user', content=self._content_from_message(prompt))
|
244
|
+
]
|
245
|
+
)
|
246
|
+
)
|
247
|
+
return request
|
129
248
|
|
130
|
-
def
|
249
|
+
def _request_args(self, options: lf.LMSamplingOptions) -> dict[str, Any]:
|
131
250
|
"""Returns a dict as request arguments."""
|
132
251
|
# Authropic requires `max_tokens` to be specified.
|
133
252
|
max_tokens = (
|
@@ -158,7 +277,6 @@ class Anthropic(lf.LanguageModel):
|
|
158
277
|
if isinstance(chunk, str):
|
159
278
|
item = dict(type='text', text=chunk)
|
160
279
|
elif isinstance(chunk, lf_modalities.Image):
|
161
|
-
# NOTE(daiyip): Anthropic only support image content instead of URL.
|
162
280
|
item = dict(
|
163
281
|
type='image',
|
164
282
|
source=dict(
|
@@ -167,6 +285,15 @@ class Anthropic(lf.LanguageModel):
|
|
167
285
|
data=base64.b64encode(chunk.to_bytes()).decode(),
|
168
286
|
),
|
169
287
|
)
|
288
|
+
elif isinstance(chunk, lf_modalities.PDF):
|
289
|
+
item = dict(
|
290
|
+
type='document',
|
291
|
+
source=dict(
|
292
|
+
type='base64',
|
293
|
+
media_type=chunk.mime_type,
|
294
|
+
data=base64.b64encode(chunk.to_bytes()).decode(),
|
295
|
+
),
|
296
|
+
)
|
170
297
|
else:
|
171
298
|
raise ValueError(f'Unsupported modality object: {chunk!r}.')
|
172
299
|
content.append(item)
|
@@ -174,6 +301,23 @@ class Anthropic(lf.LanguageModel):
|
|
174
301
|
else:
|
175
302
|
return [dict(type='text', text=prompt.text)]
|
176
303
|
|
304
|
+
def result(self, json: dict[str, Any]) -> lf.LMSamplingResult:
|
305
|
+
message = self._message_from_content(json['content'])
|
306
|
+
input_tokens = json['usage']['input_tokens']
|
307
|
+
output_tokens = json['usage']['output_tokens']
|
308
|
+
return lf.LMSamplingResult(
|
309
|
+
[lf.LMSample(message)],
|
310
|
+
usage=lf.LMSamplingUsage(
|
311
|
+
prompt_tokens=input_tokens,
|
312
|
+
completion_tokens=output_tokens,
|
313
|
+
total_tokens=input_tokens + output_tokens,
|
314
|
+
estimated_cost=self.estimate_cost(
|
315
|
+
num_input_tokens=input_tokens,
|
316
|
+
num_output_tokens=output_tokens,
|
317
|
+
),
|
318
|
+
),
|
319
|
+
)
|
320
|
+
|
177
321
|
def _message_from_content(self, content: list[dict[str, Any]]) -> lf.Message:
|
178
322
|
"""Converts Anthropic's content protocol to message."""
|
179
323
|
# Refer: https://docs.anthropic.com/claude/reference/messages-examples
|
@@ -181,55 +325,29 @@ class Anthropic(lf.LanguageModel):
|
|
181
325
|
[x['text'] for x in content if x['type'] == 'text']
|
182
326
|
)
|
183
327
|
|
184
|
-
def _parse_response(self, response: requests.Response) -> lf.LMSamplingResult:
|
185
|
-
"""Parses Anthropic's response."""
|
186
|
-
# NOTE(daiyip): Refer https://docs.anthropic.com/claude/reference/errors
|
187
|
-
if response.status_code == 200:
|
188
|
-
output = response.json()
|
189
|
-
message = self._message_from_content(output['content'])
|
190
|
-
input_tokens = output['usage']['input_tokens']
|
191
|
-
output_tokens = output['usage']['output_tokens']
|
192
|
-
return lf.LMSamplingResult(
|
193
|
-
[lf.LMSample(message)],
|
194
|
-
usage=lf.LMSamplingUsage(
|
195
|
-
prompt_tokens=input_tokens,
|
196
|
-
completion_tokens=output_tokens,
|
197
|
-
total_tokens=input_tokens + output_tokens,
|
198
|
-
),
|
199
|
-
)
|
200
|
-
else:
|
201
|
-
if response.status_code == 429:
|
202
|
-
error_cls = RateLimitError
|
203
|
-
elif response.status_code in (502, 529):
|
204
|
-
error_cls = OverloadedError
|
205
|
-
else:
|
206
|
-
error_cls = AnthropicError
|
207
|
-
raise error_cls(f'{response.status_code}: {response.content}')
|
208
|
-
|
209
|
-
def _sample_single(self, prompt: lf.Message) -> lf.LMSamplingResult:
|
210
|
-
request = dict()
|
211
|
-
request.update(self._get_request_args(self.sampling_options))
|
212
|
-
request.update(
|
213
|
-
dict(
|
214
|
-
messages=[
|
215
|
-
dict(role='user', content=self._content_from_message(prompt))
|
216
|
-
]
|
217
|
-
)
|
218
|
-
)
|
219
|
-
try:
|
220
|
-
response = self._session.post(
|
221
|
-
_ANTHROPIC_MESSAGE_API_ENDPOINT, json=request, timeout=self.timeout,
|
222
|
-
)
|
223
|
-
return self._parse_response(response)
|
224
|
-
except ConnectionError as e:
|
225
|
-
raise OverloadedError(str(e)) from e
|
226
|
-
|
227
328
|
|
228
329
|
class Claude3(Anthropic):
|
229
330
|
"""Base class for Claude 3 models. 200K input tokens and 4K output tokens."""
|
230
331
|
multimodal = True
|
231
332
|
|
232
333
|
|
334
|
+
class Claude35Sonnet(Claude3):
|
335
|
+
"""A balance between between Opus and Haiku."""
|
336
|
+
model = 'claude-3-5-sonnet-20241022'
|
337
|
+
|
338
|
+
|
339
|
+
class Claude35Sonnet20241022(Claude3):
|
340
|
+
"""A balance between between Opus and Haiku."""
|
341
|
+
|
342
|
+
model = 'claude-3-5-sonnet-20241022'
|
343
|
+
|
344
|
+
|
345
|
+
class Claude35Sonnet20240620(Claude3):
|
346
|
+
"""A balance between between Opus and Haiku."""
|
347
|
+
|
348
|
+
model = 'claude-3-5-sonnet-20240620'
|
349
|
+
|
350
|
+
|
233
351
|
class Claude3Opus(Claude3):
|
234
352
|
"""Anthropic's most powerful model."""
|
235
353
|
|
@@ -261,3 +379,110 @@ class Claude21(Anthropic):
|
|
261
379
|
class ClaudeInstant(Anthropic):
|
262
380
|
"""Cheapest small and fast model, 100K context window."""
|
263
381
|
model = 'claude-instant-1.2'
|
382
|
+
|
383
|
+
|
384
|
+
#
|
385
|
+
# Authropic models on VertexAI.
|
386
|
+
#
|
387
|
+
|
388
|
+
|
389
|
+
class VertexAIAnthropic(Anthropic):
|
390
|
+
"""Anthropic models on VertexAI."""
|
391
|
+
|
392
|
+
project: Annotated[
|
393
|
+
str | None,
|
394
|
+
'Google Cloud project ID.',
|
395
|
+
] = None
|
396
|
+
|
397
|
+
location: Annotated[
|
398
|
+
Literal['us-east5', 'europe-west1'],
|
399
|
+
'GCP location with Anthropic models hosted.'
|
400
|
+
] = 'us-east5'
|
401
|
+
|
402
|
+
credentials: Annotated[
|
403
|
+
Credentials | None, # pytype: disable=invalid-annotation
|
404
|
+
(
|
405
|
+
'Credentials to use. If None, the default credentials '
|
406
|
+
'to the environment will be used.'
|
407
|
+
),
|
408
|
+
] = None
|
409
|
+
|
410
|
+
api_version = 'vertex-2023-10-16'
|
411
|
+
|
412
|
+
def _on_bound(self):
|
413
|
+
super()._on_bound()
|
414
|
+
if google_auth is None:
|
415
|
+
raise ValueError(
|
416
|
+
'Please install "langfun[llm-google-vertex]" to use Vertex AI models.'
|
417
|
+
)
|
418
|
+
self._project = None
|
419
|
+
self._credentials = None
|
420
|
+
|
421
|
+
def _initialize(self):
|
422
|
+
project = self.project or os.environ.get('VERTEXAI_PROJECT', None)
|
423
|
+
if not project:
|
424
|
+
raise ValueError(
|
425
|
+
'Please specify `project` during `__init__` or set environment '
|
426
|
+
'variable `VERTEXAI_PROJECT` with your Vertex AI project ID.'
|
427
|
+
)
|
428
|
+
self._project = project
|
429
|
+
credentials = self.credentials
|
430
|
+
if credentials is None:
|
431
|
+
# Use default credentials.
|
432
|
+
credentials = google_auth.default(
|
433
|
+
scopes=['https://www.googleapis.com/auth/cloud-platform']
|
434
|
+
)
|
435
|
+
self._credentials = credentials
|
436
|
+
|
437
|
+
@functools.cached_property
|
438
|
+
def _session(self):
|
439
|
+
assert self._api_initialized
|
440
|
+
assert self._credentials is not None
|
441
|
+
assert auth_requests is not None
|
442
|
+
s = auth_requests.AuthorizedSession(self._credentials)
|
443
|
+
s.headers.update(self.headers or {})
|
444
|
+
return s
|
445
|
+
|
446
|
+
@property
|
447
|
+
def headers(self):
|
448
|
+
return {
|
449
|
+
'Content-Type': 'application/json; charset=utf-8',
|
450
|
+
}
|
451
|
+
|
452
|
+
@property
|
453
|
+
def api_endpoint(self) -> str:
|
454
|
+
return (
|
455
|
+
f'https://{self.location}-aiplatform.googleapis.com/v1/projects/'
|
456
|
+
f'{self._project}/locations/{self.location}/publishers/anthropic/'
|
457
|
+
f'models/{self.model}:streamRawPredict'
|
458
|
+
)
|
459
|
+
|
460
|
+
def request(
|
461
|
+
self,
|
462
|
+
prompt: lf.Message,
|
463
|
+
sampling_options: lf.LMSamplingOptions
|
464
|
+
):
|
465
|
+
request = super().request(prompt, sampling_options)
|
466
|
+
request['anthropic_version'] = self.api_version
|
467
|
+
del request['model']
|
468
|
+
return request
|
469
|
+
|
470
|
+
|
471
|
+
class VertexAIClaude3_Opus_20240229(VertexAIAnthropic): # pylint: disable=invalid-name
|
472
|
+
"""Anthropic's Claude 3 Opus model on VertexAI."""
|
473
|
+
model = 'claude-3-opus@20240229'
|
474
|
+
|
475
|
+
|
476
|
+
class VertexAIClaude3_5_Sonnet_20241022(VertexAIAnthropic): # pylint: disable=invalid-name
|
477
|
+
"""Anthropic's Claude 3.5 Sonnet model on VertexAI."""
|
478
|
+
model = 'claude-3-5-sonnet-v2@20241022'
|
479
|
+
|
480
|
+
|
481
|
+
class VertexAIClaude3_5_Sonnet_20240620(VertexAIAnthropic): # pylint: disable=invalid-name
|
482
|
+
"""Anthropic's Claude 3.5 Sonnet model on VertexAI."""
|
483
|
+
model = 'claude-3-5-sonnet@20240620'
|
484
|
+
|
485
|
+
|
486
|
+
class VertexAIClaude3_5_Haiku_20241022(VertexAIAnthropic): # pylint: disable=invalid-name
|
487
|
+
"""Anthropic's Claude 3.5 Haiku model on VertexAI."""
|
488
|
+
model = 'claude-3-5-haiku@20241022'
|