Compare commits
11 Commits
401dc64126
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d8eabcb606 | |||
| 405d7ff3b9 | |||
| e7892a21a5 | |||
| 5500c55b71 | |||
| 2aee776bad | |||
| c32995edd4 | |||
| 247d9f089c | |||
| 8db1d27758 | |||
| 16ff315a30 | |||
| df17a73c31 | |||
| 285a92d9cb |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -10,3 +10,8 @@ temp/
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
|
||||
.scripts
|
||||
|
||||
# vite 构建产物
|
||||
src/njupt_suan_api/static/
|
||||
|
||||
1
.idea/NJUPT-API-Suan.iml
generated
1
.idea/NJUPT-API-Suan.iml
generated
@@ -2,6 +2,7 @@
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="uv (NJUPT-API-Suan)" jdkType="Python SDK" />
|
||||
|
||||
27
CHANGELOG.md
Normal file
27
CHANGELOG.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# CHANGELOG
|
||||
|
||||
此文件中记录 NJUPT Suan API 的主要的版本变更日志。
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
6 种更新类别:Added、Changed、Deprecated、Removed、Fixed、Security。
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
等待中...
|
||||
|
||||
## [0.1.4] - 2026-04-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复从命令行运行 `njupt-suan-api init` 时由于 playwright 命令未找到而失败的问题。
|
||||
|
||||
## [0.1.3] - 2026-04-26
|
||||
|
||||
### Changed
|
||||
|
||||
- 更改项目的 cli 入口别名与包名 `njupt-suan-api` 一致,以支持更简单地通过 uv tool / uvx 部署本项目。
|
||||
- 依赖更新:
|
||||
- fastapi -> 0.136.1
|
||||
- typer -> 0.25.0
|
||||
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 MangoFanFanw
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
42
README.md
42
README.md
@@ -0,0 +1,42 @@
|
||||
# NJUPT Suan API
|
||||
|
||||
NJUPT Suan API 是一个 FastAPI 项目,目标在于实现对 NJUPT(南京邮电大学)的信息获取 API 和 MCP 服务。
|
||||
|
||||
在 `pyproject.toml` 中,本项目的包名,以及命令行入口名为 `njupt-suan-api`。
|
||||
|
||||
## 文档
|
||||
|
||||
虽然项目还没个两样,但是文档其实也没个两样 ~~(什么东西)~~
|
||||
|
||||
[中文名叫芒果酸](https://suan.mangofanfan.cn) - `suan.mangofanfan.cn`
|
||||
|
||||
## 功能
|
||||
|
||||
| 计划功能(芒果画饼中) | 支持进度 |
|
||||
|---------------|------------------|
|
||||
| 教务系统 - 课程表获取 | ✅ |
|
||||
| 教务系统 - 课程获取 | ⌛️ |
|
||||
| 教务系统 - 成绩获取 | ⌛️ |
|
||||
| 体育部系统 - 早锻炼获取 | ❌(无从破解微信小程序 QAQ) |
|
||||
|
||||
## 运行
|
||||
|
||||
建议查阅文档了解更多部署方式。
|
||||
|
||||
如需从源代码直接运行的话,项目的源码位于 `src/njupt_suan_api` 目录下,`main.py` 是旧的入口文件,可以直接传统方式启动。
|
||||
|
||||
`manage.py` 是命令行入口,提供了完整的帮助信息。
|
||||
|
||||
`server.py` 是 FastAPI app 所在文件,可以使用 uvicorn 命令启动。
|
||||
|
||||
另外如需从源代码启动项目,你需要自行构建 WebUI。
|
||||
|
||||
```bash
|
||||
cd webui/
|
||||
pnpm install
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
AI 说 `npm install` 然后 `npm run build` 也可以,但我还没试过,你可以帮我试试(?)
|
||||
|
||||
vite 的构建产物会放在 `src/njupt_suan_api/static` 目录下,**构建产物不会被 git 管理,但是会被项目打包进 wheel。**
|
||||
|
||||
@@ -1,26 +1,65 @@
|
||||
[project]
|
||||
name = "njupt-suan-api"
|
||||
version = "0.1.0"
|
||||
version = "0.1.5"
|
||||
description = "API and MCP server for NJUPT infomation ~"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
license = "MIT"
|
||||
|
||||
authors = [
|
||||
{ name = "MangoFanFanw", email = "mangofanfanw@icloud.com" }
|
||||
]
|
||||
|
||||
maintainers = [
|
||||
{ name = "MangoFanFanw", email = "mangofanfanw@icloud.com" }
|
||||
]
|
||||
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
"aiofiles>=25.1.0",
|
||||
"beautifulsoup4>=4.14.3",
|
||||
"ddddocr>=1.6.1",
|
||||
"fastapi>=0.135.3",
|
||||
"fastapi>=0.136.1",
|
||||
"fastmcp>=3.2.0",
|
||||
"loguru>=0.7.3",
|
||||
"mcp>=1.27.0",
|
||||
"playwright>=1.58.0",
|
||||
"pydantic>=2.12.5",
|
||||
"pydantic>=2.13.3",
|
||||
"rich>=15.0.0",
|
||||
"sqlalchemy>=2.0.49",
|
||||
"sqlmodel>=0.0.38",
|
||||
"uvicorn>=0.43.0",
|
||||
"typer>=0.25.0",
|
||||
"uvicorn>=0.46.0",
|
||||
"watchfiles>=1.1.1",
|
||||
"websockets>=16.0",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://suan.mangofanfan.cn"
|
||||
Documentation = "https://suan.mangofanfan.cn"
|
||||
Repository = "https://github.com/mangofanfan/NJUPT-Suan-API.git"
|
||||
Changelog = "https://github.com/mangofanfan/NJUPT-Suan-API/blob/master/CHANGELOG.md"
|
||||
Issues = "https://github.com/mangofanfan/NJUPT-Suan-API/issues"
|
||||
|
||||
[project.scripts]
|
||||
njupt-suan-api = "njupt_suan_api.manage:app"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.sdist]
|
||||
artifacts = ["src/njupt_suan_api/static/**"]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/njupt_suan_api"]
|
||||
artifacts = ["src/njupt_suan_api/static/**"]
|
||||
|
||||
[tool.ruff]
|
||||
preview = true
|
||||
line-length = 120
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from .__version__ import __version__
|
||||
@@ -18,7 +18,7 @@ class Config:
|
||||
|
||||
async def load_json(self) -> None:
|
||||
"""
|
||||
从 Toml 配置文件中读取配置。
|
||||
异步从配置文件中读取配置。
|
||||
"""
|
||||
logger.debug("异步读取配置文件。")
|
||||
async with aiofiles.open(file=CONFIG_PATH, mode="r") as f:
|
||||
@@ -49,7 +49,7 @@ class Config:
|
||||
|
||||
def init_config(self) -> None:
|
||||
"""
|
||||
重新初始化 Toml 配置文件。这会重置所有配置。
|
||||
重新初始化配置文件。这会重置所有配置。
|
||||
"""
|
||||
logger.warning("初始化配置文件,这会重置所有配置。")
|
||||
self._doc.clear()
|
||||
@@ -59,7 +59,7 @@ class Config:
|
||||
|
||||
doc_system["host"] = "0.0.0.0"
|
||||
doc_system["port"] = 8000
|
||||
doc_system["reload"] = True
|
||||
doc_system["reload"] = False
|
||||
doc_system["public_host"] = "http://127.0.0.1:8000"
|
||||
|
||||
doc_schedule["playwright_headless"] = True
|
||||
@@ -78,7 +78,7 @@ class Config:
|
||||
|
||||
async def save_json(self) -> None:
|
||||
"""
|
||||
异步保存 Toml 配置文件。
|
||||
异步保存配置文件。
|
||||
"""
|
||||
logger.debug("异步保存配置文件。")
|
||||
async with aiofiles.open(file=CONFIG_PATH, mode="w") as f:
|
||||
@@ -7,7 +7,7 @@ from playwright.async_api import (
|
||||
async_playwright,
|
||||
)
|
||||
|
||||
from . import config
|
||||
from .config import config
|
||||
|
||||
|
||||
class PlayContextManager:
|
||||
@@ -1,5 +1,4 @@
|
||||
from njupt_api.baselib import PlayContextManager, logger
|
||||
|
||||
from ..baselib import PlayContextManager, logger
|
||||
from .exc import LoginError
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from ddddocr import DdddOcr
|
||||
from playwright.async_api import Browser, BrowserContext, Page, Playwright
|
||||
|
||||
from njupt_api.baselib import PlayContextManager, logger
|
||||
|
||||
from ..baselib import PlayContextManager, logger
|
||||
from .createcourse import create_course_schedule
|
||||
from .exc import LoginError
|
||||
from .sso import SSO
|
||||
13
src/njupt_suan_api/cli/__init__.py
Normal file
13
src/njupt_suan_api/cli/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from .message import ALREADY_INIT_MESSAGE, INIT_STAGE_MESSAGE, NOT_INIT_MESSAGE, RUN_CHECK_MESSAGE, TOKEN_CHECK_MESSAGE
|
||||
from .path import DATA_DIR, TEMP_DIR, WORKSPACE_DIR
|
||||
|
||||
__all__ = [
|
||||
WORKSPACE_DIR,
|
||||
DATA_DIR,
|
||||
TEMP_DIR,
|
||||
NOT_INIT_MESSAGE,
|
||||
ALREADY_INIT_MESSAGE,
|
||||
RUN_CHECK_MESSAGE,
|
||||
TOKEN_CHECK_MESSAGE,
|
||||
INIT_STAGE_MESSAGE,
|
||||
]
|
||||
25
src/njupt_suan_api/cli/message.py
Normal file
25
src/njupt_suan_api/cli/message.py
Normal file
@@ -0,0 +1,25 @@
|
||||
NOT_INIT_MESSAGE = """
|
||||
❓ 当前目录或指定目录下[yellow]似乎还没有执行过初始化命令[/yellow]。
|
||||
❓ 你也许需要先执行 [green]suanapi init[/green] 。
|
||||
"""
|
||||
|
||||
ALREADY_INIT_MESSAGE = """
|
||||
❕ 当前目录或指定目录下[yellow]似乎已经执行初始化命令过[/yellow]。
|
||||
❕ 你也许需要先删除已经存在的 [blue]data[/blue] 和 [blue]temp[/blue] 目录。
|
||||
"""
|
||||
|
||||
RUN_CHECK_MESSAGE = """
|
||||
[bright_black]运行时的配置可能来自命令行参数、配置文件以及默认值,列在这里供你检查。[/bright_black]
|
||||
[cyan]主机名[/cyan] - [cyan]host[/cyan] - {host}
|
||||
[cyan]端口[/cyan] - [cyan]port[/cyan] - {port}
|
||||
[cyan]自动重启[/cyan] - [cyan]reload[/cyan] - {reload}
|
||||
[bright_black]NJUPT Suan API 会很快启动。使用 [green]Ctrl + C[/green] 以退出。[/bright_black]
|
||||
"""
|
||||
|
||||
TOKEN_CHECK_MESSAGE = """
|
||||
🔐 [green] 令牌 - [/green]{token}
|
||||
🔐 [green]有效期 - [/green]无限
|
||||
✅ WebUI 设计的令牌 cookie 有效期为一天,所以你每天都需要重新登录一次 WebUI,这并非令牌本身的有效期。
|
||||
"""
|
||||
|
||||
INIT_STAGE_MESSAGE = "[cyan]- {stage} / 3 -[/cyan] [bright_black]{message}[/bright_black]"
|
||||
5
src/njupt_suan_api/cli/path.py
Normal file
5
src/njupt_suan_api/cli/path.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from pathlib import Path
|
||||
|
||||
WORKSPACE_DIR = Path.cwd()
|
||||
DATA_DIR = WORKSPACE_DIR / "data"
|
||||
TEMP_DIR = WORKSPACE_DIR / "temp"
|
||||
@@ -1,8 +1,12 @@
|
||||
"""
|
||||
main.py 未来不再作为项目入口,日后可能会被删除。请参照 README 使用命令行作为入口,或直接使用 uvicorn 命令。
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from secrets import token_urlsafe
|
||||
|
||||
from njupt_api.baselib import config, logger
|
||||
from router import __version__
|
||||
from njupt_suan_api.api.baselib import config, logger
|
||||
from njupt_suan_api.router import __version__
|
||||
|
||||
DATA_DIR = Path.cwd() / "data"
|
||||
TEMP_DIR = Path.cwd() / "temp"
|
||||
@@ -10,7 +14,7 @@ TEMP_DIR = Path.cwd() / "temp"
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
with open(file=Path.cwd() / "njupt_api" / "art.txt", mode="r", encoding="utf-8") as f:
|
||||
with open(file=Path.cwd() / "api" / "art.txt", mode="r", encoding="utf-8") as f:
|
||||
print(f.read().format(__version__)) # noqa:T201
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
@@ -77,7 +81,7 @@ if __name__ == "__main__":
|
||||
host=host,
|
||||
port=port,
|
||||
reload=reload,
|
||||
reload_dirs=["njupt_api", "router"],
|
||||
reload_dirs=["api", "router"],
|
||||
access_log=False,
|
||||
log_level="critical",
|
||||
timeout_graceful_shutdown=2,
|
||||
185
src/njupt_suan_api/manage.py
Normal file
185
src/njupt_suan_api/manage.py
Normal file
@@ -0,0 +1,185 @@
|
||||
import subprocess
|
||||
import sys
|
||||
from secrets import token_urlsafe
|
||||
|
||||
import typer
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
|
||||
from njupt_suan_api.api.baselib import config
|
||||
from njupt_suan_api.cli import (
|
||||
ALREADY_INIT_MESSAGE,
|
||||
DATA_DIR,
|
||||
INIT_STAGE_MESSAGE,
|
||||
NOT_INIT_MESSAGE,
|
||||
RUN_CHECK_MESSAGE,
|
||||
TEMP_DIR,
|
||||
TOKEN_CHECK_MESSAGE,
|
||||
WORKSPACE_DIR,
|
||||
)
|
||||
from njupt_suan_api.router import __version__
|
||||
|
||||
console = Console()
|
||||
app = typer.Typer(
|
||||
name="NJUPT-Suan-API",
|
||||
help="NJUPT Suan API 部署与管理工具",
|
||||
rich_markup_mode="rich",
|
||||
no_args_is_help=True,
|
||||
)
|
||||
|
||||
|
||||
def version_callback(value: bool = False) -> None:
|
||||
if value:
|
||||
console.print(f"NJUPT Suan API [green]v.{__version__}[/green]")
|
||||
if __version__ == "dev":
|
||||
console.print("""
|
||||
[bright_black]显示的版本为 dev ?这是因为你正在从源代码运行 cli 入口(manage.py)。[/bright_black]
|
||||
[bright_black]从[green]已安装版本[/green]中运行 [green]suanapi --version[/green] 可以正确获取版本号。[/bright_black]""")
|
||||
raise typer.Exit
|
||||
|
||||
|
||||
@app.callback(invoke_without_command=True)
|
||||
def main(
|
||||
version: bool = typer.Option(
|
||||
False,
|
||||
"--version",
|
||||
"-v",
|
||||
help="显示版本号并退出,没有其他命令会被执行。",
|
||||
callback=version_callback,
|
||||
is_eager=True, # 优先处理,避免触发其他逻辑
|
||||
),
|
||||
) -> None:
|
||||
"""
|
||||
CLI 入口回调,所有子命令执行前都会经过这里。
|
||||
可以在这里放全局初始化(如日志级别、环境检查)。
|
||||
"""
|
||||
# 没有 --version 时就正常放行,继续执行子命令
|
||||
console.print(
|
||||
"[bright_black]NJUPT Suan API 仍然处于极早期的阶段。如果遇到任何问题,请告诉芒果帆帆喵![/bright_black]\n"
|
||||
)
|
||||
|
||||
|
||||
@app.command()
|
||||
def init(force: bool = typer.Option(False, "--force", "-f", help="强制初始化,可能导致问题,不建议使用。")) -> None:
|
||||
"""
|
||||
初始化 NJUPT Suan API [green]工作目录[/green]。(可能需要较长时间)
|
||||
|
||||
会在当前目录或指定目录下创建新文件,并尝试安装 playwright chromium。
|
||||
视网络情况,安装过程可能(几乎必然)需要较长时间。
|
||||
如果已存在 data 和/或 temp 目录,初始化会失败。你也可以强制初始化,但可能导致先前的数据丢失。
|
||||
|
||||
Raises:
|
||||
typer.Exit: 如果初始化失败,返回 1。
|
||||
"""
|
||||
if (DATA_DIR.exists() or TEMP_DIR.exists()) and not force:
|
||||
console.print(Panel(ALREADY_INIT_MESSAGE, title="工作目录已存在"))
|
||||
console.print("[bright_black]如果你想要强制初始化,使用 [green]suanapi init -f[/green] 命令。[/bright_black]")
|
||||
raise typer.Exit(code=1)
|
||||
|
||||
# 1 创建 data 和 temp 目录
|
||||
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
console.print(INIT_STAGE_MESSAGE.format(stage=1, message="工作目录 data 和 temp 已创建。"))
|
||||
|
||||
# 2 初始化配置文件
|
||||
try:
|
||||
config.sync_load_json()
|
||||
except FileNotFoundError:
|
||||
config.init_config()
|
||||
config.sync_create_json()
|
||||
console.print(INIT_STAGE_MESSAGE.format(stage=2, message="已初始化配置并创建配置文件。"))
|
||||
else:
|
||||
console.print(INIT_STAGE_MESSAGE.format(stage=2, message="配置文件已存在,跳过配置初始化。"))
|
||||
|
||||
# 3 执行 uv run playwright install chromium
|
||||
console.print("[bright_black]即将安装 playwright 的 chromium,这可能是耗时最长的部分。[/bright_black]")
|
||||
cp3 = subprocess.run([sys.executable, "-m", "playwright", "install", "chromium"], cwd=WORKSPACE_DIR)
|
||||
if cp3.returncode != 0:
|
||||
console.print("[yellow]运行 playwright install chromuim 失败,双是什么原因呢?[/yellow]")
|
||||
raise typer.Exit(code=cp3.returncode)
|
||||
console.print(INIT_STAGE_MESSAGE.format(stage=3, message="已安装 playwright chromium。"))
|
||||
|
||||
console.print("[green]初始化完成。接下来可以执行 suanapi run 来启动 NJUPT Suan API。[/green]")
|
||||
console.print(
|
||||
"[bright_black]初始化只需要执行一次即可,以后即使更新 NJUPT Suan API,也无再需重复执行。[/bright_black]"
|
||||
)
|
||||
|
||||
|
||||
@app.command()
|
||||
def token(reset: bool = typer.Option(False, "--reload", "-r", help="强制重新生成令牌,即使令牌已存在。")) -> None:
|
||||
"""
|
||||
查看或重新生成[green]管理后端令牌[/green]。
|
||||
|
||||
需要先运行过 init 初始化目录。
|
||||
|
||||
Raises:
|
||||
typer.Exit: 如果未初始化,返回 1。
|
||||
"""
|
||||
token_ = None
|
||||
# 首先检查数据目录是否存在
|
||||
if not DATA_DIR.exists():
|
||||
console.print(Panel(NOT_INIT_MESSAGE, title="数据目录不存在"))
|
||||
raise typer.Exit(code=1)
|
||||
|
||||
# 确认存在后再判断是否需要重新生成令牌
|
||||
if not reset:
|
||||
try:
|
||||
with open(file=DATA_DIR / "token.txt", mode="r") as f:
|
||||
token_ = f.read()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
if not token_:
|
||||
console.print("[yellow]重新生成令牌...[/yellow]")
|
||||
token_ = token_urlsafe(32)
|
||||
with open(file=DATA_DIR / "token.txt", mode="w") as f:
|
||||
f.write(token_)
|
||||
|
||||
panel = Panel(TOKEN_CHECK_MESSAGE.format(token=token_), title="WebUI 令牌")
|
||||
|
||||
console.print(panel)
|
||||
|
||||
|
||||
@app.command()
|
||||
def run(
|
||||
host: str | None = typer.Option(None, "--host", help="监听主机名,默认 0.0.0.0。"),
|
||||
port: int | None = typer.Option(None, "--port", help="监听端口,默认 8000。"),
|
||||
reload: bool | None = typer.Option(None, "--reload", "-r", help="在检测到代码变化时自动重启,默认 False。"),
|
||||
) -> None:
|
||||
"""
|
||||
运行 NJUPT Suan API。
|
||||
|
||||
可接收运行参数。若不提供,则尝试使用配置文件中的值,最后回退到默认值。
|
||||
|
||||
Raises:
|
||||
typer.Exit: 如果未初始化,返回 1。
|
||||
"""
|
||||
if host is None:
|
||||
host = config.get("system", "host", "0.0.0.0")
|
||||
if port is None:
|
||||
port = config.get("system", "port", 8000)
|
||||
if reload is None:
|
||||
reload = config.get("system", "reload", False)
|
||||
|
||||
if not DATA_DIR.exists() or not TEMP_DIR.exists():
|
||||
console.print(Panel(NOT_INIT_MESSAGE, title="工作目录不存在"))
|
||||
raise typer.Exit(code=1)
|
||||
|
||||
token(False)
|
||||
|
||||
console.print(Panel(RUN_CHECK_MESSAGE.format(host=host, port=port, reload=reload), title="运行前检查"))
|
||||
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(
|
||||
"njupt_suan_api.server:app",
|
||||
host=host,
|
||||
port=port,
|
||||
reload=reload,
|
||||
access_log=False,
|
||||
log_level="critical",
|
||||
timeout_graceful_shutdown=2,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
14
src/njupt_suan_api/router/__init__.py
Normal file
14
src/njupt_suan_api/router/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from .__version__ import __version__ as __version__
|
||||
from .admin_router import admin_router
|
||||
from .api_router import api_router
|
||||
from .mcp_router import mcp_app
|
||||
from .webui_router import ASSETS_DIR, webui_router
|
||||
|
||||
__all__ = [
|
||||
admin_router,
|
||||
api_router,
|
||||
mcp_app,
|
||||
webui_router,
|
||||
__version__,
|
||||
ASSETS_DIR,
|
||||
]
|
||||
@@ -6,11 +6,11 @@ from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
from sqlmodel import Session, delete, select
|
||||
|
||||
from njupt_api.baselib import config, logger
|
||||
from njupt_api.zhengfang import LoginError, course_list_serializer, jwxt
|
||||
from router.enhance.auth import verify_token
|
||||
from router.enhance.lib import AliasDto, ReturnDto, TestDto, get_session
|
||||
from router.enhance.model import Alias, Course
|
||||
from njupt_suan_api.api.baselib import config, logger
|
||||
from njupt_suan_api.api.zhengfang import LoginError, course_list_serializer, jwxt
|
||||
from njupt_suan_api.router.enhance.auth import verify_token
|
||||
from njupt_suan_api.router.enhance.lib import AliasDto, ReturnDto, TestDto, get_session
|
||||
from njupt_suan_api.router.enhance.model import Alias, Course
|
||||
|
||||
|
||||
class ValidateTokenDto(BaseModel):
|
||||
@@ -5,15 +5,10 @@ from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from njupt_api.baselib import logger
|
||||
from njupt_api.zhengfang import (
|
||||
course_dict_serializer,
|
||||
course_list_serializer,
|
||||
jwxt,
|
||||
)
|
||||
from njupt_api.zhengfang.exc import LoginError
|
||||
from router.enhance.lib import ReturnDto, ScheduleQueryDto, apply_enhance, get_session
|
||||
from router.enhance.model import Course
|
||||
from njupt_suan_api.api.baselib import logger
|
||||
from njupt_suan_api.api.zhengfang import LoginError, course_dict_serializer, course_list_serializer, jwxt
|
||||
from njupt_suan_api.router.enhance.lib import ReturnDto, ScheduleQueryDto, apply_enhance, get_session
|
||||
from njupt_suan_api.router.enhance.model import Course
|
||||
|
||||
TEMP_DIR = Path.cwd() / "temp"
|
||||
|
||||
8
src/njupt_suan_api/router/enhance/__init__.py
Normal file
8
src/njupt_suan_api/router/enhance/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from .lib import ReturnDto, apply_enhance
|
||||
from .model import create_db_and_tables
|
||||
|
||||
__all__ = [
|
||||
ReturnDto,
|
||||
apply_enhance,
|
||||
create_db_and_tables,
|
||||
]
|
||||
@@ -7,8 +7,8 @@ from typing import Sequence
|
||||
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from njupt_api.baselib import logger
|
||||
from router.enhance.model import Alias, engine
|
||||
from njupt_suan_api.api.baselib import logger
|
||||
from njupt_suan_api.router.enhance.model import Alias, engine
|
||||
|
||||
|
||||
def apply_alias(courses: list[dict]) -> list[dict]:
|
||||
@@ -4,7 +4,7 @@ from typing import Any, Generator, Literal
|
||||
from pydantic import BaseModel
|
||||
from sqlmodel import Session
|
||||
|
||||
from njupt_api.baselib import config
|
||||
from njupt_suan_api.api.baselib import config
|
||||
|
||||
from .alias import apply_alias
|
||||
from .model import engine
|
||||
@@ -3,7 +3,7 @@ from typing import Optional
|
||||
from sqlalchemy import JSON, Column
|
||||
from sqlmodel import Field, SQLModel, create_engine
|
||||
|
||||
sqlite_file_name = "data/njupt_api.db"
|
||||
sqlite_file_name = "data/njupt-api.db"
|
||||
sqlite_url = f"sqlite:///{sqlite_file_name}"
|
||||
|
||||
engine = create_engine(sqlite_url, connect_args={"check_same_thread": False})
|
||||
@@ -7,7 +7,7 @@ from uuid import uuid4
|
||||
|
||||
from playwright.async_api import ViewportSize
|
||||
|
||||
from njupt_api.baselib import PlayContextManager, logger
|
||||
from njupt_suan_api.api.baselib import PlayContextManager, logger
|
||||
|
||||
TEMP_DIR = Path.cwd() / "temp"
|
||||
|
||||
@@ -7,15 +7,10 @@ from mcp.types import ToolAnnotations
|
||||
from pydantic import Field
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from njupt_api.baselib import LoggingMiddleware, logger
|
||||
from njupt_api.zhengfang import (
|
||||
course_dict_serializer,
|
||||
course_list_serializer,
|
||||
jwxt,
|
||||
)
|
||||
from njupt_api.zhengfang.exc import LoginError
|
||||
from router.enhance.lib import ReturnDto, apply_enhance
|
||||
from router.enhance.model import Course, engine
|
||||
from njupt_suan_api.api.baselib import LoggingMiddleware, logger
|
||||
from njupt_suan_api.api.zhengfang import LoginError, course_dict_serializer, course_list_serializer, jwxt
|
||||
from njupt_suan_api.router.enhance.lib import ReturnDto, apply_enhance
|
||||
from njupt_suan_api.router.enhance.model import Course, engine
|
||||
|
||||
mcp = FastMCP("NJUPT API Suan")
|
||||
|
||||
@@ -4,8 +4,10 @@ import aiofiles
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
WEBUI_INDEX = Path.cwd() / "webui" / "dist" / "index.html"
|
||||
SCHEDULE_INDEX = Path.cwd() / "webui" / "dist" / "index-schedule.html"
|
||||
STATIC_DIR = Path(__file__).parent.parent / "static"
|
||||
WEBUI_INDEX = STATIC_DIR / "index.html"
|
||||
SCHEDULE_INDEX = STATIC_DIR / "index-schedule.html"
|
||||
ASSETS_DIR = STATIC_DIR / "assets"
|
||||
|
||||
webui_router = APIRouter(prefix="/webui")
|
||||
|
||||
@@ -12,20 +12,15 @@ from fastapi.staticfiles import StaticFiles
|
||||
from fastmcp.utilities.lifespan import combine_lifespans
|
||||
from watchfiles import awatch
|
||||
|
||||
from njupt_api.baselib import (
|
||||
from njupt_suan_api.api.baselib import (
|
||||
LogRecord,
|
||||
config,
|
||||
log_buffer,
|
||||
log_record_serialize,
|
||||
logger,
|
||||
)
|
||||
from router import __version__
|
||||
from router.admin_router import admin_router
|
||||
from router.api_router import api_router
|
||||
from router.enhance.lib import ReturnDto
|
||||
from router.enhance.model import create_db_and_tables
|
||||
from router.mcp_router import mcp_app
|
||||
from router.webui_router import webui_router
|
||||
from njupt_suan_api.router import ASSETS_DIR, __version__, admin_router, api_router, mcp_app, webui_router
|
||||
from njupt_suan_api.router.enhance import ReturnDto, create_db_and_tables
|
||||
|
||||
DATA_DIR = Path.cwd() / "data"
|
||||
|
||||
@@ -166,7 +161,7 @@ app.include_router(webui_router)
|
||||
app.mount("/mcp", mcp_app)
|
||||
app.mount(
|
||||
"/assets",
|
||||
StaticFiles(directory=Path.cwd() / "webui" / "dist" / "assets"),
|
||||
StaticFiles(directory=ASSETS_DIR),
|
||||
name="assets",
|
||||
)
|
||||
|
||||
150
uv.lock
generated
150
uv.lock
generated
@@ -333,7 +333,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.136.0"
|
||||
version = "0.136.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-doc" },
|
||||
@@ -342,9 +342,9 @@ dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4e/d9/e66315807e41e69e7f6a1b42a162dada2f249c5f06ad3f1a95f84ab336ef/fastapi-0.136.0.tar.gz", hash = "sha256:cf08e067cc66e106e102d9ba659463abfac245200752f8a5b7b1e813de4ff73e", size = 396607, upload-time = "2026-04-16T11:47:13.623Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5d/45/c130091c2dfa061bbfe3150f2a5091ef1adf149f2a8d2ae769ecaf6e99a2/fastapi-0.136.1.tar.gz", hash = "sha256:7af665ad7acfa0a3baf8983d393b6b471b9da10ede59c60045f49fbc89a0fa7f", size = 397448, upload-time = "2026-04-23T16:49:44.046Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/26/a3/0bd5f0cdb0bbc92650e8dc457e9250358411ee5d1b65e42b6632387daf81/fastapi-0.136.0-py3-none-any.whl", hash = "sha256:8793d44ec7378e2be07f8a013cf7f7aa47d6327d0dfe9804862688ec4541a6b4", size = 117556, upload-time = "2026-04-16T11:47:11.922Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/ff/2e4eca3ade2c22fe1dea7043b8ee9dabe47753349eb1b56a202de8af6349/fastapi-0.136.1-py3-none-any.whl", hash = "sha256:a6e9d7eeada96c93a4d69cb03836b44fa34e2854accb7244a1ece36cd4781c3f", size = 117683, upload-time = "2026-04-23T16:49:42.437Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -701,8 +701,8 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "njupt-suan-api"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
version = "0.1.3"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiofiles" },
|
||||
{ name = "beautifulsoup4" },
|
||||
@@ -713,8 +713,10 @@ dependencies = [
|
||||
{ name = "mcp" },
|
||||
{ name = "playwright" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "rich" },
|
||||
{ name = "sqlalchemy" },
|
||||
{ name = "sqlmodel" },
|
||||
{ name = "typer" },
|
||||
{ name = "uvicorn" },
|
||||
{ name = "watchfiles" },
|
||||
{ name = "websockets" },
|
||||
@@ -725,15 +727,17 @@ requires-dist = [
|
||||
{ name = "aiofiles", specifier = ">=25.1.0" },
|
||||
{ name = "beautifulsoup4", specifier = ">=4.14.3" },
|
||||
{ name = "ddddocr", specifier = ">=1.6.1" },
|
||||
{ name = "fastapi", specifier = ">=0.135.3" },
|
||||
{ name = "fastapi", specifier = ">=0.136.1" },
|
||||
{ name = "fastmcp", specifier = ">=3.2.0" },
|
||||
{ name = "loguru", specifier = ">=0.7.3" },
|
||||
{ name = "mcp", specifier = ">=1.27.0" },
|
||||
{ name = "playwright", specifier = ">=1.58.0" },
|
||||
{ name = "pydantic", specifier = ">=2.12.5" },
|
||||
{ name = "pydantic", specifier = ">=2.13.3" },
|
||||
{ name = "rich", specifier = ">=15.0.0" },
|
||||
{ name = "sqlalchemy", specifier = ">=2.0.49" },
|
||||
{ name = "sqlmodel", specifier = ">=0.0.38" },
|
||||
{ name = "uvicorn", specifier = ">=0.43.0" },
|
||||
{ name = "typer", specifier = ">=0.25.0" },
|
||||
{ name = "uvicorn", specifier = ">=0.46.0" },
|
||||
{ name = "watchfiles", specifier = ">=1.1.1" },
|
||||
{ name = "websockets", specifier = ">=16.0" },
|
||||
]
|
||||
@@ -1024,7 +1028,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.13.2"
|
||||
version = "2.13.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
@@ -1032,9 +1036,9 @@ dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/e5/06d23afac9973109d1e3c8ad38e1547a12e860610e327c05ee686827dc37/pydantic-2.13.2.tar.gz", hash = "sha256:b418196607e61081c3226dcd4f0672f2a194828abb9109e9cfb84026564df2d1", size = 843836, upload-time = "2026-04-17T09:31:59.636Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/77/ca/b45c378e6e8d0b90577288b533e04e95b7afd61bb1d51b6c263176435489/pydantic-2.13.2-py3-none-any.whl", hash = "sha256:a525087f4c03d7e7456a3de89b64cd693d2229933bb1068b9af6befd5563694e", size = 471947, upload-time = "2026-04-17T09:31:57.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/0a/fd7d723f8f8153418fb40cf9c940e82004fce7e987026b08a68a36dd3fe7/pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927", size = 471981, upload-time = "2026-04-20T14:46:41.402Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -1044,58 +1048,58 @@ email = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.46.2"
|
||||
version = "2.46.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/bb/4742f05b739b2478459bb16fa8470549518c802e06ddcf3f106c5081315e/pydantic_core-2.46.2.tar.gz", hash = "sha256:37bb079f9ee3f1a519392b73fda2a96379b31f2013c6b467fe693e7f2987f596", size = 471269, upload-time = "2026-04-17T09:10:07.017Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/07/2b/662e48254479a2d3450ba24b1e25061108b64339794232f503990c519144/pydantic_core-2.46.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:d26e9eea3715008a09a74585fe9becd0c67fbb145dc4df9756d597d7230a652c", size = 2101762, upload-time = "2026-04-17T09:10:13.87Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/ab/bafd7c7503757ccc8ec4d1911e106fe474c629443648c51a88f08b0fe91a/pydantic_core-2.46.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48b36e3235140510dc7861f0cd58b714b1cdd3d48f75e10ce52e69866b746f10", size = 1951814, upload-time = "2026-04-17T09:12:25.934Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/cc/7549c2d57ba2e9a42caa5861a2d398dbe31c02c6aca783253ace59ce84f8/pydantic_core-2.46.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36b1f99dc451f1a3981f236151465bcf995bbe712d0727c9f7b236fe228a8133", size = 1977329, upload-time = "2026-04-17T09:13:37.605Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/50/7ed4a8a0d478a4dca8f0134a5efa7193f03cc8520dd4c9509339fb2e5002/pydantic_core-2.46.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8641c8d535c2d95b45c2e19b646ecd23ebba35d461e0ae48a3498277006250ab", size = 2051832, upload-time = "2026-04-17T09:12:49.771Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/16/bb35b193741c0298ddc5f5e4234269efdc0c65e2bcd198aa0de9b68845e4/pydantic_core-2.46.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20fb194788a0a50993e87013e693494ba183a2af5b44e99cf060bbae10912b11", size = 2233127, upload-time = "2026-04-17T09:11:04.449Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/a5/98f4b637149185addea19e1785ea20c373cca31b202f589111d8209d9873/pydantic_core-2.46.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9262d11d0cd11ee3303a95156939402bed6cedfe5ed0e331b95a283a4da6eb8b", size = 2297418, upload-time = "2026-04-17T09:11:25.929Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/90/93a5d21990b152da7b7507b7fddb0b935f6a0984d57ac3ec45a6e17777a2/pydantic_core-2.46.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac204542736aa295fa25f713b7fad6fc50b46ab7764d16087575c85f085174f3", size = 2093735, upload-time = "2026-04-17T09:12:06.908Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/22/b8b1ffdddf08b4e84380bcb67f41dbbf4c171377c1d36fc6290794bb2094/pydantic_core-2.46.2-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9a7c43a0584742dface3ca0daf6f719d46c1ac2f87cf080050f9ae052c75e1b2", size = 2127570, upload-time = "2026-04-17T09:11:53.906Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/26/e60d72b4e2d0ce1fa811044a974412ac1c567fe067d97b3e6b290530786e/pydantic_core-2.46.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd05e1edb6a90ad446fa268ab09e59202766b837597b714b2492db11ee87fab9", size = 2183524, upload-time = "2026-04-17T09:11:30.092Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/32/36bec7584a1eefb17dec4dfa1c946d3fe4440f466c5705b8adfda69c9a9f/pydantic_core-2.46.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:91155b110788b5501abc7ea954f1d08606219e4e28e3c73a94124307c06efb80", size = 2185408, upload-time = "2026-04-17T09:10:57.228Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/d6/1a5689d873620efd67d6b163db0c444c056adb0849b5bc33e2b9f09665a6/pydantic_core-2.46.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:e4e2c72a529fa03ff228be1d2b76944013f428220b764e03cc50ada67e17a42c", size = 2335171, upload-time = "2026-04-17T09:11:43.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/8e/675104802abe8ef502b072050ee5f2e915251aa1a3af87e1015ce31ec42d/pydantic_core-2.46.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:56291ec1a11c3499890c99a8fd9053b47e60fe837a77ec72c0671b1b8b3dce24", size = 2362743, upload-time = "2026-04-17T09:10:18.333Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/bc/86c5dde4fa6e24467680eef5047da3c1a19be0a527d0d8e14aa76b39307c/pydantic_core-2.46.2-cp313-cp313-win32.whl", hash = "sha256:b50f9c5f826ddca1246f055148df939f5f3f2d0d96db73de28e2233f22210d4c", size = 1958074, upload-time = "2026-04-17T09:12:38.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/97/2537e8c1282b2c4eb062580c0d7a4339e10b072b803d1ee0b7f1f0a5c22c/pydantic_core-2.46.2-cp313-cp313-win_amd64.whl", hash = "sha256:251a57788823230ca8cbc99e6245d1a2ed6e180ec4864f251c94182c580c7f2e", size = 2071741, upload-time = "2026-04-17T09:13:32.405Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/aa/2ee75798706f9dbc4e76dbe59e41a396c5c311e3d6223b9cf6a5fa7780be/pydantic_core-2.46.2-cp313-cp313-win_arm64.whl", hash = "sha256:315d32d1a71494d6b4e1e14a9fa7a4329597b4c4340088ad7e1a9dafbeed92a9", size = 2025955, upload-time = "2026-04-17T09:10:15.567Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/96/a50ccb6b539ae780f73cea74905468777680e30c6c3bdf714b9d4c116ea0/pydantic_core-2.46.2-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:4f59b45f3ef8650c0c736a57f59031d47ed9df4c0a64e83796849d7d14863a2d", size = 2097111, upload-time = "2026-04-17T09:10:49.617Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/5f/fdead7b3afa822ab6e5a18ee0ecffd54937de1877c01ed13a342e0fb3f07/pydantic_core-2.46.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3a075a29ebef752784a91532a1a85be6b234ccffec0a9d7978a92696387c3da6", size = 1951904, upload-time = "2026-04-17T09:12:32.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/e0/1c5d547e550cdab1bec737492aa08865337af6fe7fc9b96f7f45f17d9519/pydantic_core-2.46.2-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d12d786e30c04a9d307c5d7080bf720d9bac7f1668191d8e37633a9562749e2", size = 1978667, upload-time = "2026-04-17T09:11:35.589Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/cb/665ce629e218c8228302cb94beff4f6531082a2c87d3ecc3d5e63a26f392/pydantic_core-2.46.2-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d5e6d6343b0b5dcacb3503b5de90022968da8ed0ab9ab39d3eda71c20cbf84e", size = 2046721, upload-time = "2026-04-17T09:11:47.725Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/e9/6cb2cf60f54c1472bbdfce19d957553b43dbba79d1d7b2930a195c594785/pydantic_core-2.46.2-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:233eebac0999b6b9ba76eb56f3ec8fce13164aa16b6d2225a36a79e0f95b5973", size = 2228483, upload-time = "2026-04-17T09:12:08.837Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/2a/93e018dd5571f781ebaeda8c0cf65398489d5bee9b1f484df0b6149b43b9/pydantic_core-2.46.2-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cc0eee720dd2f14f3b7c349469402b99ad81a174ab49d3533974529e9d93992", size = 2294663, upload-time = "2026-04-17T09:12:52.053Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/4f/49e57ca55c770c93d9bb046666a54949b42e3c9099a0c5fe94557873fe30/pydantic_core-2.46.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83ee76bf2c9910513dbc19e7d82367131fa7508dedd6186a462393071cc11059", size = 2098742, upload-time = "2026-04-17T09:13:45.472Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/b0/6e46b5cd3332af665f794b8cdeea206618a8630bd9e7bcc36864518fce81/pydantic_core-2.46.2-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:d61db38eb4ee5192f0c261b7f2d38e420b554df8912245e3546aee5c45e2fd78", size = 2125922, upload-time = "2026-04-17T09:12:54.304Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/d1/40850c81585be443a2abfdf7f795f8fae831baf8e2f9b2133c8246ac671c/pydantic_core-2.46.2-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8f09a713d17bcd55da8ab02ebd9110c5246a49c44182af213b5212800af8bc83", size = 2183000, upload-time = "2026-04-17T09:10:59.027Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/af/8493d7dfa03ebb7866909e577c6aa65ea0de7377b86023cc51d0c8e11db3/pydantic_core-2.46.2-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:30cacc5fb696e64b8ef6fd31d9549d394dd7d52760db072eecb98e37e3af1677", size = 2180335, upload-time = "2026-04-17T09:12:57.01Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/5b/1f6a344c4ffdf284da41c6067b82d5ebcbd11ce1b515ae4b662d4adb6f61/pydantic_core-2.46.2-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:7ccfb105fcfe91a22bbb5563ad3dc124bc1aa75bfd2e53a780ab05f78cdf6108", size = 2330002, upload-time = "2026-04-17T09:12:02.958Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/ff/9a694126c12d6d2f48a0cafa6f8eef88ef0d8825600e18d03ff2e896c3b2/pydantic_core-2.46.2-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:13ffef637dc8370c249e5b26bd18e9a80a4fca3d809618c44e18ec834a7ca7a8", size = 2359920, upload-time = "2026-04-17T09:10:27.764Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/c8/3a35c763d68a9cb2675eb10ef242cf66c5d4701b28ae12e688d67d2c180e/pydantic_core-2.46.2-cp314-cp314-win32.whl", hash = "sha256:1b0ab6d756ca2704a938e6c31b53f290c2f9c10d3914235410302a149de1a83e", size = 1953701, upload-time = "2026-04-17T09:13:30.021Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/6a/f2726a780365f7dfd89d62036f984f7acb99978c60c5e1fa7c0cb898ed11/pydantic_core-2.46.2-cp314-cp314-win_amd64.whl", hash = "sha256:99ebade8c9ada4df975372d8dd25883daa0e379a05f1cd0c99aa0c04368d01a6", size = 2071867, upload-time = "2026-04-17T09:10:39.205Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/79/76baacb9feba3d7c399b245ca1a29c74ea0db04ea693811374827eec2290/pydantic_core-2.46.2-cp314-cp314-win_arm64.whl", hash = "sha256:de87422197cf7f83db91d89c86a21660d749b3cd76cd8a45d115b8e675670f02", size = 2017252, upload-time = "2026-04-17T09:10:26.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/3b/77c26938f817668d9ad9bab1a905cb23f11d9a3d4bf724d429b3e55a8eaf/pydantic_core-2.46.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:236f22b4a206b5b61db955396b7cf9e2e1ff77f372efe9570128ccfcd6a525eb", size = 2094545, upload-time = "2026-04-17T09:12:19.339Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/de/42c13f590e3c260966aa49bcdb1674774f975467c49abd51191e502bea28/pydantic_core-2.46.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c2012f64d2cd7cca50f49f22445aa5a88691ac2b4498ee0a9a977f8ca4f7289f", size = 1933953, upload-time = "2026-04-17T09:09:55.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/84/ebe3ebb3e2d8db656937cfa6f97f544cb7132f2307a4a7dfdcd0ea102a12/pydantic_core-2.46.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d07d6c63106d3a9c9a333e2636f9c82c703b1a9e3b079299e58747964e4fdb72", size = 1974435, upload-time = "2026-04-17T09:10:12.371Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/15/0bf51ca6709477cd4ef86148b6d7844f3308f029eac361dd0383f1e17b1a/pydantic_core-2.46.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c326a2b4b85e959d9a1fc3a11f32f84611b6ec07c053e1828a860edf8d068208", size = 2031113, upload-time = "2026-04-17T09:10:00.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/ae/b7b5af9b79db036d9e61a44c481c17a213dc8fc4b8b71fe6875a72fc778b/pydantic_core-2.46.2-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac8a65e798f2462552c00d2e013d532c94d646729dda98458beaf51f9ec7b120", size = 2236325, upload-time = "2026-04-17T09:10:33.227Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/ae/ecef7477b5a03d4a499708f7e75d2836452ebb70b776c2d64612b334f57a/pydantic_core-2.46.2-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a3c2bc1cc8164bedbc160b7bb1e8cc1e8b9c27f69ae4f9ae2b976cdae02b2dd", size = 2278135, upload-time = "2026-04-17T09:10:23.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/e4/2f9d82faa47af6c39fc3f120145fd915971e1e0cb6b55b494fad9fdf8275/pydantic_core-2.46.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69aa5e10b7e8b1bb4a6888650fd12fcbf11d396ca11d4a44de1450875702830", size = 2109071, upload-time = "2026-04-17T09:11:06.149Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/9c/677cf10873fbd0b116575ab7b97c90482b21564f8a8040beb18edef7a577/pydantic_core-2.46.2-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4e6df5c3301e65fb42bc5338bf9a1027a02b0a31dc7f54c33775229af474daf0", size = 2106028, upload-time = "2026-04-17T09:10:51.525Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/53/6a06183544daba51c059123a2064a99039df25f115a06bdb26f2ea177038/pydantic_core-2.46.2-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c2f6e32548ac8d559b47944effcf8ae4d81c161f6b6c885edc53bc08b8f192d", size = 2164816, upload-time = "2026-04-17T09:11:56.187Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/6f/10fcdd9e3eca66fc828eef0f6f5850f2dd3bca2c59e6e041fb8bc3da39be/pydantic_core-2.46.2-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:b089a81c58e6ea0485562bbbbbca4f65c0549521606d5ef27fba217aac9b665a", size = 2166130, upload-time = "2026-04-17T09:10:03.804Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/83/92d3fd0e0156cad2e3cb5c26de73794af78ac9fa0c22ab666e566dd67061/pydantic_core-2.46.2-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:7f700a6d6f64112ae9193709b84303bbab84424ad4b47d0253301aabce9dfc70", size = 2316605, upload-time = "2026-04-17T09:12:45.249Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/f1/facffdb970981068219582e499b8d0871ed163ffcc6b347de5c412669e4c/pydantic_core-2.46.2-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:67db6814beaa5fefe91101ec7eb9efda613795767be96f7cf58b1ca8c9ca9972", size = 2358385, upload-time = "2026-04-17T09:09:54.657Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/a1/b8160b2f22b2199467bc68581a4ed380643c16b348a27d6165c6c242d694/pydantic_core-2.46.2-cp314-cp314t-win32.whl", hash = "sha256:32fbc7447be8e3be99bf7869f7066308f16be55b61f9882c2cefc7931f5c7664", size = 1942373, upload-time = "2026-04-17T09:12:59.594Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/90/db89acabe5b150e11d1b59fe3d947dda2ef6abbfef5c82f056ff63802f5d/pydantic_core-2.46.2-cp314-cp314t-win_amd64.whl", hash = "sha256:b317a2b97019c0b95ce99f4f901ae383f40132da6706cdf1731066a73394c25c", size = 2052078, upload-time = "2026-04-17T09:10:19.96Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/32/e19b83ceb07a3f1bb21798407790bbc9a31740158fd132b94139cb84e16c/pydantic_core-2.46.2-cp314-cp314t-win_arm64.whl", hash = "sha256:7dcb9d40930dfad7ab6b20bcc6ca9d2b030b0f347a0cd9909b54bd53ead521b1", size = 2016941, upload-time = "2026-04-17T09:12:34.447Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/3c/9b5e8eb9821936d065439c3b0fb1490ffa64163bfe7e1595985a47896073/pydantic_core-2.46.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:12bc98de041458b80c86c56b24df1d23832f3e166cbaff011f25d187f5c62c37", size = 2102109, upload-time = "2026-04-20T14:41:24.219Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/97/1c41d1f5a19f241d8069f1e249853bcce378cdb76eec8ab636d7bc426280/pydantic_core-2.46.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:85348b8f89d2c3508b65b16c3c33a4da22b8215138d8b996912bb1532868885f", size = 1951820, upload-time = "2026-04-20T14:42:14.236Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/b4/d03a7ae14571bc2b6b3c7b122441154720619afe9a336fa3a95434df5e2f/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1105677a6df914b1fb71a81b96c8cce7726857e1717d86001f29be06a25ee6f8", size = 1977785, upload-time = "2026-04-20T14:42:31.648Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/0c/4086f808834b59e3c8f1aa26df8f4b6d998cdcf354a143d18ef41529d1fe/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87082cd65669a33adeba5470769e9704c7cf026cc30afb9cc77fd865578ebaad", size = 2062761, upload-time = "2026-04-20T14:40:37.093Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/71/a649be5a5064c2df0db06e0a512c2281134ed2fcc981f52a657936a7527c/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e5f66e12c4f5212d08522963380eaaeac5ebd795826cfd19b2dfb0c7a52b9c", size = 2232989, upload-time = "2026-04-20T14:42:59.254Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/84/7756e75763e810b3a710f4724441d1ecc5883b94aacb07ca71c5fb5cfb69/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6cdf19bf84128d5e7c37e8a73a0c5c10d51103a650ac585d42dd6ae233f2b7f", size = 2303975, upload-time = "2026-04-20T14:41:32.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/35/68a762e0c1e31f35fa0dac733cbd9f5b118042853698de9509c8e5bf128b/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031bb17f4885a43773c8c763089499f242aee2ea85cf17154168775dccdecf35", size = 2095325, upload-time = "2026-04-20T14:42:47.685Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/bf/1bf8c9a8e91836c926eae5e3e51dce009bf495a60ca56060689d3df3f340/pydantic_core-2.46.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:bcf2a8b2982a6673693eae7348ef3d8cf3979c1d63b54fca7c397a635cc68687", size = 2133368, upload-time = "2026-04-20T14:41:22.766Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/50/87d818d6bab915984995157ceb2380f5aac4e563dddbed6b56f0ed057aba/pydantic_core-2.46.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28e8cf2f52d72ced402a137145923a762cbb5081e48b34312f7a0c8f55928ec3", size = 2173908, upload-time = "2026-04-20T14:42:52.044Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/88/a311fb306d0bd6185db41fa14ae888fb81d0baf648a761ae760d30819d33/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:17eaface65d9fc5abb940003020309c1bf7a211f5f608d7870297c367e6f9022", size = 2186422, upload-time = "2026-04-20T14:43:29.55Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/79/28fd0d81508525ab2054fef7c77a638c8b5b0afcbbaeee493cf7c3fef7e1/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:93fd339f23408a07e98950a89644f92c54d8729719a40b30c0a30bb9ebc55d23", size = 2332709, upload-time = "2026-04-20T14:42:16.134Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/21/795bf5fe5c0f379308b8ef19c50dedab2e7711dbc8d0c2acf08f1c7daa05/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:23cbdb3aaa74dfe0837975dbf69b469753bbde8eacace524519ffdb6b6e89eb7", size = 2372428, upload-time = "2026-04-20T14:41:10.974Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/b3/ed14c659cbe7605e3ef063077680a64680aec81eb1a04763a05190d49b7f/pydantic_core-2.46.3-cp313-cp313-win32.whl", hash = "sha256:610eda2e3838f401105e6326ca304f5da1e15393ae25dacae5c5c63f2c275b13", size = 1965601, upload-time = "2026-04-20T14:41:42.128Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/bb/adb70d9a762ddd002d723fbf1bd492244d37da41e3af7b74ad212609027e/pydantic_core-2.46.3-cp313-cp313-win_amd64.whl", hash = "sha256:68cc7866ed863db34351294187f9b729964c371ba33e31c26f478471c52e1ed0", size = 2071517, upload-time = "2026-04-20T14:43:36.096Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/eb/66faefabebfe68bd7788339c9c9127231e680b11906368c67ce112fdb47f/pydantic_core-2.46.3-cp313-cp313-win_arm64.whl", hash = "sha256:f64b5537ac62b231572879cd08ec05600308636a5d63bcbdb15063a466977bec", size = 2035802, upload-time = "2026-04-20T14:43:38.507Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/db/a7bcb4940183fda36022cd18ba8dd12f2dff40740ec7b58ce7457befa416/pydantic_core-2.46.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:afa3aa644f74e290cdede48a7b0bee37d1c35e71b05105f6b340d484af536d9b", size = 2097614, upload-time = "2026-04-20T14:44:38.374Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/35/e4066358a22e3e99519db370494c7528f5a2aa1367370e80e27e20283543/pydantic_core-2.46.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ced3310e51aa425f7f77da8bbbb5212616655bedbe82c70944320bc1dbe5e018", size = 1951896, upload-time = "2026-04-20T14:40:53.996Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/92/37cf4049d1636996e4b888c05a501f40a43ff218983a551d57f9d5e14f0d/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e29908922ce9da1a30b4da490bd1d3d82c01dcfdf864d2a74aacee674d0bfa34", size = 1979314, upload-time = "2026-04-20T14:41:49.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/36/9ff4d676dfbdfb2d591cf43f3d90ded01e15b1404fd101180ed2d62a2fd3/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c9ff69140423eea8ed2d5477df3ba037f671f5e897d206d921bc9fdc39613e7", size = 2056133, upload-time = "2026-04-20T14:42:23.574Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/f0/405b442a4d7ba855b06eec8b2bf9c617d43b8432d099dfdc7bf999293495/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b675ab0a0d5b1c8fdb81195dc5bcefea3f3c240871cdd7ff9a2de8aa50772eb2", size = 2228726, upload-time = "2026-04-20T14:44:22.816Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/f8/65cd92dd5a0bd89ba277a98ecbfaf6fc36bbd3300973c7a4b826d6ab1391/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0087084960f209a9a4af50ecd1fb063d9ad3658c07bb81a7a53f452dacbfb2ba", size = 2301214, upload-time = "2026-04-20T14:44:48.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/86/ef96a4c6e79e7a2d0410826a68fbc0eccc0fd44aa733be199d5fcac3bb87/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed42e6cc8e1b0e2b9b96e2276bad70ae625d10d6d524aed0c93de974ae029f9f", size = 2099927, upload-time = "2026-04-20T14:41:40.196Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/53/269caf30e0096e0a8a8f929d1982a27b3879872cca2d917d17c2f9fdf4fe/pydantic_core-2.46.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f1771ce258afb3e4201e67d154edbbae712a76a6081079fe247c2f53c6322c22", size = 2128789, upload-time = "2026-04-20T14:41:15.868Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/b0/1a6d9b6a587e118482910c244a1c5acf4d192604174132efd12bf0ac486f/pydantic_core-2.46.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a7610b6a5242a6c736d8ad47fd5fff87fcfe8f833b281b1c409c3d6835d9227f", size = 2173815, upload-time = "2026-04-20T14:44:25.152Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/56/e7e00d4041a7e62b5a40815590114db3b535bf3ca0bf4dca9f16cef25246/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ff5e7783bcc5476e1db448bf268f11cb257b1c276d3e89f00b5727be86dd0127", size = 2181608, upload-time = "2026-04-20T14:41:28.933Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/22/4bd23c3d41f7c185d60808a1de83c76cf5aeabf792f6c636a55c3b1ec7f9/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9d2e32edcc143bc01e95300671915d9ca052d4f745aa0a49c48d4803f8a85f2c", size = 2326968, upload-time = "2026-04-20T14:42:03.962Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/ac/66cd45129e3915e5ade3b292cb3bc7fd537f58f8f8dbdaba6170f7cabb74/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d83d1c6b87fa56b521479cff237e626a292f3b31b6345c15a99121b454c1", size = 2369842, upload-time = "2026-04-20T14:41:35.52Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/51/dd4248abb84113615473aa20d5545b7c4cd73c8644003b5259686f93996c/pydantic_core-2.46.3-cp314-cp314-win32.whl", hash = "sha256:07bc6d2a28c3adb4f7c6ae46aa4f2d2929af127f587ed44057af50bf1ce0f505", size = 1959661, upload-time = "2026-04-20T14:41:00.042Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/eb/59980e5f1ae54a3b86372bd9f0fa373ea2d402e8cdcd3459334430f91e91/pydantic_core-2.46.3-cp314-cp314-win_amd64.whl", hash = "sha256:8940562319bc621da30714617e6a7eaa6b98c84e8c685bcdc02d7ed5e7c7c44e", size = 2071686, upload-time = "2026-04-20T14:43:16.471Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/db/1cf77e5247047dfee34bc01fa9bca134854f528c8eb053e144298893d370/pydantic_core-2.46.3-cp314-cp314-win_arm64.whl", hash = "sha256:5dcbbcf4d22210ced8f837c96db941bdb078f419543472aca5d9a0bb7cddc7df", size = 2026907, upload-time = "2026-04-20T14:43:31.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/c0/b3df9f6a543276eadba0a48487b082ca1f201745329d97dbfa287034a230/pydantic_core-2.46.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d0fe3dce1e836e418f912c1ad91c73357d03e556a4d286f441bf34fed2dbeecf", size = 2095047, upload-time = "2026-04-20T14:42:37.982Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/57/886a938073b97556c168fd99e1a7305bb363cd30a6d2c76086bf0587b32a/pydantic_core-2.46.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9ce92e58abc722dac1bf835a6798a60b294e48eb0e625ec9fd994b932ac5feee", size = 1934329, upload-time = "2026-04-20T14:43:49.655Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/7c/b42eaa5c34b13b07ecb51da21761297a9b8eb43044c864a035999998f328/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03e6467f0f5ab796a486146d1b887b2dc5e5f9b3288898c1b1c3ad974e53e4a", size = 1974847, upload-time = "2026-04-20T14:42:10.737Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/9b/92b42db6543e7de4f99ae977101a2967b63122d4b6cf7773812da2d7d5b5/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2798b6ba041b9d70acfb9071a2ea13c8456dd1e6a5555798e41ba7b0790e329c", size = 2041742, upload-time = "2026-04-20T14:40:44.262Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/19/46fbe1efabb5aa2834b43b9454e70f9a83ad9c338c1291e48bdc4fecf167/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9be3e221bdc6d69abf294dcf7aff6af19c31a5cdcc8f0aa3b14be29df4bd03b1", size = 2236235, upload-time = "2026-04-20T14:41:27.307Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/da/b3f95bc009ad60ec53120f5d16c6faa8cabdbe8a20d83849a1f2b8728148/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13936129ce841f2a5ddf6f126fea3c43cd128807b5a59588c37cf10178c2e64", size = 2282633, upload-time = "2026-04-20T14:44:33.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/6e/401336117722e28f32fb8220df676769d28ebdf08f2f4469646d404c43a3/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b5f2ef03416facccb1c6ef744c69793175fd27e44ef15669201601cf423acb", size = 2109679, upload-time = "2026-04-20T14:44:41.065Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/53/b289f9bc8756a32fe718c46f55afaeaf8d489ee18d1a1e7be1db73f42cc4/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:830d1247d77ad23852314f069e9d7ddafeec5f684baf9d7e7065ed46a049c4e6", size = 2108342, upload-time = "2026-04-20T14:42:50.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/5b/8292fc7c1f9111f1b2b7c1b0dcf1179edcd014fc3ea4517499f50b829d71/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0793c90c1a3c74966e7975eaef3ed30ebdff3260a0f815a62a22adc17e4c01c", size = 2157208, upload-time = "2026-04-20T14:42:08.133Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/9e/f80044e9ec07580f057a89fc131f78dda7a58751ddf52bbe05eaf31db50f/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d2d0aead851b66f5245ec0c4fb2612ef457f8bbafefdf65a2bf9d6bac6140f47", size = 2167237, upload-time = "2026-04-20T14:42:25.412Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/84/6781a1b037f3b96be9227edbd1101f6d3946746056231bf4ac48cdff1a8d/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:2f40e4246676beb31c5ce77c38a55ca4e465c6b38d11ea1bd935420568e0b1ab", size = 2312540, upload-time = "2026-04-20T14:40:40.313Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/db/19c0839feeb728e7df03255581f198dfdf1c2aeb1e174a8420b63c5252e5/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:cf489cf8986c543939aeee17a09c04d6ffb43bfef8ca16fcbcc5cfdcbed24dba", size = 2369556, upload-time = "2026-04-20T14:41:09.427Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/15/3228774cb7cd45f5f721ddf1b2242747f4eb834d0c491f0c02d606f09fed/pydantic_core-2.46.3-cp314-cp314t-win32.whl", hash = "sha256:ffe0883b56cfc05798bf994164d2b2ff03efe2d22022a2bb080f3b626176dd56", size = 1949756, upload-time = "2026-04-20T14:41:25.717Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/2a/c79cf53fd91e5a87e30d481809f52f9a60dd221e39de66455cf04deaad37/pydantic_core-2.46.3-cp314-cp314t-win_amd64.whl", hash = "sha256:706d9d0ce9cf4593d07270d8e9f53b161f90c57d315aeec4fb4fd7a8b10240d8", size = 2051305, upload-time = "2026-04-20T14:43:18.627Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/db/d8182a7f1d9343a032265aae186eb063fe26ca4c40f256b21e8da4498e89/pydantic_core-2.46.3-cp314-cp314t-win_arm64.whl", hash = "sha256:77706aeb41df6a76568434701e0917da10692da28cb69d5fb6919ce5fdb07374", size = 2026310, upload-time = "2026-04-20T14:41:01.778Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1350,6 +1354,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "soupsieve"
|
||||
version = "2.8.3"
|
||||
@@ -1449,6 +1462,21 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.25.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-doc" },
|
||||
{ name = "click" },
|
||||
{ name = "rich" },
|
||||
{ name = "shellingham" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7b/27/ede8cec7596e0041ba7e7b80b47d132562f56ff454313a16f6084e555c9f/typer-0.25.0.tar.gz", hash = "sha256:123eaf9f19bb40fd268310e12a542c0c6b4fab9c98d9d23342a01ff95e3ce930", size = 120150, upload-time = "2026-04-26T08:46:14.767Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/72/193d4e586ec5a4db834a36bbeb47641a62f951f114ffd0fe5b1b46e8d56f/typer-0.25.0-py3-none-any.whl", hash = "sha256:ac01b48823d3db9a83c9e164338057eadbb1c9957a2a6b4eeb486669c560b5dc", size = 55993, upload-time = "2026-04-26T08:46:15.889Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
@@ -1481,15 +1509,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.44.0"
|
||||
version = "0.46.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5e/da/6eee1ff8b6cbeed47eeb5229749168e81eb4b7b999a1a15a7176e51410c9/uvicorn-0.44.0.tar.gz", hash = "sha256:6c942071b68f07e178264b9152f1f16dfac5da85880c4ce06366a96d70d4f31e", size = 86947, upload-time = "2026-04-06T09:23:22.826Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/93/041fca8274050e40e6791f267d82e0e2e27dd165627bd640d3e0e378d877/uvicorn-0.46.0.tar.gz", hash = "sha256:fb9da0926999cc6cb22dc7cd71a94a632f078e6ae47ff683c5c420750fb7413d", size = 88758, upload-time = "2026-04-23T07:16:00.151Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl", hash = "sha256:ce937c99a2cc70279556967274414c087888e8cec9f9c94644dfca11bd3ced89", size = 69425, upload-time = "2026-04-06T09:23:21.524Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/a3/5b1562db76a5a488274b2332a97199b32d0442aca0ed193697fd47786316/uvicorn-0.46.0-py3-none-any.whl", hash = "sha256:bbebbcbed972d162afca128605223022bedd345b7bc7855ce66deb31487a9048", size = 70926, upload-time = "2026-04-23T07:15:58.355Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
2
webui/components.d.ts
vendored
2
webui/components.d.ts
vendored
@@ -33,6 +33,7 @@ declare module 'vue' {
|
||||
NMenu: typeof import('naive-ui')['NMenu']
|
||||
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||
NP: typeof import('naive-ui')['NP']
|
||||
NPopover: typeof import('naive-ui')['NPopover']
|
||||
NSelect: typeof import('naive-ui')['NSelect']
|
||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||
NTag: typeof import('naive-ui')['NTag']
|
||||
@@ -65,6 +66,7 @@ declare global {
|
||||
const NMenu: typeof import('naive-ui')['NMenu']
|
||||
const NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||
const NP: typeof import('naive-ui')['NP']
|
||||
const NPopover: typeof import('naive-ui')['NPopover']
|
||||
const NSelect: typeof import('naive-ui')['NSelect']
|
||||
const NSwitch: typeof import('naive-ui')['NSwitch']
|
||||
const NTag: typeof import('naive-ui')['NTag']
|
||||
|
||||
@@ -5,9 +5,28 @@
|
||||
<div id="nav-title">
|
||||
<n-h3 class="no-margin-bottom">NJUPT Suan API</n-h3>
|
||||
</div>
|
||||
<a href="https://suan.mangofanfan.cn/" target="_blank">
|
||||
<n-button secondary type="primary">概览</n-button>
|
||||
</a>
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-button secondary type="info">源码</n-button>
|
||||
</template>
|
||||
<n-p class="no-margin-bottom"
|
||||
>NJUPT Suan API 的代码开源在以下两个地方,后面的那个可能更快?</n-p
|
||||
>
|
||||
<n-flex justify="center">
|
||||
<a href="https://github.com/mangofanfan/NJUPT-Suan-API" target="_blank">
|
||||
<n-button secondary type="info">GitHub</n-button>
|
||||
</a>
|
||||
<a href="https://gitea.mangofanfan.cn/SuanDev/NJUPT-Suan-API" target="_blank">
|
||||
<n-button secondary type="success">Mango Gitea</n-button>
|
||||
</a>
|
||||
</n-flex>
|
||||
</n-popover>
|
||||
<a href="https://mangofanfan.cn/" target="_blank">
|
||||
<n-button secondary type="error">芒果</n-button>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -35,9 +35,10 @@ export default defineConfig({
|
||||
input: {
|
||||
index: path.resolve(__dirname, 'index.html'),
|
||||
'index-schedule': path.resolve(__dirname, 'index-schedule.html'),
|
||||
}
|
||||
},
|
||||
},
|
||||
outDir: "../src/njupt_suan_api/static"
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
|
||||
Reference in New Issue
Block a user