新增自动切换地图功能等 (#4)

*  新增自动切换地图功能

* 📦 新增 `requirements.txt`
This commit is contained in:
Monst.x 2022-11-07 21:59:12 +08:00 committed by GitHub
parent 715c6813f3
commit 5905b4aebe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 66 deletions

View File

@ -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} 不存在!",
}

BIN
requirements.txt Normal file

Binary file not shown.