lmnr 0.4.47__tar.gz → 0.4.49__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.
- {lmnr-0.4.47 → lmnr-0.4.49}/PKG-INFO +29 -29
- {lmnr-0.4.47 → lmnr-0.4.49}/pyproject.toml +31 -30
- lmnr-0.4.49/src/lmnr/cli.py +101 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/evaluations.py +15 -6
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/laminar.py +10 -11
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/log.py +24 -1
- lmnr-0.4.47/src/lmnr/cli.py +0 -53
- {lmnr-0.4.47 → lmnr-0.4.49}/LICENSE +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/README.md +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/__init__.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/.flake8 +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/.python-version +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/__init__.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/config/__init__.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/decorators/__init__.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/decorators/base.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/instruments.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/tracing/__init__.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/tracing/attributes.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/tracing/content_allow_list.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/tracing/context_manager.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/tracing/tracing.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/utils/__init__.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/utils/in_memory_span_exporter.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/utils/json_encoder.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/utils/package_check.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/openllmetry_sdk/version.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/__init__.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/datasets.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/decorators.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/eval_control.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/types.py +0 -0
- {lmnr-0.4.47 → lmnr-0.4.49}/src/lmnr/sdk/utils.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lmnr
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.49
|
4
4
|
Summary: Python SDK for Laminar AI
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: lmnr.ai
|
@@ -44,35 +44,35 @@ Requires-Dist: deprecated (>=1.0)
|
|
44
44
|
Requires-Dist: opentelemetry-api (>=1.28.0)
|
45
45
|
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (>=1.28.0)
|
46
46
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.28.0)
|
47
|
-
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.
|
48
|
-
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.
|
49
|
-
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.
|
50
|
-
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.
|
51
|
-
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.
|
52
|
-
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.
|
53
|
-
Requires-Dist: opentelemetry-instrumentation-groq (>=0.
|
54
|
-
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.
|
55
|
-
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.
|
56
|
-
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.
|
57
|
-
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.
|
58
|
-
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.
|
59
|
-
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.
|
60
|
-
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.
|
61
|
-
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.
|
47
|
+
Requires-Dist: opentelemetry-instrumentation-alephalpha (>=0.34.0) ; extra == "all" or extra == "alephalpha"
|
48
|
+
Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.34.0) ; extra == "all" or extra == "anthropic"
|
49
|
+
Requires-Dist: opentelemetry-instrumentation-bedrock (>=0.34.0) ; extra == "all" or extra == "bedrock"
|
50
|
+
Requires-Dist: opentelemetry-instrumentation-chromadb (>=0.34.0) ; extra == "all" or extra == "chromadb"
|
51
|
+
Requires-Dist: opentelemetry-instrumentation-cohere (>=0.34.0) ; extra == "all" or extra == "cohere"
|
52
|
+
Requires-Dist: opentelemetry-instrumentation-google-generativeai (>=0.34.0) ; extra == "all" or extra == "google-generativeai"
|
53
|
+
Requires-Dist: opentelemetry-instrumentation-groq (>=0.34.0) ; extra == "all" or extra == "groq"
|
54
|
+
Requires-Dist: opentelemetry-instrumentation-haystack (>=0.34.0) ; extra == "all" or extra == "haystack"
|
55
|
+
Requires-Dist: opentelemetry-instrumentation-lancedb (>=0.34.0) ; extra == "all" or extra == "lancedb"
|
56
|
+
Requires-Dist: opentelemetry-instrumentation-langchain (>=0.34.0) ; extra == "all" or extra == "langchain"
|
57
|
+
Requires-Dist: opentelemetry-instrumentation-llamaindex (>=0.34.0) ; extra == "all" or extra == "llamaindex"
|
58
|
+
Requires-Dist: opentelemetry-instrumentation-marqo (>=0.34.0) ; extra == "all" or extra == "marqo"
|
59
|
+
Requires-Dist: opentelemetry-instrumentation-milvus (>=0.34.0) ; extra == "all" or extra == "milvus"
|
60
|
+
Requires-Dist: opentelemetry-instrumentation-mistralai (>=0.34.0) ; extra == "all" or extra == "mistralai"
|
61
|
+
Requires-Dist: opentelemetry-instrumentation-ollama (>=0.34.0) ; extra == "all" or extra == "ollama"
|
62
62
|
Requires-Dist: opentelemetry-instrumentation-openai (>=0.33.12) ; extra == "all" or extra == "openai"
|
63
|
-
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.
|
64
|
-
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.
|
65
|
-
Requires-Dist: opentelemetry-instrumentation-replicate (>=0.
|
66
|
-
Requires-Dist: opentelemetry-instrumentation-requests (>=0.
|
67
|
-
Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.
|
68
|
-
Requires-Dist: opentelemetry-instrumentation-sqlalchemy (>=0.
|
69
|
-
Requires-Dist: opentelemetry-instrumentation-threading (>=0.
|
70
|
-
Requires-Dist: opentelemetry-instrumentation-together (>=0.
|
71
|
-
Requires-Dist: opentelemetry-instrumentation-transformers (>=0.
|
72
|
-
Requires-Dist: opentelemetry-instrumentation-urllib3 (>=0.
|
73
|
-
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.
|
74
|
-
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.
|
75
|
-
Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.
|
63
|
+
Requires-Dist: opentelemetry-instrumentation-pinecone (>=0.34.0) ; extra == "all" or extra == "pinecone"
|
64
|
+
Requires-Dist: opentelemetry-instrumentation-qdrant (>=0.34.0) ; extra == "all" or extra == "qdrant"
|
65
|
+
Requires-Dist: opentelemetry-instrumentation-replicate (>=0.34.0) ; extra == "all" or extra == "replicate"
|
66
|
+
Requires-Dist: opentelemetry-instrumentation-requests (>=0.50b0)
|
67
|
+
Requires-Dist: opentelemetry-instrumentation-sagemaker (>=0.34.0) ; extra == "all" or extra == "sagemaker"
|
68
|
+
Requires-Dist: opentelemetry-instrumentation-sqlalchemy (>=0.50b0)
|
69
|
+
Requires-Dist: opentelemetry-instrumentation-threading (>=0.50b0)
|
70
|
+
Requires-Dist: opentelemetry-instrumentation-together (>=0.34.0) ; extra == "all" or extra == "together"
|
71
|
+
Requires-Dist: opentelemetry-instrumentation-transformers (>=0.34.0) ; extra == "all" or extra == "transformers"
|
72
|
+
Requires-Dist: opentelemetry-instrumentation-urllib3 (>=0.50b0)
|
73
|
+
Requires-Dist: opentelemetry-instrumentation-vertexai (>=0.34.0) ; extra == "all" or extra == "vertexai"
|
74
|
+
Requires-Dist: opentelemetry-instrumentation-watsonx (>=0.34.0) ; extra == "all" or extra == "watsonx"
|
75
|
+
Requires-Dist: opentelemetry-instrumentation-weaviate (>=0.34.0) ; extra == "all" or extra == "weaviate"
|
76
76
|
Requires-Dist: opentelemetry-sdk (>=1.28.0)
|
77
77
|
Requires-Dist: opentelemetry-semantic-conventions-ai (==0.4.2)
|
78
78
|
Requires-Dist: pydantic (>=2.7)
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
[project]
|
8
8
|
name = "lmnr"
|
9
|
-
version = "0.4.
|
9
|
+
version = "0.4.49"
|
10
10
|
description = "Python SDK for Laminar AI"
|
11
11
|
authors = [
|
12
12
|
{ name = "lmnr.ai", email = "founders@lmnr.ai" }
|
@@ -17,7 +17,7 @@ license = "Apache-2.0"
|
|
17
17
|
|
18
18
|
[tool.poetry]
|
19
19
|
name = "lmnr"
|
20
|
-
version = "0.4.
|
20
|
+
version = "0.4.49"
|
21
21
|
description = "Python SDK for Laminar AI"
|
22
22
|
authors = ["lmnr.ai"]
|
23
23
|
readme = "README.md"
|
@@ -32,41 +32,41 @@ opentelemetry-api = ">=1.28.0"
|
|
32
32
|
opentelemetry-sdk = ">=1.28.0"
|
33
33
|
opentelemetry-exporter-otlp-proto-http = ">=1.28.0"
|
34
34
|
opentelemetry-exporter-otlp-proto-grpc = ">=1.28.0"
|
35
|
-
opentelemetry-instrumentation-requests = "
|
36
|
-
opentelemetry-instrumentation-sqlalchemy = "
|
37
|
-
opentelemetry-instrumentation-urllib3 = "
|
38
|
-
opentelemetry-instrumentation-threading = "
|
35
|
+
opentelemetry-instrumentation-requests = ">=0.50b0"
|
36
|
+
opentelemetry-instrumentation-sqlalchemy = ">=0.50b0"
|
37
|
+
opentelemetry-instrumentation-urllib3 = ">=0.50b0"
|
38
|
+
opentelemetry-instrumentation-threading = ">=0.50b0"
|
39
39
|
opentelemetry-semantic-conventions-ai = "0.4.2"
|
40
40
|
deprecated = ">=1.0"
|
41
41
|
tqdm = ">=4.0"
|
42
42
|
argparse = ">=1.0"
|
43
43
|
aiohttp = ">=3.0"
|
44
44
|
tenacity = ">=8.0"
|
45
|
-
opentelemetry-instrumentation-alephalpha = {version = ">=0.
|
46
|
-
opentelemetry-instrumentation-anthropic = {version = ">=0.
|
47
|
-
opentelemetry-instrumentation-bedrock = {version = ">=0.
|
48
|
-
opentelemetry-instrumentation-chromadb = {version = ">=0.
|
49
|
-
opentelemetry-instrumentation-cohere = {version = ">=0.
|
50
|
-
opentelemetry-instrumentation-google-generativeai = {version = ">=0.
|
51
|
-
opentelemetry-instrumentation-groq = {version = ">=0.
|
52
|
-
opentelemetry-instrumentation-haystack = {version = ">=0.
|
53
|
-
opentelemetry-instrumentation-lancedb = {version = ">=0.
|
54
|
-
opentelemetry-instrumentation-langchain = {version = ">=0.
|
55
|
-
opentelemetry-instrumentation-llamaindex = {version = ">=0.
|
56
|
-
opentelemetry-instrumentation-marqo = {version = ">=0.
|
57
|
-
opentelemetry-instrumentation-milvus = {version = ">=0.
|
58
|
-
opentelemetry-instrumentation-mistralai = {version = ">=0.
|
59
|
-
opentelemetry-instrumentation-ollama = {version = ">=0.
|
45
|
+
opentelemetry-instrumentation-alephalpha = {version = ">=0.34.0", optional = true}
|
46
|
+
opentelemetry-instrumentation-anthropic = {version = ">=0.34.0", optional = true}
|
47
|
+
opentelemetry-instrumentation-bedrock = {version = ">=0.34.0", optional = true}
|
48
|
+
opentelemetry-instrumentation-chromadb = {version = ">=0.34.0", optional = true}
|
49
|
+
opentelemetry-instrumentation-cohere = {version = ">=0.34.0", optional = true}
|
50
|
+
opentelemetry-instrumentation-google-generativeai = {version = ">=0.34.0", optional = true}
|
51
|
+
opentelemetry-instrumentation-groq = {version = ">=0.34.0", optional = true}
|
52
|
+
opentelemetry-instrumentation-haystack = {version = ">=0.34.0", optional = true}
|
53
|
+
opentelemetry-instrumentation-lancedb = {version = ">=0.34.0", optional = true}
|
54
|
+
opentelemetry-instrumentation-langchain = {version = ">=0.34.0", optional = true}
|
55
|
+
opentelemetry-instrumentation-llamaindex = {version = ">=0.34.0", optional = true}
|
56
|
+
opentelemetry-instrumentation-marqo = {version = ">=0.34.0", optional = true}
|
57
|
+
opentelemetry-instrumentation-milvus = {version = ">=0.34.0", optional = true}
|
58
|
+
opentelemetry-instrumentation-mistralai = {version = ">=0.34.0", optional = true}
|
59
|
+
opentelemetry-instrumentation-ollama = {version = ">=0.34.0", optional = true}
|
60
60
|
opentelemetry-instrumentation-openai = {version = ">=0.33.12", optional = true}
|
61
|
-
opentelemetry-instrumentation-pinecone = {version = ">=0.
|
62
|
-
opentelemetry-instrumentation-qdrant = {version = ">=0.
|
63
|
-
opentelemetry-instrumentation-replicate = {version = ">=0.
|
64
|
-
opentelemetry-instrumentation-sagemaker = {version = ">=0.
|
65
|
-
opentelemetry-instrumentation-together = {version = ">=0.
|
66
|
-
opentelemetry-instrumentation-transformers = {version = ">=0.
|
67
|
-
opentelemetry-instrumentation-vertexai = {version = ">=0.
|
68
|
-
opentelemetry-instrumentation-watsonx = {version = ">=0.
|
69
|
-
opentelemetry-instrumentation-weaviate = {version = ">=0.
|
61
|
+
opentelemetry-instrumentation-pinecone = {version = ">=0.34.0", optional = true}
|
62
|
+
opentelemetry-instrumentation-qdrant = {version = ">=0.34.0", optional = true}
|
63
|
+
opentelemetry-instrumentation-replicate = {version = ">=0.34.0", optional = true}
|
64
|
+
opentelemetry-instrumentation-sagemaker = {version = ">=0.34.0", optional = true}
|
65
|
+
opentelemetry-instrumentation-together = {version = ">=0.34.0", optional = true}
|
66
|
+
opentelemetry-instrumentation-transformers = {version = ">=0.34.0", optional = true}
|
67
|
+
opentelemetry-instrumentation-vertexai = {version = ">=0.34.0", optional = true}
|
68
|
+
opentelemetry-instrumentation-watsonx = {version = ">=0.34.0", optional = true}
|
69
|
+
opentelemetry-instrumentation-weaviate = {version = ">=0.34.0", optional = true}
|
70
70
|
|
71
71
|
[tool.poetry.extras]
|
72
72
|
# List of all possible extras. You can specify one or more of these extras
|
@@ -136,6 +136,7 @@ autopep8 = "^2.2.0"
|
|
136
136
|
flake8 = "7.0.0"
|
137
137
|
pytest = "^8.2.2"
|
138
138
|
pytest-sugar = "1.0.0"
|
139
|
+
pytest-asyncio = "^0.24.0"
|
139
140
|
|
140
141
|
[build-system]
|
141
142
|
requires = ["poetry-core"]
|
@@ -0,0 +1,101 @@
|
|
1
|
+
from argparse import ArgumentParser
|
2
|
+
import asyncio
|
3
|
+
import importlib.util
|
4
|
+
import logging
|
5
|
+
import os
|
6
|
+
import re
|
7
|
+
import sys
|
8
|
+
|
9
|
+
from .sdk.eval_control import PREPARE_ONLY, EVALUATION_INSTANCE
|
10
|
+
from .sdk.log import ColorfulFormatter
|
11
|
+
|
12
|
+
LOG = logging.getLogger(__name__)
|
13
|
+
console_log_handler = logging.StreamHandler()
|
14
|
+
console_log_handler.setFormatter(ColorfulFormatter())
|
15
|
+
LOG.addHandler(console_log_handler)
|
16
|
+
|
17
|
+
|
18
|
+
EVAL_DIR = "evals"
|
19
|
+
|
20
|
+
|
21
|
+
async def run_evaluation(args):
|
22
|
+
sys.path.append(os.getcwd())
|
23
|
+
|
24
|
+
if args.file is None:
|
25
|
+
files = [
|
26
|
+
os.path.join(EVAL_DIR, f)
|
27
|
+
for f in os.listdir(EVAL_DIR)
|
28
|
+
if re.match(r".*_eval\.py$", f) or re.match(r"eval_.*\.py$", f)
|
29
|
+
]
|
30
|
+
if len(files) == 0:
|
31
|
+
LOG.error("No evaluation files found in evals directory")
|
32
|
+
return
|
33
|
+
files.sort()
|
34
|
+
LOG.info(f"Located {len(files)} evaluation files in {EVAL_DIR}")
|
35
|
+
|
36
|
+
else:
|
37
|
+
files = [args.file]
|
38
|
+
|
39
|
+
for file in files:
|
40
|
+
prep_token = PREPARE_ONLY.set(True)
|
41
|
+
LOG.info(f"Running evaluation from {file}")
|
42
|
+
try:
|
43
|
+
file = os.path.abspath(file)
|
44
|
+
name = "user_module" + file
|
45
|
+
|
46
|
+
spec = importlib.util.spec_from_file_location(name, file)
|
47
|
+
if spec is None or spec.loader is None:
|
48
|
+
LOG.error(f"Could not load module specification from {file}")
|
49
|
+
if args.fail_on_error:
|
50
|
+
return
|
51
|
+
continue
|
52
|
+
mod = importlib.util.module_from_spec(spec)
|
53
|
+
sys.modules[name] = mod
|
54
|
+
|
55
|
+
spec.loader.exec_module(mod)
|
56
|
+
evaluation = EVALUATION_INSTANCE.get()
|
57
|
+
if evaluation is None:
|
58
|
+
LOG.warning("Evaluation instance not found")
|
59
|
+
if args.fail_on_error:
|
60
|
+
return
|
61
|
+
continue
|
62
|
+
|
63
|
+
await evaluation.run()
|
64
|
+
finally:
|
65
|
+
PREPARE_ONLY.reset(prep_token)
|
66
|
+
|
67
|
+
|
68
|
+
def cli():
|
69
|
+
parser = ArgumentParser(
|
70
|
+
prog="lmnr",
|
71
|
+
description="CLI for Laminar. Call `lmnr [subcommand] --help` for more information on each subcommand.",
|
72
|
+
)
|
73
|
+
|
74
|
+
subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
|
75
|
+
|
76
|
+
parser_eval = subparsers.add_parser(
|
77
|
+
"eval",
|
78
|
+
description="Run an evaluation",
|
79
|
+
help="Run an evaluation",
|
80
|
+
)
|
81
|
+
parser_eval.add_argument(
|
82
|
+
"file",
|
83
|
+
nargs="?",
|
84
|
+
help="A file containing the evaluation to run."
|
85
|
+
+ "If no file name is provided, all evaluation files in the `evals` directory are run as long"
|
86
|
+
+ "as they match *_eval.py or eval_*.py",
|
87
|
+
default=None,
|
88
|
+
)
|
89
|
+
|
90
|
+
parser_eval.add_argument(
|
91
|
+
"--fail-on-error",
|
92
|
+
action="store_true",
|
93
|
+
default=False,
|
94
|
+
help="Fail on error",
|
95
|
+
)
|
96
|
+
|
97
|
+
parsed = parser.parse_args()
|
98
|
+
if parsed.subcommand == "eval":
|
99
|
+
asyncio.run(run_evaluation(parsed))
|
100
|
+
else:
|
101
|
+
parser.print_help()
|
@@ -29,8 +29,17 @@ from .utils import is_async
|
|
29
29
|
DEFAULT_BATCH_SIZE = 5
|
30
30
|
|
31
31
|
|
32
|
-
def get_evaluation_url(
|
33
|
-
|
32
|
+
def get_evaluation_url(
|
33
|
+
project_id: str, evaluation_id: str, base_url: str = "https://www.lmnr.ai"
|
34
|
+
):
|
35
|
+
url = base_url
|
36
|
+
if url.endswith("/"):
|
37
|
+
url = url[:-1]
|
38
|
+
if url.endswith("localhost") or url.endswith("127.0.0.1"):
|
39
|
+
# We best effort assume that the frontend is running on port 3000
|
40
|
+
# TODO: expose the frontend port?
|
41
|
+
url = url + ":3000"
|
42
|
+
return f"{url}/project/{project_id}/evaluations/{evaluation_id}"
|
34
43
|
|
35
44
|
|
36
45
|
def get_average_scores(results: list[EvaluationResultDatapoint]) -> dict[str, Numeric]:
|
@@ -49,8 +58,8 @@ def get_average_scores(results: list[EvaluationResultDatapoint]) -> dict[str, Nu
|
|
49
58
|
|
50
59
|
|
51
60
|
class EvaluationReporter:
|
52
|
-
def __init__(self):
|
53
|
-
|
61
|
+
def __init__(self, base_url: str = "https://www.lmnr.ai"):
|
62
|
+
self.base_url = base_url
|
54
63
|
|
55
64
|
def start(self, length: int):
|
56
65
|
self.cli_progress = tqdm(
|
@@ -71,7 +80,7 @@ class EvaluationReporter:
|
|
71
80
|
):
|
72
81
|
self.cli_progress.close()
|
73
82
|
print(
|
74
|
-
f"\nCheck the results at {get_evaluation_url(project_id, evaluation_id)}\n"
|
83
|
+
f"\nCheck the results at {get_evaluation_url(project_id, evaluation_id, self.base_url)}\n"
|
75
84
|
)
|
76
85
|
print("Average scores:")
|
77
86
|
for name, score in average_scores.items():
|
@@ -160,7 +169,7 @@ class Evaluation:
|
|
160
169
|
)
|
161
170
|
|
162
171
|
self.is_finished = False
|
163
|
-
self.reporter = EvaluationReporter()
|
172
|
+
self.reporter = EvaluationReporter(base_url)
|
164
173
|
if isinstance(data, list):
|
165
174
|
self.data = [
|
166
175
|
(Datapoint.model_validate(point) if isinstance(point, dict) else point)
|
@@ -12,6 +12,7 @@ from lmnr.openllmetry_sdk.tracing.attributes import (
|
|
12
12
|
from lmnr.openllmetry_sdk.decorators.base import json_dumps
|
13
13
|
from opentelemetry import context, trace
|
14
14
|
from opentelemetry.context import attach, detach, set_value
|
15
|
+
from opentelemetry.sdk.trace import SpanProcessor
|
15
16
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
16
17
|
from opentelemetry.util.types import AttributeValue
|
17
18
|
|
@@ -79,6 +80,7 @@ class Laminar:
|
|
79
80
|
http_port: Optional[int] = None,
|
80
81
|
grpc_port: Optional[int] = None,
|
81
82
|
instruments: Optional[Set[Instruments]] = None,
|
83
|
+
_processor: Optional[SpanProcessor] = None,
|
82
84
|
):
|
83
85
|
"""Initialize Laminar context across the application.
|
84
86
|
This method must be called before using any other Laminar methods or
|
@@ -133,6 +135,7 @@ class Laminar:
|
|
133
135
|
cls.__env = env
|
134
136
|
cls.__initialized = True
|
135
137
|
cls._initialize_logger()
|
138
|
+
|
136
139
|
Traceloop.init(
|
137
140
|
exporter=OTLPSpanExporter(
|
138
141
|
endpoint=cls.__base_grpc_url,
|
@@ -268,13 +271,9 @@ class Laminar:
|
|
268
271
|
value: Optional[AttributeValue] = None,
|
269
272
|
timestamp: Optional[Union[datetime.datetime, int]] = None,
|
270
273
|
):
|
271
|
-
"""Associate an event with the current span. If
|
272
|
-
|
273
|
-
|
274
|
-
value to the event if and only if the value is of a matching type.
|
275
|
-
Otherwise, the event won't be recorded.
|
276
|
-
Supported types are string, numeric, and boolean. If the value
|
277
|
-
is `None`, event is considered a boolean tag with the value of `True`.
|
274
|
+
"""Associate an event with the current span. If using manual\
|
275
|
+
instrumentation, use raw OpenTelemetry `span.add_event()` instead.\
|
276
|
+
`value` will be saved as a `lmnr.event.value` attribute.
|
278
277
|
|
279
278
|
Args:
|
280
279
|
name (str): event name
|
@@ -400,7 +399,7 @@ class Laminar:
|
|
400
399
|
)
|
401
400
|
yield span
|
402
401
|
|
403
|
-
#
|
402
|
+
# TODO: Figure out if this is necessary
|
404
403
|
try:
|
405
404
|
detach(ctx_token)
|
406
405
|
except Exception:
|
@@ -672,9 +671,9 @@ class Laminar:
|
|
672
671
|
def clear_metadata(cls):
|
673
672
|
"""Clear the metadata from the context"""
|
674
673
|
props: dict = copy.copy(context.get_value("association_properties"))
|
675
|
-
for k in props.keys()
|
676
|
-
|
677
|
-
|
674
|
+
metadata_keys = [k for k in props.keys() if k.startswith("metadata.")]
|
675
|
+
for k in metadata_keys:
|
676
|
+
props.pop(k)
|
678
677
|
set_association_properties(props)
|
679
678
|
|
680
679
|
@classmethod
|
@@ -24,6 +24,29 @@ class CustomFormatter(logging.Formatter):
|
|
24
24
|
return formatter.format(record)
|
25
25
|
|
26
26
|
|
27
|
+
class ColorfulFormatter(logging.Formatter):
|
28
|
+
grey = "\x1b[38;20m"
|
29
|
+
green = "\x1b[32;20m"
|
30
|
+
yellow = "\x1b[33;20m"
|
31
|
+
red = "\x1b[31;20m"
|
32
|
+
bold_red = "\x1b[31;1m"
|
33
|
+
reset = "\x1b[0m"
|
34
|
+
fmt = "Laminar %(levelname)s: %(message)s"
|
35
|
+
|
36
|
+
FORMATS = {
|
37
|
+
logging.DEBUG: grey + fmt + reset,
|
38
|
+
logging.INFO: green + fmt + reset,
|
39
|
+
logging.WARNING: yellow + fmt + reset,
|
40
|
+
logging.ERROR: red + fmt + reset,
|
41
|
+
logging.CRITICAL: bold_red + fmt + reset,
|
42
|
+
}
|
43
|
+
|
44
|
+
def format(self, record: logging.LogRecord):
|
45
|
+
log_fmt = self.FORMATS.get(record.levelno)
|
46
|
+
formatter = logging.Formatter(log_fmt)
|
47
|
+
return formatter.format(record)
|
48
|
+
|
49
|
+
|
27
50
|
# For StreamHandlers / console
|
28
51
|
class VerboseColorfulFormatter(CustomFormatter):
|
29
52
|
def format(self, record):
|
@@ -32,7 +55,7 @@ class VerboseColorfulFormatter(CustomFormatter):
|
|
32
55
|
|
33
56
|
# For Verbose FileHandlers / files
|
34
57
|
class VerboseFormatter(CustomFormatter):
|
35
|
-
fmt = "%(asctime)s::%(name)s::%(levelname)s
|
58
|
+
fmt = "%(asctime)s::%(name)s::%(levelname)s: %(message)s (%(filename)s:%(lineno)d)"
|
36
59
|
|
37
60
|
def format(self, record):
|
38
61
|
formatter = logging.Formatter(self.fmt)
|
lmnr-0.4.47/src/lmnr/cli.py
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
from argparse import ArgumentParser
|
2
|
-
import asyncio
|
3
|
-
import importlib.util
|
4
|
-
import os
|
5
|
-
import sys
|
6
|
-
|
7
|
-
from .sdk.eval_control import PREPARE_ONLY, EVALUATION_INSTANCE
|
8
|
-
|
9
|
-
|
10
|
-
async def run_evaluation(args):
|
11
|
-
sys.path.append(os.getcwd())
|
12
|
-
|
13
|
-
prep_token = PREPARE_ONLY.set(True)
|
14
|
-
try:
|
15
|
-
file = os.path.abspath(args.file)
|
16
|
-
name = "user_module"
|
17
|
-
|
18
|
-
spec = importlib.util.spec_from_file_location(name, file)
|
19
|
-
if spec is None or spec.loader is None:
|
20
|
-
raise ImportError(f"Could not load module specification from {file}")
|
21
|
-
mod = importlib.util.module_from_spec(spec)
|
22
|
-
sys.modules[name] = mod
|
23
|
-
|
24
|
-
spec.loader.exec_module(mod)
|
25
|
-
evaluation = EVALUATION_INSTANCE.get()
|
26
|
-
if evaluation is None:
|
27
|
-
raise RuntimeError("Evaluation instance not found")
|
28
|
-
|
29
|
-
await evaluation.run()
|
30
|
-
finally:
|
31
|
-
PREPARE_ONLY.reset(prep_token)
|
32
|
-
|
33
|
-
|
34
|
-
def cli():
|
35
|
-
parser = ArgumentParser(
|
36
|
-
prog="lmnr",
|
37
|
-
description="CLI for Laminar",
|
38
|
-
)
|
39
|
-
|
40
|
-
subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
|
41
|
-
|
42
|
-
parser_eval = subparsers.add_parser(
|
43
|
-
"eval",
|
44
|
-
description="Run an evaluation",
|
45
|
-
help="Run an evaluation",
|
46
|
-
)
|
47
|
-
parser_eval.add_argument("file", help="A file containing the evaluation to run")
|
48
|
-
|
49
|
-
parsed = parser.parse_args()
|
50
|
-
if parsed.subcommand == "eval":
|
51
|
-
asyncio.run(run_evaluation(parsed))
|
52
|
-
else:
|
53
|
-
parser.print_help()
|
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
|
File without changes
|
File without changes
|
File without changes
|