lionagi 0.0.306__py3-none-any.whl → 0.0.308__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lionagi/__init__.py +2 -5
- lionagi/core/__init__.py +7 -5
- lionagi/core/agent/__init__.py +3 -0
- lionagi/core/agent/base_agent.py +10 -12
- lionagi/core/branch/__init__.py +4 -0
- lionagi/core/branch/base_branch.py +81 -81
- lionagi/core/branch/branch.py +16 -28
- lionagi/core/branch/branch_flow_mixin.py +3 -7
- lionagi/core/branch/executable_branch.py +86 -56
- lionagi/core/branch/util.py +77 -162
- lionagi/core/{flow/direct → direct}/__init__.py +1 -1
- lionagi/core/{flow/direct/predict.py → direct/parallel_predict.py} +39 -17
- lionagi/core/direct/parallel_react.py +0 -0
- lionagi/core/direct/parallel_score.py +0 -0
- lionagi/core/direct/parallel_select.py +0 -0
- lionagi/core/direct/parallel_sentiment.py +0 -0
- lionagi/core/direct/predict.py +174 -0
- lionagi/core/{flow/direct → direct}/react.py +2 -2
- lionagi/core/{flow/direct → direct}/score.py +28 -23
- lionagi/core/{flow/direct → direct}/select.py +48 -45
- lionagi/core/direct/utils.py +83 -0
- lionagi/core/flow/monoflow/ReAct.py +6 -5
- lionagi/core/flow/monoflow/__init__.py +9 -0
- lionagi/core/flow/monoflow/chat.py +10 -10
- lionagi/core/flow/monoflow/chat_mixin.py +11 -10
- lionagi/core/flow/monoflow/followup.py +6 -5
- lionagi/core/flow/polyflow/__init__.py +1 -0
- lionagi/core/flow/polyflow/chat.py +15 -3
- lionagi/core/mail/mail_manager.py +18 -19
- lionagi/core/mail/schema.py +5 -4
- lionagi/core/messages/schema.py +18 -20
- lionagi/core/prompt/__init__.py +0 -0
- lionagi/core/prompt/prompt_template.py +0 -0
- lionagi/core/schema/__init__.py +2 -2
- lionagi/core/schema/action_node.py +11 -3
- lionagi/core/schema/base_mixin.py +56 -59
- lionagi/core/schema/base_node.py +34 -37
- lionagi/core/schema/condition.py +24 -0
- lionagi/core/schema/data_logger.py +96 -99
- lionagi/core/schema/data_node.py +19 -19
- lionagi/core/schema/prompt_template.py +0 -0
- lionagi/core/schema/structure.py +171 -169
- lionagi/core/session/__init__.py +1 -3
- lionagi/core/session/session.py +196 -214
- lionagi/core/tool/tool_manager.py +95 -103
- lionagi/integrations/__init__.py +1 -3
- lionagi/integrations/bridge/langchain_/documents.py +17 -18
- lionagi/integrations/bridge/langchain_/langchain_bridge.py +14 -14
- lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +22 -22
- lionagi/integrations/bridge/llamaindex_/node_parser.py +12 -12
- lionagi/integrations/bridge/llamaindex_/reader.py +11 -11
- lionagi/integrations/bridge/llamaindex_/textnode.py +7 -7
- lionagi/integrations/config/openrouter_configs.py +0 -1
- lionagi/integrations/provider/oai.py +26 -26
- lionagi/integrations/provider/services.py +38 -38
- lionagi/libs/__init__.py +34 -1
- lionagi/libs/ln_api.py +211 -221
- lionagi/libs/ln_async.py +53 -60
- lionagi/libs/ln_convert.py +118 -120
- lionagi/libs/ln_dataframe.py +32 -33
- lionagi/libs/ln_func_call.py +334 -342
- lionagi/libs/ln_nested.py +99 -107
- lionagi/libs/ln_parse.py +161 -165
- lionagi/libs/sys_util.py +52 -52
- lionagi/tests/test_core/test_session.py +254 -266
- lionagi/tests/test_core/test_session_base_util.py +299 -300
- lionagi/tests/test_core/test_tool_manager.py +70 -74
- lionagi/tests/test_libs/test_nested.py +2 -7
- lionagi/tests/test_libs/test_parse.py +2 -2
- lionagi/version.py +1 -1
- {lionagi-0.0.306.dist-info → lionagi-0.0.308.dist-info}/METADATA +4 -2
- lionagi-0.0.308.dist-info/RECORD +115 -0
- lionagi/core/flow/direct/utils.py +0 -43
- lionagi-0.0.306.dist-info/RECORD +0 -106
- /lionagi/core/{flow/direct → direct}/sentiment.py +0 -0
- {lionagi-0.0.306.dist-info → lionagi-0.0.308.dist-info}/LICENSE +0 -0
- {lionagi-0.0.306.dist-info → lionagi-0.0.308.dist-info}/WHEEL +0 -0
- {lionagi-0.0.306.dist-info → lionagi-0.0.308.dist-info}/top_level.txt +0 -0
lionagi/libs/ln_parse.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
import re
|
2
2
|
import inspect
|
3
|
+
import itertools
|
3
4
|
from collections.abc import Callable
|
4
5
|
from typing import Any
|
5
6
|
import numpy as np
|
6
7
|
import lionagi.libs.ln_convert as convert
|
7
8
|
|
8
|
-
|
9
9
|
md_json_char_map = {"\n": "\\n", "\r": "\\r", "\t": "\\t", '"': '\\"'}
|
10
10
|
|
11
11
|
|
@@ -20,35 +20,35 @@ class ParseUtil:
|
|
20
20
|
the string by appending necessary closing characters before retrying.
|
21
21
|
|
22
22
|
Args:
|
23
|
-
|
24
|
-
|
23
|
+
s (str): The JSON string to parse.
|
24
|
+
strict (bool, optional): If True, enforces strict JSON syntax. Defaults to False.
|
25
25
|
|
26
26
|
Returns:
|
27
|
-
|
27
|
+
The parsed JSON object, typically a dictionary or list.
|
28
28
|
|
29
29
|
Raises:
|
30
|
-
|
30
|
+
ValueError: If parsing fails even after attempting to correct the string.
|
31
31
|
|
32
32
|
Example:
|
33
|
-
|
34
|
-
|
33
|
+
>>> fuzzy_parse_json('{"name": "John", "age": 30, "city": "New York"')
|
34
|
+
{'name': 'John', 'age': 30, 'city': 'New York'}
|
35
35
|
"""
|
36
36
|
try:
|
37
37
|
return convert.to_dict(str_to_parse, strict=strict)
|
38
|
-
except:
|
38
|
+
except Exception:
|
39
39
|
fixed_s = ParseUtil.fix_json_string(str_to_parse)
|
40
40
|
try:
|
41
41
|
return convert.to_dict(fixed_s, strict=strict)
|
42
|
-
|
43
|
-
except:
|
42
|
+
|
43
|
+
except Exception:
|
44
44
|
try:
|
45
|
-
fixed_s = fixed_s.replace('
|
45
|
+
fixed_s = fixed_s.replace("'", '"')
|
46
46
|
return convert.to_dict(fixed_s, strict=strict)
|
47
|
-
|
47
|
+
|
48
48
|
except Exception as e:
|
49
49
|
raise ValueError(
|
50
50
|
f"Failed to parse JSON even after fixing attempts: {e}"
|
51
|
-
)
|
51
|
+
) from e
|
52
52
|
|
53
53
|
@staticmethod
|
54
54
|
def fix_json_string(str_to_parse: str) -> str:
|
@@ -76,17 +76,17 @@ class ParseUtil:
|
|
76
76
|
a default mapping is used.
|
77
77
|
|
78
78
|
Args:
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
79
|
+
value: The string to be escaped.
|
80
|
+
char_map: An optional dictionary mapping characters to their escaped versions.
|
81
|
+
If not provided, a default mapping that escapes newlines, carriage returns,
|
82
|
+
tabs, and double quotes is used.
|
83
83
|
|
84
84
|
Returns:
|
85
|
-
|
85
|
+
The escaped JSON string.
|
86
86
|
|
87
87
|
Examples:
|
88
|
-
|
89
|
-
|
88
|
+
>>> escape_chars_in_json('Line 1\nLine 2')
|
89
|
+
'Line 1\\nLine 2'
|
90
90
|
"""
|
91
91
|
|
92
92
|
def replacement(match):
|
@@ -114,22 +114,22 @@ class ParseUtil:
|
|
114
114
|
filtered by language. If a code block is found, it is parsed using the provided parser function.
|
115
115
|
|
116
116
|
Args:
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
117
|
+
str_to_parse: The Markdown content to search.
|
118
|
+
language: An optional language specifier for the code block. If provided,
|
119
|
+
only code blocks of this language are considered.
|
120
|
+
regex_pattern: An optional regular expression pattern to use for finding the code block.
|
121
|
+
If provided, it overrides the language parameter.
|
122
|
+
parser: A function to parse the extracted code block string.
|
123
123
|
|
124
124
|
Returns:
|
125
|
-
|
125
|
+
The result of parsing the code block with the provided parser function.
|
126
126
|
|
127
127
|
Raises:
|
128
|
-
|
128
|
+
ValueError: If no code block is found in the Markdown content.
|
129
129
|
|
130
130
|
Examples:
|
131
|
-
|
132
|
-
|
131
|
+
>>> extract_code_block('```python\\nprint("Hello, world!")\\n```', language='python', parser=lambda x: x)
|
132
|
+
'print("Hello, world!")'
|
133
133
|
"""
|
134
134
|
|
135
135
|
if language:
|
@@ -140,7 +140,7 @@ class ParseUtil:
|
|
140
140
|
match = re.search(regex_pattern, str_to_parse, re.DOTALL)
|
141
141
|
code_str = ""
|
142
142
|
if match:
|
143
|
-
code_str = match
|
143
|
+
code_str = match[1].strip()
|
144
144
|
else:
|
145
145
|
raise ValueError(
|
146
146
|
f"No {language or 'specified'} code block found in the Markdown content."
|
@@ -162,29 +162,28 @@ class ParseUtil:
|
|
162
162
|
Markdown string. It then optionally verifies that the parsed JSON object contains all expected keys.
|
163
163
|
|
164
164
|
Args:
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
165
|
+
str_to_parse: The Markdown content to parse.
|
166
|
+
expected_keys: An optional list of keys expected to be present in the parsed JSON object.
|
167
|
+
parser: An optional function to parse the extracted code block. If not provided,
|
168
|
+
`fuzzy_parse_json` is used with default settings.
|
169
169
|
|
170
170
|
Returns:
|
171
|
-
|
171
|
+
The parsed JSON object from the Markdown content.
|
172
172
|
|
173
173
|
Raises:
|
174
|
-
|
175
|
-
|
174
|
+
ValueError: If the JSON code block is missing, or if any of the expected keys are missing
|
175
|
+
from the parsed JSON object.
|
176
176
|
|
177
177
|
Examples:
|
178
|
-
|
179
|
-
|
178
|
+
>>> md_to_json('```json\\n{"key": "value"}\\n```', expected_keys=['key'])
|
179
|
+
{'key': 'value'}
|
180
180
|
"""
|
181
181
|
json_obj = ParseUtil.extract_code_block(
|
182
182
|
str_to_parse, language="json", parser=parser or ParseUtil.fuzzy_parse_json
|
183
183
|
)
|
184
184
|
|
185
185
|
if expected_keys:
|
186
|
-
missing_keys
|
187
|
-
if missing_keys:
|
186
|
+
if missing_keys := [key for key in expected_keys if key not in json_obj]:
|
188
187
|
raise ValueError(
|
189
188
|
f"Missing expected keys in JSON object: {', '.join(missing_keys)}"
|
190
189
|
)
|
@@ -198,26 +197,26 @@ class ParseUtil:
|
|
198
197
|
docstring following the Google style format.
|
199
198
|
|
200
199
|
Args:
|
201
|
-
|
200
|
+
func (Callable): The function from which to extract docstring details.
|
202
201
|
|
203
202
|
Returns:
|
204
|
-
|
205
|
-
|
203
|
+
Tuple[str, Dict[str, str]]: A tuple containing the function description
|
204
|
+
and a dictionary with parameter names as keys and their descriptions as values.
|
206
205
|
|
207
206
|
Examples:
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
207
|
+
>>> def example_function(param1: int, param2: str):
|
208
|
+
... '''Example function.
|
209
|
+
...
|
210
|
+
... Args:
|
211
|
+
... param1 (int): The first parameter.
|
212
|
+
... param2 (str): The second parameter.
|
213
|
+
... '''
|
214
|
+
... pass
|
215
|
+
>>> description, params = _extract_docstring_details_google(example_function)
|
216
|
+
>>> description
|
217
|
+
'Example function.'
|
218
|
+
>>> params == {'param1': 'The first parameter.', 'param2': 'The second parameter.'}
|
219
|
+
True
|
221
220
|
"""
|
222
221
|
docstring = inspect.getdoc(func)
|
223
222
|
if not docstring:
|
@@ -225,19 +224,21 @@ class ParseUtil:
|
|
225
224
|
lines = docstring.split("\n")
|
226
225
|
func_description = lines[0].strip()
|
227
226
|
|
228
|
-
param_start_pos = 0
|
229
227
|
lines_len = len(lines)
|
230
228
|
|
231
229
|
params_description = {}
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
230
|
+
param_start_pos = next(
|
231
|
+
(
|
232
|
+
i + 1
|
233
|
+
for i in range(1, lines_len)
|
234
|
+
if (
|
235
|
+
lines[i].startswith("Args")
|
236
|
+
or lines[i].startswith("Arguments")
|
237
|
+
or lines[i].startswith("Parameters")
|
238
|
+
)
|
239
|
+
),
|
240
|
+
0,
|
241
|
+
)
|
241
242
|
current_param = None
|
242
243
|
for i in range(param_start_pos, lines_len):
|
243
244
|
if lines[i] == "":
|
@@ -245,7 +246,7 @@ class ParseUtil:
|
|
245
246
|
elif lines[i].startswith(" "):
|
246
247
|
param_desc = lines[i].split(":", 1)
|
247
248
|
if len(param_desc) == 1:
|
248
|
-
params_description[current_param] += "
|
249
|
+
params_description[current_param] += f" {param_desc[0].strip()}"
|
249
250
|
continue
|
250
251
|
param, desc = param_desc
|
251
252
|
param = param.split("(")[0].strip()
|
@@ -262,27 +263,27 @@ class ParseUtil:
|
|
262
263
|
docstring following the reStructuredText (reST) style format.
|
263
264
|
|
264
265
|
Args:
|
265
|
-
|
266
|
+
func (Callable): The function from which to extract docstring details.
|
266
267
|
|
267
268
|
Returns:
|
268
|
-
|
269
|
-
|
269
|
+
Tuple[str, Dict[str, str]]: A tuple containing the function description
|
270
|
+
and a dictionary with parameter names as keys and their descriptions as values.
|
270
271
|
|
271
272
|
Examples:
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
273
|
+
>>> def example_function(param1: int, param2: str):
|
274
|
+
... '''Example function.
|
275
|
+
...
|
276
|
+
... :param param1: The first parameter.
|
277
|
+
... :type param1: int
|
278
|
+
... :param param2: The second parameter.
|
279
|
+
... :type param2: str
|
280
|
+
... '''
|
281
|
+
... pass
|
282
|
+
>>> description, params = _extract_docstring_details_rest(example_function)
|
283
|
+
>>> description
|
284
|
+
'Example function.'
|
285
|
+
>>> params == {'param1': 'The first parameter.', 'param2': 'The second parameter.'}
|
286
|
+
True
|
286
287
|
"""
|
287
288
|
docstring = inspect.getdoc(func)
|
288
289
|
if not docstring:
|
@@ -301,7 +302,7 @@ class ParseUtil:
|
|
301
302
|
params_description[param] = desc.strip()
|
302
303
|
current_param = param
|
303
304
|
elif line.startswith(" "):
|
304
|
-
params_description[current_param] += " "
|
305
|
+
params_description[current_param] += f" {line}"
|
305
306
|
|
306
307
|
return func_description, params_description
|
307
308
|
|
@@ -313,30 +314,30 @@ class ParseUtil:
|
|
313
314
|
(reST) style format.
|
314
315
|
|
315
316
|
Args:
|
316
|
-
|
317
|
-
|
317
|
+
func (Callable): The function from which to extract docstring details.
|
318
|
+
style (str): The style of docstring to parse ('google' or 'reST').
|
318
319
|
|
319
320
|
Returns:
|
320
|
-
|
321
|
-
|
321
|
+
Tuple[str, Dict[str, str]]: A tuple containing the function description
|
322
|
+
and a dictionary with parameter names as keys and their descriptions as values.
|
322
323
|
|
323
324
|
Raises:
|
324
|
-
|
325
|
+
ValueError: If an unsupported style is provided.
|
325
326
|
|
326
327
|
Examples:
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
328
|
+
>>> def example_function(param1: int, param2: str):
|
329
|
+
... '''Example function.
|
330
|
+
...
|
331
|
+
... Args:
|
332
|
+
... param1 (int): The first parameter.
|
333
|
+
... param2 (str): The second parameter.
|
334
|
+
... '''
|
335
|
+
... pass
|
336
|
+
>>> description, params = _extract_docstring_details(example_function, style='google')
|
337
|
+
>>> description
|
338
|
+
'Example function.'
|
339
|
+
>>> params == {'param1': 'The first parameter.', 'param2': 'The second parameter.'}
|
340
|
+
True
|
340
341
|
"""
|
341
342
|
if style == "google":
|
342
343
|
func_description, params_description = (
|
@@ -358,16 +359,16 @@ class ParseUtil:
|
|
358
359
|
Converts a Python type to its JSON type equivalent.
|
359
360
|
|
360
361
|
Args:
|
361
|
-
|
362
|
+
py_type (str): The name of the Python type.
|
362
363
|
|
363
364
|
Returns:
|
364
|
-
|
365
|
+
str: The corresponding JSON type.
|
365
366
|
|
366
367
|
Examples:
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
368
|
+
>>> _python_to_json_type('str')
|
369
|
+
'string'
|
370
|
+
>>> _python_to_json_type('int')
|
371
|
+
'number'
|
371
372
|
"""
|
372
373
|
type_mapping = {
|
373
374
|
"str": "string",
|
@@ -387,24 +388,24 @@ class ParseUtil:
|
|
387
388
|
docstrings. The schema includes the function's name, description, and parameters.
|
388
389
|
|
389
390
|
Args:
|
390
|
-
|
391
|
-
|
391
|
+
func (Callable): The function to generate a schema for.
|
392
|
+
style (str): The docstring format ('google' or 'reST').
|
392
393
|
|
393
394
|
Returns:
|
394
|
-
|
395
|
+
Dict[str, Any]: A schema describing the function.
|
395
396
|
|
396
397
|
Examples:
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
398
|
+
>>> def example_function(param1: int, param2: str) -> bool:
|
399
|
+
... '''Example function.
|
400
|
+
...
|
401
|
+
... Args:
|
402
|
+
... param1 (int): The first parameter.
|
403
|
+
... param2 (str): The second parameter.
|
404
|
+
... '''
|
405
|
+
... return True
|
406
|
+
>>> schema = _func_to_schema(example_function)
|
407
|
+
>>> schema['function']['name']
|
408
|
+
'example_function'
|
408
409
|
"""
|
409
410
|
# Extracting function name and docstring details
|
410
411
|
func_name = func.__name__
|
@@ -438,8 +439,7 @@ class ParseUtil:
|
|
438
439
|
"description": param_description,
|
439
440
|
}
|
440
441
|
|
441
|
-
|
442
|
-
schema = {
|
442
|
+
return {
|
443
443
|
"type": "function",
|
444
444
|
"function": {
|
445
445
|
"name": func_name,
|
@@ -448,8 +448,6 @@ class ParseUtil:
|
|
448
448
|
},
|
449
449
|
}
|
450
450
|
|
451
|
-
return schema
|
452
|
-
|
453
451
|
|
454
452
|
class StringMatch:
|
455
453
|
|
@@ -463,16 +461,16 @@ class StringMatch:
|
|
463
461
|
and 1 is an exact match.
|
464
462
|
|
465
463
|
Args:
|
466
|
-
|
467
|
-
|
464
|
+
s: The first string to compare.
|
465
|
+
t: The second string to compare.
|
468
466
|
|
469
467
|
Returns:
|
470
|
-
|
471
|
-
|
468
|
+
A float representing the Jaro distance between the two strings, ranging from 0 to 1,
|
469
|
+
where 1 means the strings are identical.
|
472
470
|
|
473
471
|
Examples:
|
474
|
-
|
475
|
-
|
472
|
+
>>> jaro_distance("martha", "marhta")
|
473
|
+
0.9444444444444445
|
476
474
|
"""
|
477
475
|
s_len = len(s)
|
478
476
|
t_len = len(t)
|
@@ -527,18 +525,18 @@ class StringMatch:
|
|
527
525
|
person names, and is designed to improve the scoring of strings that have a common prefix.
|
528
526
|
|
529
527
|
Args:
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
528
|
+
s: The first string to compare.
|
529
|
+
t: The second string to compare.
|
530
|
+
scaling: The scaling factor for how much the score is adjusted upwards for having common prefixes.
|
531
|
+
The scaling factor should be less than 1, and a typical value is 0.1.
|
534
532
|
|
535
533
|
Returns:
|
536
|
-
|
537
|
-
|
534
|
+
A float representing the Jaro-Winkler similarity between the two strings, ranging from 0 to 1,
|
535
|
+
where 1 means the strings are identical.
|
538
536
|
|
539
537
|
Examples:
|
540
|
-
|
541
|
-
|
538
|
+
>>> jaro_winkler_similarity("dixon", "dicksonx")
|
539
|
+
0.8133333333333332
|
542
540
|
"""
|
543
541
|
jaro_sim = StringMatch.jaro_distance(s, t)
|
544
542
|
prefix_len = 0
|
@@ -561,15 +559,15 @@ class StringMatch:
|
|
561
559
|
required to change one word into the other. Each operation has an equal cost.
|
562
560
|
|
563
561
|
Args:
|
564
|
-
|
565
|
-
|
562
|
+
a: The first string to compare.
|
563
|
+
b: The second string to compare.
|
566
564
|
|
567
565
|
Returns:
|
568
|
-
|
566
|
+
An integer representing the Levenshtein distance between the two strings.
|
569
567
|
|
570
568
|
Examples:
|
571
|
-
|
572
|
-
|
569
|
+
>>> levenshtein_distance("kitten", "sitting")
|
570
|
+
3
|
573
571
|
"""
|
574
572
|
m, n = len(a), len(b)
|
575
573
|
# Initialize 2D array (m+1) x (n+1)
|
@@ -582,17 +580,13 @@ class StringMatch:
|
|
582
580
|
d[0][j] = j
|
583
581
|
|
584
582
|
# Compute the distance
|
585
|
-
for i in range(1, m + 1):
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
d[i - 1][j] + 1, # deletion
|
593
|
-
d[i][j - 1] + 1, # insertion
|
594
|
-
d[i - 1][j - 1] + cost,
|
595
|
-
) # substitution
|
583
|
+
for i, j in itertools.product(range(1, m + 1), range(1, n + 1)):
|
584
|
+
cost = 0 if a[i - 1] == b[j - 1] else 1
|
585
|
+
d[i][j] = min(
|
586
|
+
d[i - 1][j] + 1, # deletion
|
587
|
+
d[i][j - 1] + 1, # insertion
|
588
|
+
d[i - 1][j - 1] + cost,
|
589
|
+
) # substitution
|
596
590
|
return d[m][n]
|
597
591
|
|
598
592
|
@staticmethod
|
@@ -632,12 +626,14 @@ class StringMatch:
|
|
632
626
|
|
633
627
|
if score_func is None:
|
634
628
|
score_func = StringMatch.jaro_winkler_similarity
|
635
|
-
|
629
|
+
|
636
630
|
# Calculate Jaro-Winkler similarity scores for each potential match
|
637
|
-
scores = np.array(
|
631
|
+
scores = np.array(
|
632
|
+
[
|
633
|
+
score_func(convert.to_str(word), correct_word)
|
634
|
+
for correct_word in correct_words_list
|
635
|
+
]
|
636
|
+
)
|
638
637
|
# Find the index of the highest score
|
639
638
|
max_score_index = np.argmax(scores)
|
640
|
-
|
641
|
-
best_match = correct_words_list[max_score_index]
|
642
|
-
|
643
|
-
return best_match
|
639
|
+
return correct_words_list[max_score_index]
|