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.
Files changed (99) hide show
  1. lionagi/__init__.py +7 -4
  2. lionagi/bridge/__init__.py +19 -4
  3. lionagi/bridge/langchain.py +23 -3
  4. lionagi/bridge/llama_index.py +5 -3
  5. lionagi/configs/__init__.py +1 -1
  6. lionagi/configs/oai_configs.py +88 -1
  7. lionagi/core/__init__.py +6 -9
  8. lionagi/core/conversations/__init__.py +5 -0
  9. lionagi/core/conversations/conversation.py +107 -0
  10. lionagi/core/flows/__init__.py +8 -0
  11. lionagi/core/flows/flow.py +8 -0
  12. lionagi/core/flows/flow_util.py +62 -0
  13. lionagi/core/instruction_set/__init__.py +5 -0
  14. lionagi/core/instruction_set/instruction_sets.py +7 -0
  15. lionagi/core/sessions/__init__.py +5 -0
  16. lionagi/core/sessions/sessions.py +187 -0
  17. lionagi/endpoints/__init__.py +5 -0
  18. lionagi/endpoints/assistants.py +0 -0
  19. lionagi/endpoints/audio.py +17 -0
  20. lionagi/endpoints/chatcompletion.py +54 -0
  21. lionagi/endpoints/embeddings.py +0 -0
  22. lionagi/endpoints/finetune.py +0 -0
  23. lionagi/endpoints/image.py +0 -0
  24. lionagi/endpoints/moderation.py +0 -0
  25. lionagi/endpoints/vision.py +0 -0
  26. lionagi/{loader → loaders}/__init__.py +7 -1
  27. lionagi/{loader → loaders}/chunker.py +6 -12
  28. lionagi/{utils/load_utils.py → loaders/load_util.py} +47 -6
  29. lionagi/{loader → loaders}/reader.py +4 -12
  30. lionagi/messages/__init__.py +11 -0
  31. lionagi/messages/instruction.py +15 -0
  32. lionagi/messages/message.py +110 -0
  33. lionagi/messages/response.py +33 -0
  34. lionagi/messages/system.py +12 -0
  35. lionagi/objs/__init__.py +10 -6
  36. lionagi/objs/abc_objs.py +39 -0
  37. lionagi/objs/async_queue.py +135 -0
  38. lionagi/objs/messenger.py +70 -148
  39. lionagi/objs/status_tracker.py +37 -0
  40. lionagi/objs/{tool_registry.py → tool_manager.py} +8 -6
  41. lionagi/schema/__init__.py +3 -3
  42. lionagi/schema/base_node.py +251 -0
  43. lionagi/schema/base_tool.py +8 -3
  44. lionagi/schema/data_logger.py +2 -3
  45. lionagi/schema/data_node.py +37 -0
  46. lionagi/services/__init__.py +1 -4
  47. lionagi/services/base_api_service.py +15 -5
  48. lionagi/services/oai.py +2 -2
  49. lionagi/services/openrouter.py +2 -3
  50. lionagi/structures/graph.py +96 -0
  51. lionagi/{structure → structures}/relationship.py +10 -2
  52. lionagi/structures/structure.py +102 -0
  53. lionagi/tests/test_api_util.py +46 -0
  54. lionagi/tests/test_call_util.py +115 -0
  55. lionagi/tests/test_convert_util.py +202 -0
  56. lionagi/tests/test_encrypt_util.py +33 -0
  57. lionagi/tests/{test_flatten_util.py → test_flat_util.py} +1 -1
  58. lionagi/tests/test_io_util.py +0 -0
  59. lionagi/tests/test_sys_util.py +0 -0
  60. lionagi/tools/__init__.py +5 -0
  61. lionagi/tools/tool_util.py +7 -0
  62. lionagi/utils/__init__.py +55 -35
  63. lionagi/utils/api_util.py +19 -17
  64. lionagi/utils/call_util.py +2 -1
  65. lionagi/utils/convert_util.py +229 -0
  66. lionagi/utils/encrypt_util.py +16 -0
  67. lionagi/utils/flat_util.py +38 -0
  68. lionagi/utils/io_util.py +2 -2
  69. lionagi/utils/sys_util.py +45 -10
  70. lionagi/version.py +1 -1
  71. {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/METADATA +2 -2
  72. lionagi-0.0.116.dist-info/RECORD +110 -0
  73. lionagi/core/conversations.py +0 -108
  74. lionagi/core/flows.py +0 -1
  75. lionagi/core/instruction_sets.py +0 -1
  76. lionagi/core/messages.py +0 -166
  77. lionagi/core/sessions.py +0 -297
  78. lionagi/schema/base_schema.py +0 -252
  79. lionagi/services/chatcompletion.py +0 -48
  80. lionagi/services/service_objs.py +0 -282
  81. lionagi/structure/structure.py +0 -160
  82. lionagi/tools/coder.py +0 -1
  83. lionagi/tools/sandbox.py +0 -1
  84. lionagi/utils/tool_util.py +0 -92
  85. lionagi/utils/type_util.py +0 -81
  86. lionagi-0.0.114.dist-info/RECORD +0 -84
  87. /lionagi/configs/{openrouter_config.py → openrouter_configs.py} +0 -0
  88. /lionagi/{datastore → datastores}/__init__.py +0 -0
  89. /lionagi/{datastore → datastores}/chroma.py +0 -0
  90. /lionagi/{datastore → datastores}/deeplake.py +0 -0
  91. /lionagi/{datastore → datastores}/elasticsearch.py +0 -0
  92. /lionagi/{datastore → datastores}/lantern.py +0 -0
  93. /lionagi/{datastore → datastores}/pinecone.py +0 -0
  94. /lionagi/{datastore → datastores}/postgres.py +0 -0
  95. /lionagi/{datastore → datastores}/qdrant.py +0 -0
  96. /lionagi/{structure → structures}/__init__.py +0 -0
  97. {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/LICENSE +0 -0
  98. {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/WHEEL +0 -0
  99. {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()
@@ -1,6 +1,6 @@
1
1
  import unittest
2
2
 
3
- from ..utils.flat_util import *
3
+ from lionagi.utils.flat_util import *
4
4
 
5
5
  class TestFlattenDict(unittest.TestCase):
6
6
 
File without changes
File without changes
lionagi/tools/__init__.py CHANGED
@@ -0,0 +1,5 @@
1
+ from .tool_util import func_to_tool
2
+
3
+ __all__ = [
4
+ "func_to_tool"
5
+ ]
@@ -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
- "api_method", "api_endpoint_from_url", "api_error",
34
- "api_rate_limit_error",
35
-
36
- "flatten_dict", "flatten_list", "change_separator",
37
- "unflatten_dict", "is_flattenable", "dynamic_flatten",
38
- "unflatten_to_list", "flatten_iterable", "flatten_iterable_to_list",
39
-
40
- "create_copy", "get_timestamp", "create_id", "create_path",
41
- "split_path", "get_bins", "change_dict_key",
42
-
43
- "hcall", "ahcall", "lcall", "alcall",
44
- "mcall", "amcall", "ecall", "aecall",
45
-
46
- "to_temp", "to_csv", "append_to_jsonl",
47
- "dir_to_path", "chunk_text", "file_to_chunks",
48
- "str_to_num", "to_list", "func_to_schema"
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 ""
@@ -1,9 +1,10 @@
1
+ # use sys_util and flat_util
1
2
  import asyncio
2
3
  import time
3
4
  from typing import Any, Callable, List, Optional, Union
4
5
 
5
6
  from .sys_util import create_copy
6
- from .type_util import to_list
7
+ from .flat_util import to_list
7
8
 
8
9
 
9
10
  def hcall(
@@ -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()
@@ -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 .type_util import to_list
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.114"
1
+ __version__ = "0.0.116"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lionagi
3
- Version: 0.0.114
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/7RGWqpSxze)
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