Merge pull request #2 from frostming/fix/command

fix: use spooled temp file to reduce memory usage
This commit is contained in:
yihong 2023-12-12 14:41:04 +08:00 committed by GitHub
commit cbfa805983
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,8 +1,10 @@
import argparse import argparse
import gc import gc
import io
import random import random
import shutil
import subprocess import subprocess
import traceback
from tempfile import SpooledTemporaryFile
import numpy as np import numpy as np
import PIL import PIL
@ -16,8 +18,7 @@ from telebot import TeleBot # type: ignore
from telebot.types import Message # type: ignore from telebot.types import Message # type: ignore
PIL.Image.MAX_IMAGE_PIXELS = 933120000 PIL.Image.MAX_IMAGE_PIXELS = 933120000
file_in = "map.jpg" MAX_IN_MEMORY = 10 * 1024 * 1024 # 10MiB
file_out = "map_out.jpg"
class Plot(PrettyPlot): class Plot(PrettyPlot):
@ -52,35 +53,38 @@ class Plot(PrettyPlot):
def sizeof_image(image): def sizeof_image(image):
with io.BytesIO() as buff: with SpooledTemporaryFile(max_size=MAX_IN_MEMORY) as f:
image.save(buff, format="JPEG", quality=95) image.save(f, format="JPEG", quality=95)
return buff.tell() return f.tell()
def compress_image(input_path, output_path, target_size): def compress_image(input_image, output_image, target_size):
quality = 95 quality = 95
factor = 1.0 factor = 1.0
with Image.open(input_path) as img: with Image.open(input_image) as img:
target_bytes = 10 * 1024 * 1024 while sizeof_image(img) > target_size:
while sizeof_image(img) > target_bytes:
factor -= 0.05 factor -= 0.05
width, height = img.size width, height = img.size
img = img.resize( img = img.resize(
(int(width * factor), int(height * factor)), (int(width * factor), int(height * factor)),
PIL.Image.Resampling.LANCZOS, PIL.Image.Resampling.LANCZOS,
) )
if sizeof_image(img) <= target_bytes: img.save(output_image, format="JPEG", quality=quality)
img.save(output_path, format="JPEG", quality=quality) output_image.seek(0)
return
def draw_pretty_map(location, file_name, style): def draw_pretty_map(location, style, output_file):
aoi = get_aoi(address=location, radius=1100, rectangular=True) aoi = get_aoi(address=location, radius=1100, rectangular=True)
df = get_osm_geometries(aoi=aoi) df = get_osm_geometries(aoi=aoi)
fig = Plot(df=df, aoi_bounds=aoi.bounds, draw_settings=STYLES[style]).plot_all() fig = Plot(df=df, aoi_bounds=aoi.bounds, draw_settings=STYLES[style]).plot_all()
fig.savefig(file_name) with SpooledTemporaryFile(max_size=MAX_IN_MEMORY) as buffer:
compress_image(file_in, file_out, 9) # telegram tog need png less than 10MB fig.savefig(buffer, format="jpeg")
buffer.seek(0)
compress_image(
buffer,
output_file,
10 * 1024 * 1024, # telegram tog need png less than 10MB
)
def main(): def main():
@ -146,16 +150,19 @@ def main():
style = random.choice(styles_list) style = random.choice(styles_list)
try: try:
# TODO why this memory leak? # TODO why this memory leak?
draw_pretty_map(location, file_in, style) with SpooledTemporaryFile(max_size=MAX_IN_MEMORY) as out_image:
draw_pretty_map(location, style, out_image)
# tg can only send image less than 10MB # tg can only send image less than 10MB
with open(file_out, "rb") as photo: with open("map_out.jpg", "wb") as f: # for debug
shutil.copyfileobj(out_image, f)
out_image.seek(0)
bot.send_photo( bot.send_photo(
message.chat.id, photo, reply_to_message_id=message.message_id message.chat.id, out_image, reply_to_message_id=message.message_id
) )
except Exception as e: except Exception:
traceback.print_exc()
bot.reply_to(message, "Something wrong please check") bot.reply_to(message, "Something wrong please check")
print(str(e))
bot.delete_message(reply_message.chat.id, reply_message.message_id) bot.delete_message(reply_message.chat.id, reply_message.message_id)
# we need this, fuck it # we need this, fuck it
gc.collect() gc.collect()