ai-microcore 4.0.0.dev3__tar.gz → 4.0.0.dev5__tar.gz
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.
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/PKG-INFO +1 -1
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/__init__.py +1 -1
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/_env.py +8 -4
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/_llm_functions.py +66 -5
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/ai_func/__init__.py +1 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/configuration.py +13 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/embedding_db/__init__.py +1 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/file_storage.py +1 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/json_parsing.py +1 -1
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/_openai_llm_v0.py +1 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/anthropic.py +9 -1
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/local_transformers.py +1 -1
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/shared.py +1 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/text2speech/elevenlabs.py +30 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/tokenizing.py +2 -1
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/types.py +3 -2
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/utils.py +4 -4
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/wrappers/llm_response_wrapper.py +20 -2
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/LICENSE +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/README.md +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/_prepare_llm_args.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/ai_func/ai-func.json.j2 +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/ai_func/ai-func.pythonic.j2 +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/ai_modules.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/embedding_db/chromadb.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/__init__.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/_openai_llm_v1.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/google_genai.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/google_vertex_ai.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/local_llm.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/llm/openai_llm.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/logging.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/message_types.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/metrics.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/python.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/templating/__init__.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/templating/jinja2.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/ui.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/wrappers/__init__.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/wrappers/prompt_wrapper.py +0 -0
- {ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-microcore
|
|
3
|
-
Version: 4.0.0.
|
|
3
|
+
Version: 4.0.0.dev5
|
|
4
4
|
Summary: # Minimalistic Foundation for AI Applications
|
|
5
5
|
Keywords: llm,large language models,ai,similarity search,ai search,gpt,openai
|
|
6
6
|
Author-email: Vitalii Stepanenko <mail@vitalii.in>
|
|
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
|
|
6
6
|
import jinja2
|
|
7
7
|
|
|
8
8
|
from .embedding_db import AbstractEmbeddingDB
|
|
9
|
-
from .configuration import Config, ApiType, LLMConfigError
|
|
9
|
+
from .configuration import Config, ApiType, LLMConfigError, EmbeddingDbType
|
|
10
10
|
from .types import TplFunctionType, LLMAsyncFunctionType, LLMFunctionType
|
|
11
11
|
from .templating.jinja2 import make_jinja2_env, make_tpl_function
|
|
12
12
|
from .llm.openai_llm import make_llm_functions as make_openai_llm_functions
|
|
@@ -14,6 +14,7 @@ from .llm.local_llm import make_llm_functions as make_local_llm_functions
|
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from .wrappers.llm_response_wrapper import LLMResponse # noqa: F401
|
|
17
|
+
from transformers import PreTrainedModel, PreTrainedTokenizer # noqa: F401
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
@dataclass
|
|
@@ -26,10 +27,10 @@ class Env:
|
|
|
26
27
|
llm_before_handlers: list[callable] = field(default_factory=list)
|
|
27
28
|
llm_after_handlers: list[callable] = field(default_factory=list)
|
|
28
29
|
texts: AbstractEmbeddingDB = None
|
|
29
|
-
model: "
|
|
30
|
+
model: "PreTrainedModel" = field(
|
|
30
31
|
default=None, init=False, repr=False
|
|
31
32
|
) # noqa
|
|
32
|
-
tokenizer: "
|
|
33
|
+
tokenizer: "PreTrainedTokenizer" = field( # noqa
|
|
33
34
|
default=None, init=False, repr=False
|
|
34
35
|
)
|
|
35
36
|
|
|
@@ -134,7 +135,10 @@ class Env:
|
|
|
134
135
|
)
|
|
135
136
|
|
|
136
137
|
def init_similarity_search(self):
|
|
137
|
-
if
|
|
138
|
+
if (
|
|
139
|
+
self.config.EMBEDDING_DB_TYPE == EmbeddingDbType.CHROMA
|
|
140
|
+
and find_spec("chromadb") is not None
|
|
141
|
+
):
|
|
138
142
|
from .embedding_db.chromadb import ChromaEmbeddingDB
|
|
139
143
|
|
|
140
144
|
self.texts = ChromaEmbeddingDB(self.config)
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from datetime import datetime
|
|
2
3
|
|
|
3
4
|
from .utils import run_parallel
|
|
4
|
-
from .wrappers.llm_response_wrapper import LLMResponse
|
|
5
|
+
from .wrappers.llm_response_wrapper import LLMResponse, DictFromLLMResponse
|
|
5
6
|
from .types import TPrompt
|
|
6
7
|
from ._env import env
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
def llm(
|
|
10
|
+
def llm(
|
|
11
|
+
prompt: TPrompt,
|
|
12
|
+
retries: int = 0,
|
|
13
|
+
parse_json: bool | dict = False,
|
|
14
|
+
**kwargs
|
|
15
|
+
) -> str | LLMResponse:
|
|
10
16
|
"""
|
|
11
17
|
Request Large Language Model synchronously
|
|
12
18
|
|
|
13
19
|
Args:
|
|
14
20
|
prompt (str | Msg | dict | list[str | Msg | dict]): Text to send to LLM
|
|
21
|
+
retries (int): Number of retries in case of error
|
|
22
|
+
parse_json (bool|dict):
|
|
23
|
+
If True, parses response as JSON,
|
|
24
|
+
alternatively non-empty dict can be used as parse_json arguments
|
|
15
25
|
**kwargs (dict): Parameters supported by the LLM API
|
|
16
26
|
|
|
17
27
|
See parameters supported by the OpenAI:
|
|
@@ -40,7 +50,18 @@ def llm(prompt: TPrompt, **kwargs) -> str | LLMResponse:
|
|
|
40
50
|
"""
|
|
41
51
|
[h(prompt, **kwargs) for h in env().llm_before_handlers]
|
|
42
52
|
start = datetime.now()
|
|
43
|
-
|
|
53
|
+
tries = retries + 1
|
|
54
|
+
while tries > 0:
|
|
55
|
+
try:
|
|
56
|
+
tries -= 1
|
|
57
|
+
response = env().llm_function(prompt, **kwargs)
|
|
58
|
+
break
|
|
59
|
+
except Exception as e:
|
|
60
|
+
if tries == 0:
|
|
61
|
+
raise e
|
|
62
|
+
logging.error(f"LLM error: {e}")
|
|
63
|
+
logging.info(f"Retrying... {tries} retries left")
|
|
64
|
+
continue
|
|
44
65
|
try:
|
|
45
66
|
response.gen_duration = (datetime.now() - start).total_seconds()
|
|
46
67
|
if not env().config.SAVE_MEMORY:
|
|
@@ -48,15 +69,35 @@ def llm(prompt: TPrompt, **kwargs) -> str | LLMResponse:
|
|
|
48
69
|
except AttributeError:
|
|
49
70
|
...
|
|
50
71
|
[h(response) for h in env().llm_after_handlers]
|
|
72
|
+
if tries > 0:
|
|
73
|
+
retry_params = dict(**kwargs)
|
|
74
|
+
retry_params["retries"] = tries - 1
|
|
75
|
+
setattr(
|
|
76
|
+
response,
|
|
77
|
+
"_retry_callback",
|
|
78
|
+
lambda: llm(prompt, **retry_params)
|
|
79
|
+
)
|
|
80
|
+
if parse_json:
|
|
81
|
+
parsing_params = parse_json if isinstance(parse_json, dict) else {}
|
|
82
|
+
return response.parse_json(**parsing_params)
|
|
51
83
|
return response
|
|
52
84
|
|
|
53
85
|
|
|
54
|
-
async def allm(
|
|
86
|
+
async def allm(
|
|
87
|
+
prompt: TPrompt,
|
|
88
|
+
retries: int = 0,
|
|
89
|
+
parse_json: bool | dict = False,
|
|
90
|
+
**kwargs
|
|
91
|
+
) -> str | LLMResponse | DictFromLLMResponse:
|
|
55
92
|
"""
|
|
56
93
|
Request Large Language Model asynchronously
|
|
57
94
|
|
|
58
95
|
Args:
|
|
59
96
|
prompt (str | Msg | dict | list[str | Msg | dict]): Text to send to LLM
|
|
97
|
+
retries (int): Number of retries in case of error
|
|
98
|
+
parse_json (bool|dict):
|
|
99
|
+
If True, parses response as JSON,
|
|
100
|
+
alternatively non-empty dict can be used as parse_json arguments
|
|
60
101
|
**kwargs (dict): Parameters supported by the LLM API
|
|
61
102
|
|
|
62
103
|
See parameters supported by the OpenAI:
|
|
@@ -87,7 +128,18 @@ async def allm(prompt: TPrompt, **kwargs) -> str | LLMResponse:
|
|
|
87
128
|
"""
|
|
88
129
|
[h(prompt, **kwargs) for h in env().llm_before_handlers]
|
|
89
130
|
start = datetime.now()
|
|
90
|
-
|
|
131
|
+
tries = retries + 1
|
|
132
|
+
while tries > 0:
|
|
133
|
+
try:
|
|
134
|
+
tries -= 1
|
|
135
|
+
response = await env().llm_async_function(prompt, **kwargs)
|
|
136
|
+
break
|
|
137
|
+
except Exception as e:
|
|
138
|
+
if tries == 0:
|
|
139
|
+
raise e
|
|
140
|
+
logging.error(f"LLM error: {e}")
|
|
141
|
+
logging.info(f"Retrying... {tries} retries left")
|
|
142
|
+
continue
|
|
91
143
|
try:
|
|
92
144
|
response.gen_duration = (datetime.now() - start).total_seconds()
|
|
93
145
|
if not env().config.SAVE_MEMORY:
|
|
@@ -95,6 +147,15 @@ async def allm(prompt: TPrompt, **kwargs) -> str | LLMResponse:
|
|
|
95
147
|
except AttributeError:
|
|
96
148
|
...
|
|
97
149
|
[h(response) for h in env().llm_after_handlers]
|
|
150
|
+
if parse_json:
|
|
151
|
+
try:
|
|
152
|
+
parsing_params = parse_json if isinstance(parse_json, dict) else {}
|
|
153
|
+
return response.parse_json(**parsing_params)
|
|
154
|
+
except Exception as e:
|
|
155
|
+
if tries > 0:
|
|
156
|
+
logging.error(f"LLM error: {e}")
|
|
157
|
+
logging.info(f"Retrying... {tries} retries left")
|
|
158
|
+
return await allm(prompt, retries=tries - 1, parse_json=parse_json, **kwargs)
|
|
98
159
|
return response
|
|
99
160
|
|
|
100
161
|
|
|
@@ -78,6 +78,17 @@ class ApiType(str, Enum):
|
|
|
78
78
|
def is_local(api_type: str) -> bool:
|
|
79
79
|
return api_type in (ApiType.FUNCTION, ApiType.TRANSFORMERS, ApiType.NONE)
|
|
80
80
|
|
|
81
|
+
def __str__(self):
|
|
82
|
+
return self.value
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class EmbeddingDbType(str, Enum):
|
|
86
|
+
CHROMA = "chroma"
|
|
87
|
+
NONE = ""
|
|
88
|
+
|
|
89
|
+
def __str__(self):
|
|
90
|
+
return self.value
|
|
91
|
+
|
|
81
92
|
|
|
82
93
|
_default_dotenv_loaded = False
|
|
83
94
|
|
|
@@ -373,6 +384,8 @@ class Config(LLMConfig):
|
|
|
373
384
|
|
|
374
385
|
EMBEDDING_DB_PORT: str = from_env(default=None)
|
|
375
386
|
|
|
387
|
+
EMBEDDING_DB_TYPE: str = from_env(EmbeddingDbType.CHROMA)
|
|
388
|
+
|
|
376
389
|
DEFAULT_ENCODING: str = from_env("utf-8")
|
|
377
390
|
"""Used in file system operations, utf-8 by default"""
|
|
378
391
|
|
|
@@ -9,6 +9,7 @@ from ..wrappers.llm_response_wrapper import LLMResponse
|
|
|
9
9
|
from ..utils import is_chat_model
|
|
10
10
|
from .shared import prepare_callbacks
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
def _get_chunk_text(chunk, mode_chat_model: bool):
|
|
13
14
|
# Azure API gives first chunk with empty choices
|
|
14
15
|
choice = chunk.choices[0] if len(chunk.choices) else {}
|
|
@@ -9,6 +9,7 @@ from ..types import LLMAsyncFunctionType, LLMFunctionType
|
|
|
9
9
|
from ..wrappers.llm_response_wrapper import LLMResponse
|
|
10
10
|
from .shared import prepare_callbacks
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
def _get_chunk_text(chunk):
|
|
13
14
|
return isinstance(chunk, ContentBlockDeltaEvent) and chunk.delta.text or ""
|
|
14
15
|
|
|
@@ -36,8 +37,15 @@ def _process_streamed_response(response, callbacks: list[callable]):
|
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
def _prepare_llm_arguments(config: Config, kwargs: dict):
|
|
39
|
-
args = {
|
|
40
|
+
args = {**config.LLM_DEFAULT_ARGS, **kwargs}
|
|
40
41
|
args["model"] = args.get("model", config.MODEL)
|
|
42
|
+
if "max_tokens" not in args:
|
|
43
|
+
if "claude-3-5-sonnet" in args["model"]:
|
|
44
|
+
args["max_tokens"] = 8192
|
|
45
|
+
elif "claude-3-7-sonnet" in args["model"]:
|
|
46
|
+
args["max_tokens"] = 16384
|
|
47
|
+
else:
|
|
48
|
+
args["max_tokens"] = 4096
|
|
41
49
|
args.pop("seed", None) # Not supported by Anthropic
|
|
42
50
|
callbacks = prepare_callbacks(config, args)
|
|
43
51
|
return args, {"callbacks": callbacks}
|
|
@@ -16,7 +16,7 @@ def inference(prompt: str, model, tokenizer, **kwargs):
|
|
|
16
16
|
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
|
17
17
|
outputs = model.generate(**inputs, **kwargs)
|
|
18
18
|
outputs = [
|
|
19
|
-
tokenizer.decode(i[len(inputs[0])
|
|
19
|
+
tokenizer.decode(i[len(inputs[0]):], skip_special_tokens=skip_special_tokens)
|
|
20
20
|
for i in outputs
|
|
21
21
|
]
|
|
22
22
|
return LLMResponse(outputs[0], dict(all=outputs))
|
|
@@ -13,6 +13,7 @@ def make_remove_hidden_output(config: Config) -> callable:
|
|
|
13
13
|
|
|
14
14
|
return remove_hidden_output
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
def prepare_callbacks(config: Config, args, set_stream: bool = True) -> list[callable]:
|
|
17
18
|
callbacks = args.pop("callbacks", []) or [] + config.CALLBACKS or []
|
|
18
19
|
if "callback" in args:
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from dataclasses import dataclass, asdict
|
|
2
3
|
from datetime import datetime
|
|
3
4
|
import aiohttp
|
|
4
5
|
from .._env import env
|
|
5
6
|
|
|
6
7
|
|
|
8
|
+
@dataclass
|
|
9
|
+
class TTSArgs:
|
|
10
|
+
text: str
|
|
11
|
+
out_file: str = None
|
|
12
|
+
voice: str = "D38z5RcWu1voky8WS1ja"
|
|
13
|
+
stability: float = 0.29
|
|
14
|
+
similarity_boost: float = 0.5
|
|
15
|
+
style: float = 0.0
|
|
16
|
+
chunk_size: int = 1024
|
|
17
|
+
speed: float = 1.0
|
|
18
|
+
use_speaker_boost: bool = False
|
|
19
|
+
previous_text: str = None
|
|
20
|
+
next_text: str = None
|
|
21
|
+
|
|
22
|
+
def to_dict(self) -> dict:
|
|
23
|
+
return asdict(self)
|
|
24
|
+
|
|
25
|
+
|
|
7
26
|
async def text_to_speech(
|
|
8
27
|
text: str,
|
|
9
28
|
out_file: str = None,
|
|
@@ -12,6 +31,10 @@ async def text_to_speech(
|
|
|
12
31
|
similarity_boost=0.5,
|
|
13
32
|
style=0.0,
|
|
14
33
|
chunk_size=1024,
|
|
34
|
+
speed=1.0,
|
|
35
|
+
use_speaker_boost: bool = False,
|
|
36
|
+
previous_text: str = None,
|
|
37
|
+
next_text: str = None,
|
|
15
38
|
) -> str:
|
|
16
39
|
url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice}"
|
|
17
40
|
if not out_file:
|
|
@@ -25,8 +48,15 @@ async def text_to_speech(
|
|
|
25
48
|
"stability": stability,
|
|
26
49
|
"similarity_boost": similarity_boost,
|
|
27
50
|
"style": style,
|
|
51
|
+
"speed": speed,
|
|
28
52
|
},
|
|
29
53
|
}
|
|
54
|
+
if use_speaker_boost:
|
|
55
|
+
data["voice_settings"]["use_speaker_boost"] = use_speaker_boost
|
|
56
|
+
if previous_text:
|
|
57
|
+
data["previous_text"] = previous_text
|
|
58
|
+
if next_text:
|
|
59
|
+
data["next_text"] = next_text
|
|
30
60
|
headers = {
|
|
31
61
|
"Accept": "audio/mpeg",
|
|
32
62
|
"Content-Type": "application/json",
|
|
@@ -5,6 +5,7 @@ from .message_types import Msg
|
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
7
|
from .wrappers.prompt_wrapper import PromptWrapper # noqa: F401
|
|
8
|
+
from .wrappers.llm_response_wrapper import LLMResponse # noqa: F401
|
|
8
9
|
|
|
9
10
|
TPrompt = Union[
|
|
10
11
|
dict, Msg, str, "PromptWrapper", List[Union[dict, Msg, str, "PromptWrapper"]]
|
|
@@ -12,9 +13,9 @@ TPrompt = Union[
|
|
|
12
13
|
"""Type for prompt argument in LLM requests"""
|
|
13
14
|
TplFunctionType = Callable[[Union[PathLike[str], str], Any], str]
|
|
14
15
|
"""Function type for rendering prompt templates"""
|
|
15
|
-
LLMFunctionType = Callable[[TPrompt, Any],
|
|
16
|
+
LLMFunctionType = Callable[[TPrompt, Any], "LLMResponse"]
|
|
16
17
|
"""Function type for requesting LLM synchronously"""
|
|
17
|
-
LLMAsyncFunctionType = Callable[[TPrompt, Any], Awaitable[
|
|
18
|
+
LLMAsyncFunctionType = Callable[[TPrompt, Any], Awaitable["LLMResponse"]]
|
|
18
19
|
"""Function type for requesting LLM asynchronously"""
|
|
19
20
|
|
|
20
21
|
|
|
@@ -412,9 +412,9 @@ def levenshtein(a: str, b: str) -> int:
|
|
|
412
412
|
cost = 0 if ch_a == ch_b else 1
|
|
413
413
|
current.append(
|
|
414
414
|
min(
|
|
415
|
-
current[-1] + 1,
|
|
416
|
-
previous[j] + 1,
|
|
417
|
-
previous[j - 1] + cost
|
|
415
|
+
current[-1] + 1, # insertion
|
|
416
|
+
previous[j] + 1, # deletion
|
|
417
|
+
previous[j - 1] + cost # substitution
|
|
418
418
|
)
|
|
419
419
|
)
|
|
420
420
|
previous = current
|
|
@@ -458,4 +458,4 @@ def most_similar(
|
|
|
458
458
|
min_dist = dist
|
|
459
459
|
most_similar_word = word
|
|
460
460
|
|
|
461
|
-
return most_similar_word, min_dist
|
|
461
|
+
return most_similar_word, min_dist
|
{ai_microcore-4.0.0.dev3 → ai_microcore-4.0.0.dev5}/microcore/wrappers/llm_response_wrapper.py
RENAMED
|
@@ -46,9 +46,27 @@ class LLMResponse(ExtendedString, ConvertableToMessage):
|
|
|
46
46
|
return obj
|
|
47
47
|
|
|
48
48
|
def parse_json(
|
|
49
|
-
self,
|
|
49
|
+
self,
|
|
50
|
+
raise_errors: bool = True,
|
|
51
|
+
required_fields: list[str] = None,
|
|
52
|
+
validator: callable = None,
|
|
50
53
|
) -> list | dict | float | int | str | DictFromLLMResponse:
|
|
51
|
-
|
|
54
|
+
try:
|
|
55
|
+
res = parse_json(self.content, True, required_fields)
|
|
56
|
+
if validator:
|
|
57
|
+
try:
|
|
58
|
+
validator(res)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
raise BadAIAnswer(f"Language model response validation failed: {e}") from None
|
|
61
|
+
except Exception as e:
|
|
62
|
+
if hasattr(self, "_retry_callback"):
|
|
63
|
+
res = self._retry_callback()
|
|
64
|
+
if isinstance(res, DictFromLLMResponse):
|
|
65
|
+
return res
|
|
66
|
+
return res.parse_json(raise_errors, required_fields, validator)
|
|
67
|
+
if raise_errors:
|
|
68
|
+
raise e
|
|
69
|
+
res = False
|
|
52
70
|
if isinstance(res, dict):
|
|
53
71
|
res = DictFromLLMResponse(res)
|
|
54
72
|
res.llm_response = self
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|