not-again-ai 0.15.0__py3-none-any.whl → 0.16.1__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.
- not_again_ai/llm/chat_completion/providers/ollama_api.py +5 -0
- not_again_ai/llm/chat_completion/providers/openai_api.py +4 -0
- not_again_ai/llm/chat_completion/types.py +5 -0
- not_again_ai/llm/embedding/__init__.py +4 -0
- not_again_ai/llm/embedding/interface.py +28 -0
- not_again_ai/llm/embedding/providers/__init__.py +0 -0
- not_again_ai/llm/embedding/providers/ollama_api.py +87 -0
- not_again_ai/llm/embedding/providers/openai_api.py +126 -0
- not_again_ai/llm/embedding/types.py +23 -0
- not_again_ai/llm/prompting/{compile_messages.py → compile_prompt.py} +39 -12
- {not_again_ai-0.15.0.dist-info → not_again_ai-0.16.1.dist-info}/METADATA +4 -4
- {not_again_ai-0.15.0.dist-info → not_again_ai-0.16.1.dist-info}/RECORD +14 -8
- {not_again_ai-0.15.0.dist-info → not_again_ai-0.16.1.dist-info}/LICENSE +0 -0
- {not_again_ai-0.15.0.dist-info → not_again_ai-0.16.1.dist-info}/WHEEL +0 -0
@@ -28,6 +28,7 @@ OLLAMA_PARAMETER_MAP = {
|
|
28
28
|
"logit_bias": None,
|
29
29
|
"top_logprobs": None,
|
30
30
|
"presence_penalty": None,
|
31
|
+
"max_tokens": "num_predict",
|
31
32
|
}
|
32
33
|
|
33
34
|
|
@@ -45,6 +46,10 @@ def validate(request: ChatCompletionRequest) -> None:
|
|
45
46
|
logger.warning("Parameter 'stop' needs to be a string and not a list. It will be ignored.")
|
46
47
|
request.stop = None
|
47
48
|
|
49
|
+
# Raise an error if both "max_tokens" and "max_completion_tokens" are provided
|
50
|
+
if request.max_tokens is not None and request.max_completion_tokens is not None:
|
51
|
+
raise ValueError("`max_tokens` and `max_completion_tokens` cannot both be provided.")
|
52
|
+
|
48
53
|
|
49
54
|
def ollama_chat_completion(
|
50
55
|
request: ChatCompletionRequest,
|
@@ -31,6 +31,10 @@ def validate(request: ChatCompletionRequest) -> None:
|
|
31
31
|
if request.json_mode and request.structured_outputs is not None:
|
32
32
|
raise ValueError("json_schema and json_mode cannot be used together.")
|
33
33
|
|
34
|
+
# Raise an error if both "max_tokens" and "max_completion_tokens" are provided
|
35
|
+
if request.max_tokens is not None and request.max_completion_tokens is not None:
|
36
|
+
raise ValueError("`max_tokens` and `max_completion_tokens` cannot both be provided.")
|
37
|
+
|
34
38
|
|
35
39
|
def openai_chat_completion(
|
36
40
|
request: ChatCompletionRequest,
|
@@ -118,6 +118,11 @@ class ChatCompletionRequest(BaseModel):
|
|
118
118
|
top_k: int | None = Field(default=None)
|
119
119
|
min_p: float | None = Field(default=None)
|
120
120
|
|
121
|
+
max_tokens: int | None = Field(
|
122
|
+
default=None,
|
123
|
+
description="Sometimes `max_completion_tokens` is not correctly supported so we provide this as a fallback.",
|
124
|
+
)
|
125
|
+
|
121
126
|
|
122
127
|
class ChatCompletionChoice(BaseModel):
|
123
128
|
message: AssistantMessage
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from collections.abc import Callable
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from not_again_ai.llm.embedding.providers.ollama_api import ollama_create_embeddings
|
5
|
+
from not_again_ai.llm.embedding.providers.openai_api import openai_create_embeddings
|
6
|
+
from not_again_ai.llm.embedding.types import EmbeddingRequest, EmbeddingResponse
|
7
|
+
|
8
|
+
|
9
|
+
def create_embeddings(request: EmbeddingRequest, provider: str, client: Callable[..., Any]) -> EmbeddingResponse:
|
10
|
+
"""Get a embedding response from the given provider. Currently supported providers:
|
11
|
+
- `openai` - OpenAI
|
12
|
+
- `azure_openai` - Azure OpenAI
|
13
|
+
- `ollama` - Ollama
|
14
|
+
|
15
|
+
Args:
|
16
|
+
request: Request parameter object
|
17
|
+
provider: The supported provider name
|
18
|
+
client: Client information, see the provider's implementation for what can be provided
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
EmbeddingResponse: The embedding response.
|
22
|
+
"""
|
23
|
+
if provider == "openai" or provider == "azure_openai":
|
24
|
+
return openai_create_embeddings(request, client)
|
25
|
+
elif provider == "ollama":
|
26
|
+
return ollama_create_embeddings(request, client)
|
27
|
+
else:
|
28
|
+
raise ValueError(f"Provider {provider} not supported")
|
File without changes
|
@@ -0,0 +1,87 @@
|
|
1
|
+
from collections.abc import Callable
|
2
|
+
import os
|
3
|
+
import re
|
4
|
+
import time
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from loguru import logger
|
8
|
+
from ollama import Client, EmbedResponse, ResponseError
|
9
|
+
|
10
|
+
from not_again_ai.llm.embedding.types import EmbeddingObject, EmbeddingRequest, EmbeddingResponse
|
11
|
+
|
12
|
+
OLLAMA_PARAMETER_MAP = {
|
13
|
+
"dimensions": None,
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
def validate(request: EmbeddingRequest) -> None:
|
18
|
+
# Check if any of the parameters set to OLLAMA_PARAMETER_MAP are not None
|
19
|
+
for key, value in OLLAMA_PARAMETER_MAP.items():
|
20
|
+
if value is None and getattr(request, key) is not None:
|
21
|
+
logger.warning(f"Parameter {key} is not supported by Ollama and will be ignored.")
|
22
|
+
|
23
|
+
|
24
|
+
def ollama_create_embeddings(request: EmbeddingRequest, client: Callable[..., Any]) -> EmbeddingResponse:
|
25
|
+
validate(request)
|
26
|
+
kwargs = request.model_dump(mode="json", exclude_none=True)
|
27
|
+
|
28
|
+
# For each key in OLLAMA_PARAMETER_MAP
|
29
|
+
# If it is not None, set the key in kwargs to the value of the corresponding value in OLLAMA_PARAMETER_MAP
|
30
|
+
# If it is None, remove that key from kwargs
|
31
|
+
for key, value in OLLAMA_PARAMETER_MAP.items():
|
32
|
+
if value is not None and key in kwargs:
|
33
|
+
kwargs[value] = kwargs.pop(key)
|
34
|
+
elif value is None and key in kwargs:
|
35
|
+
del kwargs[key]
|
36
|
+
|
37
|
+
# Explicitly set truncate to True (it is the default)
|
38
|
+
kwargs["truncate"] = True
|
39
|
+
|
40
|
+
try:
|
41
|
+
start_time = time.time()
|
42
|
+
response: EmbedResponse = client(**kwargs)
|
43
|
+
end_time = time.time()
|
44
|
+
response_duration = round(end_time - start_time, 4)
|
45
|
+
except ResponseError as e:
|
46
|
+
# If the error says "model 'model' not found" use regex then raise a more specific error
|
47
|
+
expected_pattern = f"model '{request.model}' not found"
|
48
|
+
if re.search(expected_pattern, e.error):
|
49
|
+
raise ResponseError(f"Model '{request.model}' not found.") from e
|
50
|
+
else:
|
51
|
+
raise ResponseError(e.error) from e
|
52
|
+
|
53
|
+
embeddings: list[EmbeddingObject] = []
|
54
|
+
for index, embedding in enumerate(response.embeddings):
|
55
|
+
embeddings.append(EmbeddingObject(embedding=list(embedding), index=index))
|
56
|
+
|
57
|
+
return EmbeddingResponse(
|
58
|
+
embeddings=embeddings,
|
59
|
+
response_duration=response_duration,
|
60
|
+
total_tokens=response.prompt_eval_count,
|
61
|
+
)
|
62
|
+
|
63
|
+
|
64
|
+
def ollama_client(host: str | None = None, timeout: float | None = None) -> Callable[..., Any]:
|
65
|
+
"""Create an Ollama client instance based on the specified host or will read from the OLLAMA_HOST environment variable.
|
66
|
+
|
67
|
+
Args:
|
68
|
+
host (str, optional): The host URL of the Ollama server.
|
69
|
+
timeout (float, optional): The timeout for requests
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
Client: An instance of the Ollama client.
|
73
|
+
|
74
|
+
Examples:
|
75
|
+
>>> client = client(host="http://localhost:11434")
|
76
|
+
"""
|
77
|
+
if host is None:
|
78
|
+
host = os.getenv("OLLAMA_HOST")
|
79
|
+
if host is None:
|
80
|
+
logger.warning("OLLAMA_HOST environment variable not set, using default host: http://localhost:11434")
|
81
|
+
host = "http://localhost:11434"
|
82
|
+
|
83
|
+
def client_callable(**kwargs: Any) -> Any:
|
84
|
+
client = Client(host=host, timeout=timeout)
|
85
|
+
return client.embed(**kwargs)
|
86
|
+
|
87
|
+
return client_callable
|
@@ -0,0 +1,126 @@
|
|
1
|
+
from collections.abc import Callable
|
2
|
+
import time
|
3
|
+
from typing import Any, Literal
|
4
|
+
|
5
|
+
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
|
6
|
+
from openai import AzureOpenAI, OpenAI
|
7
|
+
|
8
|
+
from not_again_ai.llm.embedding.types import EmbeddingObject, EmbeddingRequest, EmbeddingResponse
|
9
|
+
|
10
|
+
|
11
|
+
def openai_create_embeddings(request: EmbeddingRequest, client: Callable[..., Any]) -> EmbeddingResponse:
|
12
|
+
kwargs = request.model_dump(mode="json", exclude_none=True)
|
13
|
+
|
14
|
+
start_time = time.time()
|
15
|
+
response = client(**kwargs)
|
16
|
+
end_time = time.time()
|
17
|
+
response_duration = round(end_time - start_time, 4)
|
18
|
+
|
19
|
+
embeddings: list[EmbeddingObject] = []
|
20
|
+
for data in response["data"]:
|
21
|
+
embeddings.append(EmbeddingObject(embedding=data["embedding"], index=data["index"]))
|
22
|
+
|
23
|
+
return EmbeddingResponse(
|
24
|
+
embeddings=embeddings,
|
25
|
+
response_duration=response_duration,
|
26
|
+
total_tokens=response["usage"]["total_tokens"],
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
def create_client_callable(client_class: type[OpenAI | AzureOpenAI], **client_args: Any) -> Callable[..., Any]:
|
31
|
+
"""Creates a callable that instantiates and uses an OpenAI client.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
client_class: The OpenAI client class to instantiate (OpenAI or AzureOpenAI)
|
35
|
+
**client_args: Arguments to pass to the client constructor
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
A callable that creates a client and returns completion results
|
39
|
+
"""
|
40
|
+
filtered_args = {k: v for k, v in client_args.items() if v is not None}
|
41
|
+
|
42
|
+
def client_callable(**kwargs: Any) -> Any:
|
43
|
+
client = client_class(**filtered_args)
|
44
|
+
completion = client.embeddings.create(**kwargs)
|
45
|
+
return completion.to_dict()
|
46
|
+
|
47
|
+
return client_callable
|
48
|
+
|
49
|
+
|
50
|
+
class InvalidOAIAPITypeError(Exception):
|
51
|
+
"""Raised when an invalid OAIAPIType string is provided."""
|
52
|
+
|
53
|
+
|
54
|
+
def openai_client(
|
55
|
+
api_type: Literal["openai", "azure_openai"] = "openai",
|
56
|
+
api_key: str | None = None,
|
57
|
+
organization: str | None = None,
|
58
|
+
aoai_api_version: str = "2024-06-01",
|
59
|
+
azure_endpoint: str | None = None,
|
60
|
+
timeout: float | None = None,
|
61
|
+
max_retries: int | None = None,
|
62
|
+
) -> Callable[..., Any]:
|
63
|
+
"""Create an OpenAI or Azure OpenAI client instance based on the specified API type and other provided parameters.
|
64
|
+
|
65
|
+
It is preferred to use RBAC authentication for Azure OpenAI. You must be signed in with the Azure CLI and have correct role assigned.
|
66
|
+
See https://techcommunity.microsoft.com/t5/microsoft-developer-community/using-keyless-authentication-with-azure-openai/ba-p/4111521
|
67
|
+
|
68
|
+
Args:
|
69
|
+
api_type (str, optional): Type of the API to be used. Accepted values are 'openai' or 'azure_openai'.
|
70
|
+
Defaults to 'openai'.
|
71
|
+
api_key (str, optional): The API key to authenticate the client. If not provided,
|
72
|
+
OpenAI automatically uses `OPENAI_API_KEY` from the environment.
|
73
|
+
If provided for Azure OpenAI, it will be used for authentication instead of the Azure AD token provider.
|
74
|
+
organization (str, optional): The ID of the organization. If not provided,
|
75
|
+
OpenAI automotically uses `OPENAI_ORG_ID` from the environment.
|
76
|
+
aoai_api_version (str, optional): Only applicable if using Azure OpenAI https://learn.microsoft.com/azure/ai-services/openai/reference#rest-api-versioning
|
77
|
+
azure_endpoint (str, optional): The endpoint to use for Azure OpenAI.
|
78
|
+
timeout (float, optional): By default requests time out after 10 minutes.
|
79
|
+
max_retries (int, optional): Certain errors are automatically retried 2 times by default,
|
80
|
+
with a short exponential backoff. Connection errors (for example, due to a network connectivity problem),
|
81
|
+
408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors are all retried by default.
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
Callable[..., Any]: A callable that creates a client and returns completion results
|
85
|
+
|
86
|
+
|
87
|
+
Raises:
|
88
|
+
InvalidOAIAPITypeError: If an invalid API type string is provided.
|
89
|
+
NotImplementedError: If the specified API type is recognized but not yet supported (e.g., 'azure_openai').
|
90
|
+
"""
|
91
|
+
if api_type not in ["openai", "azure_openai"]:
|
92
|
+
raise InvalidOAIAPITypeError(f"Invalid OAIAPIType: {api_type}. Must be 'openai' or 'azure_openai'.")
|
93
|
+
|
94
|
+
if api_type == "openai":
|
95
|
+
return create_client_callable(
|
96
|
+
OpenAI,
|
97
|
+
api_key=api_key,
|
98
|
+
organization=organization,
|
99
|
+
timeout=timeout,
|
100
|
+
max_retries=max_retries,
|
101
|
+
)
|
102
|
+
elif api_type == "azure_openai":
|
103
|
+
if api_key:
|
104
|
+
return create_client_callable(
|
105
|
+
AzureOpenAI,
|
106
|
+
api_version=aoai_api_version,
|
107
|
+
azure_endpoint=azure_endpoint,
|
108
|
+
api_key=api_key,
|
109
|
+
timeout=timeout,
|
110
|
+
max_retries=max_retries,
|
111
|
+
)
|
112
|
+
else:
|
113
|
+
azure_credential = DefaultAzureCredential()
|
114
|
+
ad_token_provider = get_bearer_token_provider(
|
115
|
+
azure_credential, "https://cognitiveservices.azure.com/.default"
|
116
|
+
)
|
117
|
+
return create_client_callable(
|
118
|
+
AzureOpenAI,
|
119
|
+
api_version=aoai_api_version,
|
120
|
+
azure_endpoint=azure_endpoint,
|
121
|
+
azure_ad_token_provider=ad_token_provider,
|
122
|
+
timeout=timeout,
|
123
|
+
max_retries=max_retries,
|
124
|
+
)
|
125
|
+
else:
|
126
|
+
raise NotImplementedError(f"API type '{api_type}' is invalid.")
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from pydantic import BaseModel, Field
|
4
|
+
|
5
|
+
|
6
|
+
class EmbeddingRequest(BaseModel):
|
7
|
+
input: str | list[str]
|
8
|
+
model: str
|
9
|
+
dimensions: int | None = Field(default=None)
|
10
|
+
|
11
|
+
|
12
|
+
class EmbeddingObject(BaseModel):
|
13
|
+
embedding: list[float]
|
14
|
+
index: int
|
15
|
+
|
16
|
+
|
17
|
+
class EmbeddingResponse(BaseModel):
|
18
|
+
embeddings: list[EmbeddingObject]
|
19
|
+
total_tokens: int | None = Field(default=None)
|
20
|
+
response_duration: float
|
21
|
+
|
22
|
+
errors: str = Field(default="")
|
23
|
+
extras: Any | None = Field(default=None)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import base64
|
2
|
+
from collections.abc import Sequence
|
2
3
|
from copy import deepcopy
|
3
4
|
import mimetypes
|
4
5
|
from pathlib import Path
|
@@ -8,10 +9,27 @@ from liquid import Template
|
|
8
9
|
from openai.lib._pydantic import to_strict_json_schema
|
9
10
|
from pydantic import BaseModel
|
10
11
|
|
11
|
-
from not_again_ai.llm.chat_completion.types import MessageT
|
12
|
+
from not_again_ai.llm.chat_completion.types import MessageT
|
12
13
|
|
13
14
|
|
14
|
-
def
|
15
|
+
def _apply_templates(value: Any, variables: dict[str, str]) -> Any:
|
16
|
+
"""Recursively applies Liquid templating to all string fields within the given value."""
|
17
|
+
if isinstance(value, str):
|
18
|
+
return Template(value).render(**variables)
|
19
|
+
elif isinstance(value, list):
|
20
|
+
return [_apply_templates(item, variables) for item in value]
|
21
|
+
elif isinstance(value, dict):
|
22
|
+
return {key: _apply_templates(val, variables) for key, val in value.items()}
|
23
|
+
elif isinstance(value, BaseModel):
|
24
|
+
# Process each field in the BaseModel by converting it to a dict,
|
25
|
+
# applying templating to its values, and then re-instantiating the model.
|
26
|
+
processed_data = {key: _apply_templates(val, variables) for key, val in value.model_dump().items()}
|
27
|
+
return value.__class__(**processed_data)
|
28
|
+
else:
|
29
|
+
return value
|
30
|
+
|
31
|
+
|
32
|
+
def compile_messages(messages: Sequence[MessageT], variables: dict[str, str]) -> Sequence[MessageT]:
|
15
33
|
"""Compiles messages using Liquid templating and the provided variables.
|
16
34
|
Calls Template(content_part).render(**variables) on each text content part.
|
17
35
|
|
@@ -23,19 +41,28 @@ def compile_messages(messages: list[MessageT], variables: dict[str, str]) -> lis
|
|
23
41
|
The same list of messages with the content parts injected with the variables.
|
24
42
|
"""
|
25
43
|
messages_formatted = deepcopy(messages)
|
26
|
-
for message in messages_formatted
|
27
|
-
if isinstance(message.content, str):
|
28
|
-
# For simple string content, apply template directly
|
29
|
-
message.content = Template(message.content).render(**variables)
|
30
|
-
elif isinstance(message.content, list):
|
31
|
-
# For UserMessage with content parts
|
32
|
-
for content_part in message.content:
|
33
|
-
if isinstance(content_part, TextContent):
|
34
|
-
content_part.text = Template(content_part.text).render(**variables)
|
35
|
-
# ImageContent parts are left unchanged
|
44
|
+
messages_formatted = [_apply_templates(message, variables) for message in messages_formatted]
|
36
45
|
return messages_formatted
|
37
46
|
|
38
47
|
|
48
|
+
def compile_tools(tools: Sequence[dict[str, Any]], variables: dict[str, str]) -> Sequence[dict[str, Any]]:
|
49
|
+
"""Compiles a list of tool argument dictionaries using Liquid templating and provided variables.
|
50
|
+
|
51
|
+
Each dictionary in the list is deep copied and processed recursively to substitute any Liquid
|
52
|
+
templates present in its data structure.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
tools: A list of dictionaries representing tool arguments, where values can include Liquid templates.
|
56
|
+
variables: A dictionary of variables to substitute into the Liquid templates.
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
A new list of dictionaries with the Liquid templates replaced by their corresponding variable values.
|
60
|
+
"""
|
61
|
+
tools_formatted = deepcopy(tools)
|
62
|
+
tools_formatted = [_apply_templates(tool, variables) for tool in tools_formatted]
|
63
|
+
return tools_formatted
|
64
|
+
|
65
|
+
|
39
66
|
def encode_image(image_path: Path) -> str:
|
40
67
|
"""Encodes an image file at the given Path to base64.
|
41
68
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: not-again-ai
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.16.1
|
4
4
|
Summary: Designed to once and for all collect all the little things that come up over and over again in AI projects and put them in one place.
|
5
5
|
License: MIT
|
6
6
|
Author: DaveCoDev
|
@@ -25,11 +25,11 @@ Requires-Dist: loguru (>=0.7)
|
|
25
25
|
Requires-Dist: numpy (>=2.2) ; extra == "statistics"
|
26
26
|
Requires-Dist: numpy (>=2.2) ; extra == "viz"
|
27
27
|
Requires-Dist: ollama (>=0.4) ; extra == "llm"
|
28
|
-
Requires-Dist: openai (>=1
|
28
|
+
Requires-Dist: openai (>=1) ; extra == "llm"
|
29
29
|
Requires-Dist: pandas (>=2.2) ; extra == "viz"
|
30
|
-
Requires-Dist: playwright (>=1.
|
30
|
+
Requires-Dist: playwright (>=1.50) ; extra == "data"
|
31
31
|
Requires-Dist: pydantic (>=2.10)
|
32
|
-
Requires-Dist: pytest-playwright (>=0.
|
32
|
+
Requires-Dist: pytest-playwright (>=0.7) ; extra == "data"
|
33
33
|
Requires-Dist: python-liquid (>=1.12) ; extra == "llm"
|
34
34
|
Requires-Dist: scikit-learn (>=1.6) ; extra == "statistics"
|
35
35
|
Requires-Dist: scipy (>=1.15) ; extra == "statistics"
|
@@ -8,11 +8,17 @@ not_again_ai/llm/__init__.py,sha256=_wNUL6FDaT369Z8W48FsaC_NkcOZ-ib2MMUvnaLOS-0,
|
|
8
8
|
not_again_ai/llm/chat_completion/__init__.py,sha256=a2qmmmrXjMKyHGZDjt_xdqYbSrEOBea_VvZArzMboe0,200
|
9
9
|
not_again_ai/llm/chat_completion/interface.py,sha256=FCyE-1gLdhwuS0Lv8iTbZvraa4iZjnKB8qb31WF53uk,1204
|
10
10
|
not_again_ai/llm/chat_completion/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
not_again_ai/llm/chat_completion/providers/ollama_api.py,sha256=
|
12
|
-
not_again_ai/llm/chat_completion/providers/openai_api.py,sha256=
|
13
|
-
not_again_ai/llm/chat_completion/types.py,sha256=
|
11
|
+
not_again_ai/llm/chat_completion/providers/ollama_api.py,sha256=plW_nN452rd85NqxPKjSLlHn-Z9s4rQXynsxatX8xkA,8295
|
12
|
+
not_again_ai/llm/chat_completion/providers/openai_api.py,sha256=e8rOVeDq-gB8AQ5fycUjIgNSrgjYU3s8LdGUuYeahM8,12557
|
13
|
+
not_again_ai/llm/chat_completion/types.py,sha256=RnOy_CphOaFU1f0ag-zTJPgAPXOnTH4WHD1P688GQKM,4222
|
14
|
+
not_again_ai/llm/embedding/__init__.py,sha256=wscUfROukvw0M0vYccfaVTdXV0P-eICAT5mqM0LaHHc,182
|
15
|
+
not_again_ai/llm/embedding/interface.py,sha256=Hj3UiktXEeCUeMwpIDtRkwBfKgaJSnJvclLNyjwUAtE,1144
|
16
|
+
not_again_ai/llm/embedding/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
+
not_again_ai/llm/embedding/providers/ollama_api.py,sha256=m-OCis9WAUT2baGsGVPzejlive40eSNyO6tHmPh6joM,3201
|
18
|
+
not_again_ai/llm/embedding/providers/openai_api.py,sha256=JFFqbq0O5snIEnr9VESdp5xehikQBPbs7nwyE6acFsY,5441
|
19
|
+
not_again_ai/llm/embedding/types.py,sha256=J4FFLx35Aow2kOaafDReeY9cUNqhWMjaAk5gXkX7SVk,506
|
14
20
|
not_again_ai/llm/prompting/__init__.py,sha256=7YnHro1yH01FLGnao27WyqQDFjNYf9npE5UxoR9YrUU,84
|
15
|
-
not_again_ai/llm/prompting/
|
21
|
+
not_again_ai/llm/prompting/compile_prompt.py,sha256=lnbTOoTc7PumyP_GhfHaLZHp3UUpSB7VAeWOilS1wpI,4703
|
16
22
|
not_again_ai/llm/prompting/interface.py,sha256=SMKYabmu3zTWbEDukU6aLU_JQ88apeBWWOF_qZ0s3ww,1783
|
17
23
|
not_again_ai/llm/prompting/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
24
|
not_again_ai/llm/prompting/providers/openai_tiktoken.py,sha256=8YrEiK3ZHyKVGiVsJ_Rd6eVdISIvcub7ooj-HB7Prsc,4536
|
@@ -26,7 +32,7 @@ not_again_ai/viz/distributions.py,sha256=OyWwJaNI6lMRm_iSrhq-CORLNvXfeuLSgDtVo3u
|
|
26
32
|
not_again_ai/viz/scatterplot.py,sha256=5CUOWeknbBOaZPeX9oPin5sBkRKEwk8qeFH45R-9LlY,2292
|
27
33
|
not_again_ai/viz/time_series.py,sha256=pOGZqXp_2nd6nKo-PUQNCtmMh__69jxQ6bQibTGLwZA,5212
|
28
34
|
not_again_ai/viz/utils.py,sha256=hN7gwxtBt3U6jQni2K8j5m5pCXpaJDoNzGhBBikEU28,238
|
29
|
-
not_again_ai-0.
|
30
|
-
not_again_ai-0.
|
31
|
-
not_again_ai-0.
|
32
|
-
not_again_ai-0.
|
35
|
+
not_again_ai-0.16.1.dist-info/LICENSE,sha256=btjOgNGpp-ux5xOo1Gx1MddxeWtT9sof3s3Nui29QfA,1071
|
36
|
+
not_again_ai-0.16.1.dist-info/METADATA,sha256=6j9ar7vYJ77yTkg1NDzw9PbYK0-ioo5NGI2joAPHpp0,15035
|
37
|
+
not_again_ai-0.16.1.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
38
|
+
not_again_ai-0.16.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|