delightfulrachel commited on
Commit
c2acf75
·
verified ·
1 Parent(s): 62b53a3

Create api_client.py

Browse files
Files changed (1) hide show
  1. api_client.py +170 -0
api_client.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """API client functions for LLM interactions"""
2
+
3
+ import os
4
+ import time
5
+ import requests
6
+ import hashlib
7
+ from functools import lru_cache
8
+ from typing import Optional
9
+ import logging
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Model lists
14
+ together_models = [
15
+ "Qwen/Qwen2.5-Coder-32B-Instruct",
16
+ "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF",
17
+ "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
18
+ "meta-llama/Llama-3.3-70B-Instruct-Turbo-Free"
19
+ ]
20
+
21
+ anthropic_models = [
22
+ "claude-3-7-sonnet-20250219",
23
+ "claude-3-haiku-20240307",
24
+ "claude-opus-4-20250514",
25
+ "claude-sonnet-4-20250514"
26
+ ]
27
+
28
+ all_models = together_models + anthropic_models
29
+
30
+ def get_api_key(provider: str) -> str:
31
+ """Securely retrieve API key for the specified provider."""
32
+ try:
33
+ if provider == "together":
34
+ api_key = os.getenv("TOGETHER_API_KEY")
35
+ if not api_key:
36
+ raise ValueError("API key not configured. Please contact administrator.")
37
+ return api_key
38
+ elif provider == "anthropic":
39
+ api_key = os.getenv("ANTHROPIC_API_KEY")
40
+ if not api_key:
41
+ raise ValueError("API key not configured. Please contact administrator.")
42
+ return api_key
43
+ else:
44
+ raise ValueError(f"Unknown provider: {provider}")
45
+ except Exception as e:
46
+ logger.error(f"Error retrieving API key: {e}")
47
+ raise
48
+
49
+ def get_provider(model: str) -> str:
50
+ """Determine the provider for a given model."""
51
+ if model in together_models:
52
+ return "together"
53
+ elif model in anthropic_models:
54
+ return "anthropic"
55
+ else:
56
+ raise ValueError(f"Unknown model: {model}")
57
+
58
+ def call_api_with_retry(api_func, *args, max_retries: int = 3, timeout: int = 30, **kwargs):
59
+ """Call API with retry logic and timeout."""
60
+ from utils import handle_api_error
61
+
62
+ for attempt in range(max_retries):
63
+ try:
64
+ kwargs['timeout'] = timeout
65
+ return api_func(*args, **kwargs)
66
+ except requests.Timeout:
67
+ if attempt == max_retries - 1:
68
+ return "Request timed out. Please try again with a shorter input."
69
+ except requests.ConnectionError:
70
+ if attempt == max_retries - 1:
71
+ return "Connection error. Please check your internet connection."
72
+ except Exception as e:
73
+ if attempt == max_retries - 1:
74
+ return f"Error: {str(e)}"
75
+ time.sleep(2 ** attempt) # Exponential backoff
76
+
77
+ def call_together_api(model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
78
+ """Call Together AI API with enhanced error handling."""
79
+ from utils import handle_api_error
80
+
81
+ api_key = get_api_key("together")
82
+ system_message = (
83
+ "You are a Salesforce B2B Commerce expert. Be CONCISE and PRECISE. "
84
+ "Focus on CODE QUALITY over explanations. Use structured formats when requested. "
85
+ "Always check for syntax errors, security issues, and performance problems."
86
+ )
87
+
88
+ def make_request():
89
+ headers = {
90
+ "Authorization": f"Bearer {api_key}",
91
+ "Content-Type": "application/json"
92
+ }
93
+ payload = {
94
+ "model": model,
95
+ "messages": [
96
+ {"role": "system", "content": system_message},
97
+ {"role": "user", "content": prompt}
98
+ ],
99
+ "temperature": temperature,
100
+ "max_tokens": max_tokens,
101
+ "top_p": 0.9
102
+ }
103
+ resp = requests.post(
104
+ "https://api.together.xyz/v1/chat/completions",
105
+ headers=headers,
106
+ json=payload,
107
+ timeout=30
108
+ )
109
+ if resp.status_code != 200:
110
+ return handle_api_error(resp.status_code, resp.text)
111
+ data = resp.json()
112
+ return data["choices"][0]["message"]["content"]
113
+
114
+ return call_api_with_retry(make_request)
115
+
116
+ def call_anthropic_api(model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
117
+ """Call Anthropic API with enhanced error handling."""
118
+ from utils import handle_api_error
119
+
120
+ api_key = get_api_key("anthropic")
121
+ system_message = (
122
+ "You are a Salesforce B2B Commerce expert. Be CONCISE and PRECISE. "
123
+ "Focus on CODE QUALITY over explanations. Use structured formats when requested. "
124
+ "Always check for syntax errors, security issues, and performance problems."
125
+ )
126
+
127
+ def make_request():
128
+ headers = {
129
+ "x-api-key": api_key,
130
+ "anthropic-version": "2023-06-01",
131
+ "content-type": "application/json"
132
+ }
133
+ payload = {
134
+ "model": model,
135
+ "system": system_message,
136
+ "messages": [
137
+ {"role": "user", "content": prompt}
138
+ ],
139
+ "temperature": temperature,
140
+ "max_tokens": max_tokens
141
+ }
142
+ resp = requests.post(
143
+ "https://api.anthropic.com/v1/messages",
144
+ headers=headers,
145
+ json=payload,
146
+ timeout=30
147
+ )
148
+ if resp.status_code != 200:
149
+ return handle_api_error(resp.status_code, resp.text)
150
+ data = resp.json()
151
+ return data["content"][0]["text"]
152
+
153
+ return call_api_with_retry(make_request)
154
+
155
+ @lru_cache(maxsize=100)
156
+ def cached_llm_call(model_hash: str, prompt_hash: str, model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
157
+ """Cached LLM call to avoid repeated API calls for same inputs."""
158
+ provider = get_provider(model)
159
+ if provider == "together":
160
+ return call_together_api(model, prompt, temperature, max_tokens)
161
+ elif provider == "anthropic":
162
+ return call_anthropic_api(model, prompt, temperature, max_tokens)
163
+ else:
164
+ return f"Error: Unknown provider for model {model}"
165
+
166
+ def call_llm(model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
167
+ """Call LLM with caching support."""
168
+ model_hash = hashlib.md5(model.encode()).hexdigest()
169
+ prompt_hash = hashlib.md5(prompt.encode()).hexdigest()
170
+ return cached_llm_call(model_hash, prompt_hash, model, prompt, temperature, max_tokens)