diff --git a/docs/before/introduction/project/fastapi.md b/docs/before/introduction/project/fastapi.md index 38b790b9..f1658204 100644 --- a/docs/before/introduction/project/fastapi.md +++ b/docs/before/introduction/project/fastapi.md @@ -5,15 +5,16 @@ Easy FastAPI Access for GraiaCommunity. -启动 Ariadne 时同时启动一个 Uvicorn 服务器并把 FastAPI 作为其 -ASGIApplication,在退出时自动关闭 Uvicorn。 -同时,可在 Saya 模块中便捷地注册 FastAPI 的路由。 +你可以方便地使用 GraiaX FastAPI 配合 `graia.amnesia.builtins.asgi.UvicornASGIService` +轻松地在启动使用了 Graia Amnesia 的项目(如:Ariadne、Avilla)的同时启动一个 +Uvicorn 服务器并在 Saya 模块中便捷地注册 FastAPI 的路由,且在 Launart 退出的时候自动关闭 Uvicorn。 + ## 安装 @@ -43,37 +44,79 @@ pip install graiax-fastapi ## 开始 -以下教程以 Ariadne 配合 Launart 为例。 +以 Avilla 为例。 -如果你有使用 **Graia Saya** 作为模块管理工具,那么可以通过使用 **FastAPIBehaviour** 以在 Saya 模块中更方便地使用 FastAPI。 +:::warning +自 v0.4.0 版本开始, GraiaX FastAPI 抛弃了旧版 +Launart(`<0.7.0`)和旧版 Amnesia(`<0.8.0`)的支持,因此在 +Ariadne 支持新的 Launart 以及 Amnesia 之前,请使用 +`graiax-fastapi==0.3.0`。 +::: -但是 FastAPI 本身并**不自带**ASGI 服务器,因此你需要额外添加一个 **UvicornService**。 +### 配合 Launart 使用 ### 在机器人入口文件中: +#### 机器人入口文件 + +如果你有使用 **Graia Saya** 作为模块管理工具,那么你可以使用 **FastAPIBehaviour** +以在 Saya 模块中更方便地使用 FastAPI。 + +FastAPI 本身并 **不自带** ASGI 服务器,因此你需要额外添加一个 **UvicornASGIService**。 + ```python +import pkgutil + +from avilla.console.protocol import ConsoleProtocol +from avilla.core import Avilla from creart import create -from graia.ariadne.app import Ariadne -from graia.amnesia.builtins.uvicorn import UvicornService // [!code focus] -from graiax.fastapi import FastAPIBehaviour, FastAPIService // [!code focus] +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from graia.amnesia.builtins.asgi import UvicornASGIService +from graia.broadcast import Broadcast from graia.saya import Saya +from launart import Launart -app = Ariadne(...) +broadcast = create(Broadcast) saya = create(Saya) -fastapi = FastAPI() // [!code focus] +launart = create(Launart) +avilla = Avilla(broadcast=broadcast, launch_manager=launart, message_cache_size=0) +fastapi = FastAPI() -saya.install_behaviours(FastAPIBehaviour(fastapi)) // [!code focus] +avilla.apply_protocols(ConsoleProtocol()) +saya.install_behaviours(FastAPIBehaviour(fastapi)) +fastapi.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) +launart.add_component(FastAPIService(fastapi)) +launart.add_component(UvicornASGIService("127.0.0.1", 9000, {"": fastapi})) # type:ignore +# 上面这条命令会占据 Uvicorn 的所有入口点,详见下方的 Warning -# 可以不创建 FastAPI 实例, 交给 FastAPIService 自己创建 // [!code focus] -# app.launch_manager.add_service(FastAPIService()) // [!code focus] -# 这样的话就不能给 FastAPI 传参并自定义 FastAPI // [!code focus] -app.launch_manager.add_service(FastAPIService(fastapi)) // [!code focus] -app.launch_manager.add_service(UvicornService()) // [!code focus] +with saya.module_context(): + for module in pkgutil.iter_modules(["modules"]): + if module.name[0] in ("#", ".", "_"): + continue + saya.require(f"modules.{module.name}") -Ariadne.launch_blocking() +launart.launch_blocking() ``` -### 在 Saya 模块中: +:::warning +需要留意的是,在把我们的 FastAPI 实例添加到 `UvicornASGIService` 中间件时,我们通过 +`{"": fastapi}` 指定了一个**入口点**(entrypoint)`""`,这代表着我们此时传进去的 +FastAPI 实例将占据 `http://127.0.0.1:9000/` 下所有入口(例如我们可以通过 `http://127.0.0.1:9000/docs` +访问我们的 FastAPI 实例的 OpenAPI 文档),这样用起来很方便,但可能会影响其他也使用 `UvicornASGIService` +中间件的功能(例如 Avilla 的 ob11 协议)。 + +假如我们使用 `{"/api": fastapi}` 指定 `/api` 为入口点,那么我们就需要通过 `http://127.0.0.1:9000/api/docs` 而不是 +`http://127.0.0.1:9000/docs` 来访问我们的 FastAPI 实例的 OpenAPI 文档。 +::: + +#### Saya 模块中 ```python from graia.saya import Channel @@ -124,52 +167,49 @@ async def ws(websocket: WebSocket): break ``` -:::details 其他方式 -假如你不想在 Saya 模块中为 FastAPI 添加路由,那么你可以选择以下两种方式: +假如你不想在 Saya 模块中为 FastAPI 添加路由,那么你可以选择以下几种方式: +:::details 其他方式 **1. 在机器人入口文件中直接添加:** ```python ... -app = Ariadne(...) -saya = create(Saya) fastapi = FastAPI() - +... fastapi.add_middleware( CORSMiddleware, - allow_origins=['*'], + allow_origins=["*"], allow_credentials=True, - allow_methods=['*'], - allow_headers=['*'], + allow_methods=["*"], + allow_headers=["*"], ) - @fastapi.get("/main") async def main(): return "main" ... -Ariadne.launch_blocking() +launart.add_component(FastAPIService(fastapi)) +launart.add_component(UvicornASGIService("127.0.0.1", 9000, {"": fastapi})) # type:ignore +... ``` -**2. Ariadne 启动成功后在 Saya 模块中添加:** +**2. 在 Avilla 启动成功后添加:** ```python -from graia.amnesia.builtins.uvicorn import ASGIHandlerProvider -from graiax.shortcut.saya import listen - +from fastapi.responses import PlainTextResponse +from avilla.standard.core.application.event import ApplicationReady +from graiax.fastapi.interface import FastAPIProvider -async def root(...): - ... +async def interface_test(): + return PlainTextResponse("I'm from interface!") -@listen(ApplicationLaunched) -async def function(app: Ariadne): - mgr = app.launch_manager - fastapi: FastAPI = mgr.get_interface(ASGIHandlerProvider).get_asgi_handler() # type: ignore - fastapi.add_api_route('/', endpoint=root, methods=['GET']) - fastapi.get('/main')(root) - fastapi.add_api_websocket_route('/ws', endpoint=websocket) +@listen(ApplicationReady) +async def function(): + launart = Launart.current() + fastapi = launart.get_interface(FastAPIProvider) + fastapi.add_api_route("/interface", fastapi.get("/interface")(interface_test)) ``` ::: diff --git a/docs/before/introduction/project/playwright.md b/docs/before/introduction/project/playwright.md index bd6f6ed7..2c032871 100644 --- a/docs/before/introduction/project/playwright.md +++ b/docs/before/introduction/project/playwright.md @@ -5,16 +5,17 @@ Easy Playwright Access for GraiaCommunity. -GraiaX Playwright 使用 launart 作为启动管理器, 适用于 Ariadne 及 Avilla。 +Graiax Playwright 使用 [launart](https://github.com/GraiaProject/launart) 作为启动管理器, +适用于 [Ariadne](https://github.com/GraiaProject/Ariadne) 及 [Avilla](https://github.com/GraiaProject/Avilla)。 -用于在 Ariadne 启动的时候同时通过 Playwright 启动一个浏览器内核,且可以在 -Ariadne 运行过程中调用,并在其退出的时候自动关闭 Playwright。 +通过 GraiaX Playwright 你可以轻松地在 Ariadne / Avilla 启动的时候同时启动一个 +Playwright,并在其退出的时候自动关闭 Playwright。 > 需要注意的是,Playwright 将会在运行期间保持浏览器后台常驻, > 但一般情况下由于未开启任何页面,其内存占用量不是非常大(但也是可观的)。 @@ -47,37 +48,39 @@ pip install graiax-playwright ## 开始 -以下教程以 Ariadne 配合 Launart 为例。 - -### 在机器人入口文件中: +以下教程以配合 Launart 使用为例。 ```python +from creart import create +from launart import Launart from graia.ariadne.app import Ariadne -from graiax.playwright import PlaywrightService // [!code focus] +from graiax.playwright import PlaywrightService -app = Ariadne(...) -app.launch_manager.add_service(PlaywrightService("chromium")) # 默认值为 chromium // [!code focus] -app.launch_manager.add_service(PlaywrightService(user_data_dir="./browser_data")) # 与上一行二选一,使用 Persistent Context // [!code focus] +launart = create(Launart) +launart.add_component(PlaywrightService("chromium")) # 默认值为 chromium +launart.add_component(PlaywrightService("chromium", user_data_dir="./browser_data")) # 与上一行二选一,该方式使用 Persistent Context ... -Ariadne.launch_blocking() +launart.launch_blocking() ``` -### 在 Saya 模块中: +### 配合 Graia Saya 使用 ```python -from graia.ariadne.app import Ariadne +from creart import create +from launart import Launart +from graia.ariadne.util.saya import listen from graiax.playwright import PlaywrightBrowser -from graiax.shortcut.saya import listen # 此处代码为没有使用 Persistent Context 的示例 -# 若使用 Persistent Context 请使用 `context = app.launch_manager.get_interface(PlaywrightContext)` +# 若使用 Persistent Context 请使用 `context = launart.get_interface(PlaywrightContext)` # 该方法获得的对象与 playwright.async_api.BrowserContext 兼容 @listen(...) async def function(app: Ariadne): - browser = app.launch_manager.get_interface(PlaywrightBrowser) + launart = create(Launart) + browser = launart.get_interface(PlaywrightBrowser) # 此处的 browser 之用法与 playwright.async_api.Browser 无异,但要注意的是下方代码的返回值为 False。 # `isinstance(browser, playwright.async_api.Browser)` async with browser.page( # 此 API 启用了自动上下文管理 @@ -86,7 +89,59 @@ async def function(app: Ariadne): ) as page: await page.set_content("Hello World!") img = await page.screenshot(type="jpeg", quality=80, full_page=True, scale="device") + ... +``` + +### 高级用法之一 + +上面配合 Saya 使用的例子展示了创建一个页面的例子,但假如我们需要一个与其他页面**隔离**的新页面(例如 cookie +等),那么我们可以使用 `browser.page(context=True)` 在创建页面时使用一个新的上下文,如下所示: + +:::tip +该种用法不支持持久性上下文(Persistent Context) + +更多信息详见: +::: + +```python +@listen(...) +async def function(app: Ariadne): + launart = create(Launart) + browser = launart.get_interface(PlaywrightBrowser) + async with browser.page(new_context=True) as page: # 此 API 启用了自动上下文管理 + await page.set_content("Hello World!") + img = await page.screenshot(type="jpeg", quality=80, full_page=True, scale="device") + ... +``` - await app.sendMessage(..., MessageChain(Image(data_bytes=img))) +### 高级用法之二 + +上面配合 Saya 使用的例子展示了为**单个页面**设置 viewport 的功能,自 GraiaX Playwright `v0.3.1` +版本起,可以在创建 PlaywrightService 时为全局的 Browser Context 指定 viewport,然后在截图时使用全局 +Browser Context 截图,如下所示: + +:::tip +该种用法不支持持久性上下文(Persistent Context) +::: + +**机器人入口文件:** + +```python +launart.add_service(PlaywrightService("chromium")) +``` + +**Saya 模块中:** + +```python +from graiax.playwright import PlaywrightContext + + +@listen(...) +async def function(app: Ariadne): + launart = create(Launart) + context = launart.get_interface(PlaywrightContext) + async with context.page() as page: # 此 API 启用了自动上下文管理 + await page.set_content("Hello World!") + img = await page.screenshot(type="jpeg", quality=80, full_page=True, scale="device") ... ``` diff --git a/docs/before/introduction/project/shortcut.md b/docs/before/introduction/project/shortcut.md index 4d6dd2df..3b4c94f8 100644 --- a/docs/before/introduction/project/shortcut.md +++ b/docs/before/introduction/project/shortcut.md @@ -9,7 +9,7 @@ Utilities for Graia Framework Community. version="v0.2.1" author="BlueGlassBlock、RF-Tar-Railt" repoUser="GraiaCommunity" - repoName="graiax-shortcut" + repoName="Shortcut" /> :::tip diff --git a/docs/before/introduction/project/silkcoder.md b/docs/before/introduction/project/silkcoder.md index b782e46b..32b62bae 100644 --- a/docs/before/introduction/project/silkcoder.md +++ b/docs/before/introduction/project/silkcoder.md @@ -6,7 +6,7 @@ A fxxxing simple silkv3 converter. -一个基于 GraiaX Playwright 的文转图工具, 其可以将纯文本、Markdown 文本、HTML 代码通过 Playwright 转换为图片。 +GraiaX TextToImage (Playwright) 是一个基于 [GraiaX Playwright](https://github.com/GraiaCommunity/graiax-playwright) 的文转图工具, +其可以将纯文本、Markdown 文本、HTML 代码通过 Playwright 转换为图片。 ## 安装 @@ -39,9 +40,11 @@ pip install graiax-text2img-playwright ::: :::: -## 在 Saya 模块中使用 +## 开始使用 -### 将 Markdown 转换为图片 +以下示例以 Ariadne 为例。 + +### 配合 Graia Saya 使用 ```python from graiax.shortcut.saya import listen @@ -79,11 +82,3 @@ async def function(app: Ariadne, friend: Friend): :::details 预览图 ![preview](https://raw.githubusercontent.com/GraiaCommunity/graiax-text2img-playwright/master/preview.jpg) ::: - -### 将 HTML 转换为图片 - - - -### 将纯文本转换为图片 - - diff --git a/docs/guide/async_exec.md b/docs/guide/async_exec.md index 12ea1929..cf8f1f07 100644 --- a/docs/guide/async_exec.md +++ b/docs/guide/async_exec.md @@ -150,7 +150,7 @@ async def drawing(group: Group): ## 应该什么时候用? -先说结论 +先说结论: - 如果你的函数造成的延迟你**几乎感觉不到**,那你就直接用 - 如果你的函数是做 **I/O 密集型** 的工作或者是在运行途中可以 **释放 GIL 锁**,那你就用 `io_bound`