lionagi 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. lionagi/core/agent/base_agent.py +2 -3
  2. lionagi/core/branch/base.py +1 -1
  3. lionagi/core/branch/branch.py +2 -1
  4. lionagi/core/branch/flow_mixin.py +1 -1
  5. lionagi/core/branch/util.py +1 -1
  6. lionagi/core/execute/base_executor.py +1 -4
  7. lionagi/core/execute/branch_executor.py +66 -3
  8. lionagi/core/execute/instruction_map_executor.py +48 -0
  9. lionagi/core/execute/neo4j_executor.py +381 -0
  10. lionagi/core/execute/structure_executor.py +120 -4
  11. lionagi/core/flow/monoflow/ReAct.py +21 -19
  12. lionagi/core/flow/monoflow/chat_mixin.py +1 -1
  13. lionagi/core/flow/monoflow/followup.py +14 -13
  14. lionagi/core/flow/polyflow/__init__.py +1 -1
  15. lionagi/core/generic/component.py +197 -122
  16. lionagi/core/generic/condition.py +3 -1
  17. lionagi/core/generic/edge.py +77 -25
  18. lionagi/core/graph/graph.py +1 -1
  19. lionagi/core/mail/mail_manager.py +3 -2
  20. lionagi/core/session/session.py +1 -1
  21. lionagi/core/tool/tool_manager.py +10 -9
  22. lionagi/experimental/__init__.py +0 -0
  23. lionagi/experimental/directive/__init__.py +0 -0
  24. lionagi/experimental/directive/evaluator/__init__.py +0 -0
  25. lionagi/experimental/directive/evaluator/ast_evaluator.py +115 -0
  26. lionagi/experimental/directive/evaluator/base_evaluator.py +202 -0
  27. lionagi/experimental/directive/evaluator/sandbox_.py +14 -0
  28. lionagi/experimental/directive/evaluator/script_engine.py +83 -0
  29. lionagi/experimental/directive/parser/__init__.py +0 -0
  30. lionagi/experimental/directive/parser/base_parser.py +215 -0
  31. lionagi/experimental/directive/schema.py +36 -0
  32. lionagi/experimental/directive/template_/__init__.py +0 -0
  33. lionagi/experimental/directive/template_/base_template.py +63 -0
  34. lionagi/experimental/report/__init__.py +0 -0
  35. lionagi/experimental/report/form.py +64 -0
  36. lionagi/experimental/report/report.py +138 -0
  37. lionagi/experimental/report/util.py +47 -0
  38. lionagi/experimental/tool/__init__.py +0 -0
  39. lionagi/experimental/tool/function_calling.py +43 -0
  40. lionagi/experimental/tool/manual.py +66 -0
  41. lionagi/experimental/tool/schema.py +59 -0
  42. lionagi/experimental/tool/tool_manager.py +138 -0
  43. lionagi/experimental/tool/util.py +16 -0
  44. lionagi/experimental/validator/__init__.py +0 -0
  45. lionagi/experimental/validator/rule.py +139 -0
  46. lionagi/experimental/validator/validator.py +56 -0
  47. lionagi/experimental/work/__init__.py +10 -0
  48. lionagi/experimental/work/async_queue.py +54 -0
  49. lionagi/experimental/work/schema.py +73 -0
  50. lionagi/experimental/work/work_function.py +67 -0
  51. lionagi/experimental/work/worker.py +56 -0
  52. lionagi/experimental/work2/__init__.py +0 -0
  53. lionagi/experimental/work2/form.py +371 -0
  54. lionagi/experimental/work2/report.py +289 -0
  55. lionagi/experimental/work2/schema.py +30 -0
  56. lionagi/experimental/work2/tests.py +72 -0
  57. lionagi/experimental/work2/util.py +0 -0
  58. lionagi/experimental/work2/work.py +0 -0
  59. lionagi/experimental/work2/work_function.py +89 -0
  60. lionagi/experimental/work2/worker.py +12 -0
  61. lionagi/integrations/bridge/autogen_/__init__.py +0 -0
  62. lionagi/integrations/bridge/autogen_/autogen_.py +124 -0
  63. lionagi/integrations/bridge/llamaindex_/get_index.py +294 -0
  64. lionagi/integrations/bridge/llamaindex_/llama_pack.py +227 -0
  65. lionagi/integrations/bridge/transformers_/__init__.py +0 -0
  66. lionagi/integrations/bridge/transformers_/install_.py +36 -0
  67. lionagi/integrations/config/oai_configs.py +1 -1
  68. lionagi/integrations/config/ollama_configs.py +1 -1
  69. lionagi/integrations/config/openrouter_configs.py +1 -1
  70. lionagi/integrations/storage/__init__.py +3 -0
  71. lionagi/integrations/storage/neo4j.py +673 -0
  72. lionagi/integrations/storage/storage_util.py +289 -0
  73. lionagi/integrations/storage/structure_excel.py +268 -0
  74. lionagi/integrations/storage/to_csv.py +63 -0
  75. lionagi/integrations/storage/to_excel.py +76 -0
  76. lionagi/libs/__init__.py +4 -0
  77. lionagi/libs/ln_knowledge_graph.py +405 -0
  78. lionagi/libs/ln_queue.py +101 -0
  79. lionagi/libs/ln_tokenizer.py +57 -0
  80. lionagi/libs/sys_util.py +1 -1
  81. lionagi/lions/__init__.py +0 -0
  82. lionagi/lions/coder/__init__.py +0 -0
  83. lionagi/lions/coder/add_feature.py +20 -0
  84. lionagi/lions/coder/base_prompts.py +22 -0
  85. lionagi/lions/coder/coder.py +121 -0
  86. lionagi/lions/coder/util.py +91 -0
  87. lionagi/lions/researcher/__init__.py +0 -0
  88. lionagi/lions/researcher/data_source/__init__.py +0 -0
  89. lionagi/lions/researcher/data_source/finhub_.py +191 -0
  90. lionagi/lions/researcher/data_source/google_.py +199 -0
  91. lionagi/lions/researcher/data_source/wiki_.py +96 -0
  92. lionagi/lions/researcher/data_source/yfinance_.py +21 -0
  93. lionagi/tests/libs/test_queue.py +67 -0
  94. lionagi/tests/test_core/generic/__init__.py +0 -0
  95. lionagi/tests/test_core/generic/test_component.py +89 -0
  96. lionagi/tests/test_core/test_branch.py +0 -1
  97. lionagi/version.py +1 -1
  98. {lionagi-0.1.0.dist-info → lionagi-0.1.2.dist-info}/METADATA +1 -1
  99. lionagi-0.1.2.dist-info/RECORD +206 -0
  100. lionagi-0.1.0.dist-info/RECORD +0 -136
  101. {lionagi-0.1.0.dist-info → lionagi-0.1.2.dist-info}/LICENSE +0 -0
  102. {lionagi-0.1.0.dist-info → lionagi-0.1.2.dist-info}/WHEEL +0 -0
  103. {lionagi-0.1.0.dist-info → lionagi-0.1.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,76 @@
1
+ import pandas as pd
2
+ from lionagi.libs import SysUtil
3
+
4
+ from lionagi.integrations.storage.storage_util import output_node_list, output_edge_list
5
+
6
+
7
+ def _output_excel(node_list, node_dict, edge_list, edge_cls_list, structure_name, dir="structure_storage"):
8
+ """
9
+ Writes provided node and edge data into multiple sheets of a single Excel workbook.
10
+
11
+ This helper function takes lists and dictionaries of nodes and edges, converts them into pandas DataFrames,
12
+ and then writes each DataFrame to a distinct sheet in an Excel workbook. This includes a separate sheet
13
+ for each type of node and edge, as well as edge conditions if they exist.
14
+
15
+ Args:
16
+ node_list (list): A list of dictionaries where each dictionary contains attributes of a single node.
17
+ node_dict (dict): A dictionary of lists where each key represents a node type and the value is a list of
18
+ node attributes for nodes of that type.
19
+ edge_list (list): A list of dictionaries where each dictionary contains attributes of a single edge.
20
+ edge_cls_list (list): A list of dictionaries where each dictionary contains attributes of edge conditions.
21
+ structure_name (str): The base name for the output Excel file. The '.xlsx' extension will be added
22
+ automatically if not included.
23
+
24
+ Returns:
25
+ None: This function does not return a value but writes data directly to an Excel workbook.
26
+
27
+ Raises:
28
+ ImportError: If the required 'openpyxl' library is not installed, which is necessary for pandas to write Excel files.
29
+ """
30
+ SysUtil.check_import("openpyxl")
31
+
32
+ structure_id = ""
33
+
34
+ tables = {"Nodes": pd.DataFrame(node_list), "Edges": pd.DataFrame(edge_list)}
35
+ if edge_cls_list:
36
+ tables["EdgesCondClass"] = pd.DataFrame(edge_cls_list)
37
+ for i in node_dict:
38
+ if i == "StructureExecutor":
39
+ structure_node = node_dict[i][0]
40
+ structure_node["name"] = structure_name
41
+ structure_id = structure_node["id"]
42
+ tables[i] = pd.DataFrame(node_dict[i])
43
+
44
+ import os
45
+ filepath = os.path.join(dir, f"{structure_name}_{structure_id}.xlsx")
46
+
47
+ if not os.path.exists(dir):
48
+ os.makedirs(dir)
49
+
50
+ with pd.ExcelWriter(filepath) as writer:
51
+ for i in tables:
52
+ tables[i].to_excel(writer, sheet_name=i, index=False)
53
+
54
+
55
+ def to_excel(structure, structure_name, dir="structure_storage"):
56
+ """
57
+ Converts a structure into a series of Excel sheets within a single workbook.
58
+
59
+ This function processes the specified structure to extract detailed node and edge information,
60
+ including conditions if applicable. These details are then saved into separate sheets within an
61
+ Excel workbook for nodes, edges, and any edge conditions.
62
+
63
+ Args:
64
+ structure: An object representing the structure to be serialized. This should have methods
65
+ to return lists of nodes and edges suitable for output.
66
+ structure_name (str): The base name of the output Excel file. The '.xlsx' extension will be added
67
+ automatically if not included.
68
+
69
+ Returns:
70
+ None: This function does not return a value but outputs an Excel workbook with multiple sheets.
71
+ """
72
+ node_list, node_dict = output_node_list(structure)
73
+ edge_list, edge_cls_list = output_edge_list(structure)
74
+
75
+ _output_excel(node_list, node_dict, edge_list, edge_cls_list, structure_name, dir)
76
+
lionagi/libs/__init__.py CHANGED
@@ -16,6 +16,9 @@ from lionagi.libs.ln_api import (
16
16
  PayloadPackage,
17
17
  )
18
18
 
19
+ from lionagi.libs.ln_validate import validation_funcs
20
+
21
+
19
22
  __all__ = [
20
23
  "SysUtil",
21
24
  "convert",
@@ -31,4 +34,5 @@ __all__ = [
31
34
  "StatusTracker",
32
35
  "SimpleRateLimiter",
33
36
  "CallDecorator",
37
+ "validation_funcs",
34
38
  ]
@@ -0,0 +1,405 @@
1
+ import math
2
+ from lionagi.libs import CallDecorator as cd
3
+
4
+
5
+ class KnowledgeBase:
6
+ """
7
+ A class to represent a Knowledge Base (KB) containing entities, relations, and sources.
8
+
9
+ Attributes:
10
+ entities (dict): A dictionary of entities in the KB, where the keys are entity titles, and the values are
11
+ entity information (excluding the title).
12
+ relations (list): A list of relations in the KB, where each relation is a dictionary containing information
13
+ about the relation (head, type, tail) and metadata (article_url and spans).
14
+ sources (dict): A dictionary of information about the sources of relations, where the keys are article URLs,
15
+ and the values are source data (article_title and article_publish_date).
16
+
17
+ Methods:
18
+ merge_with_kb(kb2): Merge another Knowledge Base (kb2) into this KB.
19
+ are_relations_equal(r1, r2): Check if two relations (r1 and r2) are equal.
20
+ exists_relation(r1): Check if a relation (r1) already exists in the KB.
21
+ merge_relations(r2): Merge the information from relation r2 into an existing relation in the KB.
22
+ get_wikipedia_data(candidate_entity): Get data for a candidate entity from Wikipedia.
23
+ add_entity(e): Add an entity to the KB.
24
+ add_relation(r, article_title, article_publish_date): Add a relation to the KB.
25
+ print(): Print the entities, relations, and sources in the KB.
26
+ extract_relations_from_model_output(text): Extract relations from the model output text.
27
+
28
+ """
29
+
30
+ def __init__(self):
31
+ """
32
+ Initialize an empty Knowledge Base (KB) with empty dictionaries for entities, relations, and sources.
33
+ """
34
+ self.entities = {} # { entity_title: {...} }
35
+ self.relations = [] # [ head: entity_title, type: ..., tail: entity_title,
36
+ # meta: { article_url: { spans: [...] } } ]
37
+ self.sources = {} # { article_url: {...} }
38
+
39
+ def merge_with_kb(self, kb2):
40
+ """
41
+ Merge another Knowledge Base (KB) into this KB.
42
+
43
+ Args:
44
+ kb2 (KnowledgeBase): The Knowledge Base (KB) to merge into this KB.
45
+ """
46
+ for r in kb2.relations:
47
+ article_url = list(r["meta"].keys())[0]
48
+ source_data = kb2.sources[article_url]
49
+ self.add_relation(
50
+ r, source_data["article_title"], source_data["article_publish_date"]
51
+ )
52
+
53
+ def are_relations_equal(self, r1, r2):
54
+ """
55
+ Check if two relations (r1 and r2) are equal.
56
+
57
+ Args:
58
+ r1 (dict): The first relation to compare.
59
+ r2 (dict): The second relation to compare.
60
+
61
+ Returns:
62
+ bool: True if the relations are equal, False otherwise.
63
+ """
64
+ return all(r1[attr] == r2[attr] for attr in ["head", "type", "tail"])
65
+
66
+ def exists_relation(self, r1):
67
+ """
68
+ Check if a relation (r1) already exists in the KB.
69
+
70
+ Args:
71
+ r1 (dict): The relation to check for existence in the KB.
72
+
73
+ Returns:
74
+ bool: True if the relation exists in the KB, False otherwise.
75
+ """
76
+ return any(self.are_relations_equal(r1, r2) for r2 in self.relations)
77
+
78
+ def merge_relations(self, r2):
79
+ """
80
+ Merge the information from relation r2 into an existing relation in the KB.
81
+
82
+ Args:
83
+ r2 (dict): The relation to merge into an existing relation in the KB.
84
+ """
85
+ r1 = [r for r in self.relations if self.are_relations_equal(r2, r)][0]
86
+
87
+ # if different article
88
+ article_url = list(r2["meta"].keys())[0]
89
+ if article_url not in r1["meta"]:
90
+ r1["meta"][article_url] = r2["meta"][article_url]
91
+
92
+ # if existing article
93
+ else:
94
+ spans_to_add = [
95
+ span
96
+ for span in r2["meta"][article_url]["spans"]
97
+ if span not in r1["meta"][article_url]["spans"]
98
+ ]
99
+ r1["meta"][article_url]["spans"] += spans_to_add
100
+
101
+ @cd.cache(maxsize=10000)
102
+ def get_wikipedia_data(self, candidate_entity):
103
+ """
104
+ Get data for a candidate entity from Wikipedia.
105
+
106
+ Args:
107
+ candidate_entity (str): The candidate entity title.
108
+
109
+ Returns:
110
+ dict: A dictionary containing information about the candidate entity (title, url, summary).
111
+ None if the entity does not exist in Wikipedia.
112
+ """
113
+ try:
114
+ from lionagi.libs import SysUtil
115
+
116
+ SysUtil.check_import("wikipedia")
117
+ import wikipedia # type: ignore
118
+ except Exception as e:
119
+ raise Exception("wikipedia package is not installed {e}")
120
+
121
+ try:
122
+ page = wikipedia.page(candidate_entity, auto_suggest=False)
123
+ entity_data = {
124
+ "title": page.title,
125
+ "url": page.url,
126
+ "summary": page.summary,
127
+ }
128
+ return entity_data
129
+ except:
130
+ return None
131
+
132
+ def add_entity(self, e):
133
+ """
134
+ Add an entity to the KB.
135
+
136
+ Args:
137
+ e (dict): A dictionary containing information about the entity (title and additional attributes).
138
+ """
139
+ self.entities[e["title"]] = {k: v for k, v in e.items() if k != "title"}
140
+
141
+ def add_relation(self, r, article_title, article_publish_date):
142
+ """
143
+ Add a relation to the KB.
144
+
145
+ Args:
146
+ r (dict): A dictionary containing information about the relation (head, type, tail, and metadata).
147
+ article_title (str): The title of the article containing the relation.
148
+ article_publish_date (str): The publish date of the article.
149
+ """
150
+ # check on wikipedia
151
+ candidate_entities = [r["head"], r["tail"]]
152
+ entities = [self.get_wikipedia_data(ent) for ent in candidate_entities]
153
+
154
+ # if one entity does not exist, stop
155
+ if any(ent is None for ent in entities):
156
+ return
157
+
158
+ # manage new entities
159
+ for e in entities:
160
+ self.add_entity(e)
161
+
162
+ # rename relation entities with their wikipedia titles
163
+ r["head"] = entities[0]["title"]
164
+ r["tail"] = entities[1]["title"]
165
+
166
+ # add source if not in kb
167
+ article_url = list(r["meta"].keys())[0]
168
+ if article_url not in self.sources:
169
+ self.sources[article_url] = {
170
+ "article_title": article_title,
171
+ "article_publish_date": article_publish_date,
172
+ }
173
+
174
+ # manage new relation
175
+ if not self.exists_relation(r):
176
+ self.relations.append(r)
177
+ else:
178
+ self.merge_relations(r)
179
+
180
+ def print(self):
181
+ """
182
+ Print the entities, relations, and sources in the KB.
183
+
184
+ Returns:
185
+ None
186
+ """
187
+ print("Entities:")
188
+ for e in self.entities.items():
189
+ print(f" {e}")
190
+ print("Relations:")
191
+ for r in self.relations:
192
+ print(f" {r}")
193
+ print("Sources:")
194
+ for s in self.sources.items():
195
+ print(f" {s}")
196
+
197
+ @staticmethod
198
+ def extract_relations_from_model_output(text):
199
+ """
200
+ Extract relations from the model output text.
201
+
202
+ Args:
203
+ text (str): The model output text containing relations.
204
+
205
+ Returns:
206
+ list: A list of dictionaries, where each dictionary represents a relation (head, type, tail).
207
+ """
208
+ relations = []
209
+ relation, subject, relation, object_ = "", "", "", ""
210
+ text = text.strip()
211
+ current = "x"
212
+ text_replaced = text.replace("<s>", "").replace("<pad>", "").replace("</s>", "")
213
+ for token in text_replaced.split():
214
+ if token == "<triplet>":
215
+ current = "t"
216
+ if relation != "":
217
+ relations.append(
218
+ {
219
+ "head": subject.strip(),
220
+ "type": relation.strip(),
221
+ "tail": object_.strip(),
222
+ }
223
+ )
224
+ relation = ""
225
+ subject = ""
226
+ elif token == "<subj>":
227
+ current = "s"
228
+ if relation != "":
229
+ relations.append(
230
+ {
231
+ "head": subject.strip(),
232
+ "type": relation.strip(),
233
+ "tail": object_.strip(),
234
+ }
235
+ )
236
+ object_ = ""
237
+ elif token == "<obj>":
238
+ current = "o"
239
+ relation = ""
240
+ else:
241
+ if current == "t":
242
+ subject += " " + token
243
+ elif current == "s":
244
+ object_ += " " + token
245
+ elif current == "o":
246
+ relation += " " + token
247
+ if subject != "" and relation != "" and object_ != "":
248
+ relations.append(
249
+ {
250
+ "head": subject.strip(),
251
+ "type": relation.strip(),
252
+ "tail": object_.strip(),
253
+ }
254
+ )
255
+ return relations
256
+
257
+
258
+ class KGTripletExtractor:
259
+ """
260
+ A class to perform knowledge graph triplet extraction from text using a pre-trained model.
261
+
262
+ Methods:
263
+ text_to_wiki_kb(text, model=None, tokenizer=None, device='cpu', span_length=512,
264
+ article_title=None, article_publish_date=None, verbose=False):
265
+ Extract knowledge graph triplets from text and create a KnowledgeBase (KB) containing entities and relations.
266
+
267
+ """
268
+
269
+ @staticmethod
270
+ def text_to_wiki_kb(
271
+ text,
272
+ model=None,
273
+ tokenizer=None,
274
+ device="cpu",
275
+ span_length=512,
276
+ article_title=None,
277
+ article_publish_date=None,
278
+ verbose=False,
279
+ ):
280
+ from lionagi.integrations.bridge.transformers_.install_ import (
281
+ install_transformers,
282
+ )
283
+
284
+ try:
285
+ from transformers import AutoModelForSeq2SeqLM, AutoTokenizer # type: ignore
286
+ except ImportError:
287
+ install_transformers()
288
+ from transformers import AutoModelForSeq2SeqLM, AutoTokenizer # type: ignore
289
+ import torch # type: ignore
290
+
291
+ """
292
+ Extract knowledge graph triplets from text and create a KnowledgeBase (KB) containing entities and relations.
293
+
294
+ Args:
295
+ text (str): The input text from which triplets will be extracted.
296
+ model (AutoModelForSeq2SeqLM, optional): The pre-trained model for triplet extraction. Defaults to None.
297
+ tokenizer (AutoTokenizer, optional): The tokenizer for the model. Defaults to None.
298
+ device (str, optional): The device to run the model on (e.g., 'cpu', 'cuda'). Defaults to 'cpu'.
299
+ span_length (int, optional): The maximum span length for input text segmentation. Defaults to 512.
300
+ article_title (str, optional): The title of the article containing the input text. Defaults to None.
301
+ article_publish_date (str, optional): The publish date of the article. Defaults to None.
302
+ verbose (bool, optional): Whether to enable verbose mode for debugging. Defaults to False.
303
+
304
+ Returns:
305
+ KnowledgeBase: A KnowledgeBase (KB) containing extracted entities, relations, and sources.
306
+
307
+ """
308
+
309
+ if not any([model, tokenizer]):
310
+ tokenizer = AutoTokenizer.from_pretrained("Babelscape/rebel-large")
311
+ model = AutoModelForSeq2SeqLM.from_pretrained("Babelscape/rebel-large")
312
+ model.to(device)
313
+
314
+ inputs = tokenizer([text], return_tensors="pt")
315
+
316
+ num_tokens = len(inputs["input_ids"][0])
317
+ if verbose:
318
+ print(f"Input has {num_tokens} tokens")
319
+ num_spans = math.ceil(num_tokens / span_length)
320
+ if verbose:
321
+ print(f"Input has {num_spans} spans")
322
+ overlap = math.ceil(
323
+ (num_spans * span_length - num_tokens) / max(num_spans - 1, 1)
324
+ )
325
+ spans_boundaries = []
326
+ start = 0
327
+ for i in range(num_spans):
328
+ spans_boundaries.append(
329
+ [start + span_length * i, start + span_length * (i + 1)]
330
+ )
331
+ start -= overlap
332
+ if verbose:
333
+ print(f"Span boundaries are {spans_boundaries}")
334
+
335
+ # transform input with spans
336
+ tensor_ids = [
337
+ inputs["input_ids"][0][boundary[0] : boundary[1]]
338
+ for boundary in spans_boundaries
339
+ ]
340
+ tensor_masks = [
341
+ inputs["attention_mask"][0][boundary[0] : boundary[1]]
342
+ for boundary in spans_boundaries
343
+ ]
344
+
345
+ inputs = {
346
+ "input_ids": torch.stack(tensor_ids).to(device),
347
+ "attention_mask": torch.stack(tensor_masks).to(device),
348
+ }
349
+
350
+ # generate relations
351
+ num_return_sequences = 3
352
+ gen_kwargs = {
353
+ "max_length": 512,
354
+ "length_penalty": 0,
355
+ "num_beams": 3,
356
+ "num_return_sequences": num_return_sequences,
357
+ }
358
+ generated_tokens = model.generate(
359
+ **inputs,
360
+ **gen_kwargs,
361
+ )
362
+
363
+ # decode relations
364
+ decoded_preds = tokenizer.batch_decode(
365
+ generated_tokens, skip_special_tokens=False
366
+ )
367
+
368
+ # create kb
369
+ kb = KnowledgeBase()
370
+ i = 0
371
+ for sentence_pred in decoded_preds:
372
+ current_span_index = i // num_return_sequences
373
+ relations = KnowledgeBase.extract_relations_from_model_output(sentence_pred)
374
+ for relation in relations:
375
+ relation["meta"] = {
376
+ "article_url": {"spans": [spans_boundaries[current_span_index]]}
377
+ }
378
+ kb.add_relation(relation, article_title, article_publish_date)
379
+ i += 1
380
+ return kb
381
+
382
+
383
+ class KGraph:
384
+ """
385
+ A class representing a Knowledge Graph (KGraph) for extracting relations from text.
386
+
387
+ Methods:
388
+ text_to_wiki_kb(text, model=None, tokenizer=None, device='cpu', span_length=512, article_title=None,
389
+ article_publish_date=None, verbose=False):
390
+ Extract relations from input text and create a Knowledge Base (KB) containing entities and relations.
391
+ """
392
+
393
+ @staticmethod
394
+ def text_to_wiki_kb(text, **kwargs):
395
+ """
396
+ Extract relations from input text and create a Knowledge Base (KB) containing entities and relations.
397
+
398
+ Args:
399
+ text (str): The input text from which relations are extracted.
400
+ **kwargs: Additional keyword arguments passed to the underlying extraction method.
401
+
402
+ Returns:
403
+ KnowledgeBase: A Knowledge Base (KB) containing entities and relations extracted from the input text.
404
+ """
405
+ return KGTripletExtractor.text_to_wiki_kb(text, **kwargs)
@@ -0,0 +1,101 @@
1
+ """
2
+ A class that manages asynchronous task processing with controlled concurrency.
3
+ """
4
+
5
+ from typing import Any, Callable
6
+ import asyncio
7
+ from lionagi.libs import func_call
8
+
9
+
10
+ class AsyncQueue:
11
+ """
12
+ This class handles the enqueueing and processing of tasks with a limit on
13
+ how many can run simultaneously, using an asyncio.Queue for task storage and
14
+ an asyncio.Semaphore to limit concurrency.
15
+
16
+ Attributes:
17
+ queue (asyncio.Queue): The queue to store tasks.
18
+ _stop_event (asyncio.Event): Event to signal processing should stop.
19
+ max_concurrent_tasks (int): Maximum number of tasks processed concurrently.
20
+ semaphore (asyncio.Semaphore): Controls concurrent access to task execution.
21
+ """
22
+
23
+ def __init__(self, max_concurrent_tasks=5):
24
+ """
25
+ Initializes the AsyncQueue with a concurrency limit.
26
+
27
+ Args:
28
+ max_concurrent_tasks (int): The maximum number of concurrent tasks
29
+ allowed. Default is 5.
30
+ """
31
+ self.queue = asyncio.Queue()
32
+ self._stop_event = asyncio.Event()
33
+ self.max_concurrent_tasks = max_concurrent_tasks
34
+ self.semaphore = asyncio.Semaphore(max_concurrent_tasks)
35
+
36
+ async def enqueue(self, input_: Any) -> None:
37
+ """
38
+ Enqueues an item to be processed asynchronously.
39
+
40
+ Args:
41
+ input_ (Any): The item to be enqueued.
42
+ """
43
+ await self.queue.put(input_)
44
+
45
+ async def dequeue(self) -> Any:
46
+ """
47
+ Dequeues an item for processing.
48
+
49
+ Returns:
50
+ Any: The dequeued item.
51
+ """
52
+ return await self.queue.get()
53
+
54
+ async def join(self) -> None:
55
+ """Waits for all items in the queue to be processed."""
56
+ await self.queue.join()
57
+
58
+ async def stop(self) -> None:
59
+ """Signals the queue to stop processing new items."""
60
+ self._stop_event.set()
61
+
62
+ def stopped(self) -> bool:
63
+ """
64
+ Checks if the stop signal has been issued.
65
+
66
+ Returns:
67
+ bool: True if the queue has been stopped, otherwise False.
68
+ """
69
+ return self._stop_event.is_set()
70
+
71
+ async def process_requests(self, func: Callable, retry_kwargs: dict = {}) -> None:
72
+ """
73
+ Processes tasks from the queue using the provided function with retries.
74
+
75
+ This method continuously processes tasks from the queue using the specified
76
+ function until a stop event is triggered. Handles concurrency using a
77
+ semaphore and manages task completion.
78
+
79
+ Args:
80
+ func (Callable): The function to process each task.
81
+ retry_kwargs (dict): Keyword arguments for retry behavior. Default is
82
+ an empty dictionary.
83
+ """
84
+ tasks = set()
85
+ while not self.stopped():
86
+ if len(tasks) >= self.max_concurrent_tasks:
87
+ _, done = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
88
+ tasks.difference_update(done)
89
+
90
+ async with self.semaphore:
91
+ input_ = await self.dequeue()
92
+ if input_ is None:
93
+ await self.stop()
94
+ break
95
+ task = asyncio.create_task(
96
+ func_call.rcall(func, input_, **retry_kwargs)
97
+ )
98
+ tasks.add(task)
99
+
100
+ if tasks:
101
+ await asyncio.wait(tasks)
@@ -0,0 +1,57 @@
1
+ import re
2
+
3
+
4
+ class BaseToken:
5
+ def __init__(self, type_, value):
6
+ self.type = type_
7
+ self.value = value
8
+
9
+ def __repr__(self):
10
+ return f"BaseDirectiveToken({self.type}, {self.value})"
11
+
12
+
13
+ class BaseTokenizer:
14
+ TOKEN_TYPES = {
15
+ "KEYWORD": r"\b(BEGIN|END|IF|ELSE|FOR|IN|TRY|EXCEPT|ENDIF|ENDFOR|ENDTRY|DO)\b",
16
+ "OPERATOR": r"(==|!=|>=|<=|>|<|&&|\|\||!)",
17
+ "FUNCTION_CALL": r"\b[a-zA-Z_][a-zA-Z0-9_]*\b\((.*?)\)",
18
+ "LITERAL": r'(\d+|\'.*?\'|".*?")',
19
+ "IDENTIFIER": r"\b[a-zA-Z_][a-zA-Z0-9_]*\b",
20
+ "PUNCTUATION": r"(;|,|\(|\))",
21
+ "WHITESPACE": r"\s+",
22
+ }
23
+
24
+ def __init__(self, script):
25
+ self.script = script
26
+ self.tokens = []
27
+ self.tokenize()
28
+
29
+ @property
30
+ def is_empty(self):
31
+ return self.tokens == []
32
+
33
+ def tokenize(self):
34
+ position = 0
35
+ while position < len(self.script):
36
+ match = None
37
+ for type_, pattern in self.TOKEN_TYPES.items():
38
+ regex = re.compile(pattern)
39
+ match = regex.match(self.script, position)
40
+ if match:
41
+ if type_ != "WHITESPACE": # Ignore whitespace
42
+ token = BaseToken(type_, match.group())
43
+ self.tokens.append(token)
44
+ position = match.end() # Move past the matched token
45
+ break
46
+ if not match: # No match found, unrecognized token
47
+ raise SyntaxError(f"Unexpected character: {self.script[position]}")
48
+ # break
49
+
50
+ def get_tokens(self):
51
+ if self.is_empty:
52
+ try:
53
+ self.tokenize()
54
+ except SyntaxError as e:
55
+ print(e)
56
+ return []
57
+ return self.tokens
lionagi/libs/sys_util.py CHANGED
@@ -272,7 +272,7 @@ class SysUtil:
272
272
  """
273
273
  try:
274
274
  if not SysUtil.is_package_installed(package_name):
275
- print("check")
275
+ # print("check")
276
276
  if attempt_install:
277
277
  logging.info(
278
278
  f"Package {package_name} not found. Attempting to install."
File without changes
File without changes
@@ -0,0 +1,20 @@
1
+ # task1 = task1 or """
2
+ # 1. read through the given functions, and try to understand what they do.
3
+ # 2. if any function appear undefined in the environment, define them according to given information
4
+ # 3. add a few test cases and check correctness
5
+ # """
6
+
7
+ # context = "codes to evaluate: "+ context
8
+
9
+ # task2 = task2 or f"""
10
+ # 1. validate correctness, and add 5-10 new functions using pure python
11
+ # 2. improve time/space complexity while preserving usage behavior
12
+ # 3. run to make sure correctness
13
+ # """
14
+
15
+ # task3 = task3 or f"""
16
+ # present the full implementation and save as: {filename}.txt
17
+ # 1. add typing and google format docstrings
18
+ # 2. add a couple examples in the docstrings
19
+ # 3. add unittests
20
+ # """