embed-client-dev 4.0.78__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.
- embed_client/__init__.py +36 -0
- embed_client/__main__.py +15 -0
- embed_client/_version.py +3 -0
- embed_client/adapter_config_factory.py +213 -0
- embed_client/adapter_config_normalizer.py +135 -0
- embed_client/adapter_generator_bridge.py +166 -0
- embed_client/auth.py +189 -0
- embed_client/cli.py +483 -0
- embed_client/cli_core.py +427 -0
- embed_client/client_factory.py +515 -0
- embed_client/client_factory_examples.py +375 -0
- embed_client/client_factory_helpers.py +59 -0
- embed_client/config.py +408 -0
- embed_client/config_defaults.py +77 -0
- embed_client/config_examples.py +228 -0
- embed_client/config_generator.py +652 -0
- embed_client/config_generator_cli.py +151 -0
- embed_client/config_presets.py +245 -0
- embed_client/config_validator.py +246 -0
- embed_client/config_validator_cli.py +141 -0
- embed_client/constants.py +52 -0
- embed_client/demo_cli.py +78 -0
- embed_client/demo_security_cli.py +206 -0
- embed_client/embed_file_output_validate.py +348 -0
- embed_client/embed_file_status_store.py +80 -0
- embed_client/embedding_client.py +1929 -0
- embed_client/embedding_client_helpers.py +105 -0
- embed_client/example_async_usage.py +357 -0
- embed_client/example_async_usage_demo.py +282 -0
- embed_client/example_async_usage_ru.py +340 -0
- embed_client/example_async_usage_ru_demo.py +313 -0
- embed_client/exceptions.py +122 -0
- embed_client/identifier_types.py +56 -0
- embed_client/json_embed_file_preflight.py +128 -0
- embed_client/local_json_embed_file.py +73 -0
- embed_client/md_embed_file_prep.py +197 -0
- embed_client/response_normalizer.py +160 -0
- embed_client/response_parsers.py +219 -0
- embed_client/security_cli.py +200 -0
- embed_client/security_cli_core.py +227 -0
- embed_client/ssl_examples.py +278 -0
- embed_client/ssl_manager.py +141 -0
- embed_client_dev-4.0.78.dist-info/METADATA +155 -0
- embed_client_dev-4.0.78.dist-info/RECORD +48 -0
- embed_client_dev-4.0.78.dist-info/WHEEL +5 -0
- embed_client_dev-4.0.78.dist-info/entry_points.txt +4 -0
- embed_client_dev-4.0.78.dist-info/licenses/LICENSE +21 -0
- embed_client_dev-4.0.78.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helper functions for EmbeddingClient (polling and list_commands).
|
|
3
|
+
|
|
4
|
+
Author: Vasiliy Zdanovskiy
|
|
5
|
+
email: vasilyvz@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import time
|
|
10
|
+
from typing import Any, Dict, Optional, Union, cast
|
|
11
|
+
|
|
12
|
+
from embed_client.exceptions import EmbedClientError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _status_exists(status: Dict[str, Any]) -> bool:
|
|
16
|
+
"""Whether a job_status dict names a known job.
|
|
17
|
+
|
|
18
|
+
embed_job_status carries an explicit ``exists`` flag. queue_get_job_status data does not
|
|
19
|
+
(it has ``job_id``/``status``/``result``/``error`` only), so a queue status that names a
|
|
20
|
+
state means the job exists. An empty payload or ``exists: false`` means it is missing.
|
|
21
|
+
"""
|
|
22
|
+
if "exists" in status:
|
|
23
|
+
return bool(status.get("exists"))
|
|
24
|
+
return bool(status.get("status"))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _nested_result_data(inner: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
28
|
+
"""Return the first ``data`` dict inside the ``result`` chain of a queue status result.
|
|
29
|
+
|
|
30
|
+
queue_get_job_status keeps the embed envelope one level deeper than embed_job_status:
|
|
31
|
+
``result = {job_id, command, result: {success, data: <embed result>}}``.
|
|
32
|
+
"""
|
|
33
|
+
node: Any = inner.get("result")
|
|
34
|
+
while isinstance(node, dict):
|
|
35
|
+
data = node.get("data")
|
|
36
|
+
if isinstance(data, dict):
|
|
37
|
+
return data
|
|
38
|
+
node = node.get("result")
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
async def wait_for_job_poll(
|
|
43
|
+
job_status_fn: Any,
|
|
44
|
+
job_id: str,
|
|
45
|
+
timeout: Union[int, float] = 60,
|
|
46
|
+
poll_interval: float = 1.0,
|
|
47
|
+
) -> Dict[str, Any]:
|
|
48
|
+
"""
|
|
49
|
+
Poll job_status until done or timeout.
|
|
50
|
+
|
|
51
|
+
job_status_fn: async callable(job_id) -> status dict, in either the embed_job_status
|
|
52
|
+
shape (``exists``/``done``) or the queue_get_job_status shape (``status``/``result``).
|
|
53
|
+
Returns result data on completion; raises EmbedClientError or TimeoutError.
|
|
54
|
+
"""
|
|
55
|
+
start_time = time.time()
|
|
56
|
+
while timeout == 0 or (time.time() - start_time < timeout):
|
|
57
|
+
status = await job_status_fn(job_id)
|
|
58
|
+
if not _status_exists(status):
|
|
59
|
+
raise EmbedClientError(f"Job {job_id} not found")
|
|
60
|
+
done = status.get("done", False) or status.get("status") in (
|
|
61
|
+
"completed",
|
|
62
|
+
"failed",
|
|
63
|
+
"error",
|
|
64
|
+
)
|
|
65
|
+
if done:
|
|
66
|
+
job_status = status.get("status", "")
|
|
67
|
+
if job_status in ("completed", "success"):
|
|
68
|
+
inner = status.get("result") or status.get("data") or status
|
|
69
|
+
if isinstance(inner, dict):
|
|
70
|
+
data = inner.get("data")
|
|
71
|
+
if data is not None:
|
|
72
|
+
return cast(Dict[str, Any], data)
|
|
73
|
+
nested = _nested_result_data(inner)
|
|
74
|
+
if nested is not None:
|
|
75
|
+
return cast(Dict[str, Any], nested)
|
|
76
|
+
return cast(Dict[str, Any], inner if isinstance(inner, dict) else {})
|
|
77
|
+
if job_status in ("failed", "error"):
|
|
78
|
+
error = status.get("error") or status.get("message", "Unknown error")
|
|
79
|
+
raise EmbedClientError(
|
|
80
|
+
f"Job failed: {error}",
|
|
81
|
+
error=status.get("error") or status.get("message"),
|
|
82
|
+
)
|
|
83
|
+
raise EmbedClientError(
|
|
84
|
+
f"Job completed with unexpected status: {job_status}"
|
|
85
|
+
)
|
|
86
|
+
await asyncio.sleep(poll_interval)
|
|
87
|
+
raise TimeoutError(f"Job {job_id} did not complete within {timeout} seconds")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
async def list_commands_via_client(jsonrpc_call: Any) -> Dict[str, Any]:
|
|
91
|
+
"""
|
|
92
|
+
Call list/help/commands via jsonrpc_call(cmd_name, {}); return data or {}.
|
|
93
|
+
"""
|
|
94
|
+
for cmd_name in ["list", "help", "commands"]:
|
|
95
|
+
try:
|
|
96
|
+
response = await jsonrpc_call(cmd_name, {})
|
|
97
|
+
if "error" not in response:
|
|
98
|
+
result = response.get("result", {})
|
|
99
|
+
return cast(Dict[str, Any], result.get("data", result))
|
|
100
|
+
except Exception:
|
|
101
|
+
continue
|
|
102
|
+
return {}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
__all__ = ["wait_for_job_poll", "list_commands_via_client"]
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Embedding client example — :class:`~embed_client.embedding_client.EmbeddingClient` with
|
|
3
|
+
``ClientFactory`` and CLI-driven config.
|
|
4
|
+
|
|
5
|
+
Author: Vasiliy Zdanovskiy
|
|
6
|
+
email: vasilyvz@gmail.com
|
|
7
|
+
|
|
8
|
+
This script shows how to build configuration from CLI arguments, files, and environment
|
|
9
|
+
variables; construct clients for security modes via ``ClientFactory``; and run
|
|
10
|
+
demonstration flows with ``--demo-mode``.
|
|
11
|
+
|
|
12
|
+
**SEE ALSO:** ``docs/client_integration_guide.md``, ``README.md``,
|
|
13
|
+
``examples/canonical_mtls_localhost_8001.py`` (canonical localhost:8001 mTLS tour).
|
|
14
|
+
|
|
15
|
+
**ENVIRONMENT:** respects the same ``EMBED_CLIENT_*`` variables as ``ClientConfig`` when loading.
|
|
16
|
+
|
|
17
|
+
**EXIT STATUS:** ``0`` on success; ``1`` on configuration or unexpected errors (see ``main()``).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import asyncio
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
import sys
|
|
25
|
+
from typing import Any, Dict
|
|
26
|
+
|
|
27
|
+
from embed_client.embedding_client import EmbeddingClient
|
|
28
|
+
from embed_client.exceptions import EmbedConfigError
|
|
29
|
+
from embed_client.config import ClientConfig
|
|
30
|
+
from embed_client.client_factory import ClientFactory, create_client
|
|
31
|
+
from embed_client.example_async_usage_demo import (
|
|
32
|
+
run_client_examples,
|
|
33
|
+
demonstrate_security_modes,
|
|
34
|
+
demonstrate_automatic_detection,
|
|
35
|
+
demonstrate_with_auth_method,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_params() -> Any:
|
|
40
|
+
"""Parse command line arguments and environment variables for client configuration."""
|
|
41
|
+
parser = argparse.ArgumentParser(
|
|
42
|
+
description="EmbeddingClient example — all security modes (CLI + demo)"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Basic connection parameters
|
|
46
|
+
parser.add_argument("--base-url", "-b", help="Base URL of the embedding service")
|
|
47
|
+
parser.add_argument("--port", "-p", type=int, help="Port of the embedding service")
|
|
48
|
+
parser.add_argument("--config", "-c", help="Path to configuration file")
|
|
49
|
+
|
|
50
|
+
# Client factory mode
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"--factory-mode",
|
|
53
|
+
choices=[
|
|
54
|
+
"auto",
|
|
55
|
+
"http",
|
|
56
|
+
"http_token",
|
|
57
|
+
"https",
|
|
58
|
+
"https_token",
|
|
59
|
+
"mtls",
|
|
60
|
+
"mtls_roles",
|
|
61
|
+
],
|
|
62
|
+
default="auto",
|
|
63
|
+
help="Client factory mode (auto for automatic detection)",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Authentication parameters
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--auth-method",
|
|
69
|
+
choices=["none", "api_key", "jwt", "basic", "certificate"],
|
|
70
|
+
default="none",
|
|
71
|
+
help="Authentication method",
|
|
72
|
+
)
|
|
73
|
+
parser.add_argument("--api-key", help="API key for api_key authentication")
|
|
74
|
+
parser.add_argument("--jwt-secret", help="JWT secret for jwt authentication")
|
|
75
|
+
parser.add_argument("--jwt-username", help="JWT username for jwt authentication")
|
|
76
|
+
parser.add_argument("--jwt-password", help="JWT password for jwt authentication")
|
|
77
|
+
parser.add_argument("--username", help="Username for basic authentication")
|
|
78
|
+
parser.add_argument("--password", help="Password for basic authentication")
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--cert-file", help="Certificate file for certificate authentication"
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument("--key-file", help="Key file for certificate authentication")
|
|
83
|
+
|
|
84
|
+
# SSL/TLS parameters
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"--ssl-verify-mode",
|
|
87
|
+
choices=["CERT_NONE", "CERT_OPTIONAL", "CERT_REQUIRED"],
|
|
88
|
+
default="CERT_REQUIRED",
|
|
89
|
+
help="SSL certificate verification mode",
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--ssl-check-hostname",
|
|
93
|
+
action="store_true",
|
|
94
|
+
default=True,
|
|
95
|
+
help="Enable SSL hostname checking",
|
|
96
|
+
)
|
|
97
|
+
parser.add_argument(
|
|
98
|
+
"--ssl-check-expiry",
|
|
99
|
+
action="store_true",
|
|
100
|
+
default=True,
|
|
101
|
+
help="Enable SSL certificate expiry checking",
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"--ca-cert-file", help="CA certificate file for SSL verification"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Role-based access control (for mTLS + Roles)
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"--roles", help="Comma-separated list of roles for mTLS + Roles mode"
|
|
110
|
+
)
|
|
111
|
+
parser.add_argument(
|
|
112
|
+
"--role-attributes", help="JSON string of role attributes for mTLS + Roles mode"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Additional parameters
|
|
116
|
+
parser.add_argument(
|
|
117
|
+
"--timeout", type=float, default=30.0, help="Request timeout in seconds"
|
|
118
|
+
)
|
|
119
|
+
parser.add_argument(
|
|
120
|
+
"--demo-mode",
|
|
121
|
+
action="store_true",
|
|
122
|
+
help="Run in demo mode (show all security modes)",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
args = parser.parse_args()
|
|
126
|
+
|
|
127
|
+
# Store demo_mode in args for later use
|
|
128
|
+
args.demo_mode = args.demo_mode
|
|
129
|
+
|
|
130
|
+
# If demo mode is requested, return args directly
|
|
131
|
+
if args.demo_mode:
|
|
132
|
+
return args
|
|
133
|
+
|
|
134
|
+
# If config file is provided, load it
|
|
135
|
+
if args.config:
|
|
136
|
+
try:
|
|
137
|
+
config = ClientConfig()
|
|
138
|
+
config.load_from_file(args.config)
|
|
139
|
+
return config
|
|
140
|
+
except Exception as e:
|
|
141
|
+
print(f"Error loading config file {args.config}: {e}")
|
|
142
|
+
sys.exit(1)
|
|
143
|
+
|
|
144
|
+
# Otherwise, build config from arguments and environment variables
|
|
145
|
+
base_url = args.base_url or os.environ.get(
|
|
146
|
+
"EMBED_CLIENT_BASE_URL", "http://localhost"
|
|
147
|
+
)
|
|
148
|
+
port = args.port or int(os.environ.get("EMBED_CLIENT_PORT", "8001"))
|
|
149
|
+
|
|
150
|
+
if not base_url or not port:
|
|
151
|
+
print(
|
|
152
|
+
"Error: base_url and port must be provided via --base-url/--port "
|
|
153
|
+
"arguments or EMBED_CLIENT_BASE_URL/EMBED_CLIENT_PORT "
|
|
154
|
+
"environment variables."
|
|
155
|
+
)
|
|
156
|
+
sys.exit(1)
|
|
157
|
+
|
|
158
|
+
# Build configuration dictionary
|
|
159
|
+
config_dict: Dict[str, Any] = {
|
|
160
|
+
"server": {"host": base_url, "port": port},
|
|
161
|
+
"client": {"timeout": args.timeout},
|
|
162
|
+
"auth": {"method": args.auth_method},
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Add authentication configuration
|
|
166
|
+
if args.auth_method == "api_key":
|
|
167
|
+
api_key = args.api_key or os.environ.get("EMBED_CLIENT_API_KEY")
|
|
168
|
+
if api_key:
|
|
169
|
+
config_dict["auth"]["api_keys"] = {"user": api_key}
|
|
170
|
+
else:
|
|
171
|
+
print("Warning: API key not provided for api_key authentication")
|
|
172
|
+
|
|
173
|
+
elif args.auth_method == "jwt":
|
|
174
|
+
jwt_secret = args.jwt_secret or os.environ.get("EMBED_CLIENT_JWT_SECRET")
|
|
175
|
+
jwt_username = args.jwt_username or os.environ.get("EMBED_CLIENT_JWT_USERNAME")
|
|
176
|
+
jwt_password = args.jwt_password or os.environ.get("EMBED_CLIENT_JWT_PASSWORD")
|
|
177
|
+
|
|
178
|
+
if jwt_secret and jwt_username and jwt_password:
|
|
179
|
+
config_dict["auth"]["jwt"] = {
|
|
180
|
+
"secret": jwt_secret,
|
|
181
|
+
"username": jwt_username,
|
|
182
|
+
"password": jwt_password,
|
|
183
|
+
}
|
|
184
|
+
else:
|
|
185
|
+
print("Warning: JWT credentials not fully provided")
|
|
186
|
+
|
|
187
|
+
elif args.auth_method == "basic":
|
|
188
|
+
username = args.username or os.environ.get("EMBED_CLIENT_USERNAME")
|
|
189
|
+
password = args.password or os.environ.get("EMBED_CLIENT_PASSWORD")
|
|
190
|
+
|
|
191
|
+
if username and password:
|
|
192
|
+
config_dict["auth"]["basic"] = {"username": username, "password": password}
|
|
193
|
+
else:
|
|
194
|
+
print("Warning: Basic auth credentials not fully provided")
|
|
195
|
+
|
|
196
|
+
elif args.auth_method == "certificate":
|
|
197
|
+
cert_file = args.cert_file or os.environ.get("EMBED_CLIENT_CERT_FILE")
|
|
198
|
+
key_file = args.key_file or os.environ.get("EMBED_CLIENT_KEY_FILE")
|
|
199
|
+
|
|
200
|
+
if cert_file and key_file:
|
|
201
|
+
config_dict["auth"]["certificate"] = {
|
|
202
|
+
"cert_file": cert_file,
|
|
203
|
+
"key_file": key_file,
|
|
204
|
+
}
|
|
205
|
+
else:
|
|
206
|
+
print("Warning: Certificate files not fully provided")
|
|
207
|
+
|
|
208
|
+
# Add SSL configuration if HTTPS is used or SSL parameters are provided
|
|
209
|
+
if (
|
|
210
|
+
base_url.startswith("https://")
|
|
211
|
+
or args.ssl_verify_mode != "CERT_REQUIRED"
|
|
212
|
+
or args.ca_cert_file
|
|
213
|
+
):
|
|
214
|
+
# Force check_hostname=False for CERT_NONE mode
|
|
215
|
+
check_hostname = args.ssl_check_hostname
|
|
216
|
+
if args.ssl_verify_mode == "CERT_NONE":
|
|
217
|
+
check_hostname = False
|
|
218
|
+
|
|
219
|
+
config_dict["ssl"] = {
|
|
220
|
+
"enabled": True,
|
|
221
|
+
"verify_mode": args.ssl_verify_mode,
|
|
222
|
+
"check_hostname": check_hostname,
|
|
223
|
+
"check_expiry": args.ssl_check_expiry,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if args.ca_cert_file:
|
|
227
|
+
config_dict["ssl"]["ca_cert_file"] = args.ca_cert_file
|
|
228
|
+
|
|
229
|
+
# Add client certificates for mTLS
|
|
230
|
+
if args.cert_file:
|
|
231
|
+
config_dict["ssl"]["cert_file"] = args.cert_file
|
|
232
|
+
if args.key_file:
|
|
233
|
+
config_dict["ssl"]["key_file"] = args.key_file
|
|
234
|
+
|
|
235
|
+
# Add role-based access control for mTLS + Roles
|
|
236
|
+
if args.roles:
|
|
237
|
+
roles = [role.strip() for role in args.roles.split(",")]
|
|
238
|
+
config_dict["roles"] = roles
|
|
239
|
+
|
|
240
|
+
if args.role_attributes:
|
|
241
|
+
try:
|
|
242
|
+
role_attributes = json.loads(args.role_attributes)
|
|
243
|
+
config_dict["role_attributes"] = role_attributes
|
|
244
|
+
except json.JSONDecodeError:
|
|
245
|
+
print("Warning: Invalid JSON in role_attributes")
|
|
246
|
+
|
|
247
|
+
return config_dict
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
async def main():
|
|
251
|
+
try:
|
|
252
|
+
config = get_params()
|
|
253
|
+
|
|
254
|
+
# Check if demo mode is requested
|
|
255
|
+
if hasattr(config, "demo_mode") and config.demo_mode:
|
|
256
|
+
await demonstrate_security_modes()
|
|
257
|
+
await demonstrate_automatic_detection()
|
|
258
|
+
await demonstrate_with_auth_method()
|
|
259
|
+
return
|
|
260
|
+
|
|
261
|
+
# Create client based on factory mode
|
|
262
|
+
if isinstance(config, ClientConfig):
|
|
263
|
+
# Using configuration object
|
|
264
|
+
client = EmbeddingClient.from_config(config)
|
|
265
|
+
else:
|
|
266
|
+
# Using configuration dictionary
|
|
267
|
+
factory_mode = getattr(config, "factory_mode", "auto")
|
|
268
|
+
|
|
269
|
+
if factory_mode == "auto":
|
|
270
|
+
# Automatic detection
|
|
271
|
+
client = create_client(
|
|
272
|
+
config["server"]["host"],
|
|
273
|
+
config["server"]["port"],
|
|
274
|
+
auth_method=config["auth"]["method"],
|
|
275
|
+
**{
|
|
276
|
+
k: v
|
|
277
|
+
for k, v in config.items()
|
|
278
|
+
if k not in ["server", "auth", "ssl", "client"]
|
|
279
|
+
},
|
|
280
|
+
)
|
|
281
|
+
else:
|
|
282
|
+
# Specific factory method
|
|
283
|
+
base_url = config["server"]["host"]
|
|
284
|
+
port = config["server"]["port"]
|
|
285
|
+
auth_method = config["auth"]["method"]
|
|
286
|
+
|
|
287
|
+
if factory_mode == "http":
|
|
288
|
+
client = ClientFactory.create_http_client(base_url, port)
|
|
289
|
+
elif factory_mode == "http_token":
|
|
290
|
+
client = ClientFactory.create_http_token_client(
|
|
291
|
+
base_url, port, auth_method, **config.get("auth", {})
|
|
292
|
+
)
|
|
293
|
+
elif factory_mode == "https":
|
|
294
|
+
client = ClientFactory.create_https_client(base_url, port)
|
|
295
|
+
elif factory_mode == "https_token":
|
|
296
|
+
client = ClientFactory.create_https_token_client(
|
|
297
|
+
base_url, port, auth_method, **config.get("auth", {})
|
|
298
|
+
)
|
|
299
|
+
elif factory_mode == "mtls":
|
|
300
|
+
cert_file = config.get("ssl", {}).get(
|
|
301
|
+
"cert_file", "client_cert.pem"
|
|
302
|
+
)
|
|
303
|
+
key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
|
|
304
|
+
client = ClientFactory.create_mtls_client(
|
|
305
|
+
base_url, cert_file, key_file, port
|
|
306
|
+
)
|
|
307
|
+
elif factory_mode == "mtls_roles":
|
|
308
|
+
cert_file = config.get("ssl", {}).get(
|
|
309
|
+
"cert_file", "client_cert.pem"
|
|
310
|
+
)
|
|
311
|
+
key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
|
|
312
|
+
roles = config.get("roles", ["admin"])
|
|
313
|
+
role_attributes = config.get("role_attributes", {})
|
|
314
|
+
client = ClientFactory.create_mtls_roles_client(
|
|
315
|
+
base_url, cert_file, key_file, port, roles, role_attributes
|
|
316
|
+
)
|
|
317
|
+
else:
|
|
318
|
+
client = EmbeddingClient.from_config_dict(config)
|
|
319
|
+
|
|
320
|
+
print("Client configuration:")
|
|
321
|
+
print(f" Base URL: {client.base_url}")
|
|
322
|
+
print(f" Port: {client.port}")
|
|
323
|
+
print(f" Authentication: {client.get_auth_method()}")
|
|
324
|
+
print(f" Authenticated: {client.is_authenticated()}")
|
|
325
|
+
if client.is_authenticated():
|
|
326
|
+
headers = client.get_auth_headers()
|
|
327
|
+
print(f" Auth headers: {headers}")
|
|
328
|
+
print(f" SSL enabled: {client.is_ssl_enabled()}")
|
|
329
|
+
print(f" mTLS enabled: {client.is_mtls_enabled()}")
|
|
330
|
+
if client.is_ssl_enabled():
|
|
331
|
+
ssl_config = client.get_ssl_config()
|
|
332
|
+
print(f" SSL config: {ssl_config}")
|
|
333
|
+
print()
|
|
334
|
+
|
|
335
|
+
# Explicit open/close example
|
|
336
|
+
print("Explicit session open/close example:")
|
|
337
|
+
await client.close()
|
|
338
|
+
print("Session closed explicitly (manual close example).\n")
|
|
339
|
+
|
|
340
|
+
# Use context manager
|
|
341
|
+
if isinstance(config, ClientConfig):
|
|
342
|
+
async with EmbeddingClient.from_config(config) as client:
|
|
343
|
+
await run_client_examples(client)
|
|
344
|
+
else:
|
|
345
|
+
async with EmbeddingClient.from_config_dict(config) as client:
|
|
346
|
+
await run_client_examples(client)
|
|
347
|
+
|
|
348
|
+
except EmbedConfigError as e:
|
|
349
|
+
print(f"Configuration error: {e}")
|
|
350
|
+
sys.exit(1)
|
|
351
|
+
except Exception as e:
|
|
352
|
+
print(f"Unexpected error: {e}")
|
|
353
|
+
sys.exit(1)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
if __name__ == "__main__":
|
|
357
|
+
asyncio.run(main())
|