From 5905b4aebe7ec91073966a6b6b8cde2575e80d9e Mon Sep 17 00:00:00 2001 From: "Monst.x" Date: Mon, 7 Nov 2022 21:59:12 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E6=96=B0=E5=A2=9E=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=87=E6=8D=A2=E5=9C=B0=E5=9B=BE=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E7=AD=89=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :sparkles: 新增自动切换地图功能 * :package: 新增 `requirements.txt` --- .../GetMapImage/get_map_image.py | 145 ++++++++++-------- requirements.txt | Bin 0 -> 352 bytes 2 files changed, 79 insertions(+), 66 deletions(-) create mode 100644 requirements.txt diff --git a/fastapi_genshin_map/GetMapImage/get_map_image.py b/fastapi_genshin_map/GetMapImage/get_map_image.py index e88a4a0..f7fb787 100644 --- a/fastapi_genshin_map/GetMapImage/get_map_image.py +++ b/fastapi_genshin_map/GetMapImage/get_map_image.py @@ -1,47 +1,44 @@ import random -from io import BytesIO from pathlib import Path -from time import time from typing import Optional, Union import yaml - -from fastapi import APIRouter, HTTPException, Query -from fastapi.responses import FileResponse, StreamingResponse +from fastapi import APIRouter +from fastapi.responses import FileResponse from PIL import Image from .GenshinMap.genshinmap import img, models, request, utils from .logger import logger Image.MAX_IMAGE_PIXELS = 333120000 -router = APIRouter(prefix='/get_map') -TEXT_PATH = Path(__file__).parent / 'texture2d' -mark_quest = Image.open(TEXT_PATH / 'mark_quest.png').resize((32, 32)) -MAP = Path(__file__).parent / 'map_data' -RESOURCE_PATH = Path(__file__).parent / 'resource_data' -CHASM_PATH = MAP / 'chasm.png' -ENKANOMIYA_PATH = MAP / 'enkanomiya.png' -TEYVAT_PATH = MAP / 'teyvat.png' +router = APIRouter(prefix="/get_map") +TEXT_PATH = Path(__file__).parent / "texture2d" +mark_quest = Image.open(TEXT_PATH / "mark_quest.png").resize((32, 32)) +MAP = Path(__file__).parent / "map_data" +RESOURCE_PATH = Path(__file__).parent / "resource_data" +CHASM_PATH = MAP / "chasm.png" +ENKANOMIYA_PATH = MAP / "enkanomiya.png" +TEYVAT_PATH = MAP / "teyvat.png" -with open(Path(__file__).parent / 'map.yaml', 'r', encoding='utf-8') as ymlfile: +with open(Path(__file__).parent / "map.yaml", "r", encoding="utf-8") as ymlfile: resource_aliases = yaml.load(ymlfile, Loader=yaml.SafeLoader) MAP_ID_DICT = { - '2': models.MapID.teyvat, # 提瓦特 - '9': models.MapID.chasm, # 层岩巨渊 - '7': models.MapID.enkanomiya, # 渊下宫 + "2": models.MapID.teyvat, # 提瓦特 + "9": models.MapID.chasm, # 层岩巨渊 + "7": models.MapID.enkanomiya, # 渊下宫 # MapID.golden_apple_archipelago, # 金苹果群岛 } -@router.on_event('startup') +@router.on_event("startup") async def create_genshin_map(): if CHASM_PATH.exists() and ENKANOMIYA_PATH.exists() and TEYVAT_PATH.exists(): - logger.info('****************** 开始地图API服务 *****************') + logger.info("****************** 开始地图API服务 *****************") return - logger.info('****************** 地图API服务进行初始化 *****************') - mark_god_pic = Image.open(TEXT_PATH / 'mark_god.png') - mark_trans_pic = Image.open(TEXT_PATH / 'mark_trans.png') + logger.info("****************** 地图API服务进行初始化 *****************") + mark_god_pic = Image.open(TEXT_PATH / "mark_god.png") + mark_trans_pic = Image.open(TEXT_PATH / "mark_trans.png") for map_id in models.MapID: maps = await request.get_maps(map_id) points = await request.get_points(map_id) @@ -68,56 +65,29 @@ async def create_genshin_map(): ) if not MAP.exists(): MAP.mkdir() - map_img.save(MAP / f'{map_id.name}.png') - logger.info('****************** 开始地图API服务 *****************') + map_img.save(MAP / f"{map_id.name}.png") + logger.info("****************** 开始地图API服务 *****************") -@router.get('') -async def get_map_by_point( - resource_name: str = '甜甜花', - map_id: Union[str, int] = 2, - is_cluster: bool = False, -): - req_id = random.randint(10000, 99999) - # 判断别名 - for m in resource_aliases: - for a in resource_aliases[m]: - for r in resource_aliases[m][a]: - if resource_name == r: - resource_name = a - - prefix = f'>> [请求序列:{req_id}]' - logger.info(f'{prefix} 收到资源点访问请求! [资源名称] {resource_name} [地图ID] {map_id}') - ERROR = { - 'retcode': -1, - 'message': f'该资源点 - {resource_name} 不存在!', - } - # 校验map_id有效性 - if map_id not in MAP_ID_DICT: - logger.warning(f'{prefix} 请求失败! 原因: 该地图ID [{map_id}] 不存在!') - return { - 'retcode': -1, - 'message': f'该地图ID - {map_id} 不存在!', - } - +async def get_map_response( + prefix: str, resource_name: str, map_id: models.MapID, is_cluster: bool +) -> Optional[Path]: # 寻找主地图的缓存 - map_data = MAP_ID_DICT[map_id] - map_path = MAP / f'{map_data.name}.png' + map_path = MAP / f"{map_id.name}.png" # 寻找保存点 if not RESOURCE_PATH.exists(): RESOURCE_PATH.mkdir() if is_cluster: - save_path = RESOURCE_PATH / f'{map_data.name}_{resource_name}_KMEANS.jpg' + save_path = RESOURCE_PATH / f"{map_id.name}_{resource_name}_KMEANS.jpg" else: - save_path = RESOURCE_PATH / f'{map_data.name}_{resource_name}.jpg' + save_path = RESOURCE_PATH / f"{map_id.name}_{resource_name}.jpg" # 如果存在缓存,直接回复 if save_path.exists(): - logger.info(f'{prefix} [成功] [资源名称] {resource_name} 已有缓存, 直接发送!') - return FileResponse(save_path) + logger.info(f"{prefix} [查询成功]:发送缓存 [{save_path.name}]!") + return save_path - logger.info(f'{prefix} [资源名称] {resource_name} 暂无缓存, 开始执行绘制...') maps = await request.get_maps(map_id) labels = await request.get_labels(map_id) @@ -131,8 +101,7 @@ async def get_map_by_point( break if resource_id == 0: - logger.warning(f'{prefix} 请求失败! 原因: 该资源点 [{resource_name}] 不存在!') - return ERROR + return # 请求坐标点 points = await request.get_points(map_id) @@ -147,7 +116,7 @@ async def get_map_by_point( else: # 如果资源点不存在,返回错误 if len(transmittable_converted) == 0: - return ERROR + return else: # 计算极限坐标 up = 20000 @@ -172,6 +141,7 @@ async def get_map_by_point( ] ] + logger.info(f"{prefix} [新增缓存]:开始绘制 {save_path.name}...") # 打开主地图 genshin_map = Image.open(map_path) @@ -202,13 +172,56 @@ async def get_map_by_point( ) # 转换RGB图 - genshin_map = genshin_map.convert('RGB') + genshin_map = genshin_map.convert("RGB") # 转为Bytes,暂时废弃 # result_buffer = BytesIO() # genshin_map.save(result_buffer, format='PNG', quality=80, subsampling=0) # 进行保存 - genshin_map.save(save_path, 'JPEG', quality=85) - logger.info(f'{prefix} [成功] [资源名称] {resource_name} 绘制完成!') - return FileResponse(save_path) + genshin_map.save(save_path, "JPEG", quality=85) + logger.info(f"{prefix} [查询成功]:新增缓存 [{save_path.name}]!") + return save_path + + +@router.get("") +async def get_map_by_point( + resource_name: str = "甜甜花", + map_id: Union[str, int] = 0, + is_cluster: bool = False, +): + req_id = random.randint(10000, 99999) + # 判断别名 + for m in resource_aliases: + for a in resource_aliases[m]: + for r in resource_aliases[m][a]: + if resource_name == r: + resource_name = a + + prefix = f">> [请求序列:{req_id}]" + logger.info(f'{prefix} [查询请求]:在地图 ID {map_id or "auto"} 内查询 {resource_name}...') + + if map_id: + # 校验 map_id 有效性 + if map_id not in MAP_ID_DICT: + logger.warning(f"{prefix} [失败]:地图 ID - {map_id} 不存在!") + return { + "retcode": -1, + "message": f"地图 ID - {map_id} 不存在!", + } + maps = [MAP_ID_DICT[str(map_id)]] + else: + # 自动选择地图 + maps = list(MAP_ID_DICT.values()) + + for idx, map in enumerate(maps): + res = await get_map_response(prefix, resource_name, map, is_cluster) + if res: + return FileResponse(res) + if len(maps) > 1: + logger.info(f"{prefix} [自动重试]:地图 ID {map._value_} 内不存在 {resource_name}...") + logger.warning(f"{prefix} [失败]:资源点 - {resource_name} 不存在!") + return { + "retcode": -1, + "message": f"资源点 - {resource_name} 不存在!", + } diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..406e525a15957e3dc6c1f43cb4d348189c533ac1 GIT binary patch literal 352 zcmY+AO$)*>5JcxJ_*0a|g4Bb8_X>h1kA74vYAS82_To=hXE!!g3OV#;-_GRyI$(ne zj^`CQo|q!S5DCUSBlOY3k<^hsF#FOG;y^8GTu2+GhW|Y^I=iIv%&)**`9yhZmZ?2A zTl#bCf)S~9iRkihql c_AB<6x5;>`>zHT{;WciWy