初始提交
初始提交目前已有的文档和基础设置。 此提交还不包含 .gitignore 等文件。
This commit is contained in:
10
.idea/.gitignore
generated
vendored
Normal file
10
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# 已忽略包含查询文件的默认文件夹
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
8
.idea/SuanDocs.iml
generated
Normal file
8
.idea/SuanDocs.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
9
.idea/dictionaries/project.xml
generated
Normal file
9
.idea/dictionaries/project.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="project">
|
||||
<words>
|
||||
<w>Astrbot</w>
|
||||
<w>Suan</w>
|
||||
<w>njupt</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/SuanDocs.iml" filepath="$PROJECT_DIR$/.idea/SuanDocs.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
31
.vitepress/cache/deps/_metadata.json
vendored
Normal file
31
.vitepress/cache/deps/_metadata.json
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"hash": "b10f48f1",
|
||||
"configHash": "243b5d46",
|
||||
"lockfileHash": "d693947e",
|
||||
"browserHash": "320f5485",
|
||||
"optimized": {
|
||||
"vue": {
|
||||
"src": "../../../node_modules/.pnpm/vue@3.5.32/node_modules/vue/dist/vue.runtime.esm-bundler.js",
|
||||
"file": "vue.js",
|
||||
"fileHash": "7d2bde70",
|
||||
"needsInterop": false
|
||||
},
|
||||
"vitepress > @vue/devtools-api": {
|
||||
"src": "../../../node_modules/.pnpm/@vue+devtools-api@8.1.1/node_modules/@vue/devtools-api/dist/index.js",
|
||||
"file": "vitepress___@vue_devtools-api.js",
|
||||
"fileHash": "b6a43c68",
|
||||
"needsInterop": false
|
||||
},
|
||||
"vitepress > @vueuse/core": {
|
||||
"src": "../../../node_modules/.pnpm/@vueuse+core@14.2.1_vue@3.5.32/node_modules/@vueuse/core/dist/index.js",
|
||||
"file": "vitepress___@vueuse_core.js",
|
||||
"fileHash": "ba7f1e27",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
"chunks": {
|
||||
"chunk-64NPA4UK": {
|
||||
"file": "chunk-64NPA4UK.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
12950
.vitepress/cache/deps/chunk-64NPA4UK.js
vendored
Normal file
12950
.vitepress/cache/deps/chunk-64NPA4UK.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
.vitepress/cache/deps/chunk-64NPA4UK.js.map
vendored
Normal file
7
.vitepress/cache/deps/chunk-64NPA4UK.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
3
.vitepress/cache/deps/package.json
vendored
Normal file
3
.vitepress/cache/deps/package.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3813
.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
Normal file
3813
.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map
vendored
Normal file
7
.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
8737
.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
Normal file
8737
.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
.vitepress/cache/deps/vitepress___@vueuse_core.js.map
vendored
Normal file
7
.vitepress/cache/deps/vitepress___@vueuse_core.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
346
.vitepress/cache/deps/vue.js
vendored
Normal file
346
.vitepress/cache/deps/vue.js
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
import {
|
||||
BaseTransition,
|
||||
BaseTransitionPropsValidators,
|
||||
Comment,
|
||||
DeprecationTypes,
|
||||
EffectScope,
|
||||
ErrorCodes,
|
||||
ErrorTypeStrings,
|
||||
Fragment,
|
||||
KeepAlive,
|
||||
ReactiveEffect,
|
||||
Static,
|
||||
Suspense,
|
||||
Teleport,
|
||||
Text,
|
||||
TrackOpTypes,
|
||||
Transition,
|
||||
TransitionGroup,
|
||||
TriggerOpTypes,
|
||||
VueElement,
|
||||
assertNumber,
|
||||
callWithAsyncErrorHandling,
|
||||
callWithErrorHandling,
|
||||
camelize,
|
||||
capitalize,
|
||||
cloneVNode,
|
||||
compatUtils,
|
||||
compile,
|
||||
computed,
|
||||
createApp,
|
||||
createBaseVNode,
|
||||
createBlock,
|
||||
createCommentVNode,
|
||||
createElementBlock,
|
||||
createHydrationRenderer,
|
||||
createPropsRestProxy,
|
||||
createRenderer,
|
||||
createSSRApp,
|
||||
createSlots,
|
||||
createStaticVNode,
|
||||
createTextVNode,
|
||||
createVNode,
|
||||
customRef,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
defineCustomElement,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
defineModel,
|
||||
defineOptions,
|
||||
defineProps,
|
||||
defineSSRCustomElement,
|
||||
defineSlots,
|
||||
devtools,
|
||||
effect,
|
||||
effectScope,
|
||||
getCurrentInstance,
|
||||
getCurrentScope,
|
||||
getCurrentWatcher,
|
||||
getTransitionRawChildren,
|
||||
guardReactiveProps,
|
||||
h,
|
||||
handleError,
|
||||
hasInjectionContext,
|
||||
hydrate,
|
||||
hydrateOnIdle,
|
||||
hydrateOnInteraction,
|
||||
hydrateOnMediaQuery,
|
||||
hydrateOnVisible,
|
||||
initCustomFormatter,
|
||||
initDirectivesForSSR,
|
||||
inject,
|
||||
isMemoSame,
|
||||
isProxy,
|
||||
isReactive,
|
||||
isReadonly,
|
||||
isRef,
|
||||
isRuntimeOnly,
|
||||
isShallow,
|
||||
isVNode,
|
||||
markRaw,
|
||||
mergeDefaults,
|
||||
mergeModels,
|
||||
mergeProps,
|
||||
nextTick,
|
||||
nodeOps,
|
||||
normalizeClass,
|
||||
normalizeProps,
|
||||
normalizeStyle,
|
||||
onActivated,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onBeforeUpdate,
|
||||
onDeactivated,
|
||||
onErrorCaptured,
|
||||
onMounted,
|
||||
onRenderTracked,
|
||||
onRenderTriggered,
|
||||
onScopeDispose,
|
||||
onServerPrefetch,
|
||||
onUnmounted,
|
||||
onUpdated,
|
||||
onWatcherCleanup,
|
||||
openBlock,
|
||||
patchProp,
|
||||
popScopeId,
|
||||
provide,
|
||||
proxyRefs,
|
||||
pushScopeId,
|
||||
queuePostFlushCb,
|
||||
reactive,
|
||||
readonly,
|
||||
ref,
|
||||
registerRuntimeCompiler,
|
||||
render,
|
||||
renderList,
|
||||
renderSlot,
|
||||
resolveComponent,
|
||||
resolveDirective,
|
||||
resolveDynamicComponent,
|
||||
resolveFilter,
|
||||
resolveTransitionHooks,
|
||||
setBlockTracking,
|
||||
setDevtoolsHook,
|
||||
setTransitionHooks,
|
||||
shallowReactive,
|
||||
shallowReadonly,
|
||||
shallowRef,
|
||||
ssrContextKey,
|
||||
ssrUtils,
|
||||
stop,
|
||||
toDisplayString,
|
||||
toHandlerKey,
|
||||
toHandlers,
|
||||
toRaw,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
transformVNodeArgs,
|
||||
triggerRef,
|
||||
unref,
|
||||
useAttrs,
|
||||
useCssModule,
|
||||
useCssVars,
|
||||
useHost,
|
||||
useId,
|
||||
useModel,
|
||||
useSSRContext,
|
||||
useShadowRoot,
|
||||
useSlots,
|
||||
useTemplateRef,
|
||||
useTransitionState,
|
||||
vModelCheckbox,
|
||||
vModelDynamic,
|
||||
vModelRadio,
|
||||
vModelSelect,
|
||||
vModelText,
|
||||
vShow,
|
||||
version,
|
||||
warn,
|
||||
watch,
|
||||
watchEffect,
|
||||
watchPostEffect,
|
||||
watchSyncEffect,
|
||||
withAsyncContext,
|
||||
withCtx,
|
||||
withDefaults,
|
||||
withDirectives,
|
||||
withKeys,
|
||||
withMemo,
|
||||
withModifiers,
|
||||
withScopeId
|
||||
} from "./chunk-64NPA4UK.js";
|
||||
export {
|
||||
BaseTransition,
|
||||
BaseTransitionPropsValidators,
|
||||
Comment,
|
||||
DeprecationTypes,
|
||||
EffectScope,
|
||||
ErrorCodes,
|
||||
ErrorTypeStrings,
|
||||
Fragment,
|
||||
KeepAlive,
|
||||
ReactiveEffect,
|
||||
Static,
|
||||
Suspense,
|
||||
Teleport,
|
||||
Text,
|
||||
TrackOpTypes,
|
||||
Transition,
|
||||
TransitionGroup,
|
||||
TriggerOpTypes,
|
||||
VueElement,
|
||||
assertNumber,
|
||||
callWithAsyncErrorHandling,
|
||||
callWithErrorHandling,
|
||||
camelize,
|
||||
capitalize,
|
||||
cloneVNode,
|
||||
compatUtils,
|
||||
compile,
|
||||
computed,
|
||||
createApp,
|
||||
createBlock,
|
||||
createCommentVNode,
|
||||
createElementBlock,
|
||||
createBaseVNode as createElementVNode,
|
||||
createHydrationRenderer,
|
||||
createPropsRestProxy,
|
||||
createRenderer,
|
||||
createSSRApp,
|
||||
createSlots,
|
||||
createStaticVNode,
|
||||
createTextVNode,
|
||||
createVNode,
|
||||
customRef,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
defineCustomElement,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
defineModel,
|
||||
defineOptions,
|
||||
defineProps,
|
||||
defineSSRCustomElement,
|
||||
defineSlots,
|
||||
devtools,
|
||||
effect,
|
||||
effectScope,
|
||||
getCurrentInstance,
|
||||
getCurrentScope,
|
||||
getCurrentWatcher,
|
||||
getTransitionRawChildren,
|
||||
guardReactiveProps,
|
||||
h,
|
||||
handleError,
|
||||
hasInjectionContext,
|
||||
hydrate,
|
||||
hydrateOnIdle,
|
||||
hydrateOnInteraction,
|
||||
hydrateOnMediaQuery,
|
||||
hydrateOnVisible,
|
||||
initCustomFormatter,
|
||||
initDirectivesForSSR,
|
||||
inject,
|
||||
isMemoSame,
|
||||
isProxy,
|
||||
isReactive,
|
||||
isReadonly,
|
||||
isRef,
|
||||
isRuntimeOnly,
|
||||
isShallow,
|
||||
isVNode,
|
||||
markRaw,
|
||||
mergeDefaults,
|
||||
mergeModels,
|
||||
mergeProps,
|
||||
nextTick,
|
||||
nodeOps,
|
||||
normalizeClass,
|
||||
normalizeProps,
|
||||
normalizeStyle,
|
||||
onActivated,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onBeforeUpdate,
|
||||
onDeactivated,
|
||||
onErrorCaptured,
|
||||
onMounted,
|
||||
onRenderTracked,
|
||||
onRenderTriggered,
|
||||
onScopeDispose,
|
||||
onServerPrefetch,
|
||||
onUnmounted,
|
||||
onUpdated,
|
||||
onWatcherCleanup,
|
||||
openBlock,
|
||||
patchProp,
|
||||
popScopeId,
|
||||
provide,
|
||||
proxyRefs,
|
||||
pushScopeId,
|
||||
queuePostFlushCb,
|
||||
reactive,
|
||||
readonly,
|
||||
ref,
|
||||
registerRuntimeCompiler,
|
||||
render,
|
||||
renderList,
|
||||
renderSlot,
|
||||
resolveComponent,
|
||||
resolveDirective,
|
||||
resolveDynamicComponent,
|
||||
resolveFilter,
|
||||
resolveTransitionHooks,
|
||||
setBlockTracking,
|
||||
setDevtoolsHook,
|
||||
setTransitionHooks,
|
||||
shallowReactive,
|
||||
shallowReadonly,
|
||||
shallowRef,
|
||||
ssrContextKey,
|
||||
ssrUtils,
|
||||
stop,
|
||||
toDisplayString,
|
||||
toHandlerKey,
|
||||
toHandlers,
|
||||
toRaw,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
transformVNodeArgs,
|
||||
triggerRef,
|
||||
unref,
|
||||
useAttrs,
|
||||
useCssModule,
|
||||
useCssVars,
|
||||
useHost,
|
||||
useId,
|
||||
useModel,
|
||||
useSSRContext,
|
||||
useShadowRoot,
|
||||
useSlots,
|
||||
useTemplateRef,
|
||||
useTransitionState,
|
||||
vModelCheckbox,
|
||||
vModelDynamic,
|
||||
vModelRadio,
|
||||
vModelSelect,
|
||||
vModelText,
|
||||
vShow,
|
||||
version,
|
||||
warn,
|
||||
watch,
|
||||
watchEffect,
|
||||
watchPostEffect,
|
||||
watchSyncEffect,
|
||||
withAsyncContext,
|
||||
withCtx,
|
||||
withDefaults,
|
||||
withDirectives,
|
||||
withKeys,
|
||||
withMemo,
|
||||
withModifiers,
|
||||
withScopeId
|
||||
};
|
||||
7
.vitepress/cache/deps/vue.js.map
vendored
Normal file
7
.vitepress/cache/deps/vue.js.map
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [],
|
||||
"sourcesContent": [],
|
||||
"mappings": "",
|
||||
"names": []
|
||||
}
|
||||
36
.vitepress/config.mts
Normal file
36
.vitepress/config.mts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "Suan Projects",
|
||||
description: "AI Projects of Mango Suan",
|
||||
themeConfig: {
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{ text: 'README', link: '/readme' }
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: 'NJUPT Suan API',
|
||||
items: [
|
||||
{ text: '介绍', link: '/suan-api/introduction' },
|
||||
{ text: '部署', link: '/suan-api/deploy' },
|
||||
{ text: 'Playwright', link: '/suan-api/playwright' },
|
||||
{ text: 'LLM 工具', link: '/suan-api/llm-tools' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Astrbot 插件(已归档)',
|
||||
items: [
|
||||
{ text: '介绍', link: '/astrbot-plugin/introduction' },
|
||||
{ text: '图像渲染', link: '/astrbot-plugin/image-render' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
||||
]
|
||||
}
|
||||
})
|
||||
53
astrbot-plugin/image-render.md
Normal file
53
astrbot-plugin/image-render.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# 图像渲染
|
||||
|
||||
NJUPT Suan 提供的工具中包含图像渲染的需求。在现在的版本中,图像是通过 `wkhtmltoimage` 渲染的。
|
||||
|
||||
## 为什么?
|
||||
|
||||
造成芒果帆帆的这一决策的主要原因是,目前 Astrbot 的一个使用较为广泛的插件
|
||||
[BiliVideo](https://github.com/storyAura/astrbot_plugin_biliVideo)
|
||||
的图片渲染技术路线是 `wkhtmltopdf` 。
|
||||
|
||||
`wkhtmltopdf` 和 `wkhtmltoimage` 疑似是同一种东西,在芒果帆帆尝试安装 `wkhtmltopdf` 的时候两个就一起安装起来了。
|
||||
|
||||
## 如何安装?
|
||||
|
||||
安装这个东西是一个相当复杂且难绷的过程。根据芒果帆帆拷打 AI 得到的结果,`wkhtmltopdf` 是一个开源项目,但是已经存档,理由是
|
||||
**「社区认为其功能已经较为完善,因此不再需要进行开发维护。」**
|
||||
|
||||
由于该软件包已经停止维护,最新的软件包源中很可能不再包含它,比如 Debian 13。因此,芒果帆帆在 Debian 13 上不得不下载 Debian 12 的软件包来安装。
|
||||
|
||||
:::warning
|
||||
命令由 AI 生成,请谨慎使用。
|
||||
:::
|
||||
|
||||
```bash
|
||||
# 0. 到临时目录里下载适配于 Debian 12 的软件包版本
|
||||
cd /tmp
|
||||
wget -q https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb
|
||||
|
||||
# 1. 安装依赖(如果还没安装的话)
|
||||
sudo apt-get install -y ca-certificates fontconfig libfreetype6 libjpeg62-turbo libpng16-16 libssl3 libstdc++6 libx11-6 libxcb1 libxext6 libxrender1 xfonts-75dpi xfonts-base zlib1g
|
||||
|
||||
# 2. 安装下载的 deb 包
|
||||
sudo apt install /tmp/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb
|
||||
|
||||
# 或者使用 dpkg
|
||||
# sudo dpkg -i /tmp/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb
|
||||
```
|
||||
|
||||
## 这是好东西吗?
|
||||
|
||||
这显然并不是。
|
||||
|
||||
NJUPT Suan 现在使用 `wkhtmltoimage` 来将 HTML 渲染为 PNG 图像,为此,需要先在代码中拼接 HTML 文本,并写入临时文件,然后调用命令。
|
||||
|
||||
由于 `wkhtmltoimage` 已经不再维护,加上其历史包袱(基于早期的 webkit 引擎),已经不支持许多现代的 CSS 特性。
|
||||
|
||||
这会导致基于现代 CSS 设计的页面的渲染效果意外地差(或者说是样式无效),因此在 vibe coding 时,芒果帆帆不得不告诉 AI 避免使用新的 CSS 特性、
|
||||
简化颜色(避免使用渐变)以及使用系统自带字体。
|
||||
|
||||
芒果帆帆现在对于 BiliVideo 竟然会使用这套技术路线感到奇怪。按理说,Astrbot 内拥有将 Markdown 文本渲染为图片的方法,
|
||||
BiliVideo 也并没有独特的需要额外实现渲染的需求(其渲染功能用于生成视频的总结图片),但 NJUPT Suan 是真的需要做课程表的表格。
|
||||
|
||||
如果 NJUPT Suan 还有未来的话,会尝试更换渲染方案。
|
||||
32
astrbot-plugin/introduction.md
Normal file
32
astrbot-plugin/introduction.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# NJUPT Suan 插件介绍
|
||||
|
||||
**NJUPT Suan** - **芒果酸**
|
||||
|
||||
## 这是什么
|
||||
|
||||
这是一个 Astrbot 插件。
|
||||
|
||||
[Astrbot](https://astrbot.app/) 是一个跨平台 AI 助手,让 AI 直接工作在聊天软件中。你也可以把它当成一个聊天机器人,或者一个不能聊天只负责执行任务的工具人。
|
||||
|
||||
NJUPT Suan 当中的 `Suan` 是芒果酸酸的酸,本插件为 Astrbot 中运行的 LLM 提供了与 NJUPT 有关的工具。
|
||||
|
||||
## 功能介绍
|
||||
|
||||
### 生成课程表
|
||||
|
||||
NJUPT-MCP 包含了[能够返回课程表数据的工具](/njupt-mcp/llm-tools.md)。NJUPT Suan 可以根据 NJUPT-MCP 的返回数据渲染课程表图片,
|
||||
目前版本的渲染效果如下。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
上方预览效果是在插件设置中启用了忽略空行空列之后的效果。如果显示完全的话,那么完全没有课的行(时间段)和列(天)都会显示完整。
|
||||
|
||||
图片的标题由 LLM 决定,因此你可以通过提示词来让 LLM 生成更适合的标题。
|
||||
|
||||
此功能被包装为 LLM 工具,供 LLM 主动调用,需要在 Astrbot 中使用支持工具调用的模型。
|
||||
|
||||
## 技术路线
|
||||
|
||||
Astrbot 是使用 Python 构建的,其插件也使用 Python,因此 NJUPT Suan 也使用 Python 构建。
|
||||
BIN
image/astrbot-plugin-schedule-1.png
Normal file
BIN
image/astrbot-plugin-schedule-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
BIN
image/astrbot-plugin-schedule-2.png
Normal file
BIN
image/astrbot-plugin-schedule-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 209 KiB |
BIN
image/njupt-suan-api-terminal-1.png
Normal file
BIN
image/njupt-suan-api-terminal-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
25
index.md
Normal file
25
index.md
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: "Suan Projects"
|
||||
text: "AI Projects of Mango Suan"
|
||||
tagline: 中文名叫做芒果酸
|
||||
actions:
|
||||
- theme: brand
|
||||
text: README.md
|
||||
link: /readme
|
||||
- theme: alt
|
||||
text: Mango Gitea
|
||||
link: https://gitea.mangofanfan.cn/SuanDev
|
||||
|
||||
features:
|
||||
- title: Feature A
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
- title: Feature B
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
- title: Feature C
|
||||
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
---
|
||||
|
||||
10
package.json
Normal file
10
package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"vitepress": "2.0.0-alpha.17"
|
||||
},
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev --host --port 5123",
|
||||
"docs:build": "vitepress build",
|
||||
"docs:preview": "vitepress preview"
|
||||
}
|
||||
}
|
||||
1401
pnpm-lock.yaml
generated
Normal file
1401
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
readme.md
Normal file
21
readme.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# README 自述文件
|
||||
|
||||
## 简介
|
||||
|
||||
**芒果酸**、**芒果酸酸**、**Mango Suan** 都是本项目的代称。本项目包含以下子项目:
|
||||
|
||||
* **NJUPT-Suan-API** - API 与 MCP 服务器,向调用客户端以及 LLM 工具返回数据;
|
||||
* **astrbot_plugin_njupt_suan** - Astrbot 插件,需要结合 njupt-mcp 使用,提升交互体验。
|
||||
* **SuanDocs** - 文档项目,本文档站点。
|
||||
|
||||
本项目的有关仓库均位于 **[Mango Gitea](https://gitea.mangofanfan.cn)** 上,这是芒果帆帆自己的 Gitea 实例,用于存放这些代码仓库。
|
||||
|
||||
当芒果帆帆认为某个仓库的代码已经足够见人时,会将仓库公开至 GitHub,以方便任何人更方便地使用。
|
||||
|
||||
项目中的部分代码由 Kimi code 完成,芒果帆帆在其中起到一个吉祥物的作用。因此你也无需认真对待这些代码。
|
||||
|
||||
## 反馈
|
||||
|
||||
自然也可以在 Mango Gitea 的对应仓库内提交 issue。在 Gitea 中叫做工单。
|
||||
|
||||
如果芒果帆帆已经把东西扔到 GitHub 上了,那么在 GitHub 的仓库里提交 issue 也是可以的啦。
|
||||
62
suan-api/deploy.md
Normal file
62
suan-api/deploy.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# 部署
|
||||
|
||||
酸 API 同时具备 API 和 MCP 后端的功能。因此,酸 API 不支持 stdio 格式的 MCP 调用。
|
||||
|
||||
## 部署 Suan API 示例
|
||||
|
||||
目前的 Suan API 在设计上即不允许(或者说不适合)公开部署、公共服务,因此你需要自行部署 Suan API 实例。
|
||||
|
||||
### 使用 uv 部署
|
||||
|
||||
### 使用 Docker 部署
|
||||
|
||||
### 从源码部署
|
||||
|
||||
:::warning 性能警告
|
||||
直接从 `main.py` 入口运行可能会导致一些潜在的性能问题,表现为 Suan API 会占用较多的性能,而这可能不是你希望看到的。
|
||||
|
||||
等芒果帆帆再完善完善,然后争取提供其他更方便的部署选项吧~
|
||||
:::
|
||||
|
||||
使用 git 命令从 Mango Gitea 上拉取源代码:
|
||||
|
||||
```bash
|
||||
git clone https://gitea.mangofanfan.cn/SuanDev/NJUPT-Suan-API.git
|
||||
```
|
||||
|
||||
这会将项目的源代码克隆到 `NJUPT-Suan-API` 目录中。
|
||||
|
||||
然后,你需要 uv 和 pnpm 来启动项目,请确保环境中已经安装了它们。
|
||||
|
||||
在 `NJUPT-Suan-API` 目录下运行:
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
```
|
||||
|
||||
这将会构建 Python 虚拟环境,包括安装 Python 3.13(如果没有)和安装项目使用的依赖。
|
||||
|
||||
```bash
|
||||
uv run playwright install chromium
|
||||
```
|
||||
|
||||
这将会安装 chromium 供 playwright 使用。Suan API 通过这个 chromium 来模拟真实用户行为,以及截取课程表图片。
|
||||
|
||||
安装 chromium 可能需要一段**比较长的时间**。大体上这是能够成功的,只是需要一段**比较长的时间**。
|
||||
|
||||
然后(或者同时),在 `NJUPT-Suan-API/webui` 目录下运行:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
这将会安装 WebUI 所使用的依赖,然后构建 WebUI。这一般是很快的。
|
||||
|
||||
现在,回到 `NJUPT-Suan-API` 目录下,使用以下命令启动项目:
|
||||
|
||||
```bash
|
||||
uv run main.py
|
||||
```
|
||||
|
||||
NJUPT Suan API 应当可以正常启动。
|
||||
24
suan-api/introduction.md
Normal file
24
suan-api/introduction.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# NJUPT-Suan-API 介绍
|
||||
|
||||
## 这是什么
|
||||
|
||||
NJUPT 是 **南京邮电大学** 或者 **Nanjing University of Posts and Telecommunications** 的意思。
|
||||
|
||||
Suan 是本项目的代号,芒果酸或者芒果酸酸。
|
||||
|
||||
API 是这个东西的工作,作为 API,以及 MCP。
|
||||
|
||||
MCP 是模型上下文协议,用于给 LLM 提供可供调用的工具。
|
||||
|
||||
## 特别说明
|
||||
|
||||
由于在网络上缺少与南京邮电大学相关的 Web API,已有的项目([NJUPT-API](https://github.com/gaoliang/NJUPT-API))也已经年久失修,
|
||||
芒果帆帆复刻这些 API 的过程也并不顺利。
|
||||
|
||||
经过芒果帆帆的社工活动可得,我邮并不对外提供查询课表、跑操次数等数据的接口,因此 NJUPT-Suan-API 不得不另辟蹊径来获得课表数据。
|
||||
|
||||
## 技术路线
|
||||
|
||||
NJUPT-Suan-API 使用 Python 实现了 API 和 MCP 后端,主要使用了 FastAPI 和 FastMCP,所有功能一式两份在 API 和 MCP 中分别提供。
|
||||
|
||||
另外提供 WebUI 管理面板用来便于管理。管理面板使用 Vue 设计。出于一些考量,管理面板不是可选的模块。
|
||||
127
suan-api/llm-tools.md
Normal file
127
suan-api/llm-tools.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# LLM 工具
|
||||
|
||||
## 课表工具
|
||||
|
||||
### get_course_schedule_json
|
||||
|
||||
```python
|
||||
@mcp.tool(
|
||||
name="get_course_schedule_json",
|
||||
title="获取课表 JSON",
|
||||
description="以 JSON 格式获取整学期整周全部课表数据,可选择是否压缩",
|
||||
annotations=ToolAnnotations(
|
||||
title="获取课表 JSON",
|
||||
readOnlyHint=True, # 只读取数据,不修改
|
||||
destructiveHint=False, # 非破坏性操作
|
||||
idempotentHint=True, # 幂等:重复调用结果相同
|
||||
openWorldHint=False, # 不依赖外部世界状态
|
||||
),
|
||||
)
|
||||
async def get_course_schedule_json(compressed: bool = False) -> list[dict] | list[tuple]:
|
||||
"""以 JSON 格式获取整学期整周全部课表
|
||||
|
||||
Args:
|
||||
compressed: 是否压缩为紧凑的元组格式,默认为 False
|
||||
|
||||
Returns:
|
||||
未压缩时(compressed=False):
|
||||
课程字典列表,每个课程包含:
|
||||
- name: 课程名称
|
||||
- teacher: 授课教师(可能为 None)
|
||||
- classroom: 教室(可能为 None)
|
||||
- weeks: 周数,list[int]
|
||||
- day: 星期几,int
|
||||
- classes: 当日第几节课,list[int]
|
||||
压缩时(compressed=True):
|
||||
元组列表 (name, teacher, classroom, weeks_str, day, classes)
|
||||
其中 weeks_str 为压缩后的周数字符串(如 "1-17")
|
||||
失败时返回空列表
|
||||
"""
|
||||
```
|
||||
|
||||
LLM 在调用时可以选择是否压缩。
|
||||
|
||||
请注意,[NJUPT Suan](/astrbot-plugin/introduction.md) 提供的渲染课表图片的工具需要经过压缩的课程数据,否则调用时很可能会由于参数过长而失败。
|
||||
|
||||
### get_week_course_schedule_json
|
||||
|
||||
```python
|
||||
@mcp.tool(
|
||||
name="get_week_course_schedule_json",
|
||||
title="获取指定周课表",
|
||||
description="以 JSON 格式获取指定教学周的全部课表数据,可选择是否压缩",
|
||||
annotations=ToolAnnotations(
|
||||
title="获取指定周课表",
|
||||
readOnlyHint=True, # 只读取数据,不修改
|
||||
destructiveHint=False, # 非破坏性操作
|
||||
idempotentHint=True, # 幂等:重复调用结果相同
|
||||
openWorldHint=False, # 不依赖外部世界状态
|
||||
),
|
||||
)
|
||||
async def get_week_course_schedule_json(week: int, compressed: bool = False) -> list[dict] | list[tuple]:
|
||||
"""以 JSON 格式获取指定教学周的全部课表
|
||||
|
||||
Args:
|
||||
week: 教学周数,范围通常为 1-20
|
||||
compressed: 是否压缩为紧凑的元组格式,默认为 False
|
||||
|
||||
Returns:
|
||||
未压缩时(compressed=False):
|
||||
指定周的课程字典列表,每个课程包含:
|
||||
- name: 课程名称
|
||||
- teacher: 授课教师(可能为 None)
|
||||
- classroom: 教室(可能为 None)
|
||||
- weeks: 周数,list[int]
|
||||
- day: 星期几,int (1-7)
|
||||
- classes: 当日第几节课,list[int]
|
||||
压缩时(compressed=True):
|
||||
元组列表 (name, teacher, classroom, weeks_str, day, classes)
|
||||
其中 weeks_str 为压缩后的周数字符串
|
||||
该周无课程或参数错误时返回空列表
|
||||
"""
|
||||
```
|
||||
|
||||
同上。
|
||||
|
||||
### get_week_day_course_schedule_json
|
||||
|
||||
```python
|
||||
@mcp.tool(
|
||||
name="get_week_day_course_schedule_json",
|
||||
title="获取指定周星期课表",
|
||||
description="以 JSON 格式获取指定教学周和星期的课表数据,可选择是否压缩",
|
||||
annotations=ToolAnnotations(
|
||||
title="获取指定周星期课表",
|
||||
readOnlyHint=True, # 只读取数据,不修改
|
||||
destructiveHint=False, # 非破坏性操作
|
||||
idempotentHint=True, # 幂等:重复调用结果相同
|
||||
openWorldHint=False, # 不依赖外部世界状态
|
||||
),
|
||||
)
|
||||
async def get_week_day_course_schedule_json(week: int, day: int, compressed: bool = False) -> list[dict] | list[tuple]:
|
||||
"""以 JSON 格式获取指定教学周和星期的课表
|
||||
|
||||
Args:
|
||||
week: 教学周数,范围通常为 1-20
|
||||
day: 星期几,1=星期一,2=星期二,...,7=星期日
|
||||
compressed: 是否压缩为紧凑的元组格式,默认为 False
|
||||
|
||||
Returns:
|
||||
未压缩时(compressed=False):
|
||||
指定周和星期的课程字典列表,每个课程包含:
|
||||
- name: 课程名称
|
||||
- teacher: 授课教师(可能为 None)
|
||||
- classroom: 教室(可能为 None)
|
||||
- weeks: 周数,list[int]
|
||||
- day: 星期几,int (1-7)
|
||||
- classes: 当日第几节课,list[int]
|
||||
压缩时(compressed=True):
|
||||
元组列表 (name, teacher, classroom, weeks_str, day, classes)
|
||||
其中 weeks_str 为压缩后的周数字符串
|
||||
该时段无课程或参数错误时返回空列表
|
||||
"""
|
||||
```
|
||||
|
||||
同上。
|
||||
|
||||
此三个工具的返回格式是统一的。
|
||||
3
suan-api/playwright.md
Normal file
3
suan-api/playwright.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Playwright
|
||||
|
||||
Playwright 是一个用于浏览器自动化的工具,Suan API 通过 playwright 来规避教务系统和统一身份认证的反爬虫措施,顺便用它来截图。
|
||||
Reference in New Issue
Block a user