llm_batch_helper 0.1.5__tar.gz → 0.2.0__tar.gz
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.
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/PKG-INFO +47 -5
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/README.md +45 -2
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/llm_batch_helper/__init__.py +1 -1
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/llm_batch_helper/config.py +2 -0
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/llm_batch_helper/providers.py +65 -4
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/pyproject.toml +3 -3
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/LICENSE +0 -0
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/llm_batch_helper/cache.py +0 -0
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/llm_batch_helper/exceptions.py +0 -0
- {llm_batch_helper-0.1.5 → llm_batch_helper-0.2.0}/llm_batch_helper/input_handlers.py +0 -0
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: llm_batch_helper
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary: A Python package that enables batch submission of prompts to LLM APIs, with built-in async capabilities and response caching.
|
5
5
|
License: MIT
|
6
|
-
Keywords: llm,openai,together,batch,async,ai,nlp,api
|
6
|
+
Keywords: llm,openai,together,openrouter,batch,async,ai,nlp,api
|
7
7
|
Author: Tianyi Peng
|
8
8
|
Author-email: tianyipeng95@gmail.com
|
9
9
|
Requires-Python: >=3.11,<4.0
|
@@ -19,7 +19,6 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
20
20
|
Requires-Dist: httpx (>=0.24.0,<2.0.0)
|
21
21
|
Requires-Dist: openai (>=1.0.0,<2.0.0)
|
22
|
-
Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
|
23
22
|
Requires-Dist: tenacity (>=8.0.0,<9.0.0)
|
24
23
|
Requires-Dist: tqdm (>=4.65.0,<5.0.0)
|
25
24
|
Project-URL: Homepage, https://github.com/TianyiPeng/LLM_batch_helper
|
@@ -28,7 +27,29 @@ Description-Content-Type: text/markdown
|
|
28
27
|
|
29
28
|
# LLM Batch Helper
|
30
29
|
|
31
|
-
|
30
|
+
[](https://badge.fury.io/py/llm_batch_helper)
|
31
|
+
[](https://pepy.tech/project/llm_batch_helper)
|
32
|
+
[](https://pepy.tech/project/llm_batch_helper)
|
33
|
+
[](https://llm-batch-helper.readthedocs.io/en/latest/?badge=latest)
|
34
|
+
[](https://opensource.org/licenses/MIT)
|
35
|
+
|
36
|
+
A Python package that enables batch submission of prompts to LLM APIs, with built-in async capabilities, response caching, prompt verification, and more. This package is designed to streamline applications like LLM simulation, LLM-as-a-judge, and other batch processing scenarios.
|
37
|
+
|
38
|
+
📖 **[Complete Documentation](https://llm-batch-helper.readthedocs.io/)** | 🚀 **[Quick Start Guide](https://llm-batch-helper.readthedocs.io/en/latest/quickstart.html)**
|
39
|
+
|
40
|
+
## Why we designed this package
|
41
|
+
|
42
|
+
Calling LLM APIs has become increasingly common, but several pain points exist in practice:
|
43
|
+
|
44
|
+
1. **Efficient Batch Processing**: How do you run LLM calls in batches efficiently? Our async implementation is 3X-100X faster than multi-thread/multi-process approaches.
|
45
|
+
|
46
|
+
2. **API Reliability**: LLM APIs can be unstable, so we need robust retry mechanisms when calls get interrupted.
|
47
|
+
|
48
|
+
3. **Long-Running Simulations**: During long-running LLM simulations, computers can crash and APIs can fail. Can we cache LLM API calls to avoid repeating completed work?
|
49
|
+
|
50
|
+
4. **Output Validation**: LLM outputs often have format requirements. If the output isn't right, we need to retry with validation.
|
51
|
+
|
52
|
+
This package is designed to solve these exact pain points with async processing, intelligent caching, and comprehensive error handling. If there are some additional features you need, please post an issue.
|
32
53
|
|
33
54
|
## Features
|
34
55
|
|
@@ -67,6 +88,7 @@ poetry shell
|
|
67
88
|
|
68
89
|
### 1. Set up environment variables
|
69
90
|
|
91
|
+
**Option A: Environment Variables**
|
70
92
|
```bash
|
71
93
|
# For OpenAI
|
72
94
|
export OPENAI_API_KEY="your-openai-api-key"
|
@@ -75,6 +97,22 @@ export OPENAI_API_KEY="your-openai-api-key"
|
|
75
97
|
export TOGETHER_API_KEY="your-together-api-key"
|
76
98
|
```
|
77
99
|
|
100
|
+
**Option B: .env File (Recommended for Development)**
|
101
|
+
```python
|
102
|
+
# In your script, before importing llm_batch_helper
|
103
|
+
from dotenv import load_dotenv
|
104
|
+
load_dotenv() # Load from .env file
|
105
|
+
|
106
|
+
# Then use the package normally
|
107
|
+
from llm_batch_helper import LLMConfig, process_prompts_batch
|
108
|
+
```
|
109
|
+
|
110
|
+
Create a `.env` file in your project:
|
111
|
+
```
|
112
|
+
OPENAI_API_KEY=your-openai-api-key
|
113
|
+
TOGETHER_API_KEY=your-together-api-key
|
114
|
+
```
|
115
|
+
|
78
116
|
### 2. Interactive Tutorial (Recommended)
|
79
117
|
|
80
118
|
Check out the comprehensive Jupyter notebook [tutorial](https://github.com/TianyiPeng/LLM_batch_helper/blob/main/tutorials/llm_batch_helper_tutorial.ipynb).
|
@@ -85,8 +123,12 @@ The tutorial covers all features with interactive examples!
|
|
85
123
|
|
86
124
|
```python
|
87
125
|
import asyncio
|
126
|
+
from dotenv import load_dotenv # Optional: for .env file support
|
88
127
|
from llm_batch_helper import LLMConfig, process_prompts_batch
|
89
128
|
|
129
|
+
# Optional: Load environment variables from .env file
|
130
|
+
load_dotenv()
|
131
|
+
|
90
132
|
async def main():
|
91
133
|
# Create configuration
|
92
134
|
config = LLMConfig(
|
@@ -203,7 +245,7 @@ Main function for batch processing of prompts.
|
|
203
245
|
```python
|
204
246
|
async def process_prompts_batch(
|
205
247
|
config: LLMConfig,
|
206
|
-
provider: str, # "openai" or "
|
248
|
+
provider: str, # "openai", "together", or "openrouter"
|
207
249
|
prompts: Optional[List[str]] = None,
|
208
250
|
input_dir: Optional[str] = None,
|
209
251
|
cache_dir: str = "llm_cache",
|
@@ -1,6 +1,28 @@
|
|
1
1
|
# LLM Batch Helper
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/py/llm_batch_helper)
|
4
|
+
[](https://pepy.tech/project/llm_batch_helper)
|
5
|
+
[](https://pepy.tech/project/llm_batch_helper)
|
6
|
+
[](https://llm-batch-helper.readthedocs.io/en/latest/?badge=latest)
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
8
|
+
|
9
|
+
A Python package that enables batch submission of prompts to LLM APIs, with built-in async capabilities, response caching, prompt verification, and more. This package is designed to streamline applications like LLM simulation, LLM-as-a-judge, and other batch processing scenarios.
|
10
|
+
|
11
|
+
📖 **[Complete Documentation](https://llm-batch-helper.readthedocs.io/)** | 🚀 **[Quick Start Guide](https://llm-batch-helper.readthedocs.io/en/latest/quickstart.html)**
|
12
|
+
|
13
|
+
## Why we designed this package
|
14
|
+
|
15
|
+
Calling LLM APIs has become increasingly common, but several pain points exist in practice:
|
16
|
+
|
17
|
+
1. **Efficient Batch Processing**: How do you run LLM calls in batches efficiently? Our async implementation is 3X-100X faster than multi-thread/multi-process approaches.
|
18
|
+
|
19
|
+
2. **API Reliability**: LLM APIs can be unstable, so we need robust retry mechanisms when calls get interrupted.
|
20
|
+
|
21
|
+
3. **Long-Running Simulations**: During long-running LLM simulations, computers can crash and APIs can fail. Can we cache LLM API calls to avoid repeating completed work?
|
22
|
+
|
23
|
+
4. **Output Validation**: LLM outputs often have format requirements. If the output isn't right, we need to retry with validation.
|
24
|
+
|
25
|
+
This package is designed to solve these exact pain points with async processing, intelligent caching, and comprehensive error handling. If there are some additional features you need, please post an issue.
|
4
26
|
|
5
27
|
## Features
|
6
28
|
|
@@ -39,6 +61,7 @@ poetry shell
|
|
39
61
|
|
40
62
|
### 1. Set up environment variables
|
41
63
|
|
64
|
+
**Option A: Environment Variables**
|
42
65
|
```bash
|
43
66
|
# For OpenAI
|
44
67
|
export OPENAI_API_KEY="your-openai-api-key"
|
@@ -47,6 +70,22 @@ export OPENAI_API_KEY="your-openai-api-key"
|
|
47
70
|
export TOGETHER_API_KEY="your-together-api-key"
|
48
71
|
```
|
49
72
|
|
73
|
+
**Option B: .env File (Recommended for Development)**
|
74
|
+
```python
|
75
|
+
# In your script, before importing llm_batch_helper
|
76
|
+
from dotenv import load_dotenv
|
77
|
+
load_dotenv() # Load from .env file
|
78
|
+
|
79
|
+
# Then use the package normally
|
80
|
+
from llm_batch_helper import LLMConfig, process_prompts_batch
|
81
|
+
```
|
82
|
+
|
83
|
+
Create a `.env` file in your project:
|
84
|
+
```
|
85
|
+
OPENAI_API_KEY=your-openai-api-key
|
86
|
+
TOGETHER_API_KEY=your-together-api-key
|
87
|
+
```
|
88
|
+
|
50
89
|
### 2. Interactive Tutorial (Recommended)
|
51
90
|
|
52
91
|
Check out the comprehensive Jupyter notebook [tutorial](https://github.com/TianyiPeng/LLM_batch_helper/blob/main/tutorials/llm_batch_helper_tutorial.ipynb).
|
@@ -57,8 +96,12 @@ The tutorial covers all features with interactive examples!
|
|
57
96
|
|
58
97
|
```python
|
59
98
|
import asyncio
|
99
|
+
from dotenv import load_dotenv # Optional: for .env file support
|
60
100
|
from llm_batch_helper import LLMConfig, process_prompts_batch
|
61
101
|
|
102
|
+
# Optional: Load environment variables from .env file
|
103
|
+
load_dotenv()
|
104
|
+
|
62
105
|
async def main():
|
63
106
|
# Create configuration
|
64
107
|
config = LLMConfig(
|
@@ -175,7 +218,7 @@ Main function for batch processing of prompts.
|
|
175
218
|
```python
|
176
219
|
async def process_prompts_batch(
|
177
220
|
config: LLMConfig,
|
178
|
-
provider: str, # "openai" or "
|
221
|
+
provider: str, # "openai", "together", or "openrouter"
|
179
222
|
prompts: Optional[List[str]] = None,
|
180
223
|
input_dir: Optional[str] = None,
|
181
224
|
cache_dir: str = "llm_cache",
|
@@ -16,6 +16,7 @@ class LLMConfig:
|
|
16
16
|
verification_callback: Optional[Callable[..., bool]] = None,
|
17
17
|
verification_callback_args: Optional[Dict] = None,
|
18
18
|
max_completion_tokens: Optional[int] = None,
|
19
|
+
**kwargs
|
19
20
|
):
|
20
21
|
self.model_name = model_name
|
21
22
|
self.temperature = temperature
|
@@ -30,3 +31,4 @@ class LLMConfig:
|
|
30
31
|
self.verification_callback_args = (
|
31
32
|
verification_callback_args if verification_callback_args is not None else {}
|
32
33
|
)
|
34
|
+
self.kwargs = kwargs
|
@@ -4,7 +4,6 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
|
4
4
|
|
5
5
|
import httpx
|
6
6
|
import openai
|
7
|
-
from dotenv import load_dotenv
|
8
7
|
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_exponential
|
9
8
|
from tqdm.asyncio import tqdm_asyncio
|
10
9
|
|
@@ -12,8 +11,6 @@ from .cache import LLMCache
|
|
12
11
|
from .config import LLMConfig
|
13
12
|
from .input_handlers import get_prompts
|
14
13
|
|
15
|
-
load_dotenv()
|
16
|
-
|
17
14
|
|
18
15
|
@retry(
|
19
16
|
stop=stop_after_attempt(5),
|
@@ -49,6 +46,7 @@ async def _get_openai_response_direct(
|
|
49
46
|
messages=messages,
|
50
47
|
temperature=config.temperature,
|
51
48
|
max_completion_tokens=config.max_completion_tokens,
|
49
|
+
**config.kwargs,
|
52
50
|
)
|
53
51
|
usage_details = {
|
54
52
|
"prompt_token_count": response.usage.prompt_tokens,
|
@@ -97,6 +95,7 @@ async def _get_together_response_direct(
|
|
97
95
|
"messages": messages,
|
98
96
|
"temperature": config.temperature,
|
99
97
|
"max_tokens": config.max_completion_tokens,
|
98
|
+
**config.kwargs,
|
100
99
|
}
|
101
100
|
|
102
101
|
response = await client.post(
|
@@ -119,6 +118,66 @@ async def _get_together_response_direct(
|
|
119
118
|
"usage_details": usage_details,
|
120
119
|
}
|
121
120
|
|
121
|
+
|
122
|
+
@retry(
|
123
|
+
stop=stop_after_attempt(5),
|
124
|
+
wait=wait_exponential(multiplier=1, min=4, max=60),
|
125
|
+
retry=retry_if_exception_type(
|
126
|
+
(
|
127
|
+
ConnectionError,
|
128
|
+
TimeoutError,
|
129
|
+
httpx.HTTPStatusError,
|
130
|
+
httpx.RequestError,
|
131
|
+
)
|
132
|
+
),
|
133
|
+
reraise=True,
|
134
|
+
)
|
135
|
+
async def _get_openrouter_response_direct(
|
136
|
+
prompt: str, config: LLMConfig
|
137
|
+
) -> Dict[str, Union[str, Dict]]:
|
138
|
+
api_key = os.environ.get("OPENROUTER_API_KEY")
|
139
|
+
if not api_key:
|
140
|
+
raise ValueError("OPENROUTER_API_KEY environment variable not set")
|
141
|
+
|
142
|
+
async with httpx.AsyncClient(timeout=1000.0) as client:
|
143
|
+
messages = [
|
144
|
+
{"role": "system", "content": config.system_instruction},
|
145
|
+
{"role": "user", "content": prompt},
|
146
|
+
]
|
147
|
+
|
148
|
+
headers = {
|
149
|
+
"Authorization": f"Bearer {api_key}",
|
150
|
+
"Content-Type": "application/json",
|
151
|
+
}
|
152
|
+
|
153
|
+
payload = {
|
154
|
+
"model": config.model_name,
|
155
|
+
"messages": messages,
|
156
|
+
"temperature": config.temperature,
|
157
|
+
"max_tokens": config.max_completion_tokens,
|
158
|
+
**config.kwargs,
|
159
|
+
}
|
160
|
+
|
161
|
+
response = await client.post(
|
162
|
+
"https://openrouter.ai/api/v1/chat/completions",
|
163
|
+
json=payload,
|
164
|
+
headers=headers,
|
165
|
+
)
|
166
|
+
response.raise_for_status()
|
167
|
+
|
168
|
+
response_data = response.json()
|
169
|
+
usage = response_data.get("usage", {})
|
170
|
+
usage_details = {
|
171
|
+
"prompt_token_count": usage.get("prompt_tokens", 0),
|
172
|
+
"completion_token_count": usage.get("completion_tokens", 0),
|
173
|
+
"total_token_count": usage.get("total_tokens", 0),
|
174
|
+
}
|
175
|
+
|
176
|
+
return {
|
177
|
+
"response_text": response_data["choices"][0]["message"]["content"],
|
178
|
+
"usage_details": usage_details,
|
179
|
+
}
|
180
|
+
|
122
181
|
async def get_llm_response_with_internal_retry(
|
123
182
|
prompt_id: str,
|
124
183
|
prompt: str,
|
@@ -138,6 +197,8 @@ async def get_llm_response_with_internal_retry(
|
|
138
197
|
response = await _get_openai_response_direct(prompt, config)
|
139
198
|
elif provider.lower() == "together":
|
140
199
|
response = await _get_together_response_direct(prompt, config)
|
200
|
+
elif provider.lower() == "openrouter":
|
201
|
+
response = await _get_openrouter_response_direct(prompt, config)
|
141
202
|
else:
|
142
203
|
raise ValueError(f"Unsupported provider: {provider}")
|
143
204
|
|
@@ -168,7 +229,7 @@ async def process_prompts_batch(
|
|
168
229
|
prompts: Optional list of prompts in any supported format (string, tuple, or dict)
|
169
230
|
input_dir: Optional path to directory containing prompt files
|
170
231
|
config: LLM configuration
|
171
|
-
provider: LLM provider to use ("openai", "together", or "
|
232
|
+
provider: LLM provider to use ("openai", "together", or "openrouter")
|
172
233
|
desc: Description for progress bar
|
173
234
|
cache_dir: Optional directory for caching responses
|
174
235
|
force: If True, force regeneration even if cached response exists
|
@@ -1,13 +1,13 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "llm_batch_helper"
|
3
|
-
version = "0.
|
3
|
+
version = "0.2.0"
|
4
4
|
description = "A Python package that enables batch submission of prompts to LLM APIs, with built-in async capabilities and response caching."
|
5
5
|
authors = ["Tianyi Peng <tianyipeng95@gmail.com>"]
|
6
6
|
readme = "README.md"
|
7
7
|
license = "MIT"
|
8
8
|
homepage = "https://github.com/TianyiPeng/LLM_batch_helper"
|
9
9
|
repository = "https://github.com/TianyiPeng/LLM_batch_helper"
|
10
|
-
keywords = ["llm", "openai", "together", "batch", "async", "ai", "nlp", "api"]
|
10
|
+
keywords = ["llm", "openai", "together", "openrouter", "batch", "async", "ai", "nlp", "api"]
|
11
11
|
classifiers = [
|
12
12
|
"Development Status :: 4 - Beta",
|
13
13
|
"Intended Audience :: Developers",
|
@@ -25,11 +25,11 @@ packages = [{include = "llm_batch_helper"}]
|
|
25
25
|
python = "^3.11"
|
26
26
|
httpx = ">=0.24.0,<2.0.0"
|
27
27
|
openai = "^1.0.0"
|
28
|
-
python-dotenv = "^1.0.0"
|
29
28
|
tenacity = "^8.0.0"
|
30
29
|
tqdm = "^4.65.0"
|
31
30
|
|
32
31
|
[tool.poetry.group.dev.dependencies]
|
32
|
+
python-dotenv = "^1.0.0" # Optional for .env file support
|
33
33
|
pytest = "^7.0.0"
|
34
34
|
black = "^23.0.0"
|
35
35
|
isort = "^5.12.0"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|