lionagi 0.0.201__py3-none-any.whl → 0.0.204__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.
- lionagi/_services/anthropic.py +79 -1
- lionagi/_services/base_service.py +1 -1
- lionagi/_services/services.py +61 -25
- lionagi/_services/transformers.py +46 -0
- lionagi/agents/__init__.py +0 -0
- lionagi/configs/oai_configs.py +1 -1
- lionagi/configs/openrouter_configs.py +1 -1
- lionagi/core/__init__.py +3 -7
- lionagi/core/branch/__init__.py +0 -0
- lionagi/core/branch/branch.py +589 -0
- lionagi/core/branch/branch_manager.py +139 -0
- lionagi/core/branch/cluster.py +1 -0
- lionagi/core/branch/conversation.py +484 -0
- lionagi/core/core_util.py +59 -0
- lionagi/core/flow/__init__.py +0 -0
- lionagi/core/flow/flow.py +19 -0
- lionagi/core/instruction_set/__init__.py +0 -0
- lionagi/core/instruction_set/instruction_set.py +343 -0
- lionagi/core/messages/__init__.py +0 -0
- lionagi/core/messages/messages.py +176 -0
- lionagi/core/sessions/__init__.py +0 -0
- lionagi/core/sessions/session.py +428 -0
- lionagi/models/__init__.py +0 -0
- lionagi/models/base_model.py +0 -0
- lionagi/models/imodel.py +53 -0
- lionagi/schema/data_logger.py +75 -155
- lionagi/tests/test_utils/test_call_util.py +658 -657
- lionagi/tools/tool_manager.py +121 -188
- lionagi/utils/__init__.py +5 -10
- lionagi/utils/call_util.py +667 -585
- lionagi/utils/io_util.py +3 -0
- lionagi/utils/nested_util.py +17 -211
- lionagi/utils/pd_util.py +57 -0
- lionagi/utils/sys_util.py +220 -184
- lionagi/utils/url_util.py +55 -0
- lionagi/version.py +1 -1
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/METADATA +12 -8
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/RECORD +47 -32
- lionagi/core/branch.py +0 -193
- lionagi/core/conversation.py +0 -341
- lionagi/core/flow.py +0 -8
- lionagi/core/instruction_set.py +0 -150
- lionagi/core/messages.py +0 -243
- lionagi/core/sessions.py +0 -474
- /lionagi/{tools → agents}/planner.py +0 -0
- /lionagi/{tools → agents}/prompter.py +0 -0
- /lionagi/{tools → agents}/scorer.py +0 -0
- /lionagi/{tools → agents}/summarizer.py +0 -0
- /lionagi/{tools → agents}/validator.py +0 -0
- /lionagi/core/{flow_util.py → flow/flow_util.py} +0 -0
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/LICENSE +0 -0
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/WHEEL +0 -0
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/top_level.txt +0 -0
lionagi/utils/sys_util.py
CHANGED
@@ -1,300 +1,316 @@
|
|
1
1
|
import os
|
2
|
+
import copy
|
3
|
+
from datetime import datetime
|
2
4
|
import hashlib
|
3
5
|
import re
|
4
|
-
|
6
|
+
|
5
7
|
import json
|
6
|
-
|
7
|
-
|
8
|
-
from
|
9
|
-
from typing import Any, Dict, List, Optional, Type, Union
|
8
|
+
import logging
|
9
|
+
|
10
|
+
from typing import Any, List, Dict, Union
|
10
11
|
|
11
12
|
|
12
13
|
def get_timestamp() -> str:
|
13
14
|
"""
|
14
|
-
Generates a current timestamp in
|
15
|
+
Generates a current timestamp in ISO format with colons and periods replaced by
|
16
|
+
underscores.
|
15
17
|
|
16
18
|
Returns:
|
17
|
-
The current timestamp
|
19
|
+
str: The current timestamp.
|
18
20
|
|
19
21
|
Examples:
|
20
|
-
|
21
|
-
|
22
|
+
>>> isinstance(get_timestamp(), str)
|
23
|
+
True
|
22
24
|
"""
|
23
25
|
return datetime.now().isoformat().replace(":", "_").replace(".", "_")
|
24
26
|
|
25
|
-
def create_copy(input: Any, n: int) -> Any:
|
27
|
+
def create_copy(input: Any, n: int = 1) -> Any:
|
26
28
|
"""
|
27
|
-
Creates a deep copy of the input
|
29
|
+
Creates a deep copy of the given input. If 'n' is greater than 1, returns a
|
30
|
+
list of deep copies.
|
28
31
|
|
29
32
|
Args:
|
30
|
-
input: The object to be copied.
|
31
|
-
n: The number of
|
32
|
-
|
33
|
-
Raises:
|
34
|
-
ValueError: If 'n' is not a positive integer.
|
33
|
+
input (Any): The object to be copied.
|
34
|
+
n (int, optional): The number of copies to create. Defaults to 1.
|
35
35
|
|
36
36
|
Returns:
|
37
|
-
A deep copy of
|
37
|
+
Any: A deep copy of the input, or a list of deep copies.
|
38
38
|
|
39
|
+
Raises:
|
40
|
+
ValueError: If 'n' is not a positive integer.
|
41
|
+
|
39
42
|
Examples:
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
>>> create_copy([1, 2, 3], 2)
|
44
|
+
[[1, 2, 3], [1, 2, 3]]
|
45
|
+
>>> create_copy("Hello")
|
46
|
+
'Hello'
|
43
47
|
"""
|
44
48
|
if not isinstance(n, int) or n < 1:
|
45
49
|
raise ValueError(f"'n' must be a positive integer: {n}")
|
46
50
|
return copy.deepcopy(input) if n == 1 else [copy.deepcopy(input) for _ in range(n)]
|
47
51
|
|
48
|
-
def create_path(
|
52
|
+
def create_path(
|
53
|
+
dir: str, filename: str, timestamp: bool = True, dir_exist_ok: bool = True,
|
54
|
+
time_prefix: bool = False
|
55
|
+
) -> str:
|
49
56
|
"""
|
50
|
-
Creates a file path
|
57
|
+
Creates a file path with an optional timestamp, ensuring the directory exists.
|
51
58
|
|
52
59
|
Args:
|
53
|
-
dir: The directory in which the file
|
54
|
-
filename: The name of the file.
|
55
|
-
timestamp:
|
56
|
-
dir_exist_ok:
|
57
|
-
time_prefix:
|
60
|
+
dir (str): The directory in which the file will be placed.
|
61
|
+
filename (str): The name of the file.
|
62
|
+
timestamp (bool, optional): Flag to include a timestamp in the filename. Defaults to True.
|
63
|
+
dir_exist_ok (bool, optional): Flag to create the directory if it doesn't exist. Defaults to True.
|
64
|
+
time_prefix (bool, optional): Flag to place the timestamp as a prefix. Defaults to False.
|
58
65
|
|
59
66
|
Returns:
|
60
|
-
The full path
|
67
|
+
str: The full path of the file with the optional timestamp.
|
61
68
|
|
62
69
|
Examples:
|
63
|
-
|
64
|
-
|
70
|
+
>>> create_path("/tmp", "log.txt", timestamp=False)
|
71
|
+
'/tmp/log.txt'
|
72
|
+
>>> isinstance(create_path("/tmp", "report", time_prefix=True), str)
|
73
|
+
True
|
65
74
|
"""
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
os.makedirs(dir, exist_ok=dir_exist_ok)
|
70
|
-
|
71
|
-
if timestamp:
|
72
|
-
timestamp = get_timestamp()
|
73
|
-
return f"{dir}{timestamp}_{filename}.{ext}" if time_prefix else f"{dir}{filename}_{timestamp}.{ext}"
|
75
|
+
dir = dir + '/' if not dir.endswith('/') else dir
|
76
|
+
if '.' in filename:
|
77
|
+
name, ext = filename.rsplit('.', 1)
|
74
78
|
else:
|
75
|
-
|
79
|
+
name, ext = filename, ''
|
80
|
+
os.makedirs(dir, exist_ok=dir_exist_ok)
|
81
|
+
timestamp_str = get_timestamp() if timestamp else ''
|
82
|
+
filename = f"{timestamp_str}_{name}" if time_prefix else f"{name}_{timestamp_str}"
|
83
|
+
return f"{dir}{filename}.{ext}" if ext else f"{dir}{filename}"
|
76
84
|
|
77
|
-
def split_path(path:
|
85
|
+
def split_path(path: str) -> tuple:
|
78
86
|
"""
|
79
|
-
Splits a
|
87
|
+
Splits a file path into its directory name and file name.
|
80
88
|
|
81
89
|
Args:
|
82
|
-
path: The path to split.
|
90
|
+
path (str): The file path to split.
|
83
91
|
|
84
92
|
Returns:
|
85
|
-
A tuple containing the
|
93
|
+
tuple: A tuple containing the directory name and file name.
|
94
|
+
|
95
|
+
Examples:
|
96
|
+
>>> split_path("/home/user/document.txt")
|
97
|
+
('/home/user', 'document.txt')
|
98
|
+
>>> split_path("document.txt")
|
99
|
+
('', 'document.txt')
|
86
100
|
"""
|
87
|
-
folder_name = path.
|
88
|
-
file_name = path.
|
101
|
+
folder_name = os.path.dirname(path)
|
102
|
+
file_name = os.path.basename(path)
|
89
103
|
return (folder_name, file_name)
|
90
104
|
|
91
|
-
def
|
105
|
+
def str_to_num(
|
106
|
+
input: str, upper_bound: float = None, lower_bound: float = None,
|
107
|
+
num_type: type = int, precision: int = None
|
108
|
+
) -> Any:
|
92
109
|
"""
|
93
|
-
|
110
|
+
Converts the first number in a string to a specified numeric type and checks if it
|
111
|
+
falls within specified bounds.
|
94
112
|
|
95
113
|
Args:
|
96
|
-
input:
|
97
|
-
|
114
|
+
input (str): The string containing the number.
|
115
|
+
upper_bound (float, optional): The upper limit for the number. Defaults to None.
|
116
|
+
lower_bound (float, optional): The lower limit for the number. Defaults to None.
|
117
|
+
num_type (type): The numeric type to which the number will be converted. Default is int.
|
118
|
+
precision (int, optional): The precision for floating point numbers. Defaults to None.
|
98
119
|
|
99
120
|
Returns:
|
100
|
-
|
121
|
+
Any: The converted number in the specified type.
|
122
|
+
|
123
|
+
Raises:
|
124
|
+
ValueError: If no numeric value is found, or the number is outside the specified bounds.
|
101
125
|
|
102
126
|
Examples:
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
127
|
+
>>> str_to_num("Value is 20.5", upper_bound=30, num_type=float)
|
128
|
+
20.5
|
129
|
+
>>> str_to_num("Temperature -5 degrees", lower_bound=0)
|
130
|
+
ValueError: Number -5 is less than the lower bound of 0.
|
131
|
+
"""
|
132
|
+
number_str = _extract_first_number(input)
|
133
|
+
if number_str is None:
|
134
|
+
raise ValueError(f"No numeric values found in the string: {input}")
|
135
|
+
|
136
|
+
number = _convert_to_num(number_str, num_type, precision)
|
137
|
+
|
138
|
+
if upper_bound is not None and number > upper_bound:
|
139
|
+
raise ValueError(f"Number {number} is greater than the upper bound of {upper_bound}.")
|
140
|
+
if lower_bound is not None and number < lower_bound:
|
141
|
+
raise ValueError(f"Number {number} is less than the lower bound of {lower_bound}.")
|
142
|
+
|
143
|
+
return number
|
144
|
+
|
145
|
+
def get_bins(input: List[str], upper: int) -> List[List[int]]:
|
146
|
+
"""
|
147
|
+
Distributes a list of strings into bins where the total length of strings in each
|
148
|
+
bin is less than a specified upper limit.
|
149
|
+
|
150
|
+
Args:
|
151
|
+
input (List[str]): The list of strings to be distributed.
|
152
|
+
upper (int): The upper limit for the total length of strings in each bin.
|
153
|
+
|
154
|
+
Returns:
|
155
|
+
List[List[int]]: A list of lists, where each inner list contains indices of the
|
156
|
+
input list that make up a bin.
|
157
|
+
|
158
|
+
Examples:
|
159
|
+
>>> get_bins(["one", "two", "three", "four", "five"], 10)
|
160
|
+
[[0, 1], [2], [3, 4]]
|
107
161
|
"""
|
108
162
|
current = 0
|
109
163
|
bins = []
|
110
|
-
|
111
|
-
|
164
|
+
current_bin = []
|
112
165
|
for idx, item in enumerate(input):
|
113
166
|
|
114
167
|
if current + len(item) < upper:
|
115
|
-
|
168
|
+
current_bin.append(idx)
|
116
169
|
current += len(item)
|
117
|
-
|
118
|
-
|
119
|
-
bins.append(
|
120
|
-
|
170
|
+
|
171
|
+
else:
|
172
|
+
bins.append(current_bin)
|
173
|
+
current_bin = [idx]
|
121
174
|
current = len(item)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
175
|
+
|
176
|
+
if current_bin:
|
177
|
+
bins.append(current_bin)
|
178
|
+
|
126
179
|
return bins
|
127
180
|
|
128
|
-
def
|
181
|
+
def create_id(n: int = 32) -> str:
|
129
182
|
"""
|
130
|
-
|
183
|
+
Creates a unique identifier using a combination of the current time and random bytes.
|
131
184
|
|
132
185
|
Args:
|
133
|
-
|
134
|
-
old_key: The old key to be changed.
|
135
|
-
new_key: The new key to change to.
|
136
|
-
"""
|
137
|
-
dict_[new_key] = dict_.pop(old_key)
|
138
|
-
|
139
|
-
def create_id(n=32) -> str:
|
140
|
-
"""
|
141
|
-
Generates a unique ID based on the current time and random bytes.
|
142
|
-
|
143
|
-
Args:
|
144
|
-
n: Length of the unique identifier to return. Defaults to 32.
|
186
|
+
n (int, optional): The length of the identifier. Defaults to 32.
|
145
187
|
|
146
188
|
Returns:
|
147
|
-
|
189
|
+
str: The generated unique identifier.
|
148
190
|
|
149
191
|
Examples:
|
150
|
-
|
151
|
-
|
192
|
+
>>> len(create_id())
|
193
|
+
32
|
194
|
+
>>> len(create_id(16))
|
195
|
+
16
|
152
196
|
"""
|
153
197
|
current_time = datetime.now().isoformat().encode('utf-8')
|
154
198
|
random_bytes = os.urandom(32)
|
155
199
|
return hashlib.sha256(current_time + random_bytes).hexdigest()[:n]
|
156
200
|
|
157
|
-
def
|
201
|
+
def directory_cleaner(directory: str) -> None:
|
158
202
|
"""
|
159
|
-
|
203
|
+
Deletes all files within a given directory.
|
160
204
|
|
161
205
|
Args:
|
162
|
-
|
163
|
-
fmt: An optional format string.
|
206
|
+
directory (str): The path of the directory to clean.
|
164
207
|
|
165
|
-
|
166
|
-
|
208
|
+
Raises:
|
209
|
+
FileNotFoundError: If the specified directory does not exist.
|
210
|
+
Exception: If a file in the directory cannot be deleted.
|
167
211
|
|
168
212
|
Examples:
|
169
|
-
|
170
|
-
|
171
|
-
>>> str_to_datetime("January 1, 2023, 12:00 PM", "%B %d, %Y, %I:%M %p")
|
172
|
-
datetime.datetime(2023, 1, 1, 12, 0)
|
213
|
+
>>> directory_cleaner("/path/to/nonexistent/directory")
|
214
|
+
FileNotFoundError: The specified directory does not exist.
|
173
215
|
"""
|
174
|
-
if
|
175
|
-
|
176
|
-
else:
|
177
|
-
return parser.parse(datetime_str)
|
216
|
+
if not os.path.exists(directory):
|
217
|
+
raise FileNotFoundError("The specified directory does not exist.")
|
178
218
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
219
|
+
for filename in os.listdir(directory):
|
220
|
+
file_path = os.path.join(directory, filename)
|
221
|
+
try:
|
222
|
+
if os.path.isfile(file_path) or os.path.islink(file_path):
|
223
|
+
os.unlink(file_path)
|
224
|
+
logging.info(f'Successfully deleted {file_path}')
|
225
|
+
except Exception as e:
|
226
|
+
logging.error(f'Failed to delete {file_path}. Reason: {e}')
|
227
|
+
raise
|
228
|
+
|
229
|
+
def strip_lower(input: Any) -> str:
|
184
230
|
"""
|
185
|
-
|
231
|
+
Strips and converts a given input to lower case.
|
186
232
|
|
187
233
|
Args:
|
188
|
-
|
189
|
-
upper_bound: The upper bound for the numeric value (optional).
|
190
|
-
lower_bound: The lower bound for the numeric value (optional).
|
191
|
-
num_type: The type of number to return (int or float).
|
192
|
-
precision: The number of decimal places to round to if num_type is float (optional).
|
234
|
+
input (Any): The input to be processed.
|
193
235
|
|
194
236
|
Returns:
|
195
|
-
The
|
237
|
+
str: The processed string in lower case.
|
196
238
|
|
197
239
|
Raises:
|
198
|
-
|
240
|
+
Exception: If the input cannot be converted to a string.
|
199
241
|
|
200
242
|
Examples:
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
243
|
+
>>> strip_lower(" Hello WORLD ")
|
244
|
+
'hello world'
|
245
|
+
>>> strip_lower(123)
|
246
|
+
'123'
|
205
247
|
"""
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
number = numbers[0]
|
211
|
-
if num_type is int:
|
212
|
-
number = int(float(number))
|
213
|
-
elif num_type is float:
|
214
|
-
number = round(float(number), precision) if precision is not None else float(number)
|
215
|
-
else:
|
216
|
-
raise ValueError(f"Invalid number type: {num_type}")
|
217
|
-
|
218
|
-
if upper_bound is not None and number > upper_bound:
|
219
|
-
raise ValueError(f"Number {number} is greater than the upper bound of {upper_bound}.")
|
220
|
-
if lower_bound is not None and number < lower_bound:
|
221
|
-
raise ValueError(f"Number {number} is less than the lower bound of {lower_bound}.")
|
222
|
-
|
223
|
-
return number
|
248
|
+
try:
|
249
|
+
return str(input).strip().lower()
|
250
|
+
except:
|
251
|
+
return False
|
224
252
|
|
225
|
-
def
|
253
|
+
def _extract_first_number(inputstr: str) -> str:
|
226
254
|
"""
|
227
|
-
|
255
|
+
Extracts the first number from a given string.
|
228
256
|
|
229
257
|
Args:
|
230
|
-
|
231
|
-
depth_strategy: Strategy to calculate depth ('uniform' or 'mixed').
|
232
|
-
ignore_non_iterable: If True, non-iterable elements do not count towards depth.
|
258
|
+
inputstr (str): The string from which the number will be extracted.
|
233
259
|
|
234
260
|
Returns:
|
235
|
-
The
|
261
|
+
str: The first number found in the string, returned as a string.
|
262
|
+
Returns None if no number is found.
|
236
263
|
|
237
|
-
|
238
|
-
|
264
|
+
Examples:
|
265
|
+
>>> extract_first_number("The 2 little pigs")
|
266
|
+
'2'
|
267
|
+
>>> extract_first_number("No numbers")
|
268
|
+
None
|
239
269
|
"""
|
270
|
+
numbers = re.findall(r'-?\d+\.?\d*', inputstr)
|
271
|
+
return numbers[0] if numbers else None
|
240
272
|
|
241
|
-
|
242
|
-
"""Calculates depth assuming uniform data types in nested_obj."""
|
243
|
-
if isinstance(obj, (list, tuple)):
|
244
|
-
return max((_uniform_depth(item, current_depth + 1) for item in obj), default=current_depth)
|
245
|
-
elif isinstance(obj, dict):
|
246
|
-
return max((_uniform_depth(value, current_depth + 1) for value in obj.values()), default=current_depth)
|
247
|
-
else:
|
248
|
-
return current_depth if ignore_non_iterable else 1
|
249
|
-
|
250
|
-
def _mixed_depth(obj, current_depth=0):
|
251
|
-
"""Calculates depth allowing for mixed data types in nested_obj."""
|
252
|
-
if isinstance(obj, (list, tuple, dict)):
|
253
|
-
if isinstance(obj, dict):
|
254
|
-
obj = obj.values()
|
255
|
-
return max((_mixed_depth(item, current_depth + 1) for item in obj), default=current_depth)
|
256
|
-
else:
|
257
|
-
return current_depth if ignore_non_iterable else 1
|
258
|
-
|
259
|
-
if depth_strategy == 'uniform':
|
260
|
-
return _uniform_depth(nested_obj)
|
261
|
-
elif depth_strategy == 'mixed':
|
262
|
-
return _mixed_depth(nested_obj)
|
263
|
-
else:
|
264
|
-
raise ValueError("Unsupported depth strategy. Choose 'uniform' or 'mixed'.")
|
265
|
-
|
266
|
-
def is_schema(dict_: Dict, schema: Dict):
|
273
|
+
def _convert_to_num(number_str: str, num_type: type = int, precision: int = None) -> Any:
|
267
274
|
"""
|
268
|
-
|
275
|
+
Converts a string representation of a number to a specified numeric type.
|
269
276
|
|
270
277
|
Args:
|
271
|
-
|
272
|
-
|
278
|
+
number_str (str): The string representation of the number.
|
279
|
+
num_type (type): The type to which the number will be converted. Default is int.
|
280
|
+
precision (int, optional): The precision for floating point numbers. Defaults to None.
|
273
281
|
|
274
282
|
Returns:
|
275
|
-
|
283
|
+
Any: The converted number in the specified type.
|
284
|
+
|
285
|
+
Raises:
|
286
|
+
ValueError: If an invalid number type is provided.
|
287
|
+
|
288
|
+
Examples:
|
289
|
+
>>> convert_to_num("3.142", float, 2)
|
290
|
+
3.14
|
291
|
+
>>> convert_to_num("100", int)
|
292
|
+
100
|
276
293
|
"""
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
294
|
+
if num_type is int:
|
295
|
+
return int(float(number_str))
|
296
|
+
elif num_type is float:
|
297
|
+
return round(float(number_str), precision) if precision is not None else float(number_str)
|
298
|
+
else:
|
299
|
+
raise ValueError(f"Invalid number type: {num_type}")
|
281
300
|
|
282
|
-
def
|
301
|
+
def change_dict_key(dict_: Dict[Any, Any], old_key: str, new_key: str) -> None:
|
283
302
|
"""
|
284
|
-
|
303
|
+
Changes a key in a dictionary to a new key.
|
285
304
|
|
286
305
|
Args:
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
The processed string or list of strings, or False on failure.
|
306
|
+
dict_ (Dict[Any, Any]): The dictionary to change the key in.
|
307
|
+
old_key (str): The old key to be changed.
|
308
|
+
new_key (str): The new key to change to.
|
291
309
|
"""
|
292
|
-
|
293
|
-
|
294
|
-
except:
|
295
|
-
return False
|
310
|
+
if old_key in dict_:
|
311
|
+
dict_[new_key] = dict_.pop(old_key)
|
296
312
|
|
297
|
-
def as_dict(input_):
|
313
|
+
def as_dict(input_: Any) -> Dict[Any, Any]:
|
298
314
|
"""
|
299
315
|
Converts a JSON string or a dictionary to a dictionary.
|
300
316
|
|
@@ -316,3 +332,23 @@ def as_dict(input_):
|
|
316
332
|
return input_
|
317
333
|
else:
|
318
334
|
raise f"Could not convert input to dict: {input_}"
|
335
|
+
|
336
|
+
def is_schema(dict_: Dict, schema: Dict):
|
337
|
+
"""
|
338
|
+
Checks if a dictionary matches a given schema.
|
339
|
+
|
340
|
+
Args:
|
341
|
+
dict_: The dictionary to check.
|
342
|
+
schema: The schema to validate against.
|
343
|
+
|
344
|
+
Returns:
|
345
|
+
True if the dictionary matches the schema, False otherwise.
|
346
|
+
"""
|
347
|
+
for key, expected_type in schema.items():
|
348
|
+
if not isinstance(dict_[key], expected_type):
|
349
|
+
return False
|
350
|
+
return True
|
351
|
+
|
352
|
+
def timestamp_to_datetime(timestamp):
|
353
|
+
return datetime.fromtimestamp(timestamp)
|
354
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
from bs4 import BeautifulSoup
|
2
|
+
import requests
|
3
|
+
|
4
|
+
def get_url_response(url: str, timeout: tuple = (1, 1), **kwargs) -> requests.Response:
|
5
|
+
"""
|
6
|
+
Sends a GET request to a URL and returns the response.
|
7
|
+
|
8
|
+
Args:
|
9
|
+
url (str): The URL to send the GET request to.
|
10
|
+
timeout (tuple): A tuple specifying the connection and read timeouts in seconds.
|
11
|
+
Defaults to (1, 1).
|
12
|
+
**kwargs: Additional keyword arguments to be passed to the requests.get() function.
|
13
|
+
|
14
|
+
Returns:
|
15
|
+
requests.Response: A Response object containing the server's response to the GET request.
|
16
|
+
|
17
|
+
Raises:
|
18
|
+
TimeoutError: If a timeout occurs while requesting or reading the response.
|
19
|
+
Exception: If an error other than a timeout occurs during the request.
|
20
|
+
"""
|
21
|
+
try:
|
22
|
+
response = requests.get(url, timeout=timeout, **kwargs)
|
23
|
+
response.raise_for_status()
|
24
|
+
return response
|
25
|
+
except requests.exceptions.ConnectTimeout:
|
26
|
+
raise TimeoutError(f"Timeout: requesting >{timeout[0]} seconds.")
|
27
|
+
except requests.exceptions.ReadTimeout:
|
28
|
+
raise TimeoutError(f"Timeout: reading >{timeout[1]} seconds.")
|
29
|
+
except Exception as e:
|
30
|
+
raise e
|
31
|
+
|
32
|
+
def get_url_content(url: str) -> str:
|
33
|
+
"""
|
34
|
+
Retrieve and parse the content from a given URL.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
url (str): The URL to fetch and parse.
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
str: The text content extracted from the URL.
|
41
|
+
|
42
|
+
Raises:
|
43
|
+
ValueError: If there is an issue during content retrieval or parsing.
|
44
|
+
"""
|
45
|
+
try:
|
46
|
+
response = requests.get(url)
|
47
|
+
response.raise_for_status()
|
48
|
+
|
49
|
+
soup = BeautifulSoup(response.text, 'html.parser')
|
50
|
+
|
51
|
+
text_content = ' '.join([p.get_text() for p in soup.find_all('p')])
|
52
|
+
return text_content
|
53
|
+
except Exception as e:
|
54
|
+
raise f"Error fetching content for {url}: {e}"
|
55
|
+
|
lionagi/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.0.
|
1
|
+
__version__ = "0.0.204"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lionagi
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.204
|
4
4
|
Summary: Towards automated general intelligence.
|
5
5
|
Author: HaiyangLi
|
6
6
|
Author-email: Haiyang Li <ocean@lionagi.ai>
|
@@ -217,8 +217,11 @@ Description-Content-Type: text/markdown
|
|
217
217
|
License-File: LICENSE
|
218
218
|
Requires-Dist: aiohttp >=3.9.0
|
219
219
|
Requires-Dist: python-dotenv ==1.0.0
|
220
|
-
Requires-Dist: tiktoken
|
221
|
-
Requires-Dist:
|
220
|
+
Requires-Dist: tiktoken >=0.5.1
|
221
|
+
Requires-Dist: pydantic >=2.6.0
|
222
|
+
Requires-Dist: cryptography >=42.0.0
|
223
|
+
Requires-Dist: aiocache ==0.12.2
|
224
|
+
Requires-Dist: pandas >=2.1.0
|
222
225
|
|
223
226
|
   
|
224
227
|
|
@@ -269,7 +272,6 @@ LionAGI is designed to be `asynchronous` only, please check python official docu
|
|
269
272
|
The following example shows how to use LionAGI's `Session` object to interact with `gpt-4` model:
|
270
273
|
|
271
274
|
```python
|
272
|
-
import lionagi as li
|
273
275
|
|
274
276
|
# define system messages, context and user instruction
|
275
277
|
system = "You are a helpful assistant designed to perform calculations."
|
@@ -279,8 +281,10 @@ context = {"x": 10, "y": 5}
|
|
279
281
|
|
280
282
|
```python
|
281
283
|
# in interactive environment (.ipynb for example)
|
284
|
+
import lionagi as li
|
285
|
+
|
282
286
|
calculator = li.Session(system=system)
|
283
|
-
result = await calculator.
|
287
|
+
result = await calculator.chat(
|
284
288
|
instruction=instruction, context=context, model="gpt-4-1106-preview"
|
285
289
|
)
|
286
290
|
|
@@ -294,9 +298,11 @@ from dotenv import load_dotenv
|
|
294
298
|
|
295
299
|
load_dotenv()
|
296
300
|
|
301
|
+
import lionagi as li
|
302
|
+
|
297
303
|
async def main():
|
298
304
|
calculator = li.Session(system=system)
|
299
|
-
result = await calculator.
|
305
|
+
result = await calculator.chat(
|
300
306
|
instruction=instruction, context=context, model="gpt-4-1106-preview"
|
301
307
|
)
|
302
308
|
print(f"Calculation Result: {result}")
|
@@ -325,8 +331,6 @@ When referencing LionAGI in your projects or research, please cite:
|
|
325
331
|
}
|
326
332
|
```
|
327
333
|
|
328
|
-
## Star History
|
329
|
-

|
330
334
|
|
331
335
|
### Requirements
|
332
336
|
Python 3.9 or higher.
|