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`