Compare commits
9 Commits
fix/databa
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
39c7c043ca
|
|||
|
39accb16e0
|
|||
| ec1f9627f3 | |||
| c0590dacbc | |||
| d748e242db | |||
| e2fd0809a5 | |||
|
2144b1e0eb
|
|||
|
7d0d53bead
|
|||
| 4bfcc9b41c |
@ -5,6 +5,8 @@ ENV VIRTUAL_ENV=/app/.venv \
|
||||
PLAYWRIGHT_BROWSERS_PATH=/usr/lib/pw-browsers
|
||||
|
||||
# 安装所有都需要的底层依赖
|
||||
#
|
||||
# xz-utils: 解压需要它
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libfontconfig1 libgl1 libegl1 libglvnd0 mesa-vulkan-drivers at-spi2-common fontconfig \
|
||||
@ -16,6 +18,7 @@ RUN apt-get update && \
|
||||
libatk-bridge2.0-0t64 libatspi2.0-0t64 libxcomposite1 libxdamage1 libxfixes3 \
|
||||
libxkbcommon0 libasound2t64 libnss3 fonts-noto-cjk fonts-noto-cjk-extra \
|
||||
fonts-noto-color-emoji \
|
||||
xz-utils \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
|
||||
@ -50,7 +50,14 @@ class ArtifactDepends:
|
||||
tasks = set()
|
||||
for f in self.callbacks:
|
||||
tasks.add(f(downloaded))
|
||||
return await asyncio.gather(*tasks, return_exceptions=True)
|
||||
result = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
for r in result:
|
||||
if isinstance(r, BaseException):
|
||||
logger.warning("完成了二进制文件的下载,但是有未捕捉的错误")
|
||||
logger.exception(r)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
@ -73,12 +80,7 @@ async def _():
|
||||
|
||||
async def _task(artifact: ArtifactDepends):
|
||||
async with semaphore:
|
||||
downloaded = await ensure_artifact(artifact)
|
||||
result = await artifact._finished(downloaded)
|
||||
for r in result:
|
||||
if isinstance(r, BaseException):
|
||||
logger.warning("完成了二进制文件的下载,但是有未捕捉的错误")
|
||||
logger.exception(r)
|
||||
await ensure_artifact(artifact)
|
||||
|
||||
tasks: set[asyncio.Task] = set()
|
||||
for a in artifact_list:
|
||||
@ -116,9 +118,16 @@ async def download_artifact(artifact: ArtifactDepends):
|
||||
f"下载到的二进制的 sha256 与需求不同 TARGET={artifact.target} REQUESTED={artifact.sha256} ACTUAL={m.hexdigest()}"
|
||||
)
|
||||
|
||||
await artifact._finished(True)
|
||||
|
||||
|
||||
async def ensure_artifact(artifact: ArtifactDepends) -> bool:
|
||||
"""
|
||||
确保所需的二进制存在。返回是否下载了这个二进制文件。
|
||||
"""
|
||||
|
||||
if not artifact.is_corresponding_platform():
|
||||
logger.debug(f"所需求的平台不是当前平台,跳过二进制下载 artifact={artifact}")
|
||||
return False
|
||||
|
||||
if not artifact.target.exists():
|
||||
@ -136,6 +145,7 @@ async def ensure_artifact(artifact: ArtifactDepends) -> bool:
|
||||
artifact.target.unlink()
|
||||
await download_artifact(artifact)
|
||||
return True
|
||||
await artifact._finished(False)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
# 指令介绍
|
||||
简易 Raymarch 小玩具
|
||||
用法:march `<scene>`
|
||||
用法:march `[scene]`
|
||||
例:march torus(1.0, 0.2).color(1.0, 0.2, 0.2) torus(1.0, 0.2).rot(90, 0, 0).color(0.2, 0.2, 1.0) camera(4.0).pos(4, 0, 0).lookat(0)
|
||||
|
||||
# 主要语法
|
||||
`<scene>` ::= `<scene>` "." `<op>` |`<obj>`
|
||||
`[scene]` ::= `[scene]` "." `[op]` |`[obj]`
|
||||
|
||||
`<obj>` ::= `<obj_ty>` | `<obj_ty>` "(" <args> ")"
|
||||
`[obj]` ::= `[obj_ty]` | `[obj_ty]` "(" [args] ")"
|
||||
|
||||
`<op>` ::= `<op_ty>` | `<op_ty>` "(" `<args>` ")"
|
||||
`[op]` ::= `[op_ty]` | `[op_ty]` "(" `[args]` ")"
|
||||
|
||||
`<args>` ::= `<args>` "," `<arg>` | `<arg>`
|
||||
`[args]` ::= `[args]` "," `[arg]` | `[arg]`
|
||||
|
||||
其中 `obj_ty`、`op_ty` 分别为物体类型(如 `cube`、`sphere`、`torus` 等)与变换类型(如 `pos`、`rot`)。
|
||||
|
||||
@ -37,4 +37,4 @@
|
||||
`rounded`:圆角
|
||||
|
||||
# 特殊说明
|
||||
`<op_ty>` 不包含 scale。非正交的变换会破坏 SDF 的性质。
|
||||
`[op_ty]` 不包含 scale。非正交的变换会破坏 SDF 的性质。
|
||||
44
konabot/plugins/guihuasay.py
Normal file
44
konabot/plugins/guihuasay.py
Normal file
@ -0,0 +1,44 @@
|
||||
import re
|
||||
from typing import Any
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters import Event
|
||||
from nonebot_plugin_alconna import UniMessage, UniMsg
|
||||
from playwright.async_api import Page
|
||||
|
||||
from konabot.common.nb import match_keyword
|
||||
from konabot.common.web_render import WebRenderer, konaweb
|
||||
|
||||
|
||||
async def render_image(message: str) -> UniMessage[Any]:
|
||||
"""
|
||||
渲染文本为图片
|
||||
"""
|
||||
|
||||
async def page_function(page: Page):
|
||||
await page.wait_for_function("typeof setContent === 'function'")
|
||||
await page.evaluate(
|
||||
"([ message ]) => { return setContent(message); }",
|
||||
[ message ],
|
||||
)
|
||||
|
||||
img_data = await WebRenderer.render(
|
||||
url=konaweb("guihuasay"),
|
||||
target="#main",
|
||||
other_function=page_function,
|
||||
)
|
||||
return UniMessage.image(raw=img_data)
|
||||
|
||||
|
||||
cmd = on_message(
|
||||
rule=match_keyword.match_keyword(
|
||||
re.compile(r"^(桂花[说想])\s.+", re.I),
|
||||
),
|
||||
)
|
||||
|
||||
@cmd.handle()
|
||||
async def _(event: Event, msg: UniMsg):
|
||||
text = msg.extract_plain_text().lstrip()
|
||||
_, content = text.split(maxsplit=1)
|
||||
msg = await render_image(content)
|
||||
await msg.send(event)
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
const float EPS = 0.001;
|
||||
const int MAX_ITER = 128;
|
||||
const float INF = 1e10;
|
||||
const float PI = 3.14159;
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
out vec4 fragColor;
|
||||
@ -68,17 +69,76 @@ vec3 nrm(vec3 p) {
|
||||
));
|
||||
}
|
||||
|
||||
float saturate(float x) {
|
||||
return clamp(x, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float ggx_distribution(vec3 n, vec3 h, float roughness) {
|
||||
float alpha = roughness * roughness;
|
||||
float alpha2 = alpha * alpha;
|
||||
float NdotH = saturate(dot(n, h));
|
||||
float denom = NdotH * NdotH * (alpha2 - 1.0) + 1.0;
|
||||
return alpha2 / max(PI * denom * denom, EPS);
|
||||
}
|
||||
|
||||
float geometry_schlick_ggx(float NdotX, float roughness) {
|
||||
float r = roughness + 1.0;
|
||||
float k = r * r / 8.0;
|
||||
return NdotX / max(NdotX * (1.0 - k) + k, EPS);
|
||||
}
|
||||
|
||||
float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) {
|
||||
float NdotV = saturate(dot(n, v));
|
||||
float NdotL = saturate(dot(n, l));
|
||||
return geometry_schlick_ggx(NdotV, roughness) * geometry_schlick_ggx(NdotL, roughness);
|
||||
}
|
||||
|
||||
vec3 fresnel_schlick(vec3 f0, float cos_theta) {
|
||||
return f0 + (1.0 - f0) * pow(1.0 - saturate(cos_theta), 5.0);
|
||||
}
|
||||
|
||||
vec3 tonemap_aces(vec3 c) {
|
||||
const float a = 2.51;
|
||||
const float b = 0.03;
|
||||
const float c1 = 2.43;
|
||||
const float d = 0.59;
|
||||
const float e = 0.14;
|
||||
return clamp((c * (a * c + b)) / (c * (c1 * c + d) + e), 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec4 materialColor(int obj_id) {
|
||||
<COLOR_BLOCK>
|
||||
return vec4(1.0);
|
||||
}
|
||||
|
||||
vec4 color(vec3 p, int obj_id) {
|
||||
vec3 normal = nrm(p);
|
||||
vec3 light_dir = normalize(vec3(0.5, 0.8, -0.6));
|
||||
float light = 0.2 + 0.8 * max(dot(normal, light_dir), 0.0);
|
||||
vec4 base = materialColor(obj_id);
|
||||
return vec4(base.rgb * light, base.a);
|
||||
vec4 color(vec3 p, vec3 r, int obj_id) {
|
||||
vec3 light_col = vec3(1.0);
|
||||
vec4 albedo = materialColor(obj_id);
|
||||
vec3 N = nrm(p);
|
||||
vec3 V = normalize(-r);
|
||||
vec3 L = normalize(vec3(0.5, 0.8, -0.6));
|
||||
vec3 H = normalize(V + L);
|
||||
float roughness = 0.45;
|
||||
float metallic = 0.02;
|
||||
float NdotL = saturate(dot(N, L));
|
||||
float NdotV = saturate(dot(N, V));
|
||||
float D = ggx_distribution(N, H, roughness);
|
||||
float G = geometry_smith(N, V, L, roughness);
|
||||
vec3 F0 = mix(vec3(0.04), albedo.rgb, metallic);
|
||||
vec3 F = fresnel_schlick(F0, dot(V, H));
|
||||
vec3 kD = (1.0 - F) * (1.0 - metallic);
|
||||
vec3 diffuse = kD * albedo.rgb / PI;
|
||||
vec3 specular = D * G * F / max(4.0 * NdotL * NdotV, EPS);
|
||||
|
||||
float hemi = N.y * 0.5 + 0.5;
|
||||
vec3 sky_ambient = vec3(0.60, 0.72, 0.92);
|
||||
vec3 ground_ambient = vec3(0.18, 0.16, 0.14);
|
||||
vec3 ambient = mix(ground_ambient, sky_ambient, hemi) * (diffuse + 0.25 * F0) * 0.35;
|
||||
|
||||
vec3 col = ambient + (diffuse + specular) * light_col * NdotL;
|
||||
col = tonemap_aces(col);
|
||||
col = pow(col, vec3(1.0 / 2.2));
|
||||
return vec4(col, 1.0);
|
||||
}
|
||||
|
||||
vec4 march(vec3 p, vec3 r) {
|
||||
@ -87,7 +147,7 @@ vec4 march(vec3 p, vec3 r) {
|
||||
for(int i = 0; i < MAX_ITER; ++i) {
|
||||
qry = sd(p);
|
||||
if(qry.value < EPS){
|
||||
col = color(p, qry.obj_id);
|
||||
col = color(p, r, qry.obj_id);
|
||||
break;
|
||||
}
|
||||
p += qry.value * r;
|
||||
|
||||
@ -41,6 +41,7 @@ bin_path: Path | None = None
|
||||
|
||||
@arti_typst_linux.on_finished
|
||||
async def _(downloaded: bool):
|
||||
logger.debug("安装好了 Linux 版本的 Typst")
|
||||
global bin_path
|
||||
|
||||
tar_path = arti_typst_linux.target
|
||||
@ -71,6 +72,7 @@ async def _(downloaded: bool):
|
||||
|
||||
@arti_typst_windows.on_finished
|
||||
async def _(downloaded: bool):
|
||||
logger.debug("安装好了 Windows 版本的 Typst")
|
||||
global bin_path
|
||||
zip_path = arti_typst_windows.target
|
||||
bin_path = BINARY_PATH / "typst.exe"
|
||||
@ -160,6 +162,7 @@ async def _(
|
||||
# 对于本地机器,一般不会在应用启动时自动下载,这里再保证存在
|
||||
await ensure_artifact(arti_typst_linux)
|
||||
await ensure_artifact(arti_typst_windows)
|
||||
|
||||
if bin_path is None or not bin_path.exists():
|
||||
logger.warning("当前环境不存在 Typst,但仍然调用了")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user