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,282 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Demonstration helpers for ``embed_client/example_async_usage.py``.
|
|
3
|
+
|
|
4
|
+
Author: Vasiliy Zdanovskiy
|
|
5
|
+
email: vasilyvz@gmail.com
|
|
6
|
+
|
|
7
|
+
**run_client_examples** — interactive smoke checks (health, OpenAPI, commands,
|
|
8
|
+
``cmd("embed")``).
|
|
9
|
+
|
|
10
|
+
**demonstrate_security_modes** / **demonstrate_automatic_detection** /
|
|
11
|
+
**demonstrate_with_auth_method** — print-only illustrations of ``ClientFactory``
|
|
12
|
+
constructors (no live server required for most branches).
|
|
13
|
+
|
|
14
|
+
All functions use :class:`~embed_client.embedding_client.EmbeddingClient` or factory
|
|
15
|
+
helpers that yield compatible clients.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Any, Dict, List
|
|
21
|
+
|
|
22
|
+
from embed_client.embedding_client import EmbeddingClient
|
|
23
|
+
from embed_client.exceptions import EmbedError
|
|
24
|
+
from embed_client.client_factory import ClientFactory, detect_security_mode
|
|
25
|
+
from embed_client.response_parsers import extract_embeddings
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def run_client_examples(client: EmbeddingClient) -> None:
|
|
29
|
+
"""
|
|
30
|
+
Run a short interactive tour: health, OpenAPI schema, list_commands, then ``cmd('embed')``.
|
|
31
|
+
|
|
32
|
+
On the first :exc:`~embed_client.exceptions.EmbedError`, prints the error and returns early
|
|
33
|
+
from the health step only; later steps catch per-call.
|
|
34
|
+
"""
|
|
35
|
+
# Check health
|
|
36
|
+
try:
|
|
37
|
+
health = await client.health()
|
|
38
|
+
print("Service health:", health)
|
|
39
|
+
except EmbedError as exc:
|
|
40
|
+
print(f"Error during health check: {exc}")
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
# Get OpenAPI schema
|
|
44
|
+
try:
|
|
45
|
+
schema = await client.fetch_openapi_schema()
|
|
46
|
+
print(
|
|
47
|
+
"OpenAPI schema version:",
|
|
48
|
+
schema.get("info", {}).get("version", "unknown"),
|
|
49
|
+
)
|
|
50
|
+
except EmbedError as exc:
|
|
51
|
+
print(f"Error getting OpenAPI schema: {exc}")
|
|
52
|
+
|
|
53
|
+
# Get available commands
|
|
54
|
+
try:
|
|
55
|
+
commands = await client.list_commands()
|
|
56
|
+
print(f"Available commands: {commands}")
|
|
57
|
+
except EmbedError as exc:
|
|
58
|
+
print(f"Error getting commands: {exc}")
|
|
59
|
+
|
|
60
|
+
# Test embedding generation
|
|
61
|
+
try:
|
|
62
|
+
texts = [
|
|
63
|
+
"Hello, world!",
|
|
64
|
+
"This is a test sentence.",
|
|
65
|
+
"Embedding service is working!",
|
|
66
|
+
]
|
|
67
|
+
result = await client.cmd("embed", {"texts": texts})
|
|
68
|
+
|
|
69
|
+
# Extract embeddings using shared response_parsers helper
|
|
70
|
+
embeddings = extract_embeddings(result)
|
|
71
|
+
print(f"Generated {len(embeddings)} embeddings")
|
|
72
|
+
print(
|
|
73
|
+
"First embedding dimension:",
|
|
74
|
+
len(embeddings[0]) if embeddings else 0,
|
|
75
|
+
)
|
|
76
|
+
except EmbedError as exc:
|
|
77
|
+
print(f"Error during embedding generation: {exc}")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
async def demonstrate_security_modes() -> None:
|
|
81
|
+
"""
|
|
82
|
+
Print-oriented walkthrough of six factory construction patterns (HTTP through mTLS roles).
|
|
83
|
+
|
|
84
|
+
Does not connect to a real server unless the user later uses the returned configs elsewhere.
|
|
85
|
+
"""
|
|
86
|
+
print("=== Security Modes Demonstration ===")
|
|
87
|
+
print("This demonstration shows how to create clients for all 6 security modes.")
|
|
88
|
+
print(
|
|
89
|
+
"Note: These examples create client configurations "
|
|
90
|
+
"but don't connect to actual servers."
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# 1. HTTP mode
|
|
94
|
+
print("\n1. HTTP Mode (no authentication, no SSL):")
|
|
95
|
+
print(" Use case: Development, internal networks, trusted environments")
|
|
96
|
+
try:
|
|
97
|
+
client = ClientFactory.create_http_client("http://localhost", 8001)
|
|
98
|
+
print(f" ✓ Created HTTP client: {client!r}")
|
|
99
|
+
await client.close()
|
|
100
|
+
except Exception as exc: # noqa: BLE001
|
|
101
|
+
print(f" ✗ Error: {exc}")
|
|
102
|
+
|
|
103
|
+
# 2. HTTP + Token mode
|
|
104
|
+
print("\n2. HTTP + Token Mode (HTTP with API key):")
|
|
105
|
+
print(" Use case: API access control, simple authentication")
|
|
106
|
+
try:
|
|
107
|
+
client = ClientFactory.create_http_token_client(
|
|
108
|
+
"http://localhost", 8001, "api_key", api_key="demo_key"
|
|
109
|
+
)
|
|
110
|
+
print(f" ✓ Created HTTP + Token client: {client!r}")
|
|
111
|
+
await client.close()
|
|
112
|
+
except Exception as exc: # noqa: BLE001
|
|
113
|
+
print(f" ✗ Error: {exc}")
|
|
114
|
+
|
|
115
|
+
# 3. HTTPS mode
|
|
116
|
+
print("\n3. HTTPS Mode (HTTPS with server certificates):")
|
|
117
|
+
print(" Use case: Secure communication, public networks")
|
|
118
|
+
try:
|
|
119
|
+
client = ClientFactory.create_https_client("https://localhost", 9443)
|
|
120
|
+
print(f" ✓ Created HTTPS client: {client!r}")
|
|
121
|
+
await client.close()
|
|
122
|
+
except Exception as exc: # noqa: BLE001
|
|
123
|
+
print(f" ✗ Error: {exc}")
|
|
124
|
+
|
|
125
|
+
# 4. HTTPS + Token mode
|
|
126
|
+
print(
|
|
127
|
+
"\n4. HTTPS + Token Mode " "(HTTPS with server certificates + authentication):"
|
|
128
|
+
)
|
|
129
|
+
print(" Use case: Secure API access, production environments")
|
|
130
|
+
try:
|
|
131
|
+
client = ClientFactory.create_https_token_client(
|
|
132
|
+
"https://localhost",
|
|
133
|
+
9443,
|
|
134
|
+
"basic",
|
|
135
|
+
username="admin",
|
|
136
|
+
password="secret",
|
|
137
|
+
)
|
|
138
|
+
print(f" ✓ Created HTTPS + Token client: {client!r}")
|
|
139
|
+
await client.close()
|
|
140
|
+
except Exception as exc: # noqa: BLE001
|
|
141
|
+
print(f" ✗ Error: {exc}")
|
|
142
|
+
|
|
143
|
+
# 5. mTLS mode
|
|
144
|
+
print("\n5. mTLS Mode (mutual TLS with client and server certificates):")
|
|
145
|
+
print(" Use case: High security, client certificate authentication")
|
|
146
|
+
try:
|
|
147
|
+
client = ClientFactory.create_mtls_client(
|
|
148
|
+
"https://localhost",
|
|
149
|
+
"mtls_certificates/client/embedding-service.crt",
|
|
150
|
+
"mtls_certificates/client/embedding-service.key",
|
|
151
|
+
8443,
|
|
152
|
+
)
|
|
153
|
+
print(f" ✓ Created mTLS client: {client!r}")
|
|
154
|
+
await client.close()
|
|
155
|
+
except Exception as exc: # noqa: BLE001
|
|
156
|
+
print(f" ✗ Error: {exc}")
|
|
157
|
+
|
|
158
|
+
# 6. mTLS + Roles mode
|
|
159
|
+
print("\n6. mTLS + Roles Mode (mTLS with role-based access control):")
|
|
160
|
+
print(" Use case: Enterprise security, role-based permissions")
|
|
161
|
+
try:
|
|
162
|
+
client = ClientFactory.create_mtls_roles_client(
|
|
163
|
+
"https://localhost",
|
|
164
|
+
"mtls_certificates/client/embedding-service.crt",
|
|
165
|
+
"mtls_certificates/client/embedding-service.key",
|
|
166
|
+
8443,
|
|
167
|
+
roles=["admin", "user"],
|
|
168
|
+
role_attributes={"department": "IT"},
|
|
169
|
+
)
|
|
170
|
+
print(f" ✓ Created mTLS + Roles client: {client!r}")
|
|
171
|
+
await client.close()
|
|
172
|
+
except Exception as exc: # noqa: BLE001
|
|
173
|
+
print(f" ✗ Error: {exc}")
|
|
174
|
+
|
|
175
|
+
print("\n=== Security Mode Summary ===")
|
|
176
|
+
print("1. HTTP: Basic connectivity, no security")
|
|
177
|
+
print("2. HTTP + Token: API key authentication over HTTP")
|
|
178
|
+
print("3. HTTPS: Encrypted communication with server certificates")
|
|
179
|
+
print("4. HTTPS + Token: Encrypted communication + authentication")
|
|
180
|
+
print("5. mTLS: Mutual certificate authentication")
|
|
181
|
+
print("6. mTLS + Roles: Mutual certificates + role-based access control")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
async def demonstrate_automatic_detection() -> None:
|
|
185
|
+
"""Demonstrate automatic security mode detection."""
|
|
186
|
+
print("\n=== Automatic Security Mode Detection ===")
|
|
187
|
+
print(
|
|
188
|
+
"This shows how the client automatically detects the "
|
|
189
|
+
"appropriate security mode."
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
test_cases: List[Any] = [
|
|
193
|
+
("http://localhost", None, None, None, None, "HTTP"),
|
|
194
|
+
("http://localhost", "api_key", None, None, None, "HTTP + Token"),
|
|
195
|
+
("https://localhost", None, None, None, None, "HTTPS"),
|
|
196
|
+
("https://localhost", "api_key", None, None, None, "HTTPS + Token"),
|
|
197
|
+
("https://localhost", None, None, "cert.pem", "key.pem", "mTLS"),
|
|
198
|
+
(
|
|
199
|
+
"https://localhost",
|
|
200
|
+
None,
|
|
201
|
+
None,
|
|
202
|
+
"cert.pem",
|
|
203
|
+
"key.pem",
|
|
204
|
+
"mTLS + Roles",
|
|
205
|
+
{"roles": ["admin"]},
|
|
206
|
+
),
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
for case in test_cases:
|
|
210
|
+
if len(case) == 6:
|
|
211
|
+
base_url, auth_method, ssl_enabled, cert_file, key_file, expected = case
|
|
212
|
+
kwargs: Dict[str, Any] = {}
|
|
213
|
+
else:
|
|
214
|
+
(
|
|
215
|
+
base_url,
|
|
216
|
+
auth_method,
|
|
217
|
+
ssl_enabled,
|
|
218
|
+
cert_file,
|
|
219
|
+
key_file,
|
|
220
|
+
expected,
|
|
221
|
+
kwargs,
|
|
222
|
+
) = case
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
mode = detect_security_mode(
|
|
226
|
+
base_url, auth_method, ssl_enabled, cert_file, key_file, **kwargs
|
|
227
|
+
)
|
|
228
|
+
print(
|
|
229
|
+
f" ✓ {base_url} + {auth_method or 'none'} + "
|
|
230
|
+
f"{cert_file or 'no cert'} -> {mode} ({expected})"
|
|
231
|
+
)
|
|
232
|
+
except Exception as exc: # noqa: BLE001
|
|
233
|
+
print(f" ✗ Error detecting mode for {base_url}: {exc}")
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async def demonstrate_with_auth_method() -> None:
|
|
237
|
+
"""Demonstrate the with_auth method for dynamic authentication."""
|
|
238
|
+
print("\n=== Dynamic Authentication with with_auth() Method ===")
|
|
239
|
+
print(
|
|
240
|
+
"This shows how to create clients with different authentication "
|
|
241
|
+
"methods using the with_auth class method."
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Demonstrate different authentication methods
|
|
245
|
+
auth_examples = [
|
|
246
|
+
("api_key", {"api_key": "dynamic_api_key"}, "API Key Authentication"),
|
|
247
|
+
(
|
|
248
|
+
"jwt",
|
|
249
|
+
{"secret": "secret", "username": "user", "password": "pass"},
|
|
250
|
+
"JWT Authentication",
|
|
251
|
+
),
|
|
252
|
+
("basic", {"username": "admin", "password": "secret"}, "Basic Authentication"),
|
|
253
|
+
(
|
|
254
|
+
"certificate",
|
|
255
|
+
{"cert_file": "client.crt", "key_file": "client.key"},
|
|
256
|
+
"Certificate Authentication",
|
|
257
|
+
),
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
for auth_method, kwargs, description in auth_examples:
|
|
261
|
+
try:
|
|
262
|
+
print(f"\n{description}:")
|
|
263
|
+
auth_client = EmbeddingClient.with_auth(
|
|
264
|
+
"http://localhost",
|
|
265
|
+
8001,
|
|
266
|
+
auth_method,
|
|
267
|
+
**kwargs,
|
|
268
|
+
)
|
|
269
|
+
print(f" ✓ Client: {auth_client!r}")
|
|
270
|
+
await auth_client.close()
|
|
271
|
+
except Exception as exc: # noqa: BLE001
|
|
272
|
+
print(f" ✗ Error with {auth_method}: {exc}")
|
|
273
|
+
|
|
274
|
+
print("\n✓ Dynamic authentication demonstration completed.")
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
__all__ = [
|
|
278
|
+
"run_client_examples",
|
|
279
|
+
"demonstrate_security_modes",
|
|
280
|
+
"demonstrate_automatic_detection",
|
|
281
|
+
"demonstrate_with_auth_method",
|
|
282
|
+
]
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Пример :class:`~embed_client.embedding_client.EmbeddingClient` со всеми режимами безопасности и ``ClientFactory``.
|
|
3
|
+
|
|
4
|
+
Author: Vasiliy Zdanovskiy
|
|
5
|
+
email: vasilyvz@gmail.com
|
|
6
|
+
|
|
7
|
+
См. также (пути в репозитории): ``docs/client_integration_guide.md``, ``README.md``,
|
|
8
|
+
``examples/canonical_mtls_localhost_8001.py`` (канонический mTLS localhost:8001).
|
|
9
|
+
|
|
10
|
+
**Код выхода:** ``0`` при успехе, ``1`` при ошибке конфигурации или необработанном исключении.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import asyncio
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
from typing import Any, Dict
|
|
19
|
+
|
|
20
|
+
from embed_client.embedding_client import EmbeddingClient
|
|
21
|
+
from embed_client.exceptions import EmbedConfigError
|
|
22
|
+
from embed_client.config import ClientConfig
|
|
23
|
+
from embed_client.client_factory import ClientFactory, create_client
|
|
24
|
+
from embed_client.example_async_usage_ru_demo import (
|
|
25
|
+
run_client_examples,
|
|
26
|
+
demonstrate_security_modes,
|
|
27
|
+
demonstrate_automatic_detection,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_params() -> Any:
|
|
32
|
+
"""Парсинг аргументов командной строки и переменных окружения для конфигурации клиента."""
|
|
33
|
+
parser = argparse.ArgumentParser(
|
|
34
|
+
description="Пример EmbeddingClient — все режимы безопасности (CLI + демо)"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Базовые параметры подключения
|
|
38
|
+
parser.add_argument("--base-url", "-b", help="Базовый URL сервиса эмбеддингов")
|
|
39
|
+
parser.add_argument("--port", "-p", type=int, help="Порт сервиса эмбеддингов")
|
|
40
|
+
parser.add_argument("--config", "-c", help="Путь к файлу конфигурации")
|
|
41
|
+
|
|
42
|
+
# Режим фабрики клиентов
|
|
43
|
+
parser.add_argument(
|
|
44
|
+
"--factory-mode",
|
|
45
|
+
choices=[
|
|
46
|
+
"auto",
|
|
47
|
+
"http",
|
|
48
|
+
"http_token",
|
|
49
|
+
"https",
|
|
50
|
+
"https_token",
|
|
51
|
+
"mtls",
|
|
52
|
+
"mtls_roles",
|
|
53
|
+
],
|
|
54
|
+
default="auto",
|
|
55
|
+
help="Режим фабрики клиентов (auto для автоматического определения)",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Параметры аутентификации
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--auth-method",
|
|
61
|
+
choices=["none", "api_key", "jwt", "basic", "certificate"],
|
|
62
|
+
default="none",
|
|
63
|
+
help="Метод аутентификации",
|
|
64
|
+
)
|
|
65
|
+
parser.add_argument("--api-key", help="API ключ для аутентификации api_key")
|
|
66
|
+
parser.add_argument("--jwt-secret", help="JWT секрет для аутентификации jwt")
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--jwt-username", help="JWT имя пользователя для аутентификации jwt"
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument("--jwt-password", help="JWT пароль для аутентификации jwt")
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--username", help="Имя пользователя для базовой аутентификации"
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument("--password", help="Пароль для базовой аутентификации")
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"--cert-file", help="Файл сертификата для аутентификации certificate"
|
|
77
|
+
)
|
|
78
|
+
parser.add_argument("--key-file", help="Файл ключа для аутентификации certificate")
|
|
79
|
+
|
|
80
|
+
# Параметры SSL/TLS
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--ssl-verify-mode",
|
|
83
|
+
choices=["CERT_NONE", "CERT_OPTIONAL", "CERT_REQUIRED"],
|
|
84
|
+
default="CERT_REQUIRED",
|
|
85
|
+
help="Режим проверки SSL сертификатов",
|
|
86
|
+
)
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"--ssl-check-hostname",
|
|
89
|
+
action="store_true",
|
|
90
|
+
default=True,
|
|
91
|
+
help="Включить проверку имени хоста SSL",
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument(
|
|
94
|
+
"--ssl-check-expiry",
|
|
95
|
+
action="store_true",
|
|
96
|
+
default=True,
|
|
97
|
+
help="Включить проверку срока действия SSL сертификатов",
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument("--ca-cert-file", help="Файл CA сертификата для проверки SSL")
|
|
100
|
+
|
|
101
|
+
# Контроль доступа на основе ролей (для mTLS + Roles)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"--roles", help="Список ролей через запятую для режима mTLS + Roles"
|
|
104
|
+
)
|
|
105
|
+
parser.add_argument(
|
|
106
|
+
"--role-attributes", help="JSON строка атрибутов ролей для режима mTLS + Roles"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Дополнительные параметры
|
|
110
|
+
parser.add_argument(
|
|
111
|
+
"--timeout", type=float, default=30.0, help="Таймаут запроса в секундах"
|
|
112
|
+
)
|
|
113
|
+
parser.add_argument(
|
|
114
|
+
"--demo-mode",
|
|
115
|
+
action="store_true",
|
|
116
|
+
help="Запуск в демо режиме (показать все режимы безопасности)",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
args = parser.parse_args()
|
|
120
|
+
|
|
121
|
+
# Если предоставлен файл конфигурации, загружаем его
|
|
122
|
+
if args.config:
|
|
123
|
+
try:
|
|
124
|
+
config = ClientConfig()
|
|
125
|
+
config.load_config_file(args.config)
|
|
126
|
+
return config
|
|
127
|
+
except Exception as e:
|
|
128
|
+
print(f"Ошибка загрузки файла конфигурации {args.config}: {e}")
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
|
|
131
|
+
# Иначе строим конфигурацию из аргументов и переменных окружения
|
|
132
|
+
base_url = args.base_url or os.environ.get(
|
|
133
|
+
"EMBED_CLIENT_BASE_URL", "http://localhost"
|
|
134
|
+
)
|
|
135
|
+
port = args.port or int(os.environ.get("EMBED_CLIENT_PORT", "8001"))
|
|
136
|
+
|
|
137
|
+
if not base_url or not port:
|
|
138
|
+
print(
|
|
139
|
+
"Ошибка: base_url и port должны быть предоставлены через аргументы "
|
|
140
|
+
"--base-url/--port или переменные окружения EMBED_CLIENT_BASE_URL/"
|
|
141
|
+
"EMBED_CLIENT_PORT."
|
|
142
|
+
)
|
|
143
|
+
sys.exit(1)
|
|
144
|
+
|
|
145
|
+
# Строим словарь конфигурации
|
|
146
|
+
config_dict: Dict[str, Any] = {
|
|
147
|
+
"server": {"host": base_url, "port": port},
|
|
148
|
+
"client": {"timeout": args.timeout},
|
|
149
|
+
"auth": {"method": args.auth_method},
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# Добавляем конфигурацию аутентификации
|
|
153
|
+
if args.auth_method == "api_key":
|
|
154
|
+
api_key = args.api_key or os.environ.get("EMBED_CLIENT_API_KEY")
|
|
155
|
+
if api_key:
|
|
156
|
+
config_dict["auth"]["api_keys"] = {"user": api_key}
|
|
157
|
+
else:
|
|
158
|
+
print("Предупреждение: API ключ не предоставлен для аутентификации api_key")
|
|
159
|
+
|
|
160
|
+
elif args.auth_method == "jwt":
|
|
161
|
+
jwt_secret = args.jwt_secret or os.environ.get("EMBED_CLIENT_JWT_SECRET")
|
|
162
|
+
jwt_username = args.jwt_username or os.environ.get("EMBED_CLIENT_JWT_USERNAME")
|
|
163
|
+
jwt_password = args.jwt_password or os.environ.get("EMBED_CLIENT_JWT_PASSWORD")
|
|
164
|
+
|
|
165
|
+
if jwt_secret and jwt_username and jwt_password:
|
|
166
|
+
config_dict["auth"]["jwt"] = {
|
|
167
|
+
"secret": jwt_secret,
|
|
168
|
+
"username": jwt_username,
|
|
169
|
+
"password": jwt_password,
|
|
170
|
+
}
|
|
171
|
+
else:
|
|
172
|
+
print("Предупреждение: JWT учетные данные не полностью предоставлены")
|
|
173
|
+
|
|
174
|
+
elif args.auth_method == "basic":
|
|
175
|
+
username = args.username or os.environ.get("EMBED_CLIENT_USERNAME")
|
|
176
|
+
password = args.password or os.environ.get("EMBED_CLIENT_PASSWORD")
|
|
177
|
+
|
|
178
|
+
if username and password:
|
|
179
|
+
config_dict["auth"]["basic"] = {"username": username, "password": password}
|
|
180
|
+
else:
|
|
181
|
+
print(
|
|
182
|
+
"Предупреждение: Учетные данные базовой аутентификации не полностью предоставлены"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
elif args.auth_method == "certificate":
|
|
186
|
+
cert_file = args.cert_file or os.environ.get("EMBED_CLIENT_CERT_FILE")
|
|
187
|
+
key_file = args.key_file or os.environ.get("EMBED_CLIENT_KEY_FILE")
|
|
188
|
+
|
|
189
|
+
if cert_file and key_file:
|
|
190
|
+
config_dict["auth"]["certificate"] = {
|
|
191
|
+
"cert_file": cert_file,
|
|
192
|
+
"key_file": key_file,
|
|
193
|
+
}
|
|
194
|
+
else:
|
|
195
|
+
print("Предупреждение: Файлы сертификатов не полностью предоставлены")
|
|
196
|
+
|
|
197
|
+
# Добавляем конфигурацию SSL если используется HTTPS или предоставлены SSL параметры
|
|
198
|
+
if (
|
|
199
|
+
base_url.startswith("https://")
|
|
200
|
+
or args.ssl_verify_mode != "CERT_REQUIRED"
|
|
201
|
+
or args.ca_cert_file
|
|
202
|
+
):
|
|
203
|
+
config_dict["ssl"] = {
|
|
204
|
+
"enabled": True,
|
|
205
|
+
"verify_mode": args.ssl_verify_mode,
|
|
206
|
+
"check_hostname": args.ssl_check_hostname,
|
|
207
|
+
"check_expiry": args.ssl_check_expiry,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if args.ca_cert_file:
|
|
211
|
+
config_dict["ssl"]["ca_cert_file"] = args.ca_cert_file
|
|
212
|
+
|
|
213
|
+
# Добавляем клиентские сертификаты для mTLS
|
|
214
|
+
if args.cert_file:
|
|
215
|
+
config_dict["ssl"]["cert_file"] = args.cert_file
|
|
216
|
+
if args.key_file:
|
|
217
|
+
config_dict["ssl"]["key_file"] = args.key_file
|
|
218
|
+
|
|
219
|
+
# Добавляем контроль доступа на основе ролей для mTLS + Roles
|
|
220
|
+
if args.roles:
|
|
221
|
+
roles = [role.strip() for role in args.roles.split(",")]
|
|
222
|
+
config_dict["roles"] = roles
|
|
223
|
+
|
|
224
|
+
if args.role_attributes:
|
|
225
|
+
try:
|
|
226
|
+
role_attributes = json.loads(args.role_attributes)
|
|
227
|
+
config_dict["role_attributes"] = role_attributes
|
|
228
|
+
except json.JSONDecodeError:
|
|
229
|
+
print("Предупреждение: Неверный JSON в role_attributes")
|
|
230
|
+
|
|
231
|
+
return config_dict
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
async def main():
|
|
235
|
+
try:
|
|
236
|
+
config = get_params()
|
|
237
|
+
|
|
238
|
+
# Проверяем, запрошен ли демо режим
|
|
239
|
+
if hasattr(config, "demo_mode") and config.demo_mode:
|
|
240
|
+
await demonstrate_security_modes()
|
|
241
|
+
await demonstrate_automatic_detection()
|
|
242
|
+
return
|
|
243
|
+
|
|
244
|
+
# Создаем клиент на основе режима фабрики
|
|
245
|
+
if isinstance(config, ClientConfig):
|
|
246
|
+
# Использование объекта конфигурации
|
|
247
|
+
client = EmbeddingClient.from_config(config)
|
|
248
|
+
else:
|
|
249
|
+
# Использование словаря конфигурации
|
|
250
|
+
factory_mode = getattr(config, "factory_mode", "auto")
|
|
251
|
+
|
|
252
|
+
if factory_mode == "auto":
|
|
253
|
+
# Автоматическое определение
|
|
254
|
+
client = create_client(
|
|
255
|
+
config["server"]["host"],
|
|
256
|
+
config["server"]["port"],
|
|
257
|
+
auth_method=config["auth"]["method"],
|
|
258
|
+
**{
|
|
259
|
+
k: v
|
|
260
|
+
for k, v in config.items()
|
|
261
|
+
if k not in ["server", "auth", "ssl", "client"]
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
else:
|
|
265
|
+
# Конкретный метод фабрики
|
|
266
|
+
base_url = config["server"]["host"]
|
|
267
|
+
port = config["server"]["port"]
|
|
268
|
+
auth_method = config["auth"]["method"]
|
|
269
|
+
|
|
270
|
+
if factory_mode == "http":
|
|
271
|
+
client = ClientFactory.create_http_client(base_url, port)
|
|
272
|
+
elif factory_mode == "http_token":
|
|
273
|
+
client = ClientFactory.create_http_token_client(
|
|
274
|
+
base_url, port, auth_method, **config.get("auth", {})
|
|
275
|
+
)
|
|
276
|
+
elif factory_mode == "https":
|
|
277
|
+
client = ClientFactory.create_https_client(base_url, port)
|
|
278
|
+
elif factory_mode == "https_token":
|
|
279
|
+
client = ClientFactory.create_https_token_client(
|
|
280
|
+
base_url, port, auth_method, **config.get("auth", {})
|
|
281
|
+
)
|
|
282
|
+
elif factory_mode == "mtls":
|
|
283
|
+
cert_file = config.get("ssl", {}).get(
|
|
284
|
+
"cert_file", "client_cert.pem"
|
|
285
|
+
)
|
|
286
|
+
key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
|
|
287
|
+
client = ClientFactory.create_mtls_client(
|
|
288
|
+
base_url, cert_file, key_file, port
|
|
289
|
+
)
|
|
290
|
+
elif factory_mode == "mtls_roles":
|
|
291
|
+
cert_file = config.get("ssl", {}).get(
|
|
292
|
+
"cert_file", "client_cert.pem"
|
|
293
|
+
)
|
|
294
|
+
key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
|
|
295
|
+
roles = config.get("roles", ["admin"])
|
|
296
|
+
role_attributes = config.get("role_attributes", {})
|
|
297
|
+
client = ClientFactory.create_mtls_roles_client(
|
|
298
|
+
base_url, cert_file, key_file, port, roles, role_attributes
|
|
299
|
+
)
|
|
300
|
+
else:
|
|
301
|
+
client = EmbeddingClient.from_config_dict(config)
|
|
302
|
+
|
|
303
|
+
print("Конфигурация клиента:")
|
|
304
|
+
print(f" Базовый URL: {client.base_url}")
|
|
305
|
+
print(f" Порт: {client.port}")
|
|
306
|
+
print(f" Аутентификация: {client.get_auth_method()}")
|
|
307
|
+
print(f" Аутентифицирован: {client.is_authenticated()}")
|
|
308
|
+
if client.is_authenticated():
|
|
309
|
+
headers = client.get_auth_headers()
|
|
310
|
+
print(f" Заголовки аутентификации: {headers}")
|
|
311
|
+
print(f" SSL включен: {client.is_ssl_enabled()}")
|
|
312
|
+
print(f" mTLS включен: {client.is_mtls_enabled()}")
|
|
313
|
+
if client.is_ssl_enabled():
|
|
314
|
+
ssl_config = client.get_ssl_config()
|
|
315
|
+
print(f" SSL конфигурация: {ssl_config}")
|
|
316
|
+
print()
|
|
317
|
+
|
|
318
|
+
# Пример явного открытия/закрытия
|
|
319
|
+
print("Пример явного открытия/закрытия сессии:")
|
|
320
|
+
await client.close()
|
|
321
|
+
print("Сессия закрыта явно (пример ручного закрытия).\n")
|
|
322
|
+
|
|
323
|
+
# Использование контекстного менеджера
|
|
324
|
+
if isinstance(config, ClientConfig):
|
|
325
|
+
async with EmbeddingClient.from_config(config) as client:
|
|
326
|
+
await run_client_examples(client)
|
|
327
|
+
else:
|
|
328
|
+
async with EmbeddingClient.from_config_dict(config) as client:
|
|
329
|
+
await run_client_examples(client)
|
|
330
|
+
|
|
331
|
+
except EmbedConfigError as e:
|
|
332
|
+
print(f"Ошибка конфигурации: {e}")
|
|
333
|
+
sys.exit(1)
|
|
334
|
+
except Exception as e:
|
|
335
|
+
print(f"Неожиданная ошибка: {e}")
|
|
336
|
+
sys.exit(1)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
if __name__ == "__main__":
|
|
340
|
+
asyncio.run(main())
|