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.
Files changed (53) hide show
  1. lionagi/_services/anthropic.py +79 -1
  2. lionagi/_services/base_service.py +1 -1
  3. lionagi/_services/services.py +61 -25
  4. lionagi/_services/transformers.py +46 -0
  5. lionagi/agents/__init__.py +0 -0
  6. lionagi/configs/oai_configs.py +1 -1
  7. lionagi/configs/openrouter_configs.py +1 -1
  8. lionagi/core/__init__.py +3 -7
  9. lionagi/core/branch/__init__.py +0 -0
  10. lionagi/core/branch/branch.py +589 -0
  11. lionagi/core/branch/branch_manager.py +139 -0
  12. lionagi/core/branch/cluster.py +1 -0
  13. lionagi/core/branch/conversation.py +484 -0
  14. lionagi/core/core_util.py +59 -0
  15. lionagi/core/flow/__init__.py +0 -0
  16. lionagi/core/flow/flow.py +19 -0
  17. lionagi/core/instruction_set/__init__.py +0 -0
  18. lionagi/core/instruction_set/instruction_set.py +343 -0
  19. lionagi/core/messages/__init__.py +0 -0
  20. lionagi/core/messages/messages.py +176 -0
  21. lionagi/core/sessions/__init__.py +0 -0
  22. lionagi/core/sessions/session.py +428 -0
  23. lionagi/models/__init__.py +0 -0
  24. lionagi/models/base_model.py +0 -0
  25. lionagi/models/imodel.py +53 -0
  26. lionagi/schema/data_logger.py +75 -155
  27. lionagi/tests/test_utils/test_call_util.py +658 -657
  28. lionagi/tools/tool_manager.py +121 -188
  29. lionagi/utils/__init__.py +5 -10
  30. lionagi/utils/call_util.py +667 -585
  31. lionagi/utils/io_util.py +3 -0
  32. lionagi/utils/nested_util.py +17 -211
  33. lionagi/utils/pd_util.py +57 -0
  34. lionagi/utils/sys_util.py +220 -184
  35. lionagi/utils/url_util.py +55 -0
  36. lionagi/version.py +1 -1
  37. {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/METADATA +12 -8
  38. {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/RECORD +47 -32
  39. lionagi/core/branch.py +0 -193
  40. lionagi/core/conversation.py +0 -341
  41. lionagi/core/flow.py +0 -8
  42. lionagi/core/instruction_set.py +0 -150
  43. lionagi/core/messages.py +0 -243
  44. lionagi/core/sessions.py +0 -474
  45. /lionagi/{tools → agents}/planner.py +0 -0
  46. /lionagi/{tools → agents}/prompter.py +0 -0
  47. /lionagi/{tools → agents}/scorer.py +0 -0
  48. /lionagi/{tools → agents}/summarizer.py +0 -0
  49. /lionagi/{tools → agents}/validator.py +0 -0
  50. /lionagi/core/{flow_util.py → flow/flow_util.py} +0 -0
  51. {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/LICENSE +0 -0
  52. {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/WHEEL +0 -0
  53. {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
- import copy
6
+
5
7
  import json
6
- from pathlib import Path
7
- from datetime import datetime
8
- from dateutil import parser
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 a file-safe string format.
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 in a file-safe string format.
19
+ str: The current timestamp.
18
20
 
19
21
  Examples:
20
- >>> get_timestamp() # Doctest: +ELLIPSIS
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 object a specified number of times.
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 deep copies to create.
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 'input' or a list of deep copies if 'n' > 1.
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
- >>> sample_dict = {'key': 'value'}
41
- >>> create_copy(sample_dict, 2)
42
- [{'key': 'value'}, {'key': 'value'}]
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(dir: str, filename: str, timestamp: bool = True, dir_exist_ok: bool = True, time_prefix=False) -> str:
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 by optionally appending a timestamp to the filename.
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 is to be located.
54
- filename: The name of the file.
55
- timestamp: If True, appends a timestamp to the filename. Defaults to True.
56
- dir_exist_ok: If True, creates the directory if it doesn't exist. Defaults to True.
57
- time_prefix: If True, the timestamp is added as a prefix; otherwise, it's appended. Defaults to False.
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 to the file.
67
+ str: The full path of the file with the optional timestamp.
61
68
 
62
69
  Examples:
63
- >>> create_path('/tmp/', 'log.txt', timestamp=False)
64
- '/tmp/log.txt'
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
- dir = dir + '/' if str(dir)[-1] != '/' else dir
68
- filename, ext = filename.split('.')
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
- return f"{dir}{filename}"
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: Path) -> tuple:
85
+ def split_path(path: str) -> tuple:
78
86
  """
79
- Splits a given path into folder name and file name.
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 folder name and file name.
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.parent.name
88
- file_name = path.name
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 get_bins(input: List[str], upper: int = 7500) -> List[List[int]]:
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
- Get index of elements in a list based on their consecutive cumulative sum of length.
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: List of items to be binned.
97
- upper: Upper threshold for the cumulative sum of the length of items in a bin.
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
- List of lists, where each inner list contains the indices of the items that form a bin.
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
- >>> items = ['apple', 'a', 'b', 'banana', 'cheery', 'c', 'd', 'e']
104
- >>> upper = 10
105
- >>> get_bins(items, upper)
106
- [[0, 1, 2], [3], [4, 5, 6, 7]]
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
- bin = []
111
-
164
+ current_bin = []
112
165
  for idx, item in enumerate(input):
113
166
 
114
167
  if current + len(item) < upper:
115
- bin.append(idx)
168
+ current_bin.append(idx)
116
169
  current += len(item)
117
-
118
- elif current + len(item) >= upper:
119
- bins.append(bin)
120
- bin = [idx]
170
+
171
+ else:
172
+ bins.append(current_bin)
173
+ current_bin = [idx]
121
174
  current = len(item)
122
-
123
- if idx == len(input) - 1 and len(bin) > 0:
124
- bins.append(bin)
125
-
175
+
176
+ if current_bin:
177
+ bins.append(current_bin)
178
+
126
179
  return bins
127
180
 
128
- def change_dict_key(dict_, old_key, new_key):
181
+ def create_id(n: int = 32) -> str:
129
182
  """
130
- Changes a key in a dictionary to a new key.
183
+ Creates a unique identifier using a combination of the current time and random bytes.
131
184
 
132
185
  Args:
133
- dict_: The dictionary to change the key in.
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
- A unique identifier.
189
+ str: The generated unique identifier.
148
190
 
149
191
  Examples:
150
- >>> create_id() # Doctest: +ELLIPSIS
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 str_to_datetime(datetime_str: str, fmt: Optional[str] = None) -> datetime:
201
+ def directory_cleaner(directory: str) -> None:
158
202
  """
159
- Convert a string representation of a date and time to a datetime object.
203
+ Deletes all files within a given directory.
160
204
 
161
205
  Args:
162
- datetime_str: A string representing a date and time.
163
- fmt: An optional format string.
206
+ directory (str): The path of the directory to clean.
164
207
 
165
- Returns:
166
- A datetime object corresponding to the given string.
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
- >>> str_to_datetime("2023-01-01 12:00:00")
170
- datetime.datetime(2023, 1, 1, 12, 0)
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 fmt:
175
- return datetime.strptime(datetime_str, fmt)
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
- def str_to_num(input_: str,
180
- upper_bound: Optional[Union[int, float]] = None,
181
- lower_bound: Optional[Union[int, float]] = None,
182
- num_type: Type[Union[int, float]] = int,
183
- precision: Optional[int] = None) -> Union[int, float]:
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
- Convert the first numeric value in the input string to the specified number type.
231
+ Strips and converts a given input to lower case.
186
232
 
187
233
  Args:
188
- input_: The input string containing the numeric value.
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 numeric value converted to the specified type.
237
+ str: The processed string in lower case.
196
238
 
197
239
  Raises:
198
- ValueError: If no numeric values are found or if the number type is invalid.
240
+ Exception: If the input cannot be converted to a string.
199
241
 
200
242
  Examples:
201
- >>> str_to_num('Value is -123.456', num_type=float, precision=2)
202
- -123.46
203
- >>> str_to_num('Value is 100', upper_bound=99)
204
- ValueError: Number 100 is greater than the upper bound of 99.
243
+ >>> strip_lower(" Hello WORLD ")
244
+ 'hello world'
245
+ >>> strip_lower(123)
246
+ '123'
205
247
  """
206
- numbers = re.findall(r'-?\d+\.?\d*', input_)
207
- if not numbers:
208
- raise ValueError(f"No numeric values found in the string: {input_}")
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 find_depth(nested_obj, depth_strategy='uniform', ignore_non_iterable=False):
253
+ def _extract_first_number(inputstr: str) -> str:
226
254
  """
227
- Calculates the maximum depth of a nested list, dictionary, or a combination of both.
255
+ Extracts the first number from a given string.
228
256
 
229
257
  Args:
230
- nested_obj: The nested object to find the depth of.
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 maximum depth of the nested structure.
261
+ str: The first number found in the string, returned as a string.
262
+ Returns None if no number is found.
236
263
 
237
- Raises:
238
- ValueError: If an unsupported depth strategy is specified.
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
- def _uniform_depth(obj, current_depth=0):
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
- Checks if a dictionary matches a given schema.
275
+ Converts a string representation of a number to a specified numeric type.
269
276
 
270
277
  Args:
271
- dict_: The dictionary to check.
272
- schema: The schema to validate against.
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
- True if the dictionary matches the schema, False otherwise.
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
- for key, expected_type in schema.items():
278
- if not isinstance(dict_[key], expected_type):
279
- return False
280
- return True
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 strip_lower(input_: Union[str, List[str]]) -> Union[str, List[str]]:
301
+ def change_dict_key(dict_: Dict[Any, Any], old_key: str, new_key: str) -> None:
283
302
  """
284
- Strips and converts a string or each string in a list to lowercase.
303
+ Changes a key in a dictionary to a new key.
285
304
 
286
305
  Args:
287
- input_: A string or list of strings to process.
288
-
289
- Returns:
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
- try:
293
- return str(input_).strip().lower()
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.201"
1
+ __version__ = "0.0.204"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lionagi
3
- Version: 0.0.201
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 ==0.5.1
221
- Requires-Dist: httpx ==0.25.1
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.initiate(
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.initiate(
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.