lionagi 0.0.201__py3-none-any.whl → 0.0.204__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
![PyPI - Version](https://img.shields.io/pypi/v/lionagi?labelColor=233476aa&color=231fc935) ![Read the Docs](https://img.shields.io/readthedocs/lionagi) ![PyPI - License](https://img.shields.io/pypi/l/lionagi?color=231fc935) ![PyPI - Downloads](https://img.shields.io/pypi/dm/lionagi?color=blue)
|
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
|
-
![Star History Chart](https://api.star-history.com/svg?repos=lion-agi/lionagi&type=Date)
|
330
334
|
|
331
335
|
### Requirements
|
332
336
|
Python 3.9 or higher.
|