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.
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.