arpakitlib 1.8.295__py3-none-any.whl → 1.8.299__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.

Potentially problematic release.


This version of arpakitlib might be problematic. Click here for more details.

@@ -0,0 +1,21 @@
1
+ # arpakit
2
+
3
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
+
5
+ import logging
6
+
7
+ _logger = logging.getLogger()
8
+
9
+
10
+ async def log_async_func_if_error(async_func, **kwargs):
11
+ try:
12
+ await async_func(**kwargs)
13
+ except Exception as exception:
14
+ _logger.error(
15
+ f"error in async_func, {async_func.__name__=}",
16
+ exc_info=exception,
17
+ extra={
18
+ "log_async_func_if_error": True,
19
+ "async_func_name": async_func.__name__
20
+ }
21
+ )
@@ -7,7 +7,9 @@ from typing import Optional
7
7
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
8
8
 
9
9
 
10
- def init_log_file(*, log_filepath: str, write_blank: bool = True):
10
+ def init_log_file(*, log_filepath: str | None):
11
+ if not log_filepath:
12
+ return
11
13
  directory = os.path.dirname(log_filepath)
12
14
  if directory and not os.path.exists(directory):
13
15
  os.makedirs(directory, exist_ok=True)
@@ -19,13 +21,16 @@ def init_log_file(*, log_filepath: str, write_blank: bool = True):
19
21
  _logging_was_setup: bool = False
20
22
 
21
23
 
22
- def setup_normal_logging(log_filepath: Optional[str] = None):
24
+ def setup_normal_logging(
25
+ *,
26
+ log_filepath: Optional[str] = None,
27
+ ):
23
28
  global _logging_was_setup
24
29
  if _logging_was_setup:
30
+ logging.getLogger().info("normal logging was already setup")
25
31
  return
26
32
 
27
- if log_filepath:
28
- init_log_file(log_filepath=log_filepath)
33
+ init_log_file(log_filepath=log_filepath)
29
34
 
30
35
  logger = logging.getLogger()
31
36
  logger.setLevel(logging.INFO)
@@ -33,8 +38,9 @@ def setup_normal_logging(log_filepath: Optional[str] = None):
33
38
  stream_handler = logging.StreamHandler()
34
39
  stream_handler.setLevel(logging.INFO)
35
40
  stream_formatter = logging.Formatter(
36
- "%(asctime)s %(msecs)03d | %(levelname)s | %(filename)s | %(funcName)s:%(lineno)d - %(message)s",
37
- datefmt="%d.%m.%Y %I:%M:%S %p"
41
+ "%(asctime)s %(msecs)03d | %(levelname)s | %(name)s | %(filename)s | "
42
+ "%(funcName)s:%(lineno)d - %(message)s",
43
+ datefmt="%d.%m.%Y %H:%M:%S %p %Z %z",
38
44
  )
39
45
  stream_handler.setFormatter(stream_formatter)
40
46
  logger.addHandler(stream_handler)
@@ -44,7 +50,7 @@ def setup_normal_logging(log_filepath: Optional[str] = None):
44
50
  file_handler.setLevel(logging.WARNING)
45
51
  file_formatter = logging.Formatter(
46
52
  "%(asctime)s | %(levelname)s | %(filename)s | %(funcName)s:%(lineno)d - %(message)s",
47
- datefmt="%d.%m.%Y %I:%M:%S%p"
53
+ datefmt="%d.%m.%Y %H:%M:%S %p %Z %z",
48
54
  )
49
55
  file_handler.setFormatter(file_formatter)
50
56
  logger.addHandler(file_handler)
@@ -55,7 +61,9 @@ def setup_normal_logging(log_filepath: Optional[str] = None):
55
61
 
56
62
 
57
63
  def __example():
58
- pass
64
+ setup_normal_logging()
65
+ logging.getLogger().info("Hello world")
66
+ logging.getLogger().error("Hello world")
59
67
 
60
68
 
61
69
  if __name__ == '__main__':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arpakitlib
3
- Version: 1.8.295
3
+ Version: 1.8.299
4
4
  Summary: arpakitlib
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -33,7 +33,6 @@ Requires-Dist: emoji (>=2.14.1,<3.0.0)
33
33
  Requires-Dist: fastapi (>=0.118.0,<0.119.0)
34
34
  Requires-Dist: gunicorn (>=23.0.0,<24.0.0)
35
35
  Requires-Dist: itsdangerous (>=2.2.0,<3.0.0)
36
- Requires-Dist: jupyter (>=1.1.1,<2.0.0)
37
36
  Requires-Dist: markdown (>=3.7,<4.0)
38
37
  Requires-Dist: openai (>=2.2.0,<3.0.0)
39
38
  Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
@@ -73,7 +72,7 @@ Description-Content-Type: text/markdown
73
72
 
74
73
  # arpakitlib
75
74
 
76
- ## Текущая версия шаблона arpakit_project_template_v_5 находится в разработке. В скором времени будет stable version.
75
+ ## Текущая версия шаблона arpakit_project_template_v_5 находится в разработке, она неверная. В скором времени будет stable version.
77
76
 
78
77
  ## 🚀 Simplify Your Development Workflow
79
78
 
@@ -187,7 +187,6 @@ arpakitlib/_arpakit_project_template_v_5/project/core/__init__.py,sha256=47DEQpj
187
187
  arpakitlib/_arpakit_project_template_v_5/project/core/cache_file_storage_in_dir.py,sha256=0lKPKvrs30DlAZwNS5ydPsQ9ETFLBjZqEcNv8LoQVCU,623
188
188
  arpakitlib/_arpakit_project_template_v_5/project/core/const.py,sha256=hgiiPIYL9543-eEnNAhZWYgX7ZzLKjOqRD0skkROSOw,951
189
189
  arpakitlib/_arpakit_project_template_v_5/project/core/dump_file_storage_in_dir.py,sha256=u3-vStMGaseMsRLuJmQK04UDhaez9vw6o5jyHb1fwNg,617
190
- arpakitlib/_arpakit_project_template_v_5/project/core/easy_openai_api_client.py,sha256=ssQ8Ju6CBQeXSOa_lfLaqycSf0a-NIj6ucOhEsPseVc,1141
191
190
  arpakitlib/_arpakit_project_template_v_5/project/core/jinja2_templates.py,sha256=jCNLaBauGC7YNvZdTLNHuPp7hmRGt94O23Skg6ewo7o,352
192
191
  arpakitlib/_arpakit_project_template_v_5/project/core/media_file_storage_in_dir.py,sha256=fMofTsfJtA8pp5lEUhucEUu3PBsmj-elaRZzExDsdLI,623
193
192
  arpakitlib/_arpakit_project_template_v_5/project/core/settings.py,sha256=-1iKNOUQrHohahxoPl_V7e7Q53T_Sl1LTdu_EsBx9MU,7102
@@ -409,10 +408,10 @@ arpakitlib/ar_json_util.py,sha256=jnVfpQ6QSDq8NgIlh_6ZzXDveOiybr7QSQkXutE7d2s,26
409
408
  arpakitlib/ar_jwt_util.py,sha256=Rhm4ywoTAn6yOV8NLjDASfAtAtheROxxDP40G3XjnuQ,761
410
409
  arpakitlib/ar_list_of_dicts_to_xlsx.py,sha256=MyjEl4Jl4beLVZqLVQMMv0-XDtBD3Xh4Z_ZPDJeFu04,745
411
410
  arpakitlib/ar_list_util.py,sha256=xaUk2BnLvDMP5HDh_GFfH-nIXCg-f8NsrrUKXRcVUsU,1788
412
- arpakitlib/ar_logging_util.py,sha256=CvKvaKqsl1UucgwL28cWadK9f6t5vaF2DmwbZMa8FmU,1681
411
+ arpakitlib/ar_log_async_func_if_error.py,sha256=qtr_eK9o1BrcA_7S9Ns7nVmOS81Yv6eMXHdasc4MftQ,495
412
+ arpakitlib/ar_logging_util.py,sha256=X9PxY04dpJCTaahE3zKMMAwZMeu8k848dyrlIX3ENpk,1912
413
413
  arpakitlib/ar_mongodb_util.py,sha256=2ECkTnGAZ92qxioL-fmN6R4yZOSr3bXdXLWTzT1C3vk,4038
414
414
  arpakitlib/ar_need_type_util.py,sha256=XmY1kswz8j9oo5f9CxRu0_zgfvxWrXPYKOj6MM04sGk,2604
415
- arpakitlib/ar_openai_api_client_util.py,sha256=dWgsSPXtxNBxS5VRi_NharGQrUXF_YjIfhU3Bj5cW9M,5651
416
415
  arpakitlib/ar_parse_command.py,sha256=1WTdQoWVshoDZ1jDaKeTzajfqaYHP3FNO0-REyo1aMY,3003
417
416
  arpakitlib/ar_postgresql_util.py,sha256=1AuLjEaa1Lg4pzn-ukCVnDi35Eg1k91APRTqZhIJAdo,945
418
417
  arpakitlib/ar_pydantic_schema_from_sqlalchemy_model.py,sha256=SddmsEdRdVbmdZ5aSuwy6DfGYmYx_JO6lKzuEJeBAV8,10553
@@ -431,9 +430,9 @@ arpakitlib/ar_sqlalchemy_drop_check_constraints.py,sha256=XEqnMrIwSYasW_UOJ8xU-J
431
430
  arpakitlib/ar_sqlalchemy_util.py,sha256=vWNCzFv13YsGRZaemkNI1_BF__4Z1_Vqm-gqQL1PRrQ,17034
432
431
  arpakitlib/ar_str_util.py,sha256=2lGpnXDf2h1cBZpVf5i1tX_HCv5iBd6IGnrCw4QWWlY,4350
433
432
  arpakitlib/ar_type_util.py,sha256=Cs_tef-Fc5xeyAF54KgISCsP11NHyzIsglm4S3Xx7iM,4049
434
- arpakitlib/uppercase_env_keys.py,sha256=UFHLGIR70UB02eD7IAIBrZIbycwWCx3OP_W4J2cx2Jw,2395
435
- arpakitlib-1.8.295.dist-info/METADATA,sha256=0KxhTELlPr1jeVlIPJbSo3X5tHeNtLJfU2j5mbSxMQk,3981
436
- arpakitlib-1.8.295.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
437
- arpakitlib-1.8.295.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
438
- arpakitlib-1.8.295.dist-info/licenses/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
439
- arpakitlib-1.8.295.dist-info/RECORD,,
433
+ arpakitlib/ar_uppercase_env_keys.py,sha256=UFHLGIR70UB02eD7IAIBrZIbycwWCx3OP_W4J2cx2Jw,2395
434
+ arpakitlib-1.8.299.dist-info/METADATA,sha256=WPWxZQlmH1VwILgVfZ4NmRbeSpCFHkNmefwAnyaXWZY,3966
435
+ arpakitlib-1.8.299.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
436
+ arpakitlib-1.8.299.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
437
+ arpakitlib-1.8.299.dist-info/licenses/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
438
+ arpakitlib-1.8.299.dist-info/RECORD,,
@@ -1,44 +0,0 @@
1
- import asyncio
2
- from functools import lru_cache
3
-
4
- import httpx
5
- from openai import OpenAI, AsyncOpenAI
6
-
7
- from arpakitlib.ar_openai_api_client_util import EasyOpenAIAPIClient
8
- from project.core.settings import get_cached_settings
9
-
10
-
11
- def create_easy_openai_api_client() -> EasyOpenAIAPIClient | None:
12
- if get_cached_settings().openai_api_key is None:
13
- return None
14
-
15
- return EasyOpenAIAPIClient(
16
- open_ai=OpenAI(
17
- api_key=get_cached_settings().openai_api_key,
18
- base_url=get_cached_settings().openai_api_base_url,
19
- timeout=httpx.Timeout(
20
- timeout=60,
21
- connect=15,
22
- read=60,
23
- write=60,
24
- pool=15
25
- )
26
- ),
27
- async_open_ai=AsyncOpenAI(
28
- api_key=get_cached_settings().openai_api_key,
29
- base_url=get_cached_settings().openai_api_base_url
30
- )
31
- )
32
-
33
-
34
- @lru_cache()
35
- def get_cached_easy_openai_api_client() -> EasyOpenAIAPIClient | None:
36
- return create_easy_openai_api_client()
37
-
38
-
39
- async def __async_example():
40
- pass
41
-
42
-
43
- if __name__ == '__main__':
44
- asyncio.run(__async_example())
@@ -1,209 +0,0 @@
1
- # arpakit
2
-
3
- from __future__ import annotations
4
-
5
- import asyncio
6
- import logging
7
-
8
- import httpx
9
- from openai import OpenAI, AsyncOpenAI
10
- from openai.types.chat import ChatCompletion
11
-
12
- from arpakitlib.ar_base64_util import convert_file_to_base64_string
13
-
14
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
15
-
16
- """
17
- https://platform.openai.com/docs/
18
- """
19
-
20
-
21
- class EasyOpenAIAPIClient:
22
- def __init__(
23
- self,
24
- *,
25
- open_ai: OpenAI,
26
- async_open_ai: AsyncOpenAI
27
- ):
28
- self._logger = logging.getLogger(self.__class__.__name__)
29
-
30
- self.open_ai = open_ai
31
- self.async_open_ai = async_open_ai
32
-
33
- @classmethod
34
- def create_easily(
35
- cls,
36
- openai_api_key: str,
37
- openai_api_base_url: str | None = "https://api.proxyapi.ru/openai/v1"
38
- ) -> EasyOpenAIAPIClient:
39
- return EasyOpenAIAPIClient(
40
- open_ai=OpenAI(
41
- api_key=openai_api_key,
42
- base_url=openai_api_base_url,
43
- timeout=httpx.Timeout(
44
- timeout=300, # общий таймаут
45
- connect=60, # таймаут подключения
46
- read=300, # чтение ответа
47
- write=60, # запись запроса
48
- pool=60 # пул соединений
49
- )
50
- ),
51
- async_open_ai=AsyncOpenAI(
52
- api_key=openai_api_key,
53
- base_url=openai_api_base_url,
54
- http_client=httpx.AsyncClient(
55
- timeout=httpx.Timeout(
56
- timeout=300,
57
- connect=60,
58
- read=300,
59
- write=60,
60
- pool=60
61
- )
62
- )
63
- )
64
- )
65
-
66
- def check_conn(self):
67
- self.open_ai.models.list()
68
-
69
- def is_conn_good(self) -> bool:
70
- try:
71
- self.check_conn()
72
- return True
73
- except Exception as e:
74
- self._logger.error(e)
75
- return False
76
-
77
- async def async_check_conn(self):
78
- await self.async_open_ai.models.list()
79
-
80
- async def async_is_conn_good(self) -> bool:
81
- try:
82
- await self.async_check_conn()
83
- return True
84
- except Exception as e:
85
- self._logger.error(e)
86
- return False
87
-
88
- def simple_ask(
89
- self,
90
- *,
91
- prompt: str | None = None,
92
- text: str,
93
- model: str = "gpt-4o",
94
- image_links: str | list[str] | None = None,
95
- image_filepaths: str | list[str] | None = None
96
- ) -> ChatCompletion:
97
- if isinstance(image_links, str):
98
- image_links = [image_links]
99
- if isinstance(image_filepaths, str):
100
- image_filepaths = [image_filepaths]
101
-
102
- messages = []
103
-
104
- if prompt is not None:
105
- messages.append({
106
- "role": "system",
107
- "content": prompt
108
- })
109
-
110
- content = [{"type": "text", "text": text}]
111
-
112
- if image_links:
113
- for link in image_links:
114
- content.append({
115
- "type": "image_url",
116
- "image_url": {"url": link}
117
- })
118
-
119
- if image_filepaths:
120
- for path in image_filepaths:
121
- base64_url = convert_file_to_base64_string(filepath=path, raise_for_error=True)
122
- content.append({
123
- "type": "image_url",
124
- "image_url": {"url": base64_url}
125
- })
126
-
127
- messages.append({
128
- "role": "user",
129
- "content": content
130
- })
131
-
132
- response: ChatCompletion = self.open_ai.chat.completions.create(
133
- model=model,
134
- messages=messages,
135
- n=1,
136
- temperature=0.1,
137
- top_p=0.9,
138
- max_tokens=1000
139
- )
140
-
141
- return response
142
-
143
- async def async_simple_ask(
144
- self,
145
- *,
146
- prompt: str | None = None,
147
- text: str,
148
- model: str = "gpt-4o",
149
- image_links: str | list[str] | None = None,
150
- image_filepaths: str | list[str] | None = None
151
- ) -> ChatCompletion:
152
- if isinstance(image_links, str):
153
- image_links = [image_links]
154
- if isinstance(image_filepaths, str):
155
- image_filepaths = [image_filepaths]
156
-
157
- messages = []
158
-
159
- if prompt is not None:
160
- messages.append({
161
- "role": "system",
162
- "content": prompt
163
- })
164
-
165
- content = [{"type": "text", "text": text}]
166
-
167
- if image_links:
168
- for link in image_links:
169
- content.append({
170
- "type": "image_url",
171
- "image_url": {"url": link}
172
- })
173
-
174
- if image_filepaths:
175
- for path in image_filepaths:
176
- base64_url = convert_file_to_base64_string(filepath=path, raise_for_error=True)
177
- content.append({
178
- "type": "image_url",
179
- "image_url": {"url": base64_url}
180
- })
181
-
182
- messages.append({
183
- "role": "user",
184
- "content": content
185
- })
186
-
187
- response: ChatCompletion = await self.async_open_ai.chat.completions.create(
188
- model=model,
189
- messages=messages,
190
- n=1,
191
- temperature=0.1,
192
- top_p=0.9,
193
- max_tokens=1000
194
- )
195
-
196
- return response
197
-
198
-
199
- def __example():
200
- pass
201
-
202
-
203
- async def __async_example():
204
- pass
205
-
206
-
207
- if __name__ == '__main__':
208
- __example()
209
- asyncio.run(__async_example())