Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
from asyncio import create_subprocess_shell, gather, sleep
|
|
|
2 |
from pathlib import Path
|
3 |
from random import choice
|
|
|
4 |
from subprocess import CalledProcessError, PIPE
|
5 |
from typing import Any, List
|
6 |
from uuid import uuid4
|
@@ -11,6 +13,11 @@ from httpx import AsyncClient, HTTPStatusError, RequestError
|
|
11 |
from pydantic import BaseModel, HttpUrl
|
12 |
from uvicorn import run as uvicorn_run
|
13 |
|
|
|
|
|
|
|
|
|
|
|
14 |
oxipng_bin = Path(__file__).parent / 'oxipng'
|
15 |
if not oxipng_bin.stat().st_mode & 0o111:
|
16 |
oxipng_bin.chmod(0o755)
|
@@ -25,12 +32,14 @@ tokens = [
|
|
25 |
]
|
26 |
|
27 |
|
28 |
-
async def download_png(url: str, client: AsyncClient, retries: int = 5) -> Path:
|
|
|
29 |
for attempt in range(retries):
|
30 |
try:
|
31 |
response = await client.get(url, timeout=30.0)
|
32 |
response.raise_for_status()
|
33 |
-
file_path = Path(f'{uuid4()}.png'
|
|
|
34 |
file_path.write_bytes(response.content)
|
35 |
return file_path
|
36 |
except (HTTPStatusError, RequestError) as e:
|
@@ -42,13 +51,15 @@ async def download_png(url: str, client: AsyncClient, retries: int = 5) -> Path:
|
|
42 |
|
43 |
async def download_pngs(urls: str | list[str]) -> list[Any]:
|
44 |
urls = [urls] if isinstance(urls, str) else urls
|
|
|
45 |
async with AsyncClient() as client:
|
46 |
-
tasks = [download_png(url, client) for url in urls]
|
47 |
return list(await gather(*tasks))
|
48 |
|
49 |
|
50 |
async def optimize_png(image_path: Path, retries: int = 3) -> None:
|
51 |
command = f'{oxipng_bin.resolve()} --opt 2 --strip safe --out {image_path} {image_path}'
|
|
|
52 |
for attempt in range(retries):
|
53 |
try:
|
54 |
process = await create_subprocess_shell(command, stdout=PIPE, stderr=PIPE)
|
@@ -58,6 +69,7 @@ async def optimize_png(image_path: Path, retries: int = 3) -> None:
|
|
58 |
else:
|
59 |
raise CalledProcessError(process.returncode, command, output=stdout, stderr=stderr)
|
60 |
except CalledProcessError as e:
|
|
|
61 |
if attempt < retries - 1:
|
62 |
await sleep(2 ** attempt)
|
63 |
else:
|
@@ -66,6 +78,7 @@ async def optimize_png(image_path: Path, retries: int = 3) -> None:
|
|
66 |
|
67 |
async def optimize_pngs(image_paths: list[str | Path] | str | Path) -> None:
|
68 |
image_paths = [Path(image_file) for image_file in ([image_paths] if not isinstance(image_paths, list) else image_paths)]
|
|
|
69 |
tasks = [optimize_png(image_path) for image_path in image_paths]
|
70 |
await gather(*tasks)
|
71 |
|
@@ -119,6 +132,7 @@ async def upload_image(file_path: Path | str) -> str | None:
|
|
119 |
|
120 |
async def optimize_and_upload(images_urls: list[str] | str) -> list[str]:
|
121 |
images_urls = [images_urls] if isinstance(images_urls, str) else images_urls
|
|
|
122 |
images_paths = await download_pngs(images_urls)
|
123 |
await optimize_pngs(images_paths)
|
124 |
new_images_urls = []
|
@@ -126,7 +140,16 @@ async def optimize_and_upload(images_urls: list[str] | str) -> list[str]:
|
|
126 |
new_url = await upload_image(image_path)
|
127 |
if new_url:
|
128 |
new_images_urls.append(new_url)
|
129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
return new_images_urls
|
131 |
|
132 |
|
|
|
1 |
from asyncio import create_subprocess_shell, gather, sleep
|
2 |
+
from logging import ERROR, INFO, basicConfig, getLogger
|
3 |
from pathlib import Path
|
4 |
from random import choice
|
5 |
+
from shutil import rmtree
|
6 |
from subprocess import CalledProcessError, PIPE
|
7 |
from typing import Any, List
|
8 |
from uuid import uuid4
|
|
|
13 |
from pydantic import BaseModel, HttpUrl
|
14 |
from uvicorn import run as uvicorn_run
|
15 |
|
16 |
+
need_logging = True
|
17 |
+
|
18 |
+
basicConfig(level = INFO if need_logging else ERROR)
|
19 |
+
logger = getLogger(__name__)
|
20 |
+
|
21 |
oxipng_bin = Path(__file__).parent / 'oxipng'
|
22 |
if not oxipng_bin.stat().st_mode & 0o111:
|
23 |
oxipng_bin.chmod(0o755)
|
|
|
32 |
]
|
33 |
|
34 |
|
35 |
+
async def download_png(url: str, folder: str, client: AsyncClient, retries: int = 5) -> Path:
|
36 |
+
logger.info(f'загрузка изображения: {url}')
|
37 |
for attempt in range(retries):
|
38 |
try:
|
39 |
response = await client.get(url, timeout=30.0)
|
40 |
response.raise_for_status()
|
41 |
+
file_path = Path(__file__).parent / folder / f'{uuid4()}.png'
|
42 |
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
43 |
file_path.write_bytes(response.content)
|
44 |
return file_path
|
45 |
except (HTTPStatusError, RequestError) as e:
|
|
|
51 |
|
52 |
async def download_pngs(urls: str | list[str]) -> list[Any]:
|
53 |
urls = [urls] if isinstance(urls, str) else urls
|
54 |
+
logger.info(f'скачивается список список из {len(urls)}: {urls}')
|
55 |
async with AsyncClient() as client:
|
56 |
+
tasks = [download_png(url, str(uuid4()), client) for url in urls]
|
57 |
return list(await gather(*tasks))
|
58 |
|
59 |
|
60 |
async def optimize_png(image_path: Path, retries: int = 3) -> None:
|
61 |
command = f'{oxipng_bin.resolve()} --opt 2 --strip safe --out {image_path} {image_path}'
|
62 |
+
logger.info(f'оптимизация картинки {image_path}')
|
63 |
for attempt in range(retries):
|
64 |
try:
|
65 |
process = await create_subprocess_shell(command, stdout=PIPE, stderr=PIPE)
|
|
|
69 |
else:
|
70 |
raise CalledProcessError(process.returncode, command, output=stdout, stderr=stderr)
|
71 |
except CalledProcessError as e:
|
72 |
+
logger.error(f'ошибка при оптимизации {image_path}')
|
73 |
if attempt < retries - 1:
|
74 |
await sleep(2 ** attempt)
|
75 |
else:
|
|
|
78 |
|
79 |
async def optimize_pngs(image_paths: list[str | Path] | str | Path) -> None:
|
80 |
image_paths = [Path(image_file) for image_file in ([image_paths] if not isinstance(image_paths, list) else image_paths)]
|
81 |
+
logger.info(f'оптимизируется список список из {len(image_paths)}: {image_paths}')
|
82 |
tasks = [optimize_png(image_path) for image_path in image_paths]
|
83 |
await gather(*tasks)
|
84 |
|
|
|
132 |
|
133 |
async def optimize_and_upload(images_urls: list[str] | str) -> list[str]:
|
134 |
images_urls = [images_urls] if isinstance(images_urls, str) else images_urls
|
135 |
+
logger.info(f'принятые ссылки в обработку ({len(images_urls)}): {images_urls}')
|
136 |
images_paths = await download_pngs(images_urls)
|
137 |
await optimize_pngs(images_paths)
|
138 |
new_images_urls = []
|
|
|
140 |
new_url = await upload_image(image_path)
|
141 |
if new_url:
|
142 |
new_images_urls.append(new_url)
|
143 |
+
logger.info(f'загружено изображение {image_path} в {new_url}')
|
144 |
+
try:
|
145 |
+
image_path.unlink()
|
146 |
+
except Exception as e:
|
147 |
+
logger.error(f'не удалось удалить файл {image_path}: {e}')
|
148 |
+
logger.info(f'новые ссылки: ({len(new_images_urls)}): {new_images_urls}')
|
149 |
+
try:
|
150 |
+
rmtree(images_paths[0].parent)
|
151 |
+
except Exception as e:
|
152 |
+
logger.error(f'не удалось удалить файл {images_paths[0].parent}: {e}')
|
153 |
return new_images_urls
|
154 |
|
155 |
|