zach commited on
Commit
80026d8
·
1 Parent(s): 97908cd

Update Anthropic integration to be async

Browse files
Files changed (2) hide show
  1. src/app.py +2 -2
  2. src/integrations/anthropic_api.py +19 -29
src/app.py CHANGED
@@ -48,7 +48,7 @@ class App:
48
  self.config = config
49
  self.db_session_maker = db_session_maker
50
 
51
- def _generate_text(
52
  self,
53
  character_description: str,
54
  ) -> Tuple[dict, str]:
@@ -73,7 +73,7 @@ class App:
73
  raise gr.Error(str(ve))
74
 
75
  try:
76
- generated_text = generate_text_with_claude(character_description, self.config)
77
  logger.info(f"Generated text ({len(generated_text)} characters).")
78
  return gr.update(value=generated_text), generated_text
79
  except AnthropicError as ae:
 
48
  self.config = config
49
  self.db_session_maker = db_session_maker
50
 
51
+ async def _generate_text(
52
  self,
53
  character_description: str,
54
  ) -> Tuple[dict, str]:
 
73
  raise gr.Error(str(ve))
74
 
75
  try:
76
+ generated_text = await generate_text_with_claude(character_description, self.config)
77
  logger.info(f"Generated text ({len(generated_text)} characters).")
78
  return gr.update(value=generated_text), generated_text
79
  except AnthropicError as ae:
src/integrations/anthropic_api.py CHANGED
@@ -1,21 +1,14 @@
1
  """
2
  anthropic_api.py
3
 
4
- This file defines the interaction with the Anthropic API, focusing on generating text using the Claude model.
5
- It includes functionality for input validation, API request handling, and processing API responses.
6
 
7
  Key Features:
8
  - Encapsulates all logic related to the Anthropic API.
9
- - Implements retry logic for handling transient API errors.
10
  - Validates the response content to ensure API compatibility.
11
  - Provides detailed logging for debugging and error tracking.
12
-
13
- Classes:
14
- - AnthropicConfig: Immutable configuration for interacting with the Anthropic API.
15
- - AnthropicError: Custom exception for Anthropic API-related errors.
16
-
17
- Functions:
18
- - generate_text_with_claude: Generates text using the Anthropic SDK with input validation and retry logic.
19
  """
20
 
21
  # Standard Library Imports
@@ -24,9 +17,9 @@ from dataclasses import dataclass, field
24
  from typing import Any, Dict, List, Optional, Union, cast
25
 
26
  # Third-Party Library Imports
27
- from anthropic import Anthropic, APIError
28
  from anthropic.types import Message, ModelParam, TextBlock, ToolUseBlock
29
- from tenacity import after_log, before_log, retry, stop_after_attempt, wait_fixed
30
 
31
  # Local Application Imports
32
  from src.config import Config, logger
@@ -57,11 +50,9 @@ Your absolute priority is delivering complete, untruncated responses within stri
57
  </requirements>
58
  """
59
 
60
-
61
  @dataclass(frozen=True)
62
  class AnthropicConfig:
63
- """Immutable configuration for interacting with the Anthropic API."""
64
-
65
  api_key: str = field(init=False)
66
  system_prompt: str = field(init=False)
67
  model: ModelParam = "claude-3-5-sonnet-latest"
@@ -83,18 +74,19 @@ class AnthropicConfig:
83
  object.__setattr__(self, "system_prompt", computed_prompt)
84
 
85
  @property
86
- def client(self) -> Anthropic:
87
  """
88
- Lazy initialization of the Anthropic client.
89
 
90
  Returns:
91
- Anthropic: Configured client instance.
92
  """
93
- return Anthropic(api_key=self.api_key)
 
94
 
95
  def build_expressive_prompt(self, character_description: str) -> str:
96
  """
97
- Constructs and returns a prompt based solely on the provided voice description.
98
  The returned prompt is intended to instruct Claude to generate expressive text from a character,
99
  capturing the character's personality and emotional nuance, without including the system prompt.
100
 
@@ -131,41 +123,39 @@ class UnretryableAnthropicError(AnthropicError):
131
 
132
 
133
  @retry(
 
134
  stop=stop_after_attempt(3),
135
  wait=wait_fixed(2),
136
  before=before_log(logger, logging.DEBUG),
137
  after=after_log(logger, logging.DEBUG),
138
  reraise=True,
139
  )
140
- def generate_text_with_claude(character_description: str, config: Config) -> str:
141
  """
142
- Generates text using Claude (Anthropic LLM) via the Anthropic SDK.
143
 
144
  This function includes retry logic and error translation. It raises a custom
145
- UnretryableAnthropicError for API errors deemed unretryable and AnthropicError
146
- for other errors.
147
 
148
  Args:
149
- character_description (str): The input character description used to assist with generating text.
150
  config (Config): Application configuration including Anthropic settings.
151
 
152
  Returns:
153
  str: The generated text.
154
 
155
  Raises:
156
- UnretryableAnthropicError: For errors that should not be retried.
157
  AnthropicError: For other errors communicating with the Anthropic API.
158
  """
159
-
160
  try:
161
  anthropic_config = config.anthropic_config
162
  prompt = anthropic_config.build_expressive_prompt(character_description)
163
  logger.debug(f"Generating text with Claude. Character description length: {len(prompt)} characters.")
164
 
165
- # Ensure system_prompt is set (guaranteed by __post_init__)
166
  assert anthropic_config.system_prompt is not None, "system_prompt must be set."
167
 
168
- response: Message = anthropic_config.client.messages.create(
169
  model=anthropic_config.model,
170
  max_tokens=anthropic_config.max_tokens,
171
  system=anthropic_config.system_prompt,
 
1
  """
2
  anthropic_api.py
3
 
4
+ This file defines the asynchronous interaction with the Anthropic API, focusing on generating text using the Claude
5
+ model. It includes functionality for input validation, asynchronous API request handling, and processing API responses.
6
 
7
  Key Features:
8
  - Encapsulates all logic related to the Anthropic API.
9
+ - Implements asynchronous retry logic for handling transient API errors.
10
  - Validates the response content to ensure API compatibility.
11
  - Provides detailed logging for debugging and error tracking.
 
 
 
 
 
 
 
12
  """
13
 
14
  # Standard Library Imports
 
17
  from typing import Any, Dict, List, Optional, Union, cast
18
 
19
  # Third-Party Library Imports
20
+ from anthropic import APIError
21
  from anthropic.types import Message, ModelParam, TextBlock, ToolUseBlock
22
+ from tenacity import after_log, before_log, retry, retry_if_exception, stop_after_attempt, wait_fixed
23
 
24
  # Local Application Imports
25
  from src.config import Config, logger
 
50
  </requirements>
51
  """
52
 
 
53
  @dataclass(frozen=True)
54
  class AnthropicConfig:
55
+ """Immutable configuration for interacting with the Anthropic API using the asynchronous client."""
 
56
  api_key: str = field(init=False)
57
  system_prompt: str = field(init=False)
58
  model: ModelParam = "claude-3-5-sonnet-latest"
 
74
  object.__setattr__(self, "system_prompt", computed_prompt)
75
 
76
  @property
77
+ def client(self):
78
  """
79
+ Lazy initialization of the asynchronous Anthropic client.
80
 
81
  Returns:
82
+ AsyncAnthropic: Configured asynchronous client instance.
83
  """
84
+ from anthropic import AsyncAnthropic # Import the async client from Anthropic SDK
85
+ return AsyncAnthropic(api_key=self.api_key)
86
 
87
  def build_expressive_prompt(self, character_description: str) -> str:
88
  """
89
+ Constructs and returns a prompt based solely on the provided character description.
90
  The returned prompt is intended to instruct Claude to generate expressive text from a character,
91
  capturing the character's personality and emotional nuance, without including the system prompt.
92
 
 
123
 
124
 
125
  @retry(
126
+ retry=retry_if_exception(lambda e: not isinstance(e, UnretryableAnthropicError)),
127
  stop=stop_after_attempt(3),
128
  wait=wait_fixed(2),
129
  before=before_log(logger, logging.DEBUG),
130
  after=after_log(logger, logging.DEBUG),
131
  reraise=True,
132
  )
133
+ async def generate_text_with_claude(character_description: str, config: Config) -> str:
134
  """
135
+ Asynchronously generates text using Claude (Anthropic LLM) via the asynchronous Anthropic SDK.
136
 
137
  This function includes retry logic and error translation. It raises a custom
138
+ UnretryableAnthropicError for unretryable API errors and AnthropicError for other errors.
 
139
 
140
  Args:
141
+ character_description (str): The input character description.
142
  config (Config): Application configuration including Anthropic settings.
143
 
144
  Returns:
145
  str: The generated text.
146
 
147
  Raises:
148
+ UnretryableAnthropicError: For unretryable API errors.
149
  AnthropicError: For other errors communicating with the Anthropic API.
150
  """
 
151
  try:
152
  anthropic_config = config.anthropic_config
153
  prompt = anthropic_config.build_expressive_prompt(character_description)
154
  logger.debug(f"Generating text with Claude. Character description length: {len(prompt)} characters.")
155
 
 
156
  assert anthropic_config.system_prompt is not None, "system_prompt must be set."
157
 
158
+ response: Message = await anthropic_config.client.messages.create(
159
  model=anthropic_config.model,
160
  max_tokens=anthropic_config.max_tokens,
161
  system=anthropic_config.system_prompt,