structai 0.1.2__tar.gz → 0.1.4__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.
- {structai-0.1.2/structai.egg-info → structai-0.1.4}/PKG-INFO +48 -29
- {structai-0.1.2 → structai-0.1.4}/README.md +47 -28
- {structai-0.1.2 → structai-0.1.4}/pyproject.toml +1 -1
- {structai-0.1.2 → structai-0.1.4/structai.egg-info}/PKG-INFO +48 -29
- {structai-0.1.2 → structai-0.1.4}/LICENSE +0 -0
- {structai-0.1.2 → structai-0.1.4}/setup.cfg +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai/__init__.py +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai/io.py +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai/llm_api.py +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai/mp.py +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai/openai_server.py +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai/utils.py +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai.egg-info/SOURCES.txt +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai.egg-info/dependency_links.txt +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai.egg-info/requires.txt +0 -0
- {structai-0.1.2 → structai-0.1.4}/structai.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: structai
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A utility package for AI development
|
|
5
5
|
Author-email: Wanghan Xu <xu_wanghan@sjtu.edu.cn>
|
|
6
6
|
Project-URL: Homepage, https://github.com/black-yt/structai
|
|
@@ -41,9 +41,15 @@ cd structai
|
|
|
41
41
|
pip install -e .
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Usage
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
> **Note:** Before using LLM-related features, please ensure you have set the necessary environment variables:
|
|
47
|
+
> ```bash
|
|
48
|
+
> export LLM_API_KEY="your-api-key"
|
|
49
|
+
> export LLM_BASE_URL="your-api-base-url"
|
|
50
|
+
> ```
|
|
51
|
+
|
|
52
|
+
#### `load_file(path)`
|
|
47
53
|
|
|
48
54
|
Automatically reads a file based on its extension.
|
|
49
55
|
|
|
@@ -62,7 +68,7 @@ df = load_file("data.csv")
|
|
|
62
68
|
image = load_file("photo.jpg")
|
|
63
69
|
```
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
#### `save_file(data, path)`
|
|
66
72
|
|
|
67
73
|
Automatically saves data to a file based on the extension.
|
|
68
74
|
|
|
@@ -78,7 +84,7 @@ save_file(data, "output.json")
|
|
|
78
84
|
save_file(data, "backup.pkl")
|
|
79
85
|
```
|
|
80
86
|
|
|
81
|
-
|
|
87
|
+
#### `print_once(msg)`
|
|
82
88
|
|
|
83
89
|
Prints a message to stdout only the first time it is called. Useful for logging inside loops.
|
|
84
90
|
|
|
@@ -90,7 +96,7 @@ for i in range(10):
|
|
|
90
96
|
# process(i)
|
|
91
97
|
```
|
|
92
98
|
|
|
93
|
-
|
|
99
|
+
#### `make_print_once()`
|
|
94
100
|
|
|
95
101
|
Returns a new function that prints a message only once. This allows for creating local "print once" scopes.
|
|
96
102
|
|
|
@@ -106,7 +112,7 @@ logger1("Hello") # Does nothing
|
|
|
106
112
|
logger2("World") # Prints "World"
|
|
107
113
|
```
|
|
108
114
|
|
|
109
|
-
|
|
115
|
+
#### `LLMAgent`
|
|
110
116
|
|
|
111
117
|
A powerful wrapper class for interacting with OpenAI-compatible LLM APIs. It handles retries, timeouts, and structured output validation.
|
|
112
118
|
|
|
@@ -129,9 +135,9 @@ agent = LLMAgent(
|
|
|
129
135
|
**Basic Usage (`__call__` or `safe_api`):**
|
|
130
136
|
|
|
131
137
|
```python
|
|
132
|
-
response = agent("
|
|
138
|
+
response = agent("Generate a random number.", n=3, temperature=1)
|
|
133
139
|
print(response)
|
|
134
|
-
# Output: "
|
|
140
|
+
# Output: ["Sure! Here's a random number for you: 738", "Sure! Here's a random number: 7382", "Sure! Here's a random number: 487."]
|
|
135
141
|
```
|
|
136
142
|
|
|
137
143
|
**Structured Output Validation:**
|
|
@@ -141,7 +147,7 @@ You can enforce the output format (List, Dict, or specific types) using `return_
|
|
|
141
147
|
```python
|
|
142
148
|
# Enforce a list of integers
|
|
143
149
|
numbers = agent(
|
|
144
|
-
"Generate 3 random numbers",
|
|
150
|
+
"Generate 3 random numbers, for example, [1, 2, 3].",
|
|
145
151
|
return_example=[1],
|
|
146
152
|
list_len=3
|
|
147
153
|
)
|
|
@@ -149,7 +155,7 @@ numbers = agent(
|
|
|
149
155
|
|
|
150
156
|
# Enforce a dictionary with specific keys
|
|
151
157
|
profile = agent(
|
|
152
|
-
"Create a user profile for Alice",
|
|
158
|
+
"Create a user profile for Alice, for example, {'name': Alice, 'age': 1, 'city': 'shanghai'}.",
|
|
153
159
|
return_example={"name": "str", "age": 1, "city": "str"}
|
|
154
160
|
)
|
|
155
161
|
# Output: {'name': 'Alice', 'age': 25, 'city': 'New York'}
|
|
@@ -165,7 +171,20 @@ description = agent(
|
|
|
165
171
|
)
|
|
166
172
|
```
|
|
167
173
|
|
|
168
|
-
|
|
174
|
+
**Memory Context:**
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
history = [
|
|
178
|
+
{"role": "user", "content": "My name is Bob."},
|
|
179
|
+
{"role": "assistant", "content": "Hello Bob."}
|
|
180
|
+
]
|
|
181
|
+
answer = agent(
|
|
182
|
+
"What is my name?",
|
|
183
|
+
history=history,
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### `sanitize_text(text)`
|
|
169
188
|
|
|
170
189
|
Sanitizes text by keeping only ASCII English characters, digits, and common punctuation. Removes control characters and ANSI codes.
|
|
171
190
|
|
|
@@ -176,7 +195,7 @@ clean = sanitize_text("Hello \x1b[31mWorld\x1b[0m!")
|
|
|
176
195
|
print(clean) # "Hello World!"
|
|
177
196
|
```
|
|
178
197
|
|
|
179
|
-
|
|
198
|
+
#### `str2dict(s)`
|
|
180
199
|
|
|
181
200
|
Robustly converts a string representation of a dictionary to a Python `dict`. It handles common formatting errors and uses `json_repair` as a fallback.
|
|
182
201
|
|
|
@@ -187,7 +206,7 @@ d = str2dict("{'a': 1, 'b': 2}")
|
|
|
187
206
|
print(d['a']) # 1
|
|
188
207
|
```
|
|
189
208
|
|
|
190
|
-
|
|
209
|
+
#### `str2list(s)`
|
|
191
210
|
|
|
192
211
|
Robustly converts a string representation of a list to a Python `list`.
|
|
193
212
|
|
|
@@ -198,7 +217,7 @@ l = str2list("[1, 2, 3]")
|
|
|
198
217
|
print(len(l)) # 3
|
|
199
218
|
```
|
|
200
219
|
|
|
201
|
-
|
|
220
|
+
#### `add_no_proxy_if_private(url)`
|
|
202
221
|
|
|
203
222
|
Checks if the hostname in the URL is a private IP address. If so, it adds it to the `no_proxy` environment variable to bypass proxies.
|
|
204
223
|
|
|
@@ -208,7 +227,7 @@ from structai import add_no_proxy_if_private
|
|
|
208
227
|
add_no_proxy_if_private("http://192.168.1.100:8080/v1")
|
|
209
228
|
```
|
|
210
229
|
|
|
211
|
-
|
|
230
|
+
#### `read_image(image_path)`
|
|
212
231
|
|
|
213
232
|
Reads an image from a path and returns a PIL Image object.
|
|
214
233
|
|
|
@@ -218,7 +237,7 @@ from structai import read_image
|
|
|
218
237
|
img = read_image("photo.jpg")
|
|
219
238
|
```
|
|
220
239
|
|
|
221
|
-
|
|
240
|
+
#### `encode_image(image_obj)`
|
|
222
241
|
|
|
223
242
|
Encodes a PIL Image object into a base64 string.
|
|
224
243
|
|
|
@@ -228,7 +247,7 @@ from structai import encode_image
|
|
|
228
247
|
b64_str = encode_image(img)
|
|
229
248
|
```
|
|
230
249
|
|
|
231
|
-
|
|
250
|
+
#### `messages_to_responses_input(messages)`
|
|
232
251
|
|
|
233
252
|
Converts standard Chat Completions `messages` format (list of dicts) to the input format required by the Responses API.
|
|
234
253
|
|
|
@@ -239,7 +258,7 @@ messages = [{"role": "user", "content": "Hello"}]
|
|
|
239
258
|
system_prompt, input_blocks = messages_to_responses_input(messages)
|
|
240
259
|
```
|
|
241
260
|
|
|
242
|
-
|
|
261
|
+
#### `extract_text_outputs(result)`
|
|
243
262
|
|
|
244
263
|
Extracts the text content from an LLM API response object (supports both Chat Completions and Responses API formats).
|
|
245
264
|
|
|
@@ -251,7 +270,7 @@ texts = extract_text_outputs(response)
|
|
|
251
270
|
print(texts[0])
|
|
252
271
|
```
|
|
253
272
|
|
|
254
|
-
|
|
273
|
+
#### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
|
|
255
274
|
|
|
256
275
|
Executes a function concurrently for each item in `inp_list` using a thread pool.
|
|
257
276
|
|
|
@@ -267,7 +286,7 @@ results = multi_thread(inputs, square, max_workers=4)
|
|
|
267
286
|
print(results) # [0, 1, 4, 9, ...]
|
|
268
287
|
```
|
|
269
288
|
|
|
270
|
-
|
|
289
|
+
#### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
|
|
271
290
|
|
|
272
291
|
Executes a function concurrently for each item in `inp_list` using a process pool. Ideal for CPU-bound tasks.
|
|
273
292
|
|
|
@@ -281,7 +300,7 @@ inputs = [{"n": 1000000} for _ in range(5)]
|
|
|
281
300
|
results = multi_process(inputs, heavy_computation)
|
|
282
301
|
```
|
|
283
302
|
|
|
284
|
-
|
|
303
|
+
#### `run_server(host="0.0.0.0", port=8001)`
|
|
285
304
|
|
|
286
305
|
Starts a FastAPI server that acts as a proxy to an OpenAI-compatible LLM provider.
|
|
287
306
|
|
|
@@ -292,7 +311,7 @@ if __name__ == "__main__":
|
|
|
292
311
|
run_server()
|
|
293
312
|
```
|
|
294
313
|
|
|
295
|
-
|
|
314
|
+
#### `timeout_limit(timeout=None)`
|
|
296
315
|
|
|
297
316
|
A decorator that enforces a maximum execution time on a function. Raises `TimeoutError` if the limit is exceeded.
|
|
298
317
|
|
|
@@ -308,7 +327,7 @@ def task():
|
|
|
308
327
|
task()
|
|
309
328
|
```
|
|
310
329
|
|
|
311
|
-
|
|
330
|
+
#### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
|
|
312
331
|
|
|
313
332
|
Runs a function with a specified timeout without using a decorator.
|
|
314
333
|
|
|
@@ -321,7 +340,7 @@ def task(x):
|
|
|
321
340
|
result = run_with_timeout(task, args=(10,), timeout=1.0)
|
|
322
341
|
```
|
|
323
342
|
|
|
324
|
-
|
|
343
|
+
#### `parse_think_answer(text)`
|
|
325
344
|
|
|
326
345
|
Parses a string containing Chain-of-Thought tags (`<think>...</think>` and `<answer>...</answer>`) and returns the content of both.
|
|
327
346
|
|
|
@@ -334,7 +353,7 @@ print(f"Reasoning: {think}")
|
|
|
334
353
|
print(f"Result: {answer}")
|
|
335
354
|
```
|
|
336
355
|
|
|
337
|
-
|
|
356
|
+
#### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
|
|
338
357
|
|
|
339
358
|
Extracts the substring found between two specific tags.
|
|
340
359
|
|
|
@@ -345,7 +364,7 @@ text = "Result: <json>{...}</json>"
|
|
|
345
364
|
json_str = extract_within_tags(text, "<json>", "</json>")
|
|
346
365
|
```
|
|
347
366
|
|
|
348
|
-
|
|
367
|
+
#### `get_all_file_paths(directory, suffix='')`
|
|
349
368
|
|
|
350
369
|
Recursively retrieves all file paths in a directory that match a given suffix.
|
|
351
370
|
|
|
@@ -357,7 +376,7 @@ py_files = get_all_file_paths(".", suffix=".py")
|
|
|
357
376
|
print(py_files)
|
|
358
377
|
```
|
|
359
378
|
|
|
360
|
-
|
|
379
|
+
#### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
|
|
361
380
|
|
|
362
381
|
Removes specified tags from a string, replacing them with a separator (default newline).
|
|
363
382
|
|
|
@@ -369,4 +388,4 @@ clean_text = remove_tag("<think>...</think> Answer")
|
|
|
369
388
|
|
|
370
389
|
## License
|
|
371
390
|
|
|
372
|
-
MIT License
|
|
391
|
+
[MIT License](LICENSE)
|
|
@@ -17,9 +17,15 @@ cd structai
|
|
|
17
17
|
pip install -e .
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Usage
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
> **Note:** Before using LLM-related features, please ensure you have set the necessary environment variables:
|
|
23
|
+
> ```bash
|
|
24
|
+
> export LLM_API_KEY="your-api-key"
|
|
25
|
+
> export LLM_BASE_URL="your-api-base-url"
|
|
26
|
+
> ```
|
|
27
|
+
|
|
28
|
+
#### `load_file(path)`
|
|
23
29
|
|
|
24
30
|
Automatically reads a file based on its extension.
|
|
25
31
|
|
|
@@ -38,7 +44,7 @@ df = load_file("data.csv")
|
|
|
38
44
|
image = load_file("photo.jpg")
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
#### `save_file(data, path)`
|
|
42
48
|
|
|
43
49
|
Automatically saves data to a file based on the extension.
|
|
44
50
|
|
|
@@ -54,7 +60,7 @@ save_file(data, "output.json")
|
|
|
54
60
|
save_file(data, "backup.pkl")
|
|
55
61
|
```
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
#### `print_once(msg)`
|
|
58
64
|
|
|
59
65
|
Prints a message to stdout only the first time it is called. Useful for logging inside loops.
|
|
60
66
|
|
|
@@ -66,7 +72,7 @@ for i in range(10):
|
|
|
66
72
|
# process(i)
|
|
67
73
|
```
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
#### `make_print_once()`
|
|
70
76
|
|
|
71
77
|
Returns a new function that prints a message only once. This allows for creating local "print once" scopes.
|
|
72
78
|
|
|
@@ -82,7 +88,7 @@ logger1("Hello") # Does nothing
|
|
|
82
88
|
logger2("World") # Prints "World"
|
|
83
89
|
```
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
#### `LLMAgent`
|
|
86
92
|
|
|
87
93
|
A powerful wrapper class for interacting with OpenAI-compatible LLM APIs. It handles retries, timeouts, and structured output validation.
|
|
88
94
|
|
|
@@ -105,9 +111,9 @@ agent = LLMAgent(
|
|
|
105
111
|
**Basic Usage (`__call__` or `safe_api`):**
|
|
106
112
|
|
|
107
113
|
```python
|
|
108
|
-
response = agent("
|
|
114
|
+
response = agent("Generate a random number.", n=3, temperature=1)
|
|
109
115
|
print(response)
|
|
110
|
-
# Output: "
|
|
116
|
+
# Output: ["Sure! Here's a random number for you: 738", "Sure! Here's a random number: 7382", "Sure! Here's a random number: 487."]
|
|
111
117
|
```
|
|
112
118
|
|
|
113
119
|
**Structured Output Validation:**
|
|
@@ -117,7 +123,7 @@ You can enforce the output format (List, Dict, or specific types) using `return_
|
|
|
117
123
|
```python
|
|
118
124
|
# Enforce a list of integers
|
|
119
125
|
numbers = agent(
|
|
120
|
-
"Generate 3 random numbers",
|
|
126
|
+
"Generate 3 random numbers, for example, [1, 2, 3].",
|
|
121
127
|
return_example=[1],
|
|
122
128
|
list_len=3
|
|
123
129
|
)
|
|
@@ -125,7 +131,7 @@ numbers = agent(
|
|
|
125
131
|
|
|
126
132
|
# Enforce a dictionary with specific keys
|
|
127
133
|
profile = agent(
|
|
128
|
-
"Create a user profile for Alice",
|
|
134
|
+
"Create a user profile for Alice, for example, {'name': Alice, 'age': 1, 'city': 'shanghai'}.",
|
|
129
135
|
return_example={"name": "str", "age": 1, "city": "str"}
|
|
130
136
|
)
|
|
131
137
|
# Output: {'name': 'Alice', 'age': 25, 'city': 'New York'}
|
|
@@ -141,7 +147,20 @@ description = agent(
|
|
|
141
147
|
)
|
|
142
148
|
```
|
|
143
149
|
|
|
144
|
-
|
|
150
|
+
**Memory Context:**
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
history = [
|
|
154
|
+
{"role": "user", "content": "My name is Bob."},
|
|
155
|
+
{"role": "assistant", "content": "Hello Bob."}
|
|
156
|
+
]
|
|
157
|
+
answer = agent(
|
|
158
|
+
"What is my name?",
|
|
159
|
+
history=history,
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### `sanitize_text(text)`
|
|
145
164
|
|
|
146
165
|
Sanitizes text by keeping only ASCII English characters, digits, and common punctuation. Removes control characters and ANSI codes.
|
|
147
166
|
|
|
@@ -152,7 +171,7 @@ clean = sanitize_text("Hello \x1b[31mWorld\x1b[0m!")
|
|
|
152
171
|
print(clean) # "Hello World!"
|
|
153
172
|
```
|
|
154
173
|
|
|
155
|
-
|
|
174
|
+
#### `str2dict(s)`
|
|
156
175
|
|
|
157
176
|
Robustly converts a string representation of a dictionary to a Python `dict`. It handles common formatting errors and uses `json_repair` as a fallback.
|
|
158
177
|
|
|
@@ -163,7 +182,7 @@ d = str2dict("{'a': 1, 'b': 2}")
|
|
|
163
182
|
print(d['a']) # 1
|
|
164
183
|
```
|
|
165
184
|
|
|
166
|
-
|
|
185
|
+
#### `str2list(s)`
|
|
167
186
|
|
|
168
187
|
Robustly converts a string representation of a list to a Python `list`.
|
|
169
188
|
|
|
@@ -174,7 +193,7 @@ l = str2list("[1, 2, 3]")
|
|
|
174
193
|
print(len(l)) # 3
|
|
175
194
|
```
|
|
176
195
|
|
|
177
|
-
|
|
196
|
+
#### `add_no_proxy_if_private(url)`
|
|
178
197
|
|
|
179
198
|
Checks if the hostname in the URL is a private IP address. If so, it adds it to the `no_proxy` environment variable to bypass proxies.
|
|
180
199
|
|
|
@@ -184,7 +203,7 @@ from structai import add_no_proxy_if_private
|
|
|
184
203
|
add_no_proxy_if_private("http://192.168.1.100:8080/v1")
|
|
185
204
|
```
|
|
186
205
|
|
|
187
|
-
|
|
206
|
+
#### `read_image(image_path)`
|
|
188
207
|
|
|
189
208
|
Reads an image from a path and returns a PIL Image object.
|
|
190
209
|
|
|
@@ -194,7 +213,7 @@ from structai import read_image
|
|
|
194
213
|
img = read_image("photo.jpg")
|
|
195
214
|
```
|
|
196
215
|
|
|
197
|
-
|
|
216
|
+
#### `encode_image(image_obj)`
|
|
198
217
|
|
|
199
218
|
Encodes a PIL Image object into a base64 string.
|
|
200
219
|
|
|
@@ -204,7 +223,7 @@ from structai import encode_image
|
|
|
204
223
|
b64_str = encode_image(img)
|
|
205
224
|
```
|
|
206
225
|
|
|
207
|
-
|
|
226
|
+
#### `messages_to_responses_input(messages)`
|
|
208
227
|
|
|
209
228
|
Converts standard Chat Completions `messages` format (list of dicts) to the input format required by the Responses API.
|
|
210
229
|
|
|
@@ -215,7 +234,7 @@ messages = [{"role": "user", "content": "Hello"}]
|
|
|
215
234
|
system_prompt, input_blocks = messages_to_responses_input(messages)
|
|
216
235
|
```
|
|
217
236
|
|
|
218
|
-
|
|
237
|
+
#### `extract_text_outputs(result)`
|
|
219
238
|
|
|
220
239
|
Extracts the text content from an LLM API response object (supports both Chat Completions and Responses API formats).
|
|
221
240
|
|
|
@@ -227,7 +246,7 @@ texts = extract_text_outputs(response)
|
|
|
227
246
|
print(texts[0])
|
|
228
247
|
```
|
|
229
248
|
|
|
230
|
-
|
|
249
|
+
#### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
|
|
231
250
|
|
|
232
251
|
Executes a function concurrently for each item in `inp_list` using a thread pool.
|
|
233
252
|
|
|
@@ -243,7 +262,7 @@ results = multi_thread(inputs, square, max_workers=4)
|
|
|
243
262
|
print(results) # [0, 1, 4, 9, ...]
|
|
244
263
|
```
|
|
245
264
|
|
|
246
|
-
|
|
265
|
+
#### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
|
|
247
266
|
|
|
248
267
|
Executes a function concurrently for each item in `inp_list` using a process pool. Ideal for CPU-bound tasks.
|
|
249
268
|
|
|
@@ -257,7 +276,7 @@ inputs = [{"n": 1000000} for _ in range(5)]
|
|
|
257
276
|
results = multi_process(inputs, heavy_computation)
|
|
258
277
|
```
|
|
259
278
|
|
|
260
|
-
|
|
279
|
+
#### `run_server(host="0.0.0.0", port=8001)`
|
|
261
280
|
|
|
262
281
|
Starts a FastAPI server that acts as a proxy to an OpenAI-compatible LLM provider.
|
|
263
282
|
|
|
@@ -268,7 +287,7 @@ if __name__ == "__main__":
|
|
|
268
287
|
run_server()
|
|
269
288
|
```
|
|
270
289
|
|
|
271
|
-
|
|
290
|
+
#### `timeout_limit(timeout=None)`
|
|
272
291
|
|
|
273
292
|
A decorator that enforces a maximum execution time on a function. Raises `TimeoutError` if the limit is exceeded.
|
|
274
293
|
|
|
@@ -284,7 +303,7 @@ def task():
|
|
|
284
303
|
task()
|
|
285
304
|
```
|
|
286
305
|
|
|
287
|
-
|
|
306
|
+
#### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
|
|
288
307
|
|
|
289
308
|
Runs a function with a specified timeout without using a decorator.
|
|
290
309
|
|
|
@@ -297,7 +316,7 @@ def task(x):
|
|
|
297
316
|
result = run_with_timeout(task, args=(10,), timeout=1.0)
|
|
298
317
|
```
|
|
299
318
|
|
|
300
|
-
|
|
319
|
+
#### `parse_think_answer(text)`
|
|
301
320
|
|
|
302
321
|
Parses a string containing Chain-of-Thought tags (`<think>...</think>` and `<answer>...</answer>`) and returns the content of both.
|
|
303
322
|
|
|
@@ -310,7 +329,7 @@ print(f"Reasoning: {think}")
|
|
|
310
329
|
print(f"Result: {answer}")
|
|
311
330
|
```
|
|
312
331
|
|
|
313
|
-
|
|
332
|
+
#### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
|
|
314
333
|
|
|
315
334
|
Extracts the substring found between two specific tags.
|
|
316
335
|
|
|
@@ -321,7 +340,7 @@ text = "Result: <json>{...}</json>"
|
|
|
321
340
|
json_str = extract_within_tags(text, "<json>", "</json>")
|
|
322
341
|
```
|
|
323
342
|
|
|
324
|
-
|
|
343
|
+
#### `get_all_file_paths(directory, suffix='')`
|
|
325
344
|
|
|
326
345
|
Recursively retrieves all file paths in a directory that match a given suffix.
|
|
327
346
|
|
|
@@ -333,7 +352,7 @@ py_files = get_all_file_paths(".", suffix=".py")
|
|
|
333
352
|
print(py_files)
|
|
334
353
|
```
|
|
335
354
|
|
|
336
|
-
|
|
355
|
+
#### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
|
|
337
356
|
|
|
338
357
|
Removes specified tags from a string, replacing them with a separator (default newline).
|
|
339
358
|
|
|
@@ -345,4 +364,4 @@ clean_text = remove_tag("<think>...</think> Answer")
|
|
|
345
364
|
|
|
346
365
|
## License
|
|
347
366
|
|
|
348
|
-
MIT License
|
|
367
|
+
[MIT License](LICENSE)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: structai
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A utility package for AI development
|
|
5
5
|
Author-email: Wanghan Xu <xu_wanghan@sjtu.edu.cn>
|
|
6
6
|
Project-URL: Homepage, https://github.com/black-yt/structai
|
|
@@ -41,9 +41,15 @@ cd structai
|
|
|
41
41
|
pip install -e .
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Usage
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
> **Note:** Before using LLM-related features, please ensure you have set the necessary environment variables:
|
|
47
|
+
> ```bash
|
|
48
|
+
> export LLM_API_KEY="your-api-key"
|
|
49
|
+
> export LLM_BASE_URL="your-api-base-url"
|
|
50
|
+
> ```
|
|
51
|
+
|
|
52
|
+
#### `load_file(path)`
|
|
47
53
|
|
|
48
54
|
Automatically reads a file based on its extension.
|
|
49
55
|
|
|
@@ -62,7 +68,7 @@ df = load_file("data.csv")
|
|
|
62
68
|
image = load_file("photo.jpg")
|
|
63
69
|
```
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
#### `save_file(data, path)`
|
|
66
72
|
|
|
67
73
|
Automatically saves data to a file based on the extension.
|
|
68
74
|
|
|
@@ -78,7 +84,7 @@ save_file(data, "output.json")
|
|
|
78
84
|
save_file(data, "backup.pkl")
|
|
79
85
|
```
|
|
80
86
|
|
|
81
|
-
|
|
87
|
+
#### `print_once(msg)`
|
|
82
88
|
|
|
83
89
|
Prints a message to stdout only the first time it is called. Useful for logging inside loops.
|
|
84
90
|
|
|
@@ -90,7 +96,7 @@ for i in range(10):
|
|
|
90
96
|
# process(i)
|
|
91
97
|
```
|
|
92
98
|
|
|
93
|
-
|
|
99
|
+
#### `make_print_once()`
|
|
94
100
|
|
|
95
101
|
Returns a new function that prints a message only once. This allows for creating local "print once" scopes.
|
|
96
102
|
|
|
@@ -106,7 +112,7 @@ logger1("Hello") # Does nothing
|
|
|
106
112
|
logger2("World") # Prints "World"
|
|
107
113
|
```
|
|
108
114
|
|
|
109
|
-
|
|
115
|
+
#### `LLMAgent`
|
|
110
116
|
|
|
111
117
|
A powerful wrapper class for interacting with OpenAI-compatible LLM APIs. It handles retries, timeouts, and structured output validation.
|
|
112
118
|
|
|
@@ -129,9 +135,9 @@ agent = LLMAgent(
|
|
|
129
135
|
**Basic Usage (`__call__` or `safe_api`):**
|
|
130
136
|
|
|
131
137
|
```python
|
|
132
|
-
response = agent("
|
|
138
|
+
response = agent("Generate a random number.", n=3, temperature=1)
|
|
133
139
|
print(response)
|
|
134
|
-
# Output: "
|
|
140
|
+
# Output: ["Sure! Here's a random number for you: 738", "Sure! Here's a random number: 7382", "Sure! Here's a random number: 487."]
|
|
135
141
|
```
|
|
136
142
|
|
|
137
143
|
**Structured Output Validation:**
|
|
@@ -141,7 +147,7 @@ You can enforce the output format (List, Dict, or specific types) using `return_
|
|
|
141
147
|
```python
|
|
142
148
|
# Enforce a list of integers
|
|
143
149
|
numbers = agent(
|
|
144
|
-
"Generate 3 random numbers",
|
|
150
|
+
"Generate 3 random numbers, for example, [1, 2, 3].",
|
|
145
151
|
return_example=[1],
|
|
146
152
|
list_len=3
|
|
147
153
|
)
|
|
@@ -149,7 +155,7 @@ numbers = agent(
|
|
|
149
155
|
|
|
150
156
|
# Enforce a dictionary with specific keys
|
|
151
157
|
profile = agent(
|
|
152
|
-
"Create a user profile for Alice",
|
|
158
|
+
"Create a user profile for Alice, for example, {'name': Alice, 'age': 1, 'city': 'shanghai'}.",
|
|
153
159
|
return_example={"name": "str", "age": 1, "city": "str"}
|
|
154
160
|
)
|
|
155
161
|
# Output: {'name': 'Alice', 'age': 25, 'city': 'New York'}
|
|
@@ -165,7 +171,20 @@ description = agent(
|
|
|
165
171
|
)
|
|
166
172
|
```
|
|
167
173
|
|
|
168
|
-
|
|
174
|
+
**Memory Context:**
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
history = [
|
|
178
|
+
{"role": "user", "content": "My name is Bob."},
|
|
179
|
+
{"role": "assistant", "content": "Hello Bob."}
|
|
180
|
+
]
|
|
181
|
+
answer = agent(
|
|
182
|
+
"What is my name?",
|
|
183
|
+
history=history,
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### `sanitize_text(text)`
|
|
169
188
|
|
|
170
189
|
Sanitizes text by keeping only ASCII English characters, digits, and common punctuation. Removes control characters and ANSI codes.
|
|
171
190
|
|
|
@@ -176,7 +195,7 @@ clean = sanitize_text("Hello \x1b[31mWorld\x1b[0m!")
|
|
|
176
195
|
print(clean) # "Hello World!"
|
|
177
196
|
```
|
|
178
197
|
|
|
179
|
-
|
|
198
|
+
#### `str2dict(s)`
|
|
180
199
|
|
|
181
200
|
Robustly converts a string representation of a dictionary to a Python `dict`. It handles common formatting errors and uses `json_repair` as a fallback.
|
|
182
201
|
|
|
@@ -187,7 +206,7 @@ d = str2dict("{'a': 1, 'b': 2}")
|
|
|
187
206
|
print(d['a']) # 1
|
|
188
207
|
```
|
|
189
208
|
|
|
190
|
-
|
|
209
|
+
#### `str2list(s)`
|
|
191
210
|
|
|
192
211
|
Robustly converts a string representation of a list to a Python `list`.
|
|
193
212
|
|
|
@@ -198,7 +217,7 @@ l = str2list("[1, 2, 3]")
|
|
|
198
217
|
print(len(l)) # 3
|
|
199
218
|
```
|
|
200
219
|
|
|
201
|
-
|
|
220
|
+
#### `add_no_proxy_if_private(url)`
|
|
202
221
|
|
|
203
222
|
Checks if the hostname in the URL is a private IP address. If so, it adds it to the `no_proxy` environment variable to bypass proxies.
|
|
204
223
|
|
|
@@ -208,7 +227,7 @@ from structai import add_no_proxy_if_private
|
|
|
208
227
|
add_no_proxy_if_private("http://192.168.1.100:8080/v1")
|
|
209
228
|
```
|
|
210
229
|
|
|
211
|
-
|
|
230
|
+
#### `read_image(image_path)`
|
|
212
231
|
|
|
213
232
|
Reads an image from a path and returns a PIL Image object.
|
|
214
233
|
|
|
@@ -218,7 +237,7 @@ from structai import read_image
|
|
|
218
237
|
img = read_image("photo.jpg")
|
|
219
238
|
```
|
|
220
239
|
|
|
221
|
-
|
|
240
|
+
#### `encode_image(image_obj)`
|
|
222
241
|
|
|
223
242
|
Encodes a PIL Image object into a base64 string.
|
|
224
243
|
|
|
@@ -228,7 +247,7 @@ from structai import encode_image
|
|
|
228
247
|
b64_str = encode_image(img)
|
|
229
248
|
```
|
|
230
249
|
|
|
231
|
-
|
|
250
|
+
#### `messages_to_responses_input(messages)`
|
|
232
251
|
|
|
233
252
|
Converts standard Chat Completions `messages` format (list of dicts) to the input format required by the Responses API.
|
|
234
253
|
|
|
@@ -239,7 +258,7 @@ messages = [{"role": "user", "content": "Hello"}]
|
|
|
239
258
|
system_prompt, input_blocks = messages_to_responses_input(messages)
|
|
240
259
|
```
|
|
241
260
|
|
|
242
|
-
|
|
261
|
+
#### `extract_text_outputs(result)`
|
|
243
262
|
|
|
244
263
|
Extracts the text content from an LLM API response object (supports both Chat Completions and Responses API formats).
|
|
245
264
|
|
|
@@ -251,7 +270,7 @@ texts = extract_text_outputs(response)
|
|
|
251
270
|
print(texts[0])
|
|
252
271
|
```
|
|
253
272
|
|
|
254
|
-
|
|
273
|
+
#### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
|
|
255
274
|
|
|
256
275
|
Executes a function concurrently for each item in `inp_list` using a thread pool.
|
|
257
276
|
|
|
@@ -267,7 +286,7 @@ results = multi_thread(inputs, square, max_workers=4)
|
|
|
267
286
|
print(results) # [0, 1, 4, 9, ...]
|
|
268
287
|
```
|
|
269
288
|
|
|
270
|
-
|
|
289
|
+
#### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
|
|
271
290
|
|
|
272
291
|
Executes a function concurrently for each item in `inp_list` using a process pool. Ideal for CPU-bound tasks.
|
|
273
292
|
|
|
@@ -281,7 +300,7 @@ inputs = [{"n": 1000000} for _ in range(5)]
|
|
|
281
300
|
results = multi_process(inputs, heavy_computation)
|
|
282
301
|
```
|
|
283
302
|
|
|
284
|
-
|
|
303
|
+
#### `run_server(host="0.0.0.0", port=8001)`
|
|
285
304
|
|
|
286
305
|
Starts a FastAPI server that acts as a proxy to an OpenAI-compatible LLM provider.
|
|
287
306
|
|
|
@@ -292,7 +311,7 @@ if __name__ == "__main__":
|
|
|
292
311
|
run_server()
|
|
293
312
|
```
|
|
294
313
|
|
|
295
|
-
|
|
314
|
+
#### `timeout_limit(timeout=None)`
|
|
296
315
|
|
|
297
316
|
A decorator that enforces a maximum execution time on a function. Raises `TimeoutError` if the limit is exceeded.
|
|
298
317
|
|
|
@@ -308,7 +327,7 @@ def task():
|
|
|
308
327
|
task()
|
|
309
328
|
```
|
|
310
329
|
|
|
311
|
-
|
|
330
|
+
#### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
|
|
312
331
|
|
|
313
332
|
Runs a function with a specified timeout without using a decorator.
|
|
314
333
|
|
|
@@ -321,7 +340,7 @@ def task(x):
|
|
|
321
340
|
result = run_with_timeout(task, args=(10,), timeout=1.0)
|
|
322
341
|
```
|
|
323
342
|
|
|
324
|
-
|
|
343
|
+
#### `parse_think_answer(text)`
|
|
325
344
|
|
|
326
345
|
Parses a string containing Chain-of-Thought tags (`<think>...</think>` and `<answer>...</answer>`) and returns the content of both.
|
|
327
346
|
|
|
@@ -334,7 +353,7 @@ print(f"Reasoning: {think}")
|
|
|
334
353
|
print(f"Result: {answer}")
|
|
335
354
|
```
|
|
336
355
|
|
|
337
|
-
|
|
356
|
+
#### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
|
|
338
357
|
|
|
339
358
|
Extracts the substring found between two specific tags.
|
|
340
359
|
|
|
@@ -345,7 +364,7 @@ text = "Result: <json>{...}</json>"
|
|
|
345
364
|
json_str = extract_within_tags(text, "<json>", "</json>")
|
|
346
365
|
```
|
|
347
366
|
|
|
348
|
-
|
|
367
|
+
#### `get_all_file_paths(directory, suffix='')`
|
|
349
368
|
|
|
350
369
|
Recursively retrieves all file paths in a directory that match a given suffix.
|
|
351
370
|
|
|
@@ -357,7 +376,7 @@ py_files = get_all_file_paths(".", suffix=".py")
|
|
|
357
376
|
print(py_files)
|
|
358
377
|
```
|
|
359
378
|
|
|
360
|
-
|
|
379
|
+
#### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
|
|
361
380
|
|
|
362
381
|
Removes specified tags from a string, replacing them with a separator (default newline).
|
|
363
382
|
|
|
@@ -369,4 +388,4 @@ clean_text = remove_tag("<think>...</think> Answer")
|
|
|
369
388
|
|
|
370
389
|
## License
|
|
371
390
|
|
|
372
|
-
MIT License
|
|
391
|
+
[MIT License](LICENSE)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|