lionagi 0.0.115__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/__init__.py +1 -2
- lionagi/_services/__init__.py +5 -0
- lionagi/_services/anthropic.py +79 -0
- lionagi/_services/base_service.py +414 -0
- lionagi/_services/oai.py +98 -0
- lionagi/_services/openrouter.py +44 -0
- lionagi/_services/services.py +91 -0
- lionagi/_services/transformers.py +46 -0
- lionagi/bridge/langchain.py +26 -16
- lionagi/bridge/llama_index.py +50 -20
- lionagi/configs/oai_configs.py +2 -14
- lionagi/configs/openrouter_configs.py +2 -2
- lionagi/core/__init__.py +7 -8
- lionagi/core/branch/branch.py +589 -0
- lionagi/core/branch/branch_manager.py +139 -0
- lionagi/core/branch/conversation.py +484 -0
- lionagi/core/core_util.py +59 -0
- lionagi/core/flow/flow.py +19 -0
- lionagi/core/flow/flow_util.py +62 -0
- lionagi/core/instruction_set/__init__.py +0 -5
- lionagi/core/instruction_set/instruction_set.py +343 -0
- lionagi/core/messages/messages.py +176 -0
- lionagi/core/sessions/__init__.py +0 -5
- lionagi/core/sessions/session.py +428 -0
- lionagi/loaders/chunker.py +51 -47
- lionagi/loaders/load_util.py +2 -2
- lionagi/loaders/reader.py +45 -39
- lionagi/models/imodel.py +53 -0
- lionagi/schema/async_queue.py +158 -0
- lionagi/schema/base_node.py +318 -147
- lionagi/schema/base_tool.py +31 -1
- lionagi/schema/data_logger.py +74 -38
- lionagi/schema/data_node.py +57 -6
- lionagi/structures/graph.py +132 -10
- lionagi/structures/relationship.py +58 -20
- lionagi/structures/structure.py +36 -25
- lionagi/tests/test_utils/test_api_util.py +219 -0
- lionagi/tests/test_utils/test_call_util.py +785 -0
- lionagi/tests/test_utils/test_encrypt_util.py +323 -0
- lionagi/tests/test_utils/test_io_util.py +238 -0
- lionagi/tests/test_utils/test_nested_util.py +338 -0
- lionagi/tests/test_utils/test_sys_util.py +358 -0
- lionagi/tools/tool_manager.py +186 -0
- lionagi/tools/tool_util.py +266 -3
- lionagi/utils/__init__.py +21 -61
- lionagi/utils/api_util.py +359 -71
- lionagi/utils/call_util.py +839 -264
- lionagi/utils/encrypt_util.py +283 -16
- lionagi/utils/io_util.py +178 -93
- lionagi/utils/nested_util.py +672 -0
- lionagi/utils/pd_util.py +57 -0
- lionagi/utils/sys_util.py +284 -156
- lionagi/utils/url_util.py +55 -0
- lionagi/version.py +1 -1
- {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/METADATA +21 -17
- lionagi-0.0.204.dist-info/RECORD +106 -0
- lionagi/core/conversations/__init__.py +0 -5
- lionagi/core/conversations/conversation.py +0 -107
- lionagi/core/flows/__init__.py +0 -8
- lionagi/core/flows/flow.py +0 -8
- lionagi/core/flows/flow_util.py +0 -62
- lionagi/core/instruction_set/instruction_sets.py +0 -7
- lionagi/core/sessions/sessions.py +0 -185
- lionagi/endpoints/__init__.py +0 -5
- lionagi/endpoints/audio.py +0 -17
- lionagi/endpoints/chatcompletion.py +0 -54
- lionagi/messages/__init__.py +0 -11
- lionagi/messages/instruction.py +0 -15
- lionagi/messages/message.py +0 -110
- lionagi/messages/response.py +0 -33
- lionagi/messages/system.py +0 -12
- lionagi/objs/__init__.py +0 -11
- lionagi/objs/abc_objs.py +0 -39
- lionagi/objs/async_queue.py +0 -135
- lionagi/objs/messenger.py +0 -85
- lionagi/objs/tool_manager.py +0 -253
- lionagi/services/__init__.py +0 -11
- lionagi/services/base_api_service.py +0 -230
- lionagi/services/oai.py +0 -34
- lionagi/services/openrouter.py +0 -31
- lionagi/tests/test_api_util.py +0 -46
- lionagi/tests/test_call_util.py +0 -115
- lionagi/tests/test_convert_util.py +0 -202
- lionagi/tests/test_encrypt_util.py +0 -33
- lionagi/tests/test_flat_util.py +0 -426
- lionagi/tests/test_sys_util.py +0 -0
- lionagi/utils/convert_util.py +0 -229
- lionagi/utils/flat_util.py +0 -599
- lionagi-0.0.115.dist-info/RECORD +0 -110
- /lionagi/{services → _services}/anyscale.py +0 -0
- /lionagi/{services → _services}/azure.py +0 -0
- /lionagi/{services → _services}/bedrock.py +0 -0
- /lionagi/{services → _services}/everlyai.py +0 -0
- /lionagi/{services → _services}/gemini.py +0 -0
- /lionagi/{services → _services}/gpt4all.py +0 -0
- /lionagi/{services → _services}/huggingface.py +0 -0
- /lionagi/{services → _services}/litellm.py +0 -0
- /lionagi/{services → _services}/localai.py +0 -0
- /lionagi/{services → _services}/mistralai.py +0 -0
- /lionagi/{services → _services}/ollama.py +0 -0
- /lionagi/{services → _services}/openllm.py +0 -0
- /lionagi/{services → _services}/perplexity.py +0 -0
- /lionagi/{services → _services}/predibase.py +0 -0
- /lionagi/{services → _services}/rungpt.py +0 -0
- /lionagi/{services → _services}/vllm.py +0 -0
- /lionagi/{services → _services}/xinference.py +0 -0
- /lionagi/{endpoints/assistants.py → agents/__init__.py} +0 -0
- /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/{endpoints/embeddings.py → core/branch/__init__.py} +0 -0
- /lionagi/{services/anthropic.py → core/branch/cluster.py} +0 -0
- /lionagi/{endpoints/finetune.py → core/flow/__init__.py} +0 -0
- /lionagi/{endpoints/image.py → core/messages/__init__.py} +0 -0
- /lionagi/{endpoints/moderation.py → models/__init__.py} +0 -0
- /lionagi/{endpoints/vision.py → models/base_model.py} +0 -0
- /lionagi/{objs → schema}/status_tracker.py +0 -0
- /lionagi/tests/{test_io_util.py → test_utils/__init__.py} +0 -0
- {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/LICENSE +0 -0
- {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/WHEEL +0 -0
- {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/top_level.txt +0 -0
lionagi/utils/pd_util.py
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
from typing import List, Dict
|
2
|
+
import pandas as pd
|
3
|
+
from ..schema.data_node import DataNode
|
4
|
+
from .sys_util import timestamp_to_datetime
|
5
|
+
|
6
|
+
def to_pd_df(items: List[Dict], how: str = 'all') -> pd.DataFrame:
|
7
|
+
"""
|
8
|
+
Converts a list of dictionaries to a pandas DataFrame, dropping NA values.
|
9
|
+
|
10
|
+
Args:
|
11
|
+
items (List[Dict]): A list of dictionaries to be converted to a DataFrame.
|
12
|
+
how (str): How to handle NA values. Options are 'all' to drop rows with all NA values,
|
13
|
+
'any' to drop rows with any NA values, or 'none' to keep all rows.
|
14
|
+
|
15
|
+
Returns:
|
16
|
+
pd.DataFrame: A pandas DataFrame containing the data from the input list of dictionaries.
|
17
|
+
"""
|
18
|
+
df = pd.DataFrame(items).dropna(how=how)
|
19
|
+
df.reset_index(drop=True, inplace=True)
|
20
|
+
return df
|
21
|
+
|
22
|
+
def pd_row_to_node(row: pd.Series):
|
23
|
+
"""
|
24
|
+
Converts a pandas Series row to a DataNode object with structured data.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
row (pd.Series): A pandas Series containing row data to be converted.
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
DataNode: A DataNode object containing structured data from the input pandas Series.
|
31
|
+
"""
|
32
|
+
dict_ = row.to_dict()
|
33
|
+
dict_['datetime'] = str(timestamp_to_datetime(dict_['datetime']))
|
34
|
+
dict_['content'] = {'headline': dict_.pop('headline'), 'summary': dict_.pop('summary')}
|
35
|
+
dict_['metadata'] = {'datetime': dict_.pop('datetime'), 'url': dict_.pop('url'), 'id': dict_.pop('id')}
|
36
|
+
return DataNode.from_dict(dict_)
|
37
|
+
|
38
|
+
def expand_df_datetime(df: pd.DataFrame) -> pd.DataFrame:
|
39
|
+
"""
|
40
|
+
Expands a pandas DataFrame with a datetime column into separate year, month, and day columns.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
df (pd.DataFrame): The pandas DataFrame containing a 'datetime' column to be expanded.
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
pd.DataFrame: A pandas DataFrame with 'year', 'month', and 'day' columns.
|
47
|
+
"""
|
48
|
+
df_expanded = df.copy()
|
49
|
+
if df_expanded['datetime'].dtype == int:
|
50
|
+
df_expanded['datetime'] = df_expanded['datetime'].apply(lambda x: timestamp_to_datetime(x))
|
51
|
+
|
52
|
+
df_expanded.insert(0, 'year', df_expanded['datetime'].dt.year)
|
53
|
+
df_expanded.insert(1, 'month', df_expanded['datetime'].dt.month)
|
54
|
+
df_expanded.insert(2, 'day', df_expanded['datetime'].dt.day)
|
55
|
+
df_expanded.drop('datetime', axis=1, inplace=True)
|
56
|
+
|
57
|
+
return df_expanded
|
lionagi/utils/sys_util.py
CHANGED
@@ -1,226 +1,354 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
import os
|
2
|
+
import copy
|
3
|
+
from datetime import datetime
|
4
|
+
import hashlib
|
5
|
+
import re
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
You may obtain a copy of the License at
|
7
|
+
import json
|
8
|
+
import logging
|
7
9
|
|
8
|
-
|
10
|
+
from typing import Any, List, Dict, Union
|
9
11
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
See the License for the specific language governing permissions and
|
14
|
-
limitations under the License.
|
15
|
-
"""
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
13
|
+
def get_timestamp() -> str:
|
14
|
+
"""
|
15
|
+
Generates a current timestamp in ISO format with colons and periods replaced by
|
16
|
+
underscores.
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
str: The current timestamp.
|
24
20
|
|
25
|
-
|
21
|
+
Examples:
|
22
|
+
>>> isinstance(get_timestamp(), str)
|
23
|
+
True
|
26
24
|
"""
|
27
|
-
|
25
|
+
return datetime.now().isoformat().replace(":", "_").replace(".", "_")
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
def create_copy(input: Any, n: int = 1) -> Any:
|
28
|
+
"""
|
29
|
+
Creates a deep copy of the given input. If 'n' is greater than 1, returns a
|
30
|
+
list of deep copies.
|
32
31
|
|
33
|
-
|
32
|
+
Args:
|
34
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
|
+
Any: A deep copy of the input, or a list of deep copies.
|
37
38
|
|
38
39
|
Raises:
|
39
40
|
ValueError: If 'n' is not a positive integer.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
>>> make_copy(sample_dict, 2)
|
47
|
-
[{'key': 'value'}, {'key': 'value'}]
|
41
|
+
|
42
|
+
Examples:
|
43
|
+
>>> create_copy([1, 2, 3], 2)
|
44
|
+
[[1, 2, 3], [1, 2, 3]]
|
45
|
+
>>> create_copy("Hello")
|
46
|
+
'Hello'
|
48
47
|
"""
|
49
48
|
if not isinstance(n, int) or n < 1:
|
50
49
|
raise ValueError(f"'n' must be a positive integer: {n}")
|
51
50
|
return copy.deepcopy(input) if n == 1 else [copy.deepcopy(input) for _ in range(n)]
|
52
51
|
|
53
|
-
def
|
52
|
+
def create_path(
|
53
|
+
dir: str, filename: str, timestamp: bool = True, dir_exist_ok: bool = True,
|
54
|
+
time_prefix: bool = False
|
55
|
+
) -> str:
|
54
56
|
"""
|
55
|
-
|
57
|
+
Creates a file path with an optional timestamp, ensuring the directory exists.
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
Args:
|
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.
|
60
65
|
|
61
66
|
Returns:
|
62
|
-
str:
|
67
|
+
str: The full path of the file with the optional timestamp.
|
63
68
|
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
Examples:
|
70
|
+
>>> create_path("/tmp", "log.txt", timestamp=False)
|
71
|
+
'/tmp/log.txt'
|
72
|
+
>>> isinstance(create_path("/tmp", "report", time_prefix=True), str)
|
73
|
+
True
|
67
74
|
"""
|
68
|
-
|
69
|
-
|
70
|
-
|
75
|
+
dir = dir + '/' if not dir.endswith('/') else dir
|
76
|
+
if '.' in filename:
|
77
|
+
name, ext = filename.rsplit('.', 1)
|
78
|
+
else:
|
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}"
|
71
84
|
|
72
|
-
def
|
85
|
+
def split_path(path: str) -> tuple:
|
73
86
|
"""
|
74
|
-
|
87
|
+
Splits a file path into its directory name and file name.
|
75
88
|
|
76
|
-
|
77
|
-
|
78
|
-
with underscores.
|
89
|
+
Args:
|
90
|
+
path (str): The file path to split.
|
79
91
|
|
80
92
|
Returns:
|
81
|
-
|
93
|
+
tuple: A tuple containing the directory name and file name.
|
82
94
|
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
101
|
+
folder_name = os.path.dirname(path)
|
102
|
+
file_name = os.path.basename(path)
|
103
|
+
return (folder_name, file_name)
|
88
104
|
|
89
|
-
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:
|
90
109
|
"""
|
91
|
-
|
92
|
-
|
93
|
-
This function constructs a file path by combining a directory, an optional timestamp,
|
94
|
-
and a filename. It also ensures the existence of the directory.
|
95
|
-
|
96
|
-
Parameters:
|
97
|
-
dir (str): The directory in which the file is to be located.
|
98
|
-
|
99
|
-
filename (str): The name of the file.
|
100
|
-
|
101
|
-
timestamp (bool, optional): If True, appends a timestamp to the filename. Defaults to True.
|
110
|
+
Converts the first number in a string to a specified numeric type and checks if it
|
111
|
+
falls within specified bounds.
|
102
112
|
|
103
|
-
|
104
|
-
|
105
|
-
|
113
|
+
Args:
|
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.
|
106
119
|
|
107
120
|
Returns:
|
108
|
-
|
121
|
+
Any: The converted number in the specified type.
|
109
122
|
|
110
|
-
|
111
|
-
|
112
|
-
|
123
|
+
Raises:
|
124
|
+
ValueError: If no numeric value is found, or the number is outside the specified bounds.
|
125
|
+
|
126
|
+
Examples:
|
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.
|
113
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}")
|
114
135
|
|
115
|
-
|
116
|
-
filename, ext = filename.split('.')
|
117
|
-
os.makedirs(dir, exist_ok=dir_exist_ok)
|
118
|
-
|
119
|
-
if timestamp:
|
120
|
-
timestamp = get_timestamp()
|
121
|
-
return f"{dir}{timestamp}_{filename}.{ext}" if time_prefix else f"{dir}{filename}_{timestamp}.{ext}"
|
122
|
-
else:
|
123
|
-
return f"{dir}{filename}"
|
136
|
+
number = _convert_to_num(number_str, num_type, precision)
|
124
137
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
129
144
|
|
130
|
-
def get_bins(input: List[str], upper: int
|
145
|
+
def get_bins(input: List[str], upper: int) -> List[List[int]]:
|
131
146
|
"""
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
input (List[str]):
|
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.
|
137
153
|
|
138
|
-
upper (int, optional): Upper threshold for the cumulative sum of the length of items in a bin. Default is 7500.
|
139
|
-
|
140
154
|
Returns:
|
141
|
-
List[List[int]]:
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
[[0, 1, 2], [3], [4, 5, 6, 7]]
|
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]]
|
148
161
|
"""
|
149
162
|
current = 0
|
150
163
|
bins = []
|
151
|
-
|
152
|
-
|
164
|
+
current_bin = []
|
153
165
|
for idx, item in enumerate(input):
|
154
166
|
|
155
167
|
if current + len(item) < upper:
|
156
|
-
|
168
|
+
current_bin.append(idx)
|
157
169
|
current += len(item)
|
158
|
-
|
159
|
-
|
160
|
-
bins.append(
|
161
|
-
|
170
|
+
|
171
|
+
else:
|
172
|
+
bins.append(current_bin)
|
173
|
+
current_bin = [idx]
|
162
174
|
current = len(item)
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
175
|
+
|
176
|
+
if current_bin:
|
177
|
+
bins.append(current_bin)
|
178
|
+
|
167
179
|
return bins
|
168
180
|
|
169
|
-
def
|
170
|
-
|
181
|
+
def create_id(n: int = 32) -> str:
|
182
|
+
"""
|
183
|
+
Creates a unique identifier using a combination of the current time and random bytes.
|
171
184
|
|
172
|
-
|
173
|
-
|
174
|
-
try:
|
175
|
-
timestamp = int(timestamp)
|
176
|
-
except:
|
177
|
-
return timestamp
|
178
|
-
return datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
|
185
|
+
Args:
|
186
|
+
n (int, optional): The length of the identifier. Defaults to 32.
|
179
187
|
|
180
|
-
|
181
|
-
|
182
|
-
if not isinstance(dict_[key], expected_type):
|
183
|
-
return False
|
184
|
-
return True
|
188
|
+
Returns:
|
189
|
+
str: The generated unique identifier.
|
185
190
|
|
186
|
-
|
191
|
+
Examples:
|
192
|
+
>>> len(create_id())
|
193
|
+
32
|
194
|
+
>>> len(create_id(16))
|
195
|
+
16
|
196
|
+
"""
|
197
|
+
current_time = datetime.now().isoformat().encode('utf-8')
|
198
|
+
random_bytes = os.urandom(32)
|
199
|
+
return hashlib.sha256(current_time + random_bytes).hexdigest()[:n]
|
200
|
+
|
201
|
+
def directory_cleaner(directory: str) -> None:
|
202
|
+
"""
|
203
|
+
Deletes all files within a given directory.
|
204
|
+
|
205
|
+
Args:
|
206
|
+
directory (str): The path of the directory to clean.
|
207
|
+
|
208
|
+
Raises:
|
209
|
+
FileNotFoundError: If the specified directory does not exist.
|
210
|
+
Exception: If a file in the directory cannot be deleted.
|
211
|
+
|
212
|
+
Examples:
|
213
|
+
>>> directory_cleaner("/path/to/nonexistent/directory")
|
214
|
+
FileNotFoundError: The specified directory does not exist.
|
187
215
|
"""
|
188
|
-
|
216
|
+
if not os.path.exists(directory):
|
217
|
+
raise FileNotFoundError("The specified directory does not exist.")
|
218
|
+
|
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:
|
230
|
+
"""
|
231
|
+
Strips and converts a given input to lower case.
|
189
232
|
|
190
|
-
|
191
|
-
|
192
|
-
algorithm (str): The hashing algorithm to use (e.g., 'sha256', 'md5').
|
233
|
+
Args:
|
234
|
+
input (Any): The input to be processed.
|
193
235
|
|
194
236
|
Returns:
|
195
|
-
str: The
|
237
|
+
str: The processed string in lower case.
|
238
|
+
|
239
|
+
Raises:
|
240
|
+
Exception: If the input cannot be converted to a string.
|
241
|
+
|
242
|
+
Examples:
|
243
|
+
>>> strip_lower(" Hello WORLD ")
|
244
|
+
'hello world'
|
245
|
+
>>> strip_lower(123)
|
246
|
+
'123'
|
196
247
|
"""
|
197
|
-
|
198
|
-
|
199
|
-
|
248
|
+
try:
|
249
|
+
return str(input).strip().lower()
|
250
|
+
except:
|
251
|
+
return False
|
200
252
|
|
253
|
+
def _extract_first_number(inputstr: str) -> str:
|
254
|
+
"""
|
255
|
+
Extracts the first number from a given string.
|
201
256
|
|
257
|
+
Args:
|
258
|
+
inputstr (str): The string from which the number will be extracted.
|
202
259
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
260
|
+
Returns:
|
261
|
+
str: The first number found in the string, returned as a string.
|
262
|
+
Returns None if no number is found.
|
263
|
+
|
264
|
+
Examples:
|
265
|
+
>>> extract_first_number("The 2 little pigs")
|
266
|
+
'2'
|
267
|
+
>>> extract_first_number("No numbers")
|
268
|
+
None
|
269
|
+
"""
|
270
|
+
numbers = re.findall(r'-?\d+\.?\d*', inputstr)
|
271
|
+
return numbers[0] if numbers else None
|
208
272
|
|
209
|
-
|
210
|
-
# credit to OpenAI for the following functions
|
211
|
-
def task_id_generator() -> Generator[int, None, None]:
|
273
|
+
def _convert_to_num(number_str: str, num_type: type = int, precision: int = None) -> Any:
|
212
274
|
"""
|
213
|
-
|
275
|
+
Converts a string representation of a number to a specified numeric type.
|
276
|
+
|
277
|
+
Args:
|
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.
|
281
|
+
|
282
|
+
Returns:
|
283
|
+
Any: The converted number in the specified type.
|
214
284
|
|
215
|
-
|
216
|
-
|
285
|
+
Raises:
|
286
|
+
ValueError: If an invalid number type is provided.
|
217
287
|
|
218
288
|
Examples:
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
289
|
+
>>> convert_to_num("3.142", float, 2)
|
290
|
+
3.14
|
291
|
+
>>> convert_to_num("100", int)
|
292
|
+
100
|
293
|
+
"""
|
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}")
|
300
|
+
|
301
|
+
def change_dict_key(dict_: Dict[Any, Any], old_key: str, new_key: str) -> None:
|
302
|
+
"""
|
303
|
+
Changes a key in a dictionary to a new key.
|
304
|
+
|
305
|
+
Args:
|
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.
|
309
|
+
"""
|
310
|
+
if old_key in dict_:
|
311
|
+
dict_[new_key] = dict_.pop(old_key)
|
312
|
+
|
313
|
+
def as_dict(input_: Any) -> Dict[Any, Any]:
|
314
|
+
"""
|
315
|
+
Converts a JSON string or a dictionary to a dictionary.
|
316
|
+
|
317
|
+
Args:
|
318
|
+
input_: A JSON string or dictionary to convert.
|
319
|
+
|
320
|
+
Returns:
|
321
|
+
The input converted to a dictionary.
|
322
|
+
|
323
|
+
Raises:
|
324
|
+
ValueError: If the input cannot be converted to a dictionary.
|
325
|
+
"""
|
326
|
+
if isinstance(input_, str):
|
327
|
+
try:
|
328
|
+
return json.loads(input_)
|
329
|
+
except Exception as e:
|
330
|
+
raise f"Could not convert input to dict: {e}"
|
331
|
+
elif isinstance(input_, dict):
|
332
|
+
return input_
|
333
|
+
else:
|
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"
|