lionagi 0.0.114__py3-none-any.whl → 0.0.116__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- lionagi/__init__.py +7 -4
- lionagi/bridge/__init__.py +19 -4
- lionagi/bridge/langchain.py +23 -3
- lionagi/bridge/llama_index.py +5 -3
- lionagi/configs/__init__.py +1 -1
- lionagi/configs/oai_configs.py +88 -1
- lionagi/core/__init__.py +6 -9
- lionagi/core/conversations/__init__.py +5 -0
- lionagi/core/conversations/conversation.py +107 -0
- lionagi/core/flows/__init__.py +8 -0
- lionagi/core/flows/flow.py +8 -0
- lionagi/core/flows/flow_util.py +62 -0
- lionagi/core/instruction_set/__init__.py +5 -0
- lionagi/core/instruction_set/instruction_sets.py +7 -0
- lionagi/core/sessions/__init__.py +5 -0
- lionagi/core/sessions/sessions.py +187 -0
- lionagi/endpoints/__init__.py +5 -0
- lionagi/endpoints/assistants.py +0 -0
- lionagi/endpoints/audio.py +17 -0
- lionagi/endpoints/chatcompletion.py +54 -0
- lionagi/endpoints/embeddings.py +0 -0
- lionagi/endpoints/finetune.py +0 -0
- lionagi/endpoints/image.py +0 -0
- lionagi/endpoints/moderation.py +0 -0
- lionagi/endpoints/vision.py +0 -0
- lionagi/{loader → loaders}/__init__.py +7 -1
- lionagi/{loader → loaders}/chunker.py +6 -12
- lionagi/{utils/load_utils.py → loaders/load_util.py} +47 -6
- lionagi/{loader → loaders}/reader.py +4 -12
- lionagi/messages/__init__.py +11 -0
- lionagi/messages/instruction.py +15 -0
- lionagi/messages/message.py +110 -0
- lionagi/messages/response.py +33 -0
- lionagi/messages/system.py +12 -0
- lionagi/objs/__init__.py +10 -6
- lionagi/objs/abc_objs.py +39 -0
- lionagi/objs/async_queue.py +135 -0
- lionagi/objs/messenger.py +70 -148
- lionagi/objs/status_tracker.py +37 -0
- lionagi/objs/{tool_registry.py → tool_manager.py} +8 -6
- lionagi/schema/__init__.py +3 -3
- lionagi/schema/base_node.py +251 -0
- lionagi/schema/base_tool.py +8 -3
- lionagi/schema/data_logger.py +2 -3
- lionagi/schema/data_node.py +37 -0
- lionagi/services/__init__.py +1 -4
- lionagi/services/base_api_service.py +15 -5
- lionagi/services/oai.py +2 -2
- lionagi/services/openrouter.py +2 -3
- lionagi/structures/graph.py +96 -0
- lionagi/{structure → structures}/relationship.py +10 -2
- lionagi/structures/structure.py +102 -0
- lionagi/tests/test_api_util.py +46 -0
- lionagi/tests/test_call_util.py +115 -0
- lionagi/tests/test_convert_util.py +202 -0
- lionagi/tests/test_encrypt_util.py +33 -0
- lionagi/tests/{test_flatten_util.py → test_flat_util.py} +1 -1
- lionagi/tests/test_io_util.py +0 -0
- lionagi/tests/test_sys_util.py +0 -0
- lionagi/tools/__init__.py +5 -0
- lionagi/tools/tool_util.py +7 -0
- lionagi/utils/__init__.py +55 -35
- lionagi/utils/api_util.py +19 -17
- lionagi/utils/call_util.py +2 -1
- lionagi/utils/convert_util.py +229 -0
- lionagi/utils/encrypt_util.py +16 -0
- lionagi/utils/flat_util.py +38 -0
- lionagi/utils/io_util.py +2 -2
- lionagi/utils/sys_util.py +45 -10
- lionagi/version.py +1 -1
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/METADATA +2 -2
- lionagi-0.0.116.dist-info/RECORD +110 -0
- lionagi/core/conversations.py +0 -108
- lionagi/core/flows.py +0 -1
- lionagi/core/instruction_sets.py +0 -1
- lionagi/core/messages.py +0 -166
- lionagi/core/sessions.py +0 -297
- lionagi/schema/base_schema.py +0 -252
- lionagi/services/chatcompletion.py +0 -48
- lionagi/services/service_objs.py +0 -282
- lionagi/structure/structure.py +0 -160
- lionagi/tools/coder.py +0 -1
- lionagi/tools/sandbox.py +0 -1
- lionagi/utils/tool_util.py +0 -92
- lionagi/utils/type_util.py +0 -81
- lionagi-0.0.114.dist-info/RECORD +0 -84
- /lionagi/configs/{openrouter_config.py → openrouter_configs.py} +0 -0
- /lionagi/{datastore → datastores}/__init__.py +0 -0
- /lionagi/{datastore → datastores}/chroma.py +0 -0
- /lionagi/{datastore → datastores}/deeplake.py +0 -0
- /lionagi/{datastore → datastores}/elasticsearch.py +0 -0
- /lionagi/{datastore → datastores}/lantern.py +0 -0
- /lionagi/{datastore → datastores}/pinecone.py +0 -0
- /lionagi/{datastore → datastores}/postgres.py +0 -0
- /lionagi/{datastore → datastores}/qdrant.py +0 -0
- /lionagi/{structure → structures}/__init__.py +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/LICENSE +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/WHEEL +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
import unittest
|
2
|
+
from cryptography.fernet import Fernet
|
3
|
+
|
4
|
+
# Assuming the Python module with the above functions is named 'encryption_utils'
|
5
|
+
from lionagi.utils.encrypt_util import generate_encryption_key, encrypt, decrypt
|
6
|
+
|
7
|
+
class TestEncryptionUtils(unittest.TestCase):
|
8
|
+
|
9
|
+
def test_generate_encryption_key(self):
|
10
|
+
key = generate_encryption_key()
|
11
|
+
self.assertIsInstance(key, str)
|
12
|
+
self.assertEqual(len(key), 44) # Fernet keys are 44 bytes long in URL-safe base64 encoding
|
13
|
+
|
14
|
+
def test_encrypt_decrypt(self):
|
15
|
+
key = generate_encryption_key()
|
16
|
+
original_data = "Test data for encryption"
|
17
|
+
encrypted_data = encrypt(original_data, key)
|
18
|
+
decrypted_data = decrypt(encrypted_data, key)
|
19
|
+
|
20
|
+
self.assertNotEqual(encrypted_data, original_data)
|
21
|
+
self.assertEqual(decrypted_data, original_data)
|
22
|
+
|
23
|
+
def test_invalid_key(self):
|
24
|
+
key = generate_encryption_key()
|
25
|
+
wrong_key = Fernet.generate_key().decode()
|
26
|
+
original_data = "Test data for encryption"
|
27
|
+
encrypted_data = encrypt(original_data, key)
|
28
|
+
|
29
|
+
with self.assertRaises(Exception):
|
30
|
+
decrypt(encrypted_data, wrong_key)
|
31
|
+
|
32
|
+
if __name__ == '__main__':
|
33
|
+
unittest.main()
|
File without changes
|
File without changes
|
lionagi/tools/__init__.py
CHANGED
@@ -0,0 +1,7 @@
|
|
1
|
+
# use schema and convert_util
|
2
|
+
from ..utils.convert_util import func_to_schema
|
3
|
+
from ..schema.base_tool import Tool
|
4
|
+
|
5
|
+
def func_to_tool(func_, parser=None, docstring_style='google'):
|
6
|
+
schema = func_to_schema(func_, docstring_style)
|
7
|
+
return Tool(func=func_, parser=parser, schema_=schema)
|
lionagi/utils/__init__.py
CHANGED
@@ -1,49 +1,69 @@
|
|
1
|
+
from .sys_util import (
|
2
|
+
create_copy, create_id, create_path, create_hash,
|
3
|
+
change_dict_key, get_timestamp, get_bins, timestamp_to_datetime,
|
4
|
+
is_schema, split_path
|
5
|
+
)
|
6
|
+
|
1
7
|
from .flat_util import (
|
2
8
|
flatten_dict, flatten_list, change_separator,
|
3
9
|
unflatten_dict, is_flattenable, dynamic_flatten,
|
4
|
-
unflatten_to_list, flatten_iterable, flatten_iterable_to_list
|
5
|
-
|
6
|
-
|
7
|
-
from .sys_util import (
|
8
|
-
create_copy, get_timestamp, create_id, create_path,
|
9
|
-
split_path, get_bins, change_dict_key
|
10
|
-
)
|
11
|
-
|
10
|
+
unflatten_to_list, flatten_iterable, flatten_iterable_to_list,
|
11
|
+
to_list
|
12
|
+
)
|
12
13
|
|
13
14
|
from .api_util import (
|
14
15
|
api_method, api_endpoint_from_url, api_error,
|
15
16
|
api_rate_limit_error
|
16
|
-
|
17
|
+
)
|
18
|
+
from .encrypt_util import generate_encryption_key, encrypt, decrypt
|
19
|
+
from .convert_util import str_to_num, dict_to_xml, xml_to_dict
|
17
20
|
|
21
|
+
from .io_util import to_temp, to_csv, append_to_jsonl
|
18
22
|
from .call_util import (
|
19
23
|
hcall, ahcall, lcall, alcall,
|
20
24
|
mcall, amcall, ecall, aecall
|
21
|
-
|
22
|
-
|
23
|
-
from .io_util import to_temp, to_csv, append_to_jsonl
|
24
|
-
from .load_utils import dir_to_path, dir_to_nodes, chunk_text, read_text, file_to_chunks
|
25
|
-
from .type_util import str_to_num, to_list
|
26
|
-
from .tool_util import func_to_schema
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
)
|
30
26
|
|
31
27
|
|
32
28
|
__all__ = [
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
29
|
+
'api_method',
|
30
|
+
'api_endpoint_from_url',
|
31
|
+
'api_error',
|
32
|
+
'api_rate_limit_error',
|
33
|
+
'flatten_dict',
|
34
|
+
'flatten_list',
|
35
|
+
'change_separator',
|
36
|
+
'unflatten_dict',
|
37
|
+
'is_flattenable',
|
38
|
+
'dynamic_flatten',
|
39
|
+
'unflatten_to_list',
|
40
|
+
'flatten_iterable',
|
41
|
+
'flatten_iterable_to_list',
|
42
|
+
'create_copy',
|
43
|
+
'create_id',
|
44
|
+
'create_path',
|
45
|
+
'create_hash',
|
46
|
+
'change_dict_key',
|
47
|
+
'get_timestamp',
|
48
|
+
'get_bins',
|
49
|
+
'timestamp_to_datetime',
|
50
|
+
'is_schema',
|
51
|
+
'split_path',
|
52
|
+
'generate_encryption_key',
|
53
|
+
'encrypt', 'decrypt',
|
54
|
+
'str_to_num',
|
55
|
+
'to_list',
|
56
|
+
'dict_to_xml',
|
57
|
+
'xml_to_dict',
|
58
|
+
'to_temp',
|
59
|
+
'to_csv',
|
60
|
+
'append_to_jsonl',
|
61
|
+
'hcall',
|
62
|
+
'ahcall',
|
63
|
+
'lcall',
|
64
|
+
'alcall',
|
65
|
+
'mcall',
|
66
|
+
'amcall',
|
67
|
+
'ecall',
|
68
|
+
'aecall'
|
69
|
+
]
|
lionagi/utils/api_util.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# this module has no internal dependency
|
1
2
|
import logging
|
2
3
|
import re
|
3
4
|
from typing import Callable
|
@@ -32,23 +33,6 @@ def api_method(http_session, method: str = "post") -> Callable:
|
|
32
33
|
return http_session.options
|
33
34
|
elif method == "patch":
|
34
35
|
return http_session.patch
|
35
|
-
|
36
|
-
def api_endpoint_from_url(request_url: str) -> str:
|
37
|
-
"""
|
38
|
-
Extracts the API endpoint from a given URL.
|
39
|
-
|
40
|
-
Parameters:
|
41
|
-
request_url (str): The URL from which to extract the API endpoint.
|
42
|
-
|
43
|
-
Returns:
|
44
|
-
str: The extracted API endpoint, or an empty string if no match is found.
|
45
|
-
|
46
|
-
Examples:
|
47
|
-
endpoint = api_endpoint_from_url("https://api.example.com/v1/users")
|
48
|
-
# endpoint will be 'users'
|
49
|
-
"""
|
50
|
-
match = re.search(r"^https://[^/]+/v\d+/(.+)$", request_url)
|
51
|
-
return match.group(1) if match else ""
|
52
36
|
|
53
37
|
def api_error(response_json: dict) -> bool:
|
54
38
|
"""
|
@@ -84,3 +68,21 @@ def api_rate_limit_error(response_json: dict) -> bool:
|
|
84
68
|
# Handle the rate limit error
|
85
69
|
"""
|
86
70
|
return "Rate limit" in response_json["error"].get("message", "")
|
71
|
+
|
72
|
+
# credit to OpenAI for this method
|
73
|
+
def api_endpoint_from_url(request_url: str) -> str:
|
74
|
+
"""
|
75
|
+
Extracts the API endpoint from a given URL.
|
76
|
+
|
77
|
+
Parameters:
|
78
|
+
request_url (str): The URL from which to extract the API endpoint.
|
79
|
+
|
80
|
+
Returns:
|
81
|
+
str: The extracted API endpoint, or an empty string if no match is found.
|
82
|
+
|
83
|
+
Examples:
|
84
|
+
endpoint = api_endpoint_from_url("https://api.example.com/v1/users")
|
85
|
+
# endpoint will be 'users'
|
86
|
+
"""
|
87
|
+
match = re.search(r"^https://[^/]+/v\d+/(.+)$", request_url)
|
88
|
+
return match.group(1) if match else ""
|
lionagi/utils/call_util.py
CHANGED
@@ -0,0 +1,229 @@
|
|
1
|
+
# this module has no internal dependency
|
2
|
+
import inspect
|
3
|
+
import re
|
4
|
+
import xml.etree.ElementTree as ET
|
5
|
+
from typing import Optional, Union, Any, Type, Dict
|
6
|
+
|
7
|
+
|
8
|
+
def str_to_num(input_: str,
|
9
|
+
upper_bound: Optional[Union[int, float]] = None,
|
10
|
+
lower_bound: Optional[Union[int, float]] = None,
|
11
|
+
num_type: Type[Union[int, float]] = int,
|
12
|
+
precision: Optional[int] = None) -> Union[int, float]:
|
13
|
+
"""
|
14
|
+
Converts the first number in the input string to the specified numeric type.
|
15
|
+
|
16
|
+
Parameters:
|
17
|
+
input_ (str): The input string to extract the number from.
|
18
|
+
|
19
|
+
upper_bound (Optional[Union[int, float]]): The upper bound for the number. Defaults to None.
|
20
|
+
|
21
|
+
lower_bound (Optional[Union[int, float]]): The lower bound for the number. Defaults to None.
|
22
|
+
|
23
|
+
num_type (Type[Union[int, float]]): The type of the number to return (int or float). Defaults to int.
|
24
|
+
|
25
|
+
precision (Optional[int]): The precision for the floating-point number. Defaults to None.
|
26
|
+
|
27
|
+
Returns:
|
28
|
+
Union[int, float]: The converted number.
|
29
|
+
|
30
|
+
Raises:
|
31
|
+
ValueError: If no numeric values are found in the string or if there are conversion errors.
|
32
|
+
"""
|
33
|
+
numbers = re.findall(r'-?\d+\.?\d*', input_)
|
34
|
+
if not numbers:
|
35
|
+
raise ValueError(f"No numeric values found in the string: {input_}")
|
36
|
+
|
37
|
+
try:
|
38
|
+
numbers = numbers[0]
|
39
|
+
if num_type is int:
|
40
|
+
numbers = int(float(numbers))
|
41
|
+
elif num_type is float:
|
42
|
+
numbers = round(float(numbers), precision) if precision is not None else float(numbers)
|
43
|
+
else:
|
44
|
+
raise ValueError(f"Invalid number type: {num_type}")
|
45
|
+
if upper_bound is not None and numbers > upper_bound:
|
46
|
+
raise ValueError(f"Number {numbers} is greater than the upper bound of {upper_bound}.")
|
47
|
+
if lower_bound is not None and numbers < lower_bound:
|
48
|
+
raise ValueError(f"Number {numbers} is less than the lower bound of {lower_bound}.")
|
49
|
+
return numbers
|
50
|
+
|
51
|
+
except ValueError as e:
|
52
|
+
raise ValueError(f"Error converting string to number: {e}")
|
53
|
+
|
54
|
+
def dict_to_xml(data: Dict[str, Any], root_tag: str = 'node') -> str:
|
55
|
+
"""
|
56
|
+
Helper method to convert a dictionary to an XML string.
|
57
|
+
|
58
|
+
Parameters:
|
59
|
+
data (Dict[str, Any]): The dictionary to convert to XML.
|
60
|
+
root_tag (str): The root tag name for the XML.
|
61
|
+
|
62
|
+
Returns:
|
63
|
+
str: An XML string representation of the dictionary.
|
64
|
+
"""
|
65
|
+
root = ET.Element(root_tag)
|
66
|
+
_build_xml(root, data)
|
67
|
+
return ET.tostring(root, encoding='unicode')
|
68
|
+
|
69
|
+
def _build_xml(element: ET.Element, data: Any):
|
70
|
+
"""Recursively builds XML elements from data."""
|
71
|
+
if isinstance(data, dict):
|
72
|
+
for key, value in data.items():
|
73
|
+
sub_element = ET.SubElement(element, key)
|
74
|
+
_build_xml(sub_element, value)
|
75
|
+
elif isinstance(data, list):
|
76
|
+
for item in data:
|
77
|
+
item_element = ET.SubElement(element, 'item')
|
78
|
+
_build_xml(item_element, item)
|
79
|
+
else:
|
80
|
+
element.text = str(data)
|
81
|
+
|
82
|
+
def xml_to_dict(element: ET.Element) -> Dict[str, Any]:
|
83
|
+
"""
|
84
|
+
Helper method to convert an XML element back into a dictionary.
|
85
|
+
"""
|
86
|
+
dict_data = {}
|
87
|
+
for child in element:
|
88
|
+
if child.getchildren():
|
89
|
+
dict_data[child.tag] = xml_to_dict(child)
|
90
|
+
else:
|
91
|
+
dict_data[child.tag] = child.text
|
92
|
+
return dict_data
|
93
|
+
|
94
|
+
def extract_docstring_details_google(func):
|
95
|
+
docstring = inspect.getdoc(func)
|
96
|
+
if not docstring:
|
97
|
+
return "No description available.", {}
|
98
|
+
lines = docstring.split('\n')
|
99
|
+
func_description = lines[0].strip()
|
100
|
+
|
101
|
+
param_start_pos = 0
|
102
|
+
lines_len = len(lines)
|
103
|
+
|
104
|
+
params_description = {}
|
105
|
+
for i in range(1, lines_len):
|
106
|
+
if lines[i].startswith('Args') or lines[i].startswith('Arguments') or lines[i].startswith('Parameters'):
|
107
|
+
param_start_pos = i + 1
|
108
|
+
break
|
109
|
+
|
110
|
+
current_param = None
|
111
|
+
for i in range(param_start_pos, lines_len):
|
112
|
+
if lines[i] == '':
|
113
|
+
continue
|
114
|
+
elif lines[i].startswith(' '):
|
115
|
+
param_desc = lines[i].split(':', 1)
|
116
|
+
if len(param_desc) == 1:
|
117
|
+
params_description[current_param] += ' ' + param_desc[0].strip()
|
118
|
+
continue
|
119
|
+
param, desc = param_desc
|
120
|
+
param = param.split('(')[0].strip()
|
121
|
+
params_description[param] = desc.strip()
|
122
|
+
current_param = param
|
123
|
+
else:
|
124
|
+
break
|
125
|
+
return func_description, params_description
|
126
|
+
|
127
|
+
def extract_docstring_details_rest(func):
|
128
|
+
docstring = inspect.getdoc(func)
|
129
|
+
if not docstring:
|
130
|
+
return "No description available.", {}
|
131
|
+
lines = docstring.split('\n')
|
132
|
+
func_description = lines[0].strip()
|
133
|
+
|
134
|
+
params_description = {}
|
135
|
+
current_param = None
|
136
|
+
for line in lines[1:]:
|
137
|
+
line = line.strip()
|
138
|
+
if line.startswith(':param'):
|
139
|
+
param_desc = line.split(':', 2)
|
140
|
+
_, param, desc = param_desc
|
141
|
+
param = param.split()[-1].strip()
|
142
|
+
params_description[param] = desc.strip()
|
143
|
+
current_param = param
|
144
|
+
elif line.startswith(' '):
|
145
|
+
params_description[current_param] += ' ' + line
|
146
|
+
|
147
|
+
return func_description, params_description
|
148
|
+
|
149
|
+
def extract_docstring_details(func, style='google'):
|
150
|
+
if style == 'google':
|
151
|
+
func_description, params_description = extract_docstring_details_google(func)
|
152
|
+
elif style == 'reST':
|
153
|
+
func_description, params_description = extract_docstring_details_rest(func)
|
154
|
+
else:
|
155
|
+
raise ValueError(f'{style} is not supported. Please choose either "google" or "reST".')
|
156
|
+
return func_description, params_description
|
157
|
+
|
158
|
+
def python_to_json_type(py_type):
|
159
|
+
"""
|
160
|
+
Converts a Python type to its JSON type equivalent.
|
161
|
+
|
162
|
+
Parameters:
|
163
|
+
py_type (str): The name of the Python type.
|
164
|
+
|
165
|
+
Returns:
|
166
|
+
str: The corresponding JSON type.
|
167
|
+
"""
|
168
|
+
type_mapping = {
|
169
|
+
'str': 'string',
|
170
|
+
'int': 'number',
|
171
|
+
'float': 'number',
|
172
|
+
'list': 'array',
|
173
|
+
'tuple': 'array',
|
174
|
+
'bool': 'boolean',
|
175
|
+
'dict': 'object'
|
176
|
+
}
|
177
|
+
return type_mapping.get(py_type, 'object')
|
178
|
+
|
179
|
+
def func_to_schema(func, style='google'):
|
180
|
+
"""
|
181
|
+
Generates a schema description for a given function, using typing hints and docstrings.
|
182
|
+
The schema includes the function's name, description, and parameters.
|
183
|
+
|
184
|
+
Parameters:
|
185
|
+
func (function): The function to generate a schema for.
|
186
|
+
|
187
|
+
style (str): The docstring format.
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
dict: A schema describing the function.
|
191
|
+
"""
|
192
|
+
# Extracting function name and docstring details
|
193
|
+
func_name = func.__name__
|
194
|
+
func_description, params_description = extract_docstring_details(func, style)
|
195
|
+
|
196
|
+
# Extracting parameters with typing hints
|
197
|
+
sig = inspect.signature(func)
|
198
|
+
parameters = {
|
199
|
+
"type": "object",
|
200
|
+
"properties": {},
|
201
|
+
"required": [],
|
202
|
+
}
|
203
|
+
|
204
|
+
for name, param in sig.parameters.items():
|
205
|
+
# Default type to string and update if type hint is available
|
206
|
+
param_type = "string"
|
207
|
+
if param.annotation is not inspect.Parameter.empty:
|
208
|
+
param_type = python_to_json_type(param.annotation.__name__)
|
209
|
+
|
210
|
+
# Extract parameter description from docstring, if available
|
211
|
+
param_description = params_description.get(name, "No description available.")
|
212
|
+
|
213
|
+
# Assuming all parameters are required for simplicity
|
214
|
+
parameters["required"].append(name)
|
215
|
+
parameters["properties"][name] = {
|
216
|
+
"type": param_type,
|
217
|
+
"description": param_description,
|
218
|
+
}
|
219
|
+
|
220
|
+
# Constructing the schema
|
221
|
+
schema = {
|
222
|
+
"type": "function",
|
223
|
+
"function": {
|
224
|
+
"name": func_name,
|
225
|
+
"description": func_description,
|
226
|
+
"parameters": parameters,
|
227
|
+
}
|
228
|
+
}
|
229
|
+
return schema
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# this module has no internal dependency
|
2
|
+
from cryptography.fernet import Fernet
|
3
|
+
|
4
|
+
def generate_encryption_key() -> str:
|
5
|
+
"""Generates a key for encryption."""
|
6
|
+
return Fernet.generate_key().decode()
|
7
|
+
|
8
|
+
def encrypt(data: str, key: str) -> str:
|
9
|
+
"""Encrypts data using the provided key."""
|
10
|
+
fernet = Fernet(key.encode())
|
11
|
+
return fernet.encrypt(data.encode()).decode()
|
12
|
+
|
13
|
+
def decrypt(data: str, key: str) -> str:
|
14
|
+
"""Decrypts data using the provided key."""
|
15
|
+
fernet = Fernet(key.encode())
|
16
|
+
return fernet.decrypt(data.encode()).decode()
|
lionagi/utils/flat_util.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# this module has no internal dependency
|
1
2
|
from typing import Dict, Iterable, List, Any, Callable, Generator, Tuple
|
2
3
|
|
3
4
|
|
@@ -487,6 +488,43 @@ def unflatten_dict_with_custom_logic(
|
|
487
488
|
d[modified_last_part] = modified_value
|
488
489
|
return reconstructed
|
489
490
|
|
491
|
+
def to_list(input_: Any, flatten: bool = True, dropna: bool = False) -> List[Any]:
|
492
|
+
"""
|
493
|
+
Converts the input to a list, optionally flattening it and dropping None values.
|
494
|
+
|
495
|
+
Parameters:
|
496
|
+
input_ (Any): The input to convert to a list.
|
497
|
+
|
498
|
+
flatten (bool): Whether to flatten the input if it is a nested list. Defaults to True.
|
499
|
+
|
500
|
+
dropna (bool): Whether to drop None values from the list. Defaults to False.
|
501
|
+
|
502
|
+
Returns:
|
503
|
+
List[Any]: The input converted to a list.
|
504
|
+
|
505
|
+
Raises:
|
506
|
+
ValueError: If the input cannot be converted to a list.
|
507
|
+
"""
|
508
|
+
if isinstance(input_, list) and flatten:
|
509
|
+
input_ = flatten_list(input_)
|
510
|
+
if dropna:
|
511
|
+
input_ = [i for i in input_ if i is not None]
|
512
|
+
elif isinstance(input_, Iterable) and not isinstance(input_, (str, dict)):
|
513
|
+
try:
|
514
|
+
input_ = list(input_)
|
515
|
+
except:
|
516
|
+
raise ValueError("Input cannot be converted to a list.")
|
517
|
+
else:
|
518
|
+
input_ = [input_]
|
519
|
+
return input_
|
520
|
+
|
521
|
+
|
522
|
+
|
523
|
+
|
524
|
+
|
525
|
+
|
526
|
+
|
527
|
+
|
490
528
|
# def dynamic_unflatten(flat_dict, sep='_', custom_logic=None, max_depth=None):
|
491
529
|
# """
|
492
530
|
# Unflattens a dictionary with flat keys into a nested dictionary or list.
|
lionagi/utils/io_util.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# used flat_util
|
1
2
|
import csv
|
2
3
|
import json
|
3
4
|
import os
|
4
5
|
import tempfile
|
5
6
|
from typing import Any, Dict, List
|
6
|
-
from .
|
7
|
+
from .flat_util import to_list
|
7
8
|
|
8
9
|
|
9
10
|
def to_temp(input: Any,
|
@@ -79,7 +80,6 @@ def to_csv(input: List[Dict[str, Any]]=None,
|
|
79
80
|
writer.writeheader()
|
80
81
|
writer.writerows(input)
|
81
82
|
|
82
|
-
|
83
83
|
def append_to_jsonl(data: Any, filepath: str) -> None:
|
84
84
|
"""
|
85
85
|
Appends data to a JSON lines (jsonl) file.
|
lionagi/utils/sys_util.py
CHANGED
@@ -13,12 +13,14 @@ Copyright 2023 HaiyangLi <ocean@lionagi.ai>
|
|
13
13
|
See the License for the specific language governing permissions and
|
14
14
|
limitations under the License.
|
15
15
|
"""
|
16
|
+
|
17
|
+
# this module has no internal dependency
|
16
18
|
import os
|
17
19
|
import copy
|
18
20
|
import hashlib
|
19
21
|
from pathlib import Path
|
20
22
|
from datetime import datetime
|
21
|
-
from typing import Any, Generator, List
|
23
|
+
from typing import Any, Generator, List, Dict
|
22
24
|
|
23
25
|
def create_copy(input: Any, n: int) -> Any:
|
24
26
|
"""
|
@@ -164,6 +166,48 @@ def get_bins(input: List[str], upper: int = 7500) -> List[List[int]]:
|
|
164
166
|
|
165
167
|
return bins
|
166
168
|
|
169
|
+
def change_dict_key(dict_, old_key, new_key):
|
170
|
+
dict_[new_key] = dict_.pop(old_key)
|
171
|
+
|
172
|
+
def timestamp_to_datetime(timestamp: int) -> str:
|
173
|
+
if isinstance(timestamp, str):
|
174
|
+
try:
|
175
|
+
timestamp = int(timestamp)
|
176
|
+
except:
|
177
|
+
return timestamp
|
178
|
+
return datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
|
179
|
+
|
180
|
+
def is_schema(dict_: Dict, schema: Dict):
|
181
|
+
for key, expected_type in schema.items():
|
182
|
+
if not isinstance(dict_[key], expected_type):
|
183
|
+
return False
|
184
|
+
return True
|
185
|
+
|
186
|
+
def create_hash(data: str, algorithm: str = 'sha256') -> str:
|
187
|
+
"""
|
188
|
+
Generates a hash for the given data using the specified algorithm.
|
189
|
+
|
190
|
+
Parameters:
|
191
|
+
data (str): The data to be hashed.
|
192
|
+
algorithm (str): The hashing algorithm to use (e.g., 'sha256', 'md5').
|
193
|
+
|
194
|
+
Returns:
|
195
|
+
str: The generated hash string.
|
196
|
+
"""
|
197
|
+
hasher = hashlib.new(algorithm)
|
198
|
+
hasher.update(data.encode())
|
199
|
+
return hasher.hexdigest()
|
200
|
+
|
201
|
+
|
202
|
+
|
203
|
+
# def parse_function_call(response: str) -> Tuple[str, Dict]:
|
204
|
+
# out = json.loads(response)
|
205
|
+
# func = out.get('function', '').lstrip('call_')
|
206
|
+
# args = json.loads(out.get('arguments', '{}'))
|
207
|
+
# return func, args
|
208
|
+
|
209
|
+
# ------------------------------------------------------------------------
|
210
|
+
# credit to OpenAI for the following functions
|
167
211
|
def task_id_generator() -> Generator[int, None, None]:
|
168
212
|
"""
|
169
213
|
A generator function that yields a sequential series of task IDs.
|
@@ -180,12 +224,3 @@ def task_id_generator() -> Generator[int, None, None]:
|
|
180
224
|
while True:
|
181
225
|
yield task_id
|
182
226
|
task_id += 1
|
183
|
-
|
184
|
-
def change_dict_key(dict_, old_key, new_key):
|
185
|
-
dict_[new_key] = dict_.pop(old_key)
|
186
|
-
|
187
|
-
# def parse_function_call(response: str) -> Tuple[str, Dict]:
|
188
|
-
# out = json.loads(response)
|
189
|
-
# func = out.get('function', '').lstrip('call_')
|
190
|
-
# args = json.loads(out.get('arguments', '{}'))
|
191
|
-
# return func, args
|
lionagi/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.0.
|
1
|
+
__version__ = "0.0.116"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lionagi
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.116
|
4
4
|
Summary: Towards automated general intelligence.
|
5
5
|
Author: HaiyangLi
|
6
6
|
Author-email: Haiyang Li <ocean@lionagi.ai>
|
@@ -224,7 +224,7 @@ Requires-Dist: httpx ==0.25.1
|
|
224
224
|
|
225
225
|
|
226
226
|
|
227
|
-
[PyPI](https://pypi.org/project/lionagi/) | [Documentation](https://lionagi.readthedocs.io/en/latest/) | [Discord](https://discord.gg/
|
227
|
+
[PyPI](https://pypi.org/project/lionagi/) | [Documentation](https://lionagi.readthedocs.io/en/latest/) | [Discord](https://discord.gg/mzDD5JtYRp)
|
228
228
|
|
229
229
|
|
230
230
|
# LionAGI
|