mirror of
https://github.com/PaiGramTeam/PamGram.git
synced 2024-11-21 21:58:04 +00:00
✨ 增加用于模板预览和调试的 web server
This commit is contained in:
parent
6302ba72b1
commit
ada56a2382
@ -41,3 +41,9 @@ API_HASH="abcdefg"
|
|||||||
|
|
||||||
# ENKA_NETWORK_API 可选配置项
|
# ENKA_NETWORK_API 可选配置项
|
||||||
ENKA_NETWORK_API_AGENT=""
|
ENKA_NETWORK_API_AGENT=""
|
||||||
|
|
||||||
|
# Web Server
|
||||||
|
# 目前只用于预览模板,仅开发环境启动
|
||||||
|
# WEB_URL=http://localhost:8080/
|
||||||
|
# WEB_HOST=localhost
|
||||||
|
# WEB_PORT=8080
|
||||||
|
65
core/base/webserver.py
Normal file
65
core/base/webserver.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import asyncio
|
||||||
|
import uvicorn
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
from core.config import BotConfig, config as botConfig
|
||||||
|
from core.service import Service
|
||||||
|
|
||||||
|
__all__ = ["webapp", "WebServer"]
|
||||||
|
|
||||||
|
webapp = FastAPI(debug=botConfig.debug)
|
||||||
|
|
||||||
|
|
||||||
|
@webapp.get("/")
|
||||||
|
def index():
|
||||||
|
return {"Hello": "Paimon"}
|
||||||
|
|
||||||
|
|
||||||
|
class WebServer(Service):
|
||||||
|
debug: bool
|
||||||
|
|
||||||
|
host: str
|
||||||
|
port: int
|
||||||
|
|
||||||
|
server: uvicorn.Server
|
||||||
|
|
||||||
|
_server_task: asyncio.Task
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_config(cls, config: BotConfig) -> Service:
|
||||||
|
return cls(debug=config.debug, **config.webserver.dict())
|
||||||
|
|
||||||
|
def __init__(self, debug: bool, host: str, port: int):
|
||||||
|
self.debug = debug
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
|
||||||
|
self.server = uvicorn.Server(
|
||||||
|
uvicorn.Config(
|
||||||
|
app=webapp,
|
||||||
|
port=port,
|
||||||
|
use_colors=False,
|
||||||
|
host=host,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
"""启动 service"""
|
||||||
|
|
||||||
|
# 暂时只在开发环境启动 webserver 用于开发调试
|
||||||
|
if not self.debug:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 防止 uvicorn server 拦截 signals
|
||||||
|
self.server.install_signal_handlers = lambda: None
|
||||||
|
self._server_task = asyncio.create_task(self.server.serve())
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
"""关闭 service"""
|
||||||
|
if not self.debug:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.server.should_exit = True
|
||||||
|
|
||||||
|
# 等待 task 结束
|
||||||
|
await self._server_task
|
@ -52,6 +52,10 @@ class BotConfig(BaseSettings):
|
|||||||
pass_challenge_api: str = ""
|
pass_challenge_api: str = ""
|
||||||
pass_challenge_app_key: str = ""
|
pass_challenge_app_key: str = ""
|
||||||
|
|
||||||
|
web_url: str = "http://localhost:8080/"
|
||||||
|
web_host: str = "localhost"
|
||||||
|
web_port: int = 8080
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
case_sensitive = False
|
case_sensitive = False
|
||||||
json_loads = json.loads
|
json_loads = json.loads
|
||||||
@ -92,6 +96,13 @@ class BotConfig(BaseSettings):
|
|||||||
api_hash=self.api_hash,
|
api_hash=self.api_hash,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def webserver(self) -> "WebServerConfig":
|
||||||
|
return WebServerConfig(
|
||||||
|
host=self.web_host,
|
||||||
|
port=self.web_port,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConfigChannel(BaseModel):
|
class ConfigChannel(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
@ -130,5 +141,10 @@ class MTProtoConfig(BaseModel):
|
|||||||
api_hash: Optional[str]
|
api_hash: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class WebServerConfig(BaseModel):
|
||||||
|
host: Optional[str]
|
||||||
|
port: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
BotConfig.update_forward_refs()
|
BotConfig.update_forward_refs()
|
||||||
config = BotConfig()
|
config = BotConfig()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from types import FunctionType
|
from typing import Callable
|
||||||
|
|
||||||
from utils.log import logger
|
from utils.log import logger
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class Service(ABC):
|
|||||||
"""关闭 service"""
|
"""关闭 service"""
|
||||||
|
|
||||||
|
|
||||||
def init_service(func: FunctionType):
|
def init_service(func: Callable):
|
||||||
from core.bot import bot
|
from core.bot import bot
|
||||||
|
|
||||||
if bot.is_running:
|
if bot.is_running:
|
||||||
|
11
core/template/README.md
Normal file
11
core/template/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# TemplateService
|
||||||
|
|
||||||
|
使用 jinja2 渲染 html 为图片的服务。
|
||||||
|
|
||||||
|
## 预览模板
|
||||||
|
|
||||||
|
为了方便调试 html,在开发环境中,我们会启动 web server 用于预览模板。(可以在 .env 里调整端口等参数,参数均为 `web_` 开头)
|
||||||
|
|
||||||
|
在派蒙收到指令开始渲染某个模板的时候,控制台会输出一个预览链接,类似 `http://localhost:8080/preview/genshin/stats/stats.html?id=45f7d86a-058e-4f64-bdeb-42903d8415b2`,有效时间 8 小时。
|
||||||
|
|
||||||
|
如果是无需数据的模板,永久有效,比如 `http://localhost:8080/preview/bot/help/help.html`
|
@ -1,9 +1,11 @@
|
|||||||
from core.base.aiobrowser import AioBrowser
|
from core.base.aiobrowser import AioBrowser
|
||||||
from core.service import init_service
|
from core.service import init_service
|
||||||
from .services import TemplateService
|
from core.base.redisdb import RedisDB
|
||||||
|
from core.template.services import TemplateService
|
||||||
|
from core.template.cache import TemplatePreviewCache
|
||||||
|
|
||||||
@init_service
|
@init_service
|
||||||
def create_template_service(browser: AioBrowser):
|
def create_template_service(browser: AioBrowser, redis: RedisDB):
|
||||||
_service = TemplateService(browser)
|
_cache = TemplatePreviewCache(redis)
|
||||||
|
_service = TemplateService(browser, _cache)
|
||||||
return _service
|
return _service
|
||||||
|
28
core/template/cache.py
Normal file
28
core/template/cache.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from typing import Any
|
||||||
|
import pickle # nosec B403
|
||||||
|
import gzip
|
||||||
|
|
||||||
|
from core.base.redisdb import RedisDB
|
||||||
|
|
||||||
|
|
||||||
|
class TemplatePreviewCache:
|
||||||
|
'''暂存渲染模板的数据用于预览'''
|
||||||
|
|
||||||
|
def __init__(self, redis: RedisDB):
|
||||||
|
self.client = redis.client
|
||||||
|
self.qname = "bot:template:preview"
|
||||||
|
|
||||||
|
async def get_data(self, key: str) -> Any:
|
||||||
|
data = await self.client.get(self.cache_key(key))
|
||||||
|
if data:
|
||||||
|
# skipcq: BAN-B301
|
||||||
|
return pickle.loads(gzip.decompress(data)) # nosec B301
|
||||||
|
|
||||||
|
async def set_data(self, key: str, data: Any, ttl: int = 8 * 60 * 60):
|
||||||
|
ck = self.cache_key(key)
|
||||||
|
await self.client.set(ck, gzip.compress(pickle.dumps(data)))
|
||||||
|
if ttl != -1:
|
||||||
|
await self.client.expire(ck, ttl)
|
||||||
|
|
||||||
|
def cache_key(self, key: str) -> str:
|
||||||
|
return f"{self.qname}:{key}"
|
@ -1,13 +1,21 @@
|
|||||||
import os
|
|
||||||
import time
|
import time
|
||||||
from typing import Dict, Optional
|
from typing import Optional
|
||||||
|
from urllib.parse import urlencode, urljoin, urlsplit
|
||||||
|
|
||||||
from jinja2 import Environment, PackageLoader, Template
|
from jinja2 import Environment, FileSystemLoader, Template
|
||||||
from playwright.async_api import ViewportSize
|
from playwright.async_api import ViewportSize
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from fastapi.responses import FileResponse, HTMLResponse
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
from core.base.aiobrowser import AioBrowser
|
from core.base.aiobrowser import AioBrowser
|
||||||
from core.bot import bot
|
from core.bot import bot
|
||||||
|
from core.base.webserver import webapp
|
||||||
|
from utils.const import PROJECT_ROOT
|
||||||
from utils.log import logger
|
from utils.log import logger
|
||||||
|
from core.template.cache import TemplatePreviewCache
|
||||||
|
|
||||||
|
|
||||||
class _QuerySelectorNotFound(Exception):
|
class _QuerySelectorNotFound(Exception):
|
||||||
@ -15,51 +23,35 @@ class _QuerySelectorNotFound(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class TemplateService:
|
class TemplateService:
|
||||||
def __init__(self, browser: AioBrowser, template_package_name: str = "resources", cache_dir_name: str = "cache"):
|
def __init__(self, browser: AioBrowser, preview_cache: TemplatePreviewCache, template_dir: str = "resources"):
|
||||||
self._browser = browser
|
self._browser = browser
|
||||||
self._template_package_name = template_package_name
|
self.template_dir = PROJECT_ROOT / template_dir
|
||||||
self._current_dir = os.getcwd()
|
|
||||||
self._output_dir = os.path.join(self._current_dir, cache_dir_name)
|
|
||||||
if not os.path.exists(self._output_dir):
|
|
||||||
os.mkdir(self._output_dir)
|
|
||||||
self._jinja2_env: Dict[str, Environment] = {}
|
|
||||||
self._jinja2_template: Dict[str, Template] = {}
|
|
||||||
|
|
||||||
def get_template(self, package_path: str, template_name: str) -> Template:
|
self._jinja2_env = Environment(
|
||||||
if bot.config.debug:
|
loader=FileSystemLoader(template_dir),
|
||||||
# DEBUG下 禁止复用 方便查看和修改模板
|
enable_async=True,
|
||||||
loader = PackageLoader(self._template_package_name, package_path)
|
autoescape=True,
|
||||||
jinja2_env = Environment(loader=loader, enable_async=True, autoescape=True)
|
auto_reload=bot.config.debug,
|
||||||
jinja2_template = jinja2_env.get_template(template_name)
|
)
|
||||||
else:
|
|
||||||
jinja2_env = self._jinja2_env.get(package_path)
|
|
||||||
jinja2_template = self._jinja2_template.get(package_path + template_name)
|
|
||||||
if jinja2_env is None:
|
|
||||||
loader = PackageLoader(self._template_package_name, package_path)
|
|
||||||
jinja2_env = Environment(loader=loader, enable_async=True, autoescape=True)
|
|
||||||
jinja2_template = jinja2_env.get_template(template_name)
|
|
||||||
self._jinja2_env[package_path] = jinja2_env
|
|
||||||
self._jinja2_template[package_path + template_name] = jinja2_template
|
|
||||||
elif jinja2_template is None:
|
|
||||||
jinja2_template = jinja2_env.get_template(template_name)
|
|
||||||
self._jinja2_template[package_path + template_name] = jinja2_template
|
|
||||||
return jinja2_template
|
|
||||||
|
|
||||||
async def render_async(self, template_path: str, template_name: str, template_data: dict):
|
self.previewer = TemplatePreviewer(self, preview_cache)
|
||||||
|
|
||||||
|
def get_template(self, template_name: str) -> Template:
|
||||||
|
return self._jinja2_env.get_template(template_name)
|
||||||
|
|
||||||
|
async def render_async(self, template_name: str, template_data: dict):
|
||||||
"""模板渲染
|
"""模板渲染
|
||||||
:param template_path: 模板目录
|
|
||||||
:param template_name: 模板文件名
|
:param template_name: 模板文件名
|
||||||
:param template_data: 模板数据
|
:param template_data: 模板数据
|
||||||
"""
|
"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
template = self.get_template(template_path, template_name)
|
template = self.get_template(template_name)
|
||||||
html = await template.render_async(**template_data)
|
html = await template.render_async(**template_data)
|
||||||
logger.debug(f"{template_name} 模板渲染使用了 {str(time.time() - start_time)}")
|
logger.debug(f"{template_name} 模板渲染使用了 {str(time.time() - start_time)}")
|
||||||
return html
|
return html
|
||||||
|
|
||||||
async def render(
|
async def render(
|
||||||
self,
|
self,
|
||||||
template_path: str,
|
|
||||||
template_name: str,
|
template_name: str,
|
||||||
template_data: dict,
|
template_data: dict,
|
||||||
viewport: ViewportSize = None,
|
viewport: ViewportSize = None,
|
||||||
@ -78,14 +70,20 @@ class TemplateService:
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
template = self.get_template(template_path, template_name)
|
template = self.get_template(template_name)
|
||||||
template_data["res_path"] = f"file://{self._current_dir}"
|
|
||||||
|
if bot.config.debug:
|
||||||
|
preview_url = await self.previewer.get_preview_url(template_name, template_data)
|
||||||
|
logger.debug(f"调试模板 URL: {preview_url}")
|
||||||
|
|
||||||
html = await template.render_async(**template_data)
|
html = await template.render_async(**template_data)
|
||||||
logger.debug(f"{template_name} 模板渲染使用了 {str(time.time() - start_time)}")
|
logger.debug(f"{template_name} 模板渲染使用了 {str(time.time() - start_time)}")
|
||||||
|
|
||||||
browser = await self._browser.get_browser()
|
browser = await self._browser.get_browser()
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
page = await browser.new_page(viewport=viewport)
|
page = await browser.new_page(viewport=viewport)
|
||||||
await page.goto(f"file://{template.filename}")
|
uri = (PROJECT_ROOT / template.filename).as_uri()
|
||||||
|
await page.goto(uri)
|
||||||
await page.set_content(html, wait_until="networkidle")
|
await page.set_content(html, wait_until="networkidle")
|
||||||
if evaluate:
|
if evaluate:
|
||||||
await page.evaluate(evaluate)
|
await page.evaluate(evaluate)
|
||||||
@ -104,3 +102,52 @@ class TemplateService:
|
|||||||
await page.close()
|
await page.close()
|
||||||
logger.debug(f"{template_name} 图片渲染使用了 {str(time.time() - start_time)}")
|
logger.debug(f"{template_name} 图片渲染使用了 {str(time.time() - start_time)}")
|
||||||
return png_data
|
return png_data
|
||||||
|
|
||||||
|
|
||||||
|
class TemplatePreviewer:
|
||||||
|
def __init__(self, template_service: TemplateService, cache: TemplatePreviewCache):
|
||||||
|
self.template_service = template_service
|
||||||
|
self.cache = cache
|
||||||
|
self.register_routes()
|
||||||
|
|
||||||
|
async def get_preview_url(self, template: str, data: dict):
|
||||||
|
"""获取预览 URL"""
|
||||||
|
components = urlsplit(bot.config.web_url)
|
||||||
|
path = urljoin("/preview/", template)
|
||||||
|
query = {}
|
||||||
|
|
||||||
|
# 如果有数据,暂存在 redis 中
|
||||||
|
if data:
|
||||||
|
key = str(uuid4())
|
||||||
|
await self.cache.set_data(key, data)
|
||||||
|
query["key"] = key
|
||||||
|
|
||||||
|
return components._replace(path=path, query=urlencode(query)).geturl()
|
||||||
|
|
||||||
|
def register_routes(self):
|
||||||
|
"""注册预览用到的路由"""
|
||||||
|
|
||||||
|
@webapp.get("/preview/{path:path}")
|
||||||
|
async def preview_template(path: str, key: Optional[str] = None): # pylint: disable=W0612
|
||||||
|
# 如果是 /preview/ 开头的静态文件,直接返回内容。比如使用相对链接 ../ 引入的静态资源
|
||||||
|
if not path.endswith(".html"):
|
||||||
|
full_path = self.template_service.template_dir / path
|
||||||
|
if not full_path.is_file():
|
||||||
|
raise HTTPException(status_code=404, detail=f"Template '{path}' not found")
|
||||||
|
return FileResponse(full_path)
|
||||||
|
|
||||||
|
# 取回暂存的渲染数据
|
||||||
|
data = await self.cache.get_data(key) if key else {}
|
||||||
|
if key and data is None:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Template data {key} not found")
|
||||||
|
|
||||||
|
# 渲染 jinja2 模板
|
||||||
|
html = await self.template_service.render_async(path, data)
|
||||||
|
# 将本地 URL file:// 修改为 HTTP url,因为浏览器内不允许加载本地文件
|
||||||
|
# file:///project_dir/cache/image.jpg => /cache/image.jpg
|
||||||
|
html = html.replace(PROJECT_ROOT.as_uri(), "")
|
||||||
|
return HTMLResponse(html)
|
||||||
|
|
||||||
|
# 其他静态资源
|
||||||
|
for name in ["cache", "resources"]:
|
||||||
|
webapp.mount(f"/{name}", StaticFiles(directory=PROJECT_ROOT / name), name=name)
|
||||||
|
@ -258,7 +258,7 @@ class Abyss(Plugin, BasePlugin):
|
|||||||
[
|
[
|
||||||
-1,
|
-1,
|
||||||
await self.template_service.render(
|
await self.template_service.render(
|
||||||
"genshin/abyss", "overview.html", render_data, viewport={"width": 750, "height": 580}
|
"genshin/abyss/overview.html", render_data, viewport={"width": 750, "height": 580}
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -269,8 +269,7 @@ class Abyss(Plugin, BasePlugin):
|
|||||||
[
|
[
|
||||||
floor_d["floor"],
|
floor_d["floor"],
|
||||||
await self.template_service.render(
|
await self.template_service.render(
|
||||||
"genshin/abyss",
|
"genshin/abyss/floor.html",
|
||||||
"floor.html",
|
|
||||||
{
|
{
|
||||||
**render_data,
|
**render_data,
|
||||||
"floor": floor_d,
|
"floor": floor_d,
|
||||||
@ -293,8 +292,7 @@ class Abyss(Plugin, BasePlugin):
|
|||||||
render_data["data"] = json.loads(result)
|
render_data["data"] = json.loads(result)
|
||||||
return [
|
return [
|
||||||
await self.template_service.render(
|
await self.template_service.render(
|
||||||
"genshin/abyss",
|
"genshin/abyss/overview.html",
|
||||||
"overview.html",
|
|
||||||
render_data,
|
render_data,
|
||||||
viewport={"width": 750, "height": 580},
|
viewport={"width": 750, "height": 580},
|
||||||
)
|
)
|
||||||
@ -325,6 +323,6 @@ class Abyss(Plugin, BasePlugin):
|
|||||||
render_data["total_stars"] = f"{floor_data[0]['stars']}/{floor_data[0]['max_stars']}"
|
render_data["total_stars"] = f"{floor_data[0]['stars']}/{floor_data[0]['max_stars']}"
|
||||||
return [
|
return [
|
||||||
await self.template_service.render(
|
await self.template_service.render(
|
||||||
"genshin/abyss", "floor.html", render_data, viewport={"width": 690, "height": 500}, full_page=True
|
"genshin/abyss/floor.html", render_data, viewport={"width": 690, "height": 500}, full_page=True
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -83,8 +83,7 @@ class AbyssTeam(Plugin, BasePlugin):
|
|||||||
|
|
||||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||||
png_data = await self.template_service.render(
|
png_data = await self.template_service.render(
|
||||||
"genshin/abyss_team",
|
"genshin/abyss_team/abyss_team.html",
|
||||||
"abyss_team.html",
|
|
||||||
abyss_teams_data,
|
abyss_teams_data,
|
||||||
{"width": 785, "height": 800},
|
{"width": 785, "height": 800},
|
||||||
full_page=True,
|
full_page=True,
|
||||||
|
@ -258,7 +258,8 @@ class DailyMaterial(Plugin, BasePlugin):
|
|||||||
AreaData(
|
AreaData(
|
||||||
name=area_data["name"],
|
name=area_data["name"],
|
||||||
materials=materials,
|
materials=materials,
|
||||||
items=sort_item(items),
|
# template previewer pickle cannot serialize generator
|
||||||
|
items=list(sort_item(items)),
|
||||||
material_name=get_material_serial_name(map(lambda x: x.name, materials)),
|
material_name=get_material_serial_name(map(lambda x: x.name, materials)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -268,12 +269,12 @@ class DailyMaterial(Plugin, BasePlugin):
|
|||||||
render_tasks = [
|
render_tasks = [
|
||||||
asyncio.create_task(
|
asyncio.create_task(
|
||||||
self.template_service.render( # 渲染角色素材页
|
self.template_service.render( # 渲染角色素材页
|
||||||
"genshin/daily_material", "character.html", {"data": render_data}, {"width": 1164, "height": 500}
|
"genshin/daily_material/character.html", {"data": render_data}, {"width": 1164, "height": 500}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
asyncio.create_task(
|
asyncio.create_task(
|
||||||
self.template_service.render( # 渲染武器素材页
|
self.template_service.render( # 渲染武器素材页
|
||||||
"genshin/daily_material", "weapon.html", {"data": render_data}, {"width": 1164, "height": 500}
|
"genshin/daily_material/weapon.html", {"data": render_data}, {"width": 1164, "height": 500}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -86,7 +86,7 @@ class DailyNote(Plugin, BasePlugin):
|
|||||||
"transformer_recovery_time": transformer_recovery_time,
|
"transformer_recovery_time": transformer_recovery_time,
|
||||||
}
|
}
|
||||||
png_data = await self.template_service.render(
|
png_data = await self.template_service.render(
|
||||||
"genshin/daily_note", "daily_note.html", daily_data, {"width": 600, "height": 548}, full_page=False
|
"genshin/daily_note/daily_note.html", daily_data, {"width": 600, "height": 548}, full_page=False
|
||||||
)
|
)
|
||||||
return png_data
|
return png_data
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ class Gacha(Plugin, BasePlugin):
|
|||||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||||
# 因为 gacha_info["title"] 返回的是 HTML 标签 尝试关闭自动转义
|
# 因为 gacha_info["title"] 返回的是 HTML 标签 尝试关闭自动转义
|
||||||
png_data = await self.template_service.render(
|
png_data = await self.template_service.render(
|
||||||
"genshin/gacha", "gacha.html", data, {"width": 1157, "height": 603}, False
|
"genshin/gacha/gacha.html", data, {"width": 1157, "height": 603}, False
|
||||||
)
|
)
|
||||||
|
|
||||||
reply_message = await message.reply_photo(png_data)
|
reply_message = await message.reply_photo(png_data)
|
||||||
|
@ -290,7 +290,7 @@ class GachaLog(Plugin.Conversation, BasePlugin.Conversation):
|
|||||||
else:
|
else:
|
||||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||||
png_data = await self.template_service.render(
|
png_data = await self.template_service.render(
|
||||||
"genshin/gacha_log", "gacha_log.html", data, full_page=True, query_selector=".body_box"
|
"genshin/gacha_log/gacha_log.html", data, full_page=True, query_selector=".body_box"
|
||||||
)
|
)
|
||||||
await message.reply_photo(png_data)
|
await message.reply_photo(png_data)
|
||||||
except UserNotFoundError:
|
except UserNotFoundError:
|
||||||
@ -336,7 +336,7 @@ class GachaLog(Plugin.Conversation, BasePlugin.Conversation):
|
|||||||
document = True
|
document = True
|
||||||
data["hasMore"] = False
|
data["hasMore"] = False
|
||||||
png_data = await self.template_service.render(
|
png_data = await self.template_service.render(
|
||||||
"genshin/gacha_count", "gacha_count.html", data, full_page=True, query_selector=".body_box"
|
"genshin/gacha_count/gacha_count.html", data, full_page=True, query_selector=".body_box"
|
||||||
)
|
)
|
||||||
if document:
|
if document:
|
||||||
await message.reply_chat_action(ChatAction.UPLOAD_DOCUMENT)
|
await message.reply_chat_action(ChatAction.UPLOAD_DOCUMENT)
|
||||||
|
@ -28,7 +28,7 @@ class HelpPlugin(Plugin):
|
|||||||
logger.info(f"用户 {user.full_name}[{user.id}] 发出help命令")
|
logger.info(f"用户 {user.full_name}[{user.id}] 发出help命令")
|
||||||
if self.file_id is None or bot.config.debug:
|
if self.file_id is None or bot.config.debug:
|
||||||
await message.reply_chat_action(ChatAction.TYPING)
|
await message.reply_chat_action(ChatAction.TYPING)
|
||||||
help_png = await self.template_service.render("bot/help", "help.html", {}, {"width": 1280, "height": 900})
|
help_png = await self.template_service.render("bot/help/help.html", {}, {"width": 1280, "height": 900})
|
||||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||||
reply_photo = await message.reply_photo(help_png, filename="help.png", allow_sending_without_reply=True)
|
reply_photo = await message.reply_photo(help_png, filename="help.png", allow_sending_without_reply=True)
|
||||||
photo = reply_photo.photo[0]
|
photo = reply_photo.photo[0]
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@ -89,52 +88,6 @@ class Ledger(Plugin, BasePlugin):
|
|||||||
def format_amount(amount: int) -> str:
|
def format_amount(amount: int) -> str:
|
||||||
return f"{round(amount / 10000, 2)}w" if amount >= 10000 else amount
|
return f"{round(amount / 10000, 2)}w" if amount >= 10000 else amount
|
||||||
|
|
||||||
evaluate = (
|
|
||||||
"""const { Pie } = G2Plot;
|
|
||||||
const data = JSON.parse(`"""
|
|
||||||
+ json.dumps(categories)
|
|
||||||
+ """`);
|
|
||||||
const piePlot = new Pie("chartContainer", {
|
|
||||||
renderer: "svg",
|
|
||||||
animation: false,
|
|
||||||
data: data,
|
|
||||||
appendPadding: 10,
|
|
||||||
angleField: "amount",
|
|
||||||
colorField: "name",
|
|
||||||
radius: 1,
|
|
||||||
innerRadius: 0.7,
|
|
||||||
color: JSON.parse(`"""
|
|
||||||
+ json.dumps(color)
|
|
||||||
+ """`),
|
|
||||||
meta: {},
|
|
||||||
label: {
|
|
||||||
type: "inner",
|
|
||||||
offset: "-50%",
|
|
||||||
autoRotate: false,
|
|
||||||
style: {
|
|
||||||
textAlign: "center",
|
|
||||||
fontFamily: "tttgbnumber",
|
|
||||||
},
|
|
||||||
formatter: ({ percentage }) => {
|
|
||||||
return percentage > 2 ? `${percentage}%` : "";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
statistic: {
|
|
||||||
title: {
|
|
||||||
offsetY: -18,
|
|
||||||
content: "总计",
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
offsetY: -10,
|
|
||||||
style: {
|
|
||||||
fontFamily: "tttgbnumber",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
legend:false,
|
|
||||||
});
|
|
||||||
piePlot.render();"""
|
|
||||||
)
|
|
||||||
ledger_data = {
|
ledger_data = {
|
||||||
"uid": client.uid,
|
"uid": client.uid,
|
||||||
"day": diary_info.month,
|
"day": diary_info.month,
|
||||||
@ -145,9 +98,10 @@ class Ledger(Plugin, BasePlugin):
|
|||||||
"last_gacha": int(diary_info.month_data.last_primogems / 160),
|
"last_gacha": int(diary_info.month_data.last_primogems / 160),
|
||||||
"last_mora": format_amount(diary_info.month_data.last_mora),
|
"last_mora": format_amount(diary_info.month_data.last_mora),
|
||||||
"categories": categories,
|
"categories": categories,
|
||||||
|
"color": color,
|
||||||
}
|
}
|
||||||
png_data = await self.template_service.render(
|
png_data = await self.template_service.render(
|
||||||
"genshin/ledger", "ledger.html", ledger_data, {"width": 580, "height": 610}, evaluate=evaluate
|
"genshin/ledger/ledger.html", ledger_data, {"width": 580, "height": 610}
|
||||||
)
|
)
|
||||||
return png_data
|
return png_data
|
||||||
|
|
||||||
|
@ -271,13 +271,12 @@ class RenderTemplate:
|
|||||||
}
|
}
|
||||||
|
|
||||||
# html = await self.template_service.render_async(
|
# html = await self.template_service.render_async(
|
||||||
# "genshin/player_card", "player_card.html", data
|
# "genshin/player_card/player_card.html", data
|
||||||
# )
|
# )
|
||||||
# logger.debug(html)
|
# logger.debug(html)
|
||||||
|
|
||||||
return await self.template_service.render(
|
return await self.template_service.render(
|
||||||
"genshin/player_card",
|
"genshin/player_card/player_card.html",
|
||||||
"player_card.html",
|
|
||||||
data,
|
data,
|
||||||
{"width": 950, "height": 1080},
|
{"width": 950, "height": 1080},
|
||||||
full_page=True,
|
full_page=True,
|
||||||
|
@ -112,15 +112,14 @@ class UserStatsPlugins(Plugin, BasePlugin):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# html = await self.template_service.render_async(
|
# html = await self.template_service.render_async(
|
||||||
# "genshin/stats", "stats.html", data
|
# "genshin/stats/stats.html", data
|
||||||
# )
|
# )
|
||||||
# logger.debug(html)
|
# logger.debug(html)
|
||||||
|
|
||||||
await self.cache_images(user_info)
|
await self.cache_images(user_info)
|
||||||
|
|
||||||
return await self.template_service.render(
|
return await self.template_service.render(
|
||||||
"genshin/stats",
|
"genshin/stats/stats.html",
|
||||||
"stats.html",
|
|
||||||
data,
|
data,
|
||||||
{"width": 650, "height": 800},
|
{"width": 650, "height": 800},
|
||||||
full_page=True,
|
full_page=True,
|
||||||
|
@ -111,7 +111,7 @@ class WeaponPlugin(Plugin, BasePlugin):
|
|||||||
|
|
||||||
template_data = await input_template_data(weapon_data)
|
template_data = await input_template_data(weapon_data)
|
||||||
png_data = await self.template_service.render(
|
png_data = await self.template_service.render(
|
||||||
"genshin/weapon", "weapon.html", template_data, {"width": 540, "height": 540}
|
"genshin/weapon/weapon.html", template_data, {"width": 540, "height": 540}
|
||||||
)
|
)
|
||||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||||
await message.reply_photo(
|
await message.reply_photo(
|
||||||
|
249
poetry.lock
generated
249
poetry.lock
generated
@ -329,6 +329,24 @@ sortedcontainers = ">=2.4.0,<3.0.0"
|
|||||||
aioredis = ["aioredis (>=2.0.1,<3.0.0)"]
|
aioredis = ["aioredis (>=2.0.1,<3.0.0)"]
|
||||||
lua = ["lupa (>=1.13,<2.0)"]
|
lua = ["lupa (>=1.13,<2.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastapi"
|
||||||
|
version = "0.85.0"
|
||||||
|
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0"
|
||||||
|
starlette = "0.20.4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
all = ["email-validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"]
|
||||||
|
dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"]
|
||||||
|
doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.7.0)"]
|
||||||
|
test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-orjson (==3.6.2)", "types-ujson (==5.4.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flaky"
|
name = "flaky"
|
||||||
version = "3.7.0"
|
version = "3.7.0"
|
||||||
@ -407,6 +425,17 @@ sniffio = ">=1.0.0,<2.0.0"
|
|||||||
http2 = ["h2 (>=3,<5)"]
|
http2 = ["h2 (>=3,<5)"]
|
||||||
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httptools"
|
||||||
|
version = "0.5.0"
|
||||||
|
description = "A collection of framework independent HTTP protocol utils."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["Cython (>=0.29.24,<0.30.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpx"
|
name = "httpx"
|
||||||
version = "0.23.0"
|
version = "0.23.0"
|
||||||
@ -815,6 +844,14 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
|||||||
"backports.zoneinfo" = {version = "*", markers = "python_version >= \"3.6\" and python_version < \"3.9\""}
|
"backports.zoneinfo" = {version = "*", markers = "python_version >= \"3.6\" and python_version < \"3.9\""}
|
||||||
tzdata = {version = "*", markers = "python_version >= \"3.6\""}
|
tzdata = {version = "*", markers = "python_version >= \"3.6\""}
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "PyYAML"
|
||||||
|
version = "6.0"
|
||||||
|
description = "YAML parser and emitter for Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redis"
|
name = "redis"
|
||||||
version = "4.3.4"
|
version = "4.3.4"
|
||||||
@ -963,6 +1000,21 @@ pydantic = ">=1.8.2,<2.0.0"
|
|||||||
SQLAlchemy = ">=1.4.17,<=1.4.41"
|
SQLAlchemy = ">=1.4.17,<=1.4.41"
|
||||||
sqlalchemy2-stubs = "*"
|
sqlalchemy2-stubs = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "starlette"
|
||||||
|
version = "0.20.4"
|
||||||
|
description = "The little ASGI library that shines."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
anyio = ">=3.4.0,<5"
|
||||||
|
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "TgCrypto"
|
name = "TgCrypto"
|
||||||
version = "1.2.4"
|
version = "1.2.4"
|
||||||
@ -1058,6 +1110,52 @@ brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
|||||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uvicorn"
|
||||||
|
version = "0.18.3"
|
||||||
|
description = "The lightning-fast ASGI server."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
click = ">=7.0"
|
||||||
|
colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""}
|
||||||
|
h11 = ">=0.8"
|
||||||
|
httptools = {version = ">=0.4.0", optional = true, markers = "extra == \"standard\""}
|
||||||
|
python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
|
||||||
|
pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""}
|
||||||
|
uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
|
||||||
|
watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
|
||||||
|
websockets = {version = ">=10.0", optional = true, markers = "extra == \"standard\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uvloop"
|
||||||
|
version = "0.17.0"
|
||||||
|
description = "Fast implementation of asyncio event loop on top of libuv"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["Cython (>=0.29.32,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"]
|
||||||
|
docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"]
|
||||||
|
test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "watchfiles"
|
||||||
|
version = "0.17.0"
|
||||||
|
description = "Simple, modern and high performance file watching and code reload in python."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
anyio = ">=3.0.0,<4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websockets"
|
name = "websockets"
|
||||||
version = "10.1"
|
version = "10.1"
|
||||||
@ -1106,7 +1204,7 @@ test = ["pytest", "pytest-asyncio", "flaky"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.8"
|
||||||
content-hash = "5108671687c709ce2ec1deae867f16271447adfc995ae6d043093e3f4d8c64fd"
|
content-hash = "7ba810263a9ddf763ea7b44030edf84a31f6137a8201835a695c76afe20d1b25"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
aiofiles = [
|
aiofiles = [
|
||||||
@ -1335,6 +1433,10 @@ fakeredis = [
|
|||||||
{file = "fakeredis-1.9.3-py3-none-any.whl", hash = "sha256:74a2f1e5e8781014418fe734b156808d5d1a2d15edec982fada3d6e7603f8536"},
|
{file = "fakeredis-1.9.3-py3-none-any.whl", hash = "sha256:74a2f1e5e8781014418fe734b156808d5d1a2d15edec982fada3d6e7603f8536"},
|
||||||
{file = "fakeredis-1.9.3.tar.gz", hash = "sha256:ea7e4ed076def2eea36188662586a9f2271946ae56ebc2de6a998c82b33df776"},
|
{file = "fakeredis-1.9.3.tar.gz", hash = "sha256:ea7e4ed076def2eea36188662586a9f2271946ae56ebc2de6a998c82b33df776"},
|
||||||
]
|
]
|
||||||
|
fastapi = [
|
||||||
|
{file = "fastapi-0.85.0-py3-none-any.whl", hash = "sha256:1803d962f169dc9f8dde54a64b22eb16f6d81573f54401971f90f0a67234a8b4"},
|
||||||
|
{file = "fastapi-0.85.0.tar.gz", hash = "sha256:bb219cfafd0d2ccf8f32310c9a257a06b0210bd8e2a03706a6f5a9f9f1416878"},
|
||||||
|
]
|
||||||
flaky = [
|
flaky = [
|
||||||
{file = "flaky-3.7.0-py2.py3-none-any.whl", hash = "sha256:d6eda73cab5ae7364504b7c44670f70abed9e75f77dd116352f662817592ec9c"},
|
{file = "flaky-3.7.0-py2.py3-none-any.whl", hash = "sha256:d6eda73cab5ae7364504b7c44670f70abed9e75f77dd116352f662817592ec9c"},
|
||||||
{file = "flaky-3.7.0.tar.gz", hash = "sha256:3ad100780721a1911f57a165809b7ea265a7863305acb66708220820caf8aa0d"},
|
{file = "flaky-3.7.0.tar.gz", hash = "sha256:3ad100780721a1911f57a165809b7ea265a7863305acb66708220820caf8aa0d"},
|
||||||
@ -1465,6 +1567,49 @@ httpcore = [
|
|||||||
{file = "httpcore-0.15.0-py3-none-any.whl", hash = "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6"},
|
{file = "httpcore-0.15.0-py3-none-any.whl", hash = "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6"},
|
||||||
{file = "httpcore-0.15.0.tar.gz", hash = "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b"},
|
{file = "httpcore-0.15.0.tar.gz", hash = "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b"},
|
||||||
]
|
]
|
||||||
|
httptools = [
|
||||||
|
{file = "httptools-0.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f470c79061599a126d74385623ff4744c4e0f4a0997a353a44923c0b561ee51"},
|
||||||
|
{file = "httptools-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e90491a4d77d0cb82e0e7a9cb35d86284c677402e4ce7ba6b448ccc7325c5421"},
|
||||||
|
{file = "httptools-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d2357f791b12d86faced7b5736dea9ef4f5ecdc6c3f253e445ee82da579449"},
|
||||||
|
{file = "httptools-0.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f90cd6fd97c9a1b7fe9215e60c3bd97336742a0857f00a4cb31547bc22560c2"},
|
||||||
|
{file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5230a99e724a1bdbbf236a1b58d6e8504b912b0552721c7c6b8570925ee0ccde"},
|
||||||
|
{file = "httptools-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a47a34f6015dd52c9eb629c0f5a8a5193e47bf2a12d9a3194d231eaf1bc451a"},
|
||||||
|
{file = "httptools-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:24bb4bb8ac3882f90aa95403a1cb48465de877e2d5298ad6ddcfdebec060787d"},
|
||||||
|
{file = "httptools-0.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e67d4f8734f8054d2c4858570cc4b233bf753f56e85217de4dfb2495904cf02e"},
|
||||||
|
{file = "httptools-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e5eefc58d20e4c2da82c78d91b2906f1a947ef42bd668db05f4ab4201a99f49"},
|
||||||
|
{file = "httptools-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0297822cea9f90a38df29f48e40b42ac3d48a28637368f3ec6d15eebefd182f9"},
|
||||||
|
{file = "httptools-0.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:557be7fbf2bfa4a2ec65192c254e151684545ebab45eca5d50477d562c40f986"},
|
||||||
|
{file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:54465401dbbec9a6a42cf737627fb0f014d50dc7365a6b6cd57753f151a86ff0"},
|
||||||
|
{file = "httptools-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4d9ebac23d2de960726ce45f49d70eb5466725c0087a078866043dad115f850f"},
|
||||||
|
{file = "httptools-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:e8a34e4c0ab7b1ca17b8763613783e2458e77938092c18ac919420ab8655c8c1"},
|
||||||
|
{file = "httptools-0.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f659d7a48401158c59933904040085c200b4be631cb5f23a7d561fbae593ec1f"},
|
||||||
|
{file = "httptools-0.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1616b3ba965cd68e6f759eeb5d34fbf596a79e84215eeceebf34ba3f61fdc7"},
|
||||||
|
{file = "httptools-0.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3625a55886257755cb15194efbf209584754e31d336e09e2ffe0685a76cb4b60"},
|
||||||
|
{file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:72ad589ba5e4a87e1d404cc1cb1b5780bfcb16e2aec957b88ce15fe879cc08ca"},
|
||||||
|
{file = "httptools-0.5.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:850fec36c48df5a790aa735417dca8ce7d4b48d59b3ebd6f83e88a8125cde324"},
|
||||||
|
{file = "httptools-0.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f222e1e9d3f13b68ff8a835574eda02e67277d51631d69d7cf7f8e07df678c86"},
|
||||||
|
{file = "httptools-0.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3cb8acf8f951363b617a8420768a9f249099b92e703c052f9a51b66342eea89b"},
|
||||||
|
{file = "httptools-0.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550059885dc9c19a072ca6d6735739d879be3b5959ec218ba3e013fd2255a11b"},
|
||||||
|
{file = "httptools-0.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a04fe458a4597aa559b79c7f48fe3dceabef0f69f562daf5c5e926b153817281"},
|
||||||
|
{file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d0c1044bce274ec6711f0770fd2d5544fe392591d204c68328e60a46f88843b"},
|
||||||
|
{file = "httptools-0.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c6eeefd4435055a8ebb6c5cc36111b8591c192c56a95b45fe2af22d9881eee25"},
|
||||||
|
{file = "httptools-0.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b65be160adcd9de7a7e6413a4966665756e263f0d5ddeffde277ffeee0576a5"},
|
||||||
|
{file = "httptools-0.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fe9c766a0c35b7e3d6b6939393c8dfdd5da3ac5dec7f971ec9134f284c6c36d6"},
|
||||||
|
{file = "httptools-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85b392aba273566c3d5596a0a490978c085b79700814fb22bfd537d381dd230c"},
|
||||||
|
{file = "httptools-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5e3088f4ed33947e16fd865b8200f9cfae1144f41b64a8cf19b599508e096bc"},
|
||||||
|
{file = "httptools-0.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c2a56b6aad7cc8f5551d8e04ff5a319d203f9d870398b94702300de50190f63"},
|
||||||
|
{file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b571b281a19762adb3f48a7731f6842f920fa71108aff9be49888320ac3e24d"},
|
||||||
|
{file = "httptools-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa47ffcf70ba6f7848349b8a6f9b481ee0f7637931d91a9860a1838bfc586901"},
|
||||||
|
{file = "httptools-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:bede7ee075e54b9a5bde695b4fc8f569f30185891796b2e4e09e2226801d09bd"},
|
||||||
|
{file = "httptools-0.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:64eba6f168803a7469866a9c9b5263a7463fa8b7a25b35e547492aa7322036b6"},
|
||||||
|
{file = "httptools-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b098e4bb1174096a93f48f6193e7d9aa7071506a5877da09a783509ca5fff42"},
|
||||||
|
{file = "httptools-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9423a2de923820c7e82e18980b937893f4aa8251c43684fa1772e341f6e06887"},
|
||||||
|
{file = "httptools-0.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1b7becf7d9d3ccdbb2f038f665c0f4857e08e1d8481cbcc1a86a0afcfb62b2"},
|
||||||
|
{file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:50d4613025f15f4b11f1c54bbed4761c0020f7f921b95143ad6d58c151198142"},
|
||||||
|
{file = "httptools-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ffce9d81c825ac1deaa13bc9694c0562e2840a48ba21cfc9f3b4c922c16f372"},
|
||||||
|
{file = "httptools-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:1af91b3650ce518d226466f30bbba5b6376dbd3ddb1b2be8b0658c6799dd450b"},
|
||||||
|
{file = "httptools-0.5.0.tar.gz", hash = "sha256:295874861c173f9101960bba332429bb77ed4dcd8cdf5cee9922eb00e4f6bc09"},
|
||||||
|
]
|
||||||
httpx = [
|
httpx = [
|
||||||
{file = "httpx-0.23.0-py3-none-any.whl", hash = "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b"},
|
{file = "httpx-0.23.0-py3-none-any.whl", hash = "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b"},
|
||||||
{file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"},
|
{file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"},
|
||||||
@ -1885,6 +2030,48 @@ pytz-deprecation-shim = [
|
|||||||
{file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
|
{file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
|
||||||
{file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
|
{file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
|
||||||
]
|
]
|
||||||
|
PyYAML = [
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
|
||||||
|
{file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
|
||||||
|
{file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
|
||||||
|
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
|
||||||
|
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
|
||||||
|
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
|
||||||
|
{file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
|
||||||
|
{file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
|
||||||
|
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
|
||||||
|
]
|
||||||
redis = [
|
redis = [
|
||||||
{file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"},
|
{file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"},
|
||||||
{file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"},
|
{file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"},
|
||||||
@ -1968,6 +2155,10 @@ sqlmodel = [
|
|||||||
{file = "sqlmodel-0.0.8-py3-none-any.whl", hash = "sha256:0fd805719e0c5d4f22be32eb3ffc856eca3f7f20e8c7aa3e117ad91684b518ee"},
|
{file = "sqlmodel-0.0.8-py3-none-any.whl", hash = "sha256:0fd805719e0c5d4f22be32eb3ffc856eca3f7f20e8c7aa3e117ad91684b518ee"},
|
||||||
{file = "sqlmodel-0.0.8.tar.gz", hash = "sha256:3371b4d1ad59d2ffd0c530582c2140b6c06b090b32af9b9c6412986d7b117036"},
|
{file = "sqlmodel-0.0.8.tar.gz", hash = "sha256:3371b4d1ad59d2ffd0c530582c2140b6c06b090b32af9b9c6412986d7b117036"},
|
||||||
]
|
]
|
||||||
|
starlette = [
|
||||||
|
{file = "starlette-0.20.4-py3-none-any.whl", hash = "sha256:c0414d5a56297d37f3db96a84034d61ce29889b9eaccf65eb98a0b39441fcaa3"},
|
||||||
|
{file = "starlette-0.20.4.tar.gz", hash = "sha256:42fcf3122f998fefce3e2c5ad7e5edbf0f02cf685d646a83a08d404726af5084"},
|
||||||
|
]
|
||||||
TgCrypto = [
|
TgCrypto = [
|
||||||
{file = "TgCrypto-1.2.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b51c00f85d0ef762e1b5fa11e7d26ad84fa3dcd4d92e7a3e3e2f104ac5cbd59d"},
|
{file = "TgCrypto-1.2.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b51c00f85d0ef762e1b5fa11e7d26ad84fa3dcd4d92e7a3e3e2f104ac5cbd59d"},
|
||||||
{file = "TgCrypto-1.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e8e7d5aeaff1a8b1694d0647a60ba539b9e3b5360b115d7df4f526b85a04f3f0"},
|
{file = "TgCrypto-1.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e8e7d5aeaff1a8b1694d0647a60ba539b9e3b5360b115d7df4f526b85a04f3f0"},
|
||||||
@ -2117,6 +2308,62 @@ urllib3 = [
|
|||||||
{file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
|
{file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
|
||||||
{file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
|
{file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
|
||||||
]
|
]
|
||||||
|
uvicorn = [
|
||||||
|
{file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"},
|
||||||
|
{file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"},
|
||||||
|
]
|
||||||
|
uvloop = [
|
||||||
|
{file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718"},
|
||||||
|
{file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c"},
|
||||||
|
{file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d"},
|
||||||
|
{file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024"},
|
||||||
|
{file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa"},
|
||||||
|
{file = "uvloop-0.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811"},
|
||||||
|
{file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c"},
|
||||||
|
{file = "uvloop-0.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e"},
|
||||||
|
{file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539"},
|
||||||
|
{file = "uvloop-0.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4"},
|
||||||
|
{file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05"},
|
||||||
|
{file = "uvloop-0.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376"},
|
||||||
|
{file = "uvloop-0.17.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b"},
|
||||||
|
{file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8"},
|
||||||
|
{file = "uvloop-0.17.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62"},
|
||||||
|
{file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d"},
|
||||||
|
{file = "uvloop-0.17.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667"},
|
||||||
|
{file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738"},
|
||||||
|
{file = "uvloop-0.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20"},
|
||||||
|
{file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f"},
|
||||||
|
{file = "uvloop-0.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595"},
|
||||||
|
{file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578"},
|
||||||
|
{file = "uvloop-0.17.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474"},
|
||||||
|
{file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b"},
|
||||||
|
{file = "uvloop-0.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c"},
|
||||||
|
{file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8"},
|
||||||
|
{file = "uvloop-0.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c"},
|
||||||
|
{file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9"},
|
||||||
|
{file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded"},
|
||||||
|
{file = "uvloop-0.17.0.tar.gz", hash = "sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1"},
|
||||||
|
]
|
||||||
|
watchfiles = [
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:c7e1ffbd03cbcb46d1b7833e10e7d6b678ab083b4e4b80db06cfff5baca3c93f"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:539bcdb55a487126776c9d8c011094214d1df3f9a2321a6c0b1583197309405a"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:00e5f307a58752ec1478eeb738863544bde21cc7a2728bd1c216060406bde9c1"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:92675f379a9d5adbc6a52179f3e39aa56944c6eecb80384608fff2ed2619103a"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dd1e3181ad5d83ca35e9147c72e24f39437fcdf570c9cdc532016399fb62957"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:204950f1d6083539af5c8b7d4f5f8039c3ce36fa692da12d9743448f3199cb15"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:4056398d8f6d4972fe0918707b59d4cb84470c91d3c37f0e11e5a66c2a598760"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ffff3418dc753a2aed2d00200a4daeaac295c40458f8012836a65555f288be8b"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-win32.whl", hash = "sha256:b5c334cd3bc88aa4a8a1e08ec9f702b63c947211275defdc2dd79dc037fcb500"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-win_amd64.whl", hash = "sha256:53a2faeb121bc51bb6b960984f46901227e2e2475acc5a8d4c905a600436752d"},
|
||||||
|
{file = "watchfiles-0.17.0-cp37-abi3-win_arm64.whl", hash = "sha256:58dc3140dcf02a8aa76464a77a093016f10e89306fec21a4814922a64f3e8b9f"},
|
||||||
|
{file = "watchfiles-0.17.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:adcf15ecc2182ea9d2358c1a8c2b53203c3909484918776929b7bbe205522c0e"},
|
||||||
|
{file = "watchfiles-0.17.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:afd35a1bd3b9e68efe384ae7538481ae725597feb66f56f4bd23ecdbda726da0"},
|
||||||
|
{file = "watchfiles-0.17.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2bdcae4c0f07ca6c090f5a2c30188cc6edba011b45e7c96eb1896648092367"},
|
||||||
|
{file = "watchfiles-0.17.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:a53cb6c06e5c1f216c792fbb432ce315239d432cb8b68d508547100939ec0399"},
|
||||||
|
{file = "watchfiles-0.17.0-pp39-pypy39_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6a3d6c699f3ce238dfa90bcef501f331a69b0d9b076f14459ed8eab26ba2f4cf"},
|
||||||
|
{file = "watchfiles-0.17.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f4271af86569bdbf131dd5c7c121c45d0ed194f3c88b88326e48a3b6a2db12"},
|
||||||
|
{file = "watchfiles-0.17.0.tar.gz", hash = "sha256:ae7c57ef920589a40270d5ef3216d693f4e6f8864d8fc8b6cb7885ca98ad2a61"},
|
||||||
|
]
|
||||||
websockets = [
|
websockets = [
|
||||||
{file = "websockets-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:38db6e2163b021642d0a43200ee2dec8f4980bdbda96db54fde72b283b54cbfc"},
|
{file = "websockets-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:38db6e2163b021642d0a43200ee2dec8f4980bdbda96db54fde72b283b54cbfc"},
|
||||||
{file = "websockets-10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1b60fd297adb9fc78375778a5220da7f07bf54d2a33ac781319650413fc6a60"},
|
{file = "websockets-10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1b60fd297adb9fc78375778a5220da7f07bf54d2a33ac781319650413fc6a60"},
|
||||||
|
@ -35,6 +35,8 @@ pytest-asyncio = { version = "^0.19.0", optional = true }
|
|||||||
flaky = { version = "^3.7.0", optional = true }
|
flaky = { version = "^3.7.0", optional = true }
|
||||||
lxml = "^4.9.1"
|
lxml = "^4.9.1"
|
||||||
arko-wrapper = "^0.2.3"
|
arko-wrapper = "^0.2.3"
|
||||||
|
fastapi = "^0.85.0"
|
||||||
|
uvicorn = {extras = ["standard"], version = "^0.18.3"}
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
pyro = ["Pyrogram", "TgCrypto"]
|
pyro = ["Pyrogram", "TgCrypto"]
|
||||||
|
@ -58,47 +58,48 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="g2plot.min.js"></script>
|
<script type="text/javascript" src="g2plot.min.js"></script>
|
||||||
<!-- <script>
|
<script>
|
||||||
const { Pie } = G2Plot;
|
const { Pie } = G2Plot;
|
||||||
const data = JSON.parse(`{{ group_by }}`);
|
const data = {{ categories | tojson }};
|
||||||
const piePlot = new Pie("chartContainer", {
|
const color = {{ color | tojson }};
|
||||||
renderer: "svg",
|
const piePlot = new Pie("chartContainer", {
|
||||||
animation: false,
|
renderer: "svg",
|
||||||
data: data,
|
animation: false,
|
||||||
appendPadding: 10,
|
data,
|
||||||
angleField: "amount",
|
appendPadding: 10,
|
||||||
colorField: "name",
|
angleField: "amount",
|
||||||
radius: 1,
|
colorField: "name",
|
||||||
innerRadius: 0.7,
|
radius: 1,
|
||||||
color: JSON.parse(`{{ color }}`),
|
innerRadius: 0.7,
|
||||||
meta: {},
|
color,
|
||||||
label: {
|
meta: {},
|
||||||
type: "inner",
|
label: {
|
||||||
offset: "-50%",
|
type: "inner",
|
||||||
autoRotate: false,
|
offset: "-50%",
|
||||||
style: {
|
autoRotate: false,
|
||||||
textAlign: "center",
|
|
||||||
fontFamily: "tttgbnumber",
|
|
||||||
},
|
|
||||||
formatter: ({ percentage }) => {
|
|
||||||
return percentage > 2 ? `${percentage}%` : "";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
statistic: {
|
|
||||||
title: {
|
|
||||||
offsetY: -18,
|
|
||||||
content: "总计",
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
offsetY: -10,
|
|
||||||
style: {
|
style: {
|
||||||
|
textAlign: "center",
|
||||||
fontFamily: "tttgbnumber",
|
fontFamily: "tttgbnumber",
|
||||||
},
|
},
|
||||||
|
formatter: ({ percentage }) => {
|
||||||
|
return percentage > 2 ? `${percentage}%` : "";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
statistic: {
|
||||||
legend:false,
|
title: {
|
||||||
});
|
offsetY: -18,
|
||||||
piePlot.render();
|
content: "总计",
|
||||||
</script> -->
|
},
|
||||||
|
content: {
|
||||||
|
offsetY: -10,
|
||||||
|
style: {
|
||||||
|
fontFamily: "tttgbnumber",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend:false,
|
||||||
|
});
|
||||||
|
piePlot.render();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
<script src="../../js/tailwindcss-3.1.8.js"></script>
|
<script src="../../js/tailwindcss-3.1.8.js"></script>
|
||||||
<link type="text/css" href="../../styles/public.css" rel="stylesheet">
|
<link type="text/css" href="../../styles/public.css" rel="stylesheet" />
|
||||||
<style>
|
<style>
|
||||||
.text-shadow {
|
.text-shadow {
|
||||||
text-shadow: 0 0.08em 0.1em #000, 0 0.1em 0.3em rgba(0, 0, 0, 0.4);
|
text-shadow: 0 0.08em 0.1em #000, 0 0.1em 0.3em rgba(0, 0, 0, 0.4);
|
||||||
@ -46,7 +46,7 @@
|
|||||||
style="background-image: url('{{ character.image.banner.url }}');"
|
style="background-image: url('{{ character.image.banner.url }}');"
|
||||||
></div>
|
></div>
|
||||||
<div class="relative w-full flex p-5 space-x-8">
|
<div class="relative w-full flex p-5 space-x-8">
|
||||||
{% include 'constellations.html' %}
|
{% include 'genshin/player_card/constellations.html' %}
|
||||||
|
|
||||||
<div class="flex-1 space-y-4">
|
<div class="flex-1 space-y-4">
|
||||||
<div class="text-right italic">
|
<div class="text-right italic">
|
||||||
@ -64,7 +64,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include 'skills.html' %} {% include 'stats.html' %}
|
{% include 'genshin/player_card/skills.html' %}
|
||||||
|
{% include 'genshin/player_card/stats.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -72,13 +73,12 @@
|
|||||||
<!-- Info -->
|
<!-- Info -->
|
||||||
<div class="px-5 relative">
|
<div class="px-5 relative">
|
||||||
<div class="grid grid-cols-3 gap-4">
|
<div class="grid grid-cols-3 gap-4">
|
||||||
|
|
||||||
<div class="flex flex-col space-y-2">
|
<div class="flex flex-col space-y-2">
|
||||||
{% include 'weapon.html' %}
|
{% include 'genshin/player_card/weapon.html' %}
|
||||||
{% include 'score.html' %}
|
{% include 'genshin/player_card/score.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include 'artifacts.html' %}
|
{% include 'genshin/player_card/artifacts.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user