embed-client 2.0.0.0__py3-none-any.whl → 3.1.0.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.
@@ -1,128 +1,562 @@
1
1
  """
2
- Пример использования EmbeddingServiceAsyncClient (асинхронный клиент).
2
+ Пример использования EmbeddingServiceAsyncClient со всеми режимами безопасности и ClientFactory.
3
3
 
4
- USAGE:
5
- python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001
6
- # или
7
- python -m asyncio embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
8
6
 
9
- # Можно также использовать переменные окружения:
7
+ ИСПОЛЬЗОВАНИЕ:
8
+ # Базовое использование без аутентификации
9
+ python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001
10
+
11
+ # С аутентификацией по API ключу
12
+ python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001 --auth-method api_key --api-key your_key
13
+
14
+ # С JWT аутентификацией
15
+ python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001 --auth-method jwt --jwt-secret secret --jwt-username user
16
+
17
+ # С базовой аутентификацией
18
+ python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001 --auth-method basic --username user --password pass
19
+
20
+ # С файлом конфигурации
21
+ python embed_client/example_async_usage_ru.py --config configs/http_token.json
22
+
23
+ # С переменными окружения
10
24
  export EMBED_CLIENT_BASE_URL=http://localhost
11
25
  export EMBED_CLIENT_PORT=8001
26
+ export EMBED_CLIENT_AUTH_METHOD=api_key
27
+ export EMBED_CLIENT_API_KEY=your_key
12
28
  python embed_client/example_async_usage_ru.py
13
29
 
14
- # ВАЖНО:
15
- # --base-url и --port должны быть отдельными аргументами (через пробел),
16
- # а не через = (НЕ --base_url=...)
17
- # base_url должен содержать http:// или https://
18
-
19
- EXAMPLES:
30
+ ПРИМЕРЫ РЕЖИМОВ БЕЗОПАСНОСТИ:
31
+ # 1. HTTP - обычный HTTP без аутентификации
20
32
  python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001
21
- python -m asyncio embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001
22
- export EMBED_CLIENT_BASE_URL=http://localhost
23
- export EMBED_CLIENT_PORT=8001
33
+
34
+ # 2. HTTP + Token - HTTP с аутентификацией по API ключу
35
+ python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001 --auth-method api_key --api-key admin_key_123
36
+
37
+ # 3. HTTPS - HTTPS с проверкой сертификатов сервера
38
+ python embed_client/example_async_usage_ru.py --base-url https://localhost --port 9443
39
+
40
+ # 4. HTTPS + Token - HTTPS с сертификатами сервера + аутентификация
41
+ python embed_client/example_async_usage_ru.py --base-url https://localhost --port 9443 --auth-method jwt --jwt-secret secret --jwt-username admin
42
+
43
+ # 5. mTLS - взаимная TLS с сертификатами клиента и сервера
44
+ python embed_client/example_async_usage_ru.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key
45
+
46
+ # 6. mTLS + Roles - mTLS с контролем доступа на основе ролей
47
+ python embed_client/example_async_usage_ru.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key --roles admin,user
48
+
49
+ ПРИМЕРЫ ФАБРИКИ КЛИЕНТОВ:
50
+ # Автоматическое определение режима безопасности
51
+ python embed_client/example_async_usage_ru.py --factory-mode auto --base-url https://localhost --port 9443 --auth-method api_key --api-key key
52
+
53
+ # Создание конкретного режима безопасности
54
+ python embed_client/example_async_usage_ru.py --factory-mode https_token --base-url https://localhost --port 9443 --auth-method basic --username user --password pass
55
+
56
+ # mTLS с фабрикой
57
+ python embed_client/example_async_usage_ru.py --factory-mode mtls --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key
58
+
59
+ ПРИМЕРЫ SSL/TLS:
60
+ # HTTPS с отключенной проверкой SSL
61
+ python embed_client/example_async_usage_ru.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_NONE
62
+
63
+ # mTLS с пользовательским CA сертификатом
64
+ python embed_client/example_async_usage_ru.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key --ca-cert-file mtls_certificates/ca/ca.crt
65
+
66
+ # HTTPS с пользовательскими настройками SSL
67
+ python embed_client/example_async_usage_ru.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_REQUIRED --ssl-check-hostname --ssl-check-expiry
68
+
69
+ ПРИМЕРЫ КОНФИГУРАЦИИ:
70
+ # Использование файла конфигурации
71
+ python embed_client/example_async_usage_ru.py --config configs/https_token.json
72
+
73
+ # Использование переменных окружения
74
+ export EMBED_CLIENT_BASE_URL=https://secure.example.com
75
+ export EMBED_CLIENT_PORT=9443
76
+ export EMBED_CLIENT_AUTH_METHOD=api_key
77
+ export EMBED_CLIENT_API_KEY=production_key
24
78
  python embed_client/example_async_usage_ru.py
79
+
80
+ Пример явного закрытия сессии:
81
+ import asyncio
82
+ from embed_client.async_client import EmbeddingServiceAsyncClient
83
+ from embed_client.config import ClientConfig
84
+ from embed_client.client_factory import ClientFactory, create_client
85
+
86
+ async def main():
87
+ # Метод 1: Прямое создание клиента
88
+ client = EmbeddingServiceAsyncClient('http://localhost', 8001)
89
+ await client.close()
90
+
91
+ # Метод 2: Использование конфигурации
92
+ config = ClientConfig()
93
+ config.configure_server('http://localhost', 8001)
94
+ client = EmbeddingServiceAsyncClient.from_config(config)
95
+ await client.close()
96
+
97
+ # Метод 3: Использование фабрики с автоматическим определением
98
+ client = create_client('https://localhost', 9443, auth_method='api_key', api_key='key')
99
+ await client.close()
100
+
101
+ # Метод 4: Использование конкретного метода фабрики
102
+ client = ClientFactory.create_https_token_client(
103
+ 'https://localhost', 9443, 'api_key', api_key='key'
104
+ )
105
+ await client.close()
106
+
107
+ asyncio.run(main())
25
108
  """
26
109
 
110
+ import argparse
27
111
  import asyncio
28
- import sys
112
+ import json
29
113
  import os
30
- from embed_client.async_client import (
31
- EmbeddingServiceAsyncClient,
32
- EmbeddingServiceConnectionError,
33
- EmbeddingServiceHTTPError,
34
- EmbeddingServiceAPIError,
35
- EmbeddingServiceError,
114
+ import sys
115
+ from typing import Dict, Any, Optional, Union
116
+
117
+ from embed_client.async_client import EmbeddingServiceAsyncClient, EmbeddingServiceError, EmbeddingServiceConfigError
118
+ from embed_client.config import ClientConfig
119
+ from embed_client.client_factory import (
120
+ ClientFactory, SecurityMode, create_client, create_client_from_config,
121
+ create_client_from_env, detect_security_mode
36
122
  )
37
123
 
124
+
38
125
  def get_params():
39
- base_url = None
40
- port = None
41
- for i, arg in enumerate(sys.argv):
42
- if arg in ("--base-url", "-b") and i + 1 < len(sys.argv):
43
- base_url = sys.argv[i + 1]
44
- if arg in ("--port", "-p") and i + 1 < len(sys.argv):
45
- port = sys.argv[i + 1]
46
- if not base_url:
47
- base_url = os.environ.get("EMBED_CLIENT_BASE_URL")
48
- if not port:
49
- port = os.environ.get("EMBED_CLIENT_PORT")
126
+ """Парсинг аргументов командной строки и переменных окружения для конфигурации клиента."""
127
+ parser = argparse.ArgumentParser(description="Пример Embedding Service Async Client - Все режимы безопасности")
128
+
129
+ # Базовые параметры подключения
130
+ parser.add_argument("--base-url", "-b", help="Базовый URL сервиса эмбеддингов")
131
+ parser.add_argument("--port", "-p", type=int, help="Порт сервиса эмбеддингов")
132
+ parser.add_argument("--config", "-c", help="Путь к файлу конфигурации")
133
+
134
+ # Режим фабрики клиентов
135
+ parser.add_argument("--factory-mode", choices=["auto", "http", "http_token", "https", "https_token", "mtls", "mtls_roles"],
136
+ default="auto", help="Режим фабрики клиентов (auto для автоматического определения)")
137
+
138
+ # Параметры аутентификации
139
+ parser.add_argument("--auth-method", choices=["none", "api_key", "jwt", "basic", "certificate"],
140
+ default="none", help="Метод аутентификации")
141
+ parser.add_argument("--api-key", help="API ключ для аутентификации api_key")
142
+ parser.add_argument("--jwt-secret", help="JWT секрет для аутентификации jwt")
143
+ parser.add_argument("--jwt-username", help="JWT имя пользователя для аутентификации jwt")
144
+ parser.add_argument("--jwt-password", help="JWT пароль для аутентификации jwt")
145
+ parser.add_argument("--username", help="Имя пользователя для базовой аутентификации")
146
+ parser.add_argument("--password", help="Пароль для базовой аутентификации")
147
+ parser.add_argument("--cert-file", help="Файл сертификата для аутентификации certificate")
148
+ parser.add_argument("--key-file", help="Файл ключа для аутентификации certificate")
149
+
150
+ # Параметры SSL/TLS
151
+ parser.add_argument("--ssl-verify-mode", choices=["CERT_NONE", "CERT_OPTIONAL", "CERT_REQUIRED"],
152
+ default="CERT_REQUIRED", help="Режим проверки SSL сертификатов")
153
+ parser.add_argument("--ssl-check-hostname", action="store_true", default=True,
154
+ help="Включить проверку имени хоста SSL")
155
+ parser.add_argument("--ssl-check-expiry", action="store_true", default=True,
156
+ help="Включить проверку срока действия SSL сертификатов")
157
+ parser.add_argument("--ca-cert-file", help="Файл CA сертификата для проверки SSL")
158
+
159
+ # Контроль доступа на основе ролей (для mTLS + Roles)
160
+ parser.add_argument("--roles", help="Список ролей через запятую для режима mTLS + Roles")
161
+ parser.add_argument("--role-attributes", help="JSON строка атрибутов ролей для режима mTLS + Roles")
162
+
163
+ # Дополнительные параметры
164
+ parser.add_argument("--timeout", type=float, default=30.0, help="Таймаут запроса в секундах")
165
+ parser.add_argument("--demo-mode", action="store_true", help="Запуск в демо режиме (показать все режимы безопасности)")
166
+
167
+ args = parser.parse_args()
168
+
169
+ # Если предоставлен файл конфигурации, загружаем его
170
+ if args.config:
171
+ try:
172
+ config = ClientConfig()
173
+ config.load_config_file(args.config)
174
+ return config
175
+ except Exception as e:
176
+ print(f"Ошибка загрузки файла конфигурации {args.config}: {e}")
177
+ sys.exit(1)
178
+
179
+ # Иначе строим конфигурацию из аргументов и переменных окружения
180
+ base_url = args.base_url or os.environ.get("EMBED_CLIENT_BASE_URL", "http://localhost")
181
+ port = args.port or int(os.environ.get("EMBED_CLIENT_PORT", "8001"))
182
+
50
183
  if not base_url or not port:
51
- print("Error: base_url and port must be provided via [--base-url | --port] arguments or [EMBED_CLIENT_BASE_URL/EMBED_CLIENT_PORT] environment variables.")
184
+ print("Ошибка: base_url и port должны быть предоставлены через аргументы --base-url/--port или переменные окружения EMBED_CLIENT_BASE_URL/EMBED_CLIENT_PORT.")
52
185
  sys.exit(1)
53
- return None, None
54
- return base_url, int(port)
186
+
187
+ # Строим словарь конфигурации
188
+ config_dict = {
189
+ "server": {
190
+ "host": base_url,
191
+ "port": port
192
+ },
193
+ "client": {
194
+ "timeout": args.timeout
195
+ },
196
+ "auth": {
197
+ "method": args.auth_method
198
+ }
199
+ }
200
+
201
+ # Добавляем конфигурацию аутентификации
202
+ if args.auth_method == "api_key":
203
+ api_key = args.api_key or os.environ.get("EMBED_CLIENT_API_KEY")
204
+ if api_key:
205
+ config_dict["auth"]["api_keys"] = {"user": api_key}
206
+ else:
207
+ print("Предупреждение: API ключ не предоставлен для аутентификации api_key")
208
+
209
+ elif args.auth_method == "jwt":
210
+ jwt_secret = args.jwt_secret or os.environ.get("EMBED_CLIENT_JWT_SECRET")
211
+ jwt_username = args.jwt_username or os.environ.get("EMBED_CLIENT_JWT_USERNAME")
212
+ jwt_password = args.jwt_password or os.environ.get("EMBED_CLIENT_JWT_PASSWORD")
213
+
214
+ if jwt_secret and jwt_username and jwt_password:
215
+ config_dict["auth"]["jwt"] = {
216
+ "secret": jwt_secret,
217
+ "username": jwt_username,
218
+ "password": jwt_password
219
+ }
220
+ else:
221
+ print("Предупреждение: JWT учетные данные не полностью предоставлены")
222
+
223
+ elif args.auth_method == "basic":
224
+ username = args.username or os.environ.get("EMBED_CLIENT_USERNAME")
225
+ password = args.password or os.environ.get("EMBED_CLIENT_PASSWORD")
226
+
227
+ if username and password:
228
+ config_dict["auth"]["basic"] = {
229
+ "username": username,
230
+ "password": password
231
+ }
232
+ else:
233
+ print("Предупреждение: Учетные данные базовой аутентификации не полностью предоставлены")
234
+
235
+ elif args.auth_method == "certificate":
236
+ cert_file = args.cert_file or os.environ.get("EMBED_CLIENT_CERT_FILE")
237
+ key_file = args.key_file or os.environ.get("EMBED_CLIENT_KEY_FILE")
238
+
239
+ if cert_file and key_file:
240
+ config_dict["auth"]["certificate"] = {
241
+ "cert_file": cert_file,
242
+ "key_file": key_file
243
+ }
244
+ else:
245
+ print("Предупреждение: Файлы сертификатов не полностью предоставлены")
246
+
247
+ # Добавляем конфигурацию SSL если используется HTTPS или предоставлены SSL параметры
248
+ if base_url.startswith("https://") or args.ssl_verify_mode != "CERT_REQUIRED" or args.ca_cert_file:
249
+ config_dict["ssl"] = {
250
+ "enabled": True,
251
+ "verify_mode": args.ssl_verify_mode,
252
+ "check_hostname": args.ssl_check_hostname,
253
+ "check_expiry": args.ssl_check_expiry
254
+ }
255
+
256
+ if args.ca_cert_file:
257
+ config_dict["ssl"]["ca_cert_file"] = args.ca_cert_file
258
+
259
+ # Добавляем клиентские сертификаты для mTLS
260
+ if args.cert_file:
261
+ config_dict["ssl"]["cert_file"] = args.cert_file
262
+ if args.key_file:
263
+ config_dict["ssl"]["key_file"] = args.key_file
264
+
265
+ # Добавляем контроль доступа на основе ролей для mTLS + Roles
266
+ if args.roles:
267
+ roles = [role.strip() for role in args.roles.split(",")]
268
+ config_dict["roles"] = roles
269
+
270
+ if args.role_attributes:
271
+ try:
272
+ role_attributes = json.loads(args.role_attributes)
273
+ config_dict["role_attributes"] = role_attributes
274
+ except json.JSONDecodeError:
275
+ print("Предупреждение: Неверный JSON в role_attributes")
276
+
277
+ return config_dict
278
+
279
+
280
+ def extract_embeddings(result):
281
+ """Извлечение эмбеддингов из ответа API, поддерживая старый и новый форматы."""
282
+ # Обработка прямого поля embeddings (совместимость со старым форматом)
283
+ if "embeddings" in result:
284
+ return result["embeddings"]
285
+
286
+ # Обработка обертки result
287
+ if "result" in result:
288
+ res = result["result"]
289
+
290
+ # Обработка прямого списка в result (старый формат)
291
+ if isinstance(res, list):
292
+ return res
293
+
294
+ if isinstance(res, dict):
295
+ # Обработка старого формата: result.embeddings
296
+ if "embeddings" in res:
297
+ return res["embeddings"]
298
+
299
+ # Обработка старого формата: result.data.embeddings
300
+ if "data" in res and isinstance(res["data"], dict) and "embeddings" in res["data"]:
301
+ return res["data"]["embeddings"]
302
+
303
+ # Обработка нового формата: result.data[].embedding
304
+ if "data" in res and isinstance(res["data"], list):
305
+ embeddings = []
306
+ for item in res["data"]:
307
+ if isinstance(item, dict) and "embedding" in item:
308
+ embeddings.append(item["embedding"])
309
+ else:
310
+ raise ValueError(f"Неверный формат элемента в новом ответе API: {item}")
311
+ return embeddings
312
+
313
+ raise ValueError(f"Не удается извлечь эмбеддинги из ответа: {result}")
314
+
315
+
316
+ async def run_client_examples(client):
317
+ """Запуск примеров операций с клиентом."""
318
+ # Проверка здоровья
319
+ try:
320
+ health = await client.health()
321
+ print("Состояние сервиса:", health)
322
+ except EmbeddingServiceError as e:
323
+ print(f"Ошибка при проверке здоровья: {e}")
324
+ return
325
+
326
+ # Получение схемы OpenAPI
327
+ try:
328
+ schema = await client.get_openapi_schema()
329
+ print(f"Версия схемы OpenAPI: {schema.get('info', {}).get('version', 'неизвестно')}")
330
+ except EmbeddingServiceError as e:
331
+ print(f"Ошибка получения схемы OpenAPI: {e}")
332
+
333
+ # Получение доступных команд
334
+ try:
335
+ commands = await client.get_commands()
336
+ print(f"Доступные команды: {commands}")
337
+ except EmbeddingServiceError as e:
338
+ print(f"Ошибка получения команд: {e}")
339
+
340
+ # Тест генерации эмбеддингов
341
+ try:
342
+ texts = ["Привет, мир!", "Это тестовое предложение.", "Сервис эмбеддингов работает!"]
343
+ result = await client.cmd("embed", {"texts": texts})
344
+
345
+ if result.get("success"):
346
+ embeddings = extract_embeddings(result)
347
+ print(f"Сгенерировано {len(embeddings)} эмбеддингов")
348
+ print(f"Размерность первого эмбеддинга: {len(embeddings[0]) if embeddings else 0}")
349
+ else:
350
+ print(f"Генерация эмбеддингов не удалась: {result.get('error', 'Неизвестная ошибка')}")
351
+ except EmbeddingServiceError as e:
352
+ print(f"Ошибка при генерации эмбеддингов: {e}")
353
+
354
+
355
+ async def demonstrate_security_modes():
356
+ """Демонстрация всех режимов безопасности с использованием ClientFactory."""
357
+ print("=== Демонстрация режимов безопасности ===")
358
+
359
+ # 1. HTTP режим
360
+ print("\n1. HTTP режим (без аутентификации, без SSL):")
361
+ try:
362
+ client = ClientFactory.create_http_client("http://localhost", 8001)
363
+ print(f" Создан HTTP клиент: {client.base_url}:{client.port}")
364
+ print(f" SSL включен: {client.is_ssl_enabled()}")
365
+ print(f" Аутентифицирован: {client.is_authenticated()}")
366
+ await client.close()
367
+ except Exception as e:
368
+ print(f" Ошибка: {e}")
369
+
370
+ # 2. HTTP + Token режим
371
+ print("\n2. HTTP + Token режим (HTTP с API ключом):")
372
+ try:
373
+ client = ClientFactory.create_http_token_client(
374
+ "http://localhost", 8001, "api_key", api_key="demo_key"
375
+ )
376
+ print(f" Создан HTTP + Token клиент: {client.base_url}:{client.port}")
377
+ print(f" SSL включен: {client.is_ssl_enabled()}")
378
+ print(f" Аутентифицирован: {client.is_authenticated()}")
379
+ print(f" Метод аутентификации: {client.get_auth_method()}")
380
+ await client.close()
381
+ except Exception as e:
382
+ print(f" Ошибка: {e}")
383
+
384
+ # 3. HTTPS режим
385
+ print("\n3. HTTPS режим (HTTPS с сертификатами сервера):")
386
+ try:
387
+ client = ClientFactory.create_https_client("https://localhost", 9443)
388
+ print(f" Создан HTTPS клиент: {client.base_url}:{client.port}")
389
+ print(f" SSL включен: {client.is_ssl_enabled()}")
390
+ print(f" Аутентифицирован: {client.is_authenticated()}")
391
+ if client.is_ssl_enabled():
392
+ ssl_config = client.get_ssl_config()
393
+ print(f" SSL конфигурация: {ssl_config}")
394
+ await client.close()
395
+ except Exception as e:
396
+ print(f" Ошибка: {e}")
397
+
398
+ # 4. HTTPS + Token режим
399
+ print("\n4. HTTPS + Token режим (HTTPS с сертификатами сервера + аутентификация):")
400
+ try:
401
+ client = ClientFactory.create_https_token_client(
402
+ "https://localhost", 9443, "basic", username="admin", password="secret"
403
+ )
404
+ print(f" Создан HTTPS + Token клиент: {client.base_url}:{client.port}")
405
+ print(f" SSL включен: {client.is_ssl_enabled()}")
406
+ print(f" Аутентифицирован: {client.is_authenticated()}")
407
+ print(f" Метод аутентификации: {client.get_auth_method()}")
408
+ await client.close()
409
+ except Exception as e:
410
+ print(f" Ошибка: {e}")
411
+
412
+ # 5. mTLS режим
413
+ print("\n5. mTLS режим (взаимная TLS с сертификатами клиента и сервера):")
414
+ try:
415
+ client = ClientFactory.create_mtls_client(
416
+ "https://localhost", "mtls_certificates/client/embedding-service.crt", "mtls_certificates/client/embedding-service.key", 8443
417
+ )
418
+ print(f" Создан mTLS клиент: {client.base_url}:{client.port}")
419
+ print(f" SSL включен: {client.is_ssl_enabled()}")
420
+ print(f" mTLS включен: {client.is_mtls_enabled()}")
421
+ print(f" Аутентифицирован: {client.is_authenticated()}")
422
+ await client.close()
423
+ except Exception as e:
424
+ print(f" Ошибка: {e}")
425
+
426
+ # 6. mTLS + Roles режим
427
+ print("\n6. mTLS + Roles режим (mTLS с контролем доступа на основе ролей):")
428
+ try:
429
+ client = ClientFactory.create_mtls_roles_client(
430
+ "https://localhost", "client_cert.pem", "client_key.pem", 9443,
431
+ roles=["admin", "user"], role_attributes={"department": "IT"}
432
+ )
433
+ print(f" Создан mTLS + Roles клиент: {client.base_url}:{client.port}")
434
+ print(f" SSL включен: {client.is_ssl_enabled()}")
435
+ print(f" mTLS включен: {client.is_mtls_enabled()}")
436
+ print(f" Аутентифицирован: {client.is_authenticated()}")
437
+ await client.close()
438
+ except Exception as e:
439
+ print(f" Ошибка: {e}")
440
+
441
+
442
+ async def demonstrate_automatic_detection():
443
+ """Демонстрация автоматического определения режима безопасности."""
444
+ print("\n=== Автоматическое определение режима безопасности ===")
445
+
446
+ test_cases = [
447
+ ("http://localhost", None, None, None, None, "HTTP"),
448
+ ("http://localhost", "api_key", None, None, None, "HTTP + Token"),
449
+ ("https://localhost", None, None, None, None, "HTTPS"),
450
+ ("https://localhost", "api_key", None, None, None, "HTTPS + Token"),
451
+ ("https://localhost", None, None, "cert.pem", "key.pem", "mTLS"),
452
+ ("https://localhost", None, None, "cert.pem", "key.pem", "mTLS + Roles", {"roles": ["admin"]}),
453
+ ]
454
+
455
+ for case in test_cases:
456
+ if len(case) == 6:
457
+ base_url, auth_method, ssl_enabled, cert_file, key_file, expected = case
458
+ kwargs = {}
459
+ else:
460
+ base_url, auth_method, ssl_enabled, cert_file, key_file, expected, kwargs = case
461
+
462
+ try:
463
+ mode = detect_security_mode(base_url, auth_method, ssl_enabled, cert_file, key_file, **kwargs)
464
+ print(f" {base_url} + {auth_method or 'none'} + {cert_file or 'no cert'} -> {mode} ({expected})")
465
+ except Exception as e:
466
+ print(f" Ошибка определения режима для {base_url}: {e}")
467
+
55
468
 
56
469
  async def main():
57
- base_url, port = get_params()
58
- # Always use try/except to handle all possible errors
59
470
  try:
60
- async with EmbeddingServiceAsyncClient(base_url=base_url, port=port) as client:
61
- # Check health
62
- try:
63
- health = await client.health()
64
- print("Service health:", health)
65
- except EmbeddingServiceConnectionError as e:
66
- print("[Connection error]", e)
67
- return
68
- except EmbeddingServiceHTTPError as e:
69
- print(f"[HTTP error] {e.status}: {e.message}")
70
- return
71
- except EmbeddingServiceError as e:
72
- print("[Other error]", e)
73
- return
74
-
75
- # Request embeddings for a list of texts
76
- texts = ["hello world", "test embedding"]
77
- try:
78
- result = await client.cmd("embed", params={"texts": texts})
79
- # Use client's extract method for compatibility with both old and new formats
80
- vectors = client.extract_embeddings(result)
81
- print(f"Embeddings for {len(texts)} texts:")
82
- for i, vec in enumerate(vectors):
83
- print(f" Text: {texts[i]!r}\n Vector: {vec[:5]}... (total {len(vec)} dims)")
471
+ config = get_params()
472
+
473
+ # Проверяем, запрошен ли демо режим
474
+ if hasattr(config, 'demo_mode') and config.demo_mode:
475
+ await demonstrate_security_modes()
476
+ await demonstrate_automatic_detection()
477
+ return
478
+
479
+ # Создаем клиент на основе режима фабрики
480
+ if isinstance(config, ClientConfig):
481
+ # Использование объекта конфигурации
482
+ client = EmbeddingServiceAsyncClient.from_config(config)
483
+ else:
484
+ # Использование словаря конфигурации
485
+ factory_mode = getattr(config, 'factory_mode', 'auto')
486
+
487
+ if factory_mode == "auto":
488
+ # Автоматическое определение
489
+ client = create_client(
490
+ config["server"]["host"],
491
+ config["server"]["port"],
492
+ auth_method=config["auth"]["method"],
493
+ **{k: v for k, v in config.items() if k not in ["server", "auth", "ssl", "client"]}
494
+ )
495
+ else:
496
+ # Конкретный метод фабрики
497
+ base_url = config["server"]["host"]
498
+ port = config["server"]["port"]
499
+ auth_method = config["auth"]["method"]
84
500
 
85
- # Try to extract additional data if new format is available
86
- try:
87
- embedding_data = client.extract_embedding_data(result)
88
- print("\nAdditional data from new format:")
89
- for i, data in enumerate(embedding_data):
90
- print(f" Text: {data['body']!r}")
91
- print(f" Tokens: {data['tokens']}")
92
- print(f" BM25 tokens: {data['bm25_tokens']}")
93
-
94
- # Extract tokens and BM25 tokens separately
95
- tokens = client.extract_tokens(result)
96
- bm25_tokens = client.extract_bm25_tokens(result)
97
- print(f"\nExtracted tokens: {tokens}")
98
- print(f"Extracted BM25 tokens: {bm25_tokens}")
99
-
100
- except ValueError as e:
101
- print(f"(Old format detected - no additional data available): {e}")
102
-
103
- except EmbeddingServiceAPIError as e:
104
- print("[API error]", e.error)
105
- except EmbeddingServiceHTTPError as e:
106
- print(f"[HTTP error] {e.status}: {e.message}")
107
- except EmbeddingServiceConnectionError as e:
108
- print("[Connection error]", e)
109
- except EmbeddingServiceError as e:
110
- print("[Other error]", e)
111
-
112
- # Example: error handling for invalid command
113
- try:
114
- await client.cmd("not_a_command")
115
- except EmbeddingServiceAPIError as e:
116
- print("[API error for invalid command]", e.error)
117
-
118
- # Example: error handling for empty texts
119
- try:
120
- await client.cmd("embed", params={"texts": []})
121
- except EmbeddingServiceAPIError as e:
122
- print("[API error for empty texts]", e.error)
501
+ if factory_mode == "http":
502
+ client = ClientFactory.create_http_client(base_url, port)
503
+ elif factory_mode == "http_token":
504
+ client = ClientFactory.create_http_token_client(base_url, port, auth_method, **config.get("auth", {}))
505
+ elif factory_mode == "https":
506
+ client = ClientFactory.create_https_client(base_url, port)
507
+ elif factory_mode == "https_token":
508
+ client = ClientFactory.create_https_token_client(base_url, port, auth_method, **config.get("auth", {}))
509
+ elif factory_mode == "mtls":
510
+ cert_file = config.get("ssl", {}).get("cert_file", "client_cert.pem")
511
+ key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
512
+ client = ClientFactory.create_mtls_client(base_url, cert_file, key_file, port)
513
+ elif factory_mode == "mtls_roles":
514
+ cert_file = config.get("ssl", {}).get("cert_file", "client_cert.pem")
515
+ key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
516
+ roles = config.get("roles", ["admin"])
517
+ role_attributes = config.get("role_attributes", {})
518
+ client = ClientFactory.create_mtls_roles_client(
519
+ base_url, cert_file, key_file, port, roles, role_attributes
520
+ )
521
+ else:
522
+ client = EmbeddingServiceAsyncClient(config_dict=config)
523
+
524
+ print(f"Конфигурация клиента:")
525
+ print(f" Базовый URL: {client.base_url}")
526
+ print(f" Порт: {client.port}")
527
+ print(f" Аутентификация: {client.get_auth_method()}")
528
+ print(f" Аутентифицирован: {client.is_authenticated()}")
529
+ if client.is_authenticated():
530
+ headers = client.get_auth_headers()
531
+ print(f" Заголовки аутентификации: {headers}")
532
+ print(f" SSL включен: {client.is_ssl_enabled()}")
533
+ print(f" mTLS включен: {client.is_mtls_enabled()}")
534
+ if client.is_ssl_enabled():
535
+ ssl_config = client.get_ssl_config()
536
+ print(f" SSL конфигурация: {ssl_config}")
537
+ protocols = client.get_supported_ssl_protocols()
538
+ print(f" Поддерживаемые SSL протоколы: {protocols}")
539
+ print()
540
+
541
+ # Пример явного открытия/закрытия
542
+ print("Пример явного открытия/закрытия сессии:")
543
+ await client.close()
544
+ print("Сессия закрыта явно (пример ручного закрытия).\n")
545
+
546
+ # Использование контекстного менеджера
547
+ if isinstance(config, ClientConfig):
548
+ async with EmbeddingServiceAsyncClient.from_config(config) as client:
549
+ await run_client_examples(client)
550
+ else:
551
+ async with EmbeddingServiceAsyncClient(config_dict=config) as client:
552
+ await run_client_examples(client)
123
553
 
554
+ except EmbeddingServiceConfigError as e:
555
+ print(f"Ошибка конфигурации: {e}")
556
+ sys.exit(1)
124
557
  except Exception as e:
125
- print("[Unexpected error]", e)
558
+ print(f"Неожиданная ошибка: {e}")
559
+ sys.exit(1)
126
560
 
127
561
  if __name__ == "__main__":
128
- asyncio.run(main())
562
+ asyncio.run(main())