hydro-ai-helper 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +31 -0
- package/.github/workflows/sync-releases-to-gitee.yml +119 -0
- package/.github/workflows/sync-to-gitee.yml +53 -0
- package/.vercelignore +31 -0
- package/CONTRIBUTING.md +165 -0
- package/README.md +273 -0
- package/TROUBLESHOOTING.md +355 -0
- package/api/badge-active.ts +88 -0
- package/api/badge-installs.ts +75 -0
- package/api/report.ts +242 -0
- package/assets/screenshots/1.png +0 -0
- package/assets/screenshots/2.png +0 -0
- package/assets/screenshots/3.png +0 -0
- package/assets/screenshots/4.png +0 -0
- package/assets/screenshots/5.png +0 -0
- package/assets/screenshots/6.png +0 -0
- package/assets/screenshots/7.png +0 -0
- package/dist/__tests__/__mocks__/hydrooj.js +29 -0
- package/dist/__tests__/__mocks__/hydrooj.js.map +1 -0
- package/dist/constants/jailbreakRules.js +29 -0
- package/dist/constants/jailbreakRules.js.map +1 -0
- package/dist/constants/permissions.js +42 -0
- package/dist/constants/permissions.js.map +1 -0
- package/dist/handlers/adminConfigHandler.js +347 -0
- package/dist/handlers/adminConfigHandler.js.map +1 -0
- package/dist/handlers/adminHandler.js +378 -0
- package/dist/handlers/adminHandler.js.map +1 -0
- package/dist/handlers/analyticsHandler.js +433 -0
- package/dist/handlers/analyticsHandler.js.map +1 -0
- package/dist/handlers/dashboardHandler.js +22 -0
- package/dist/handlers/dashboardHandler.js.map +1 -0
- package/dist/handlers/exportHandler.js +118 -0
- package/dist/handlers/exportHandler.js.map +1 -0
- package/dist/handlers/studentHandler.js +430 -0
- package/dist/handlers/studentHandler.js.map +1 -0
- package/dist/handlers/teacherHandler.js +246 -0
- package/dist/handlers/teacherHandler.js.map +1 -0
- package/dist/handlers/testHandler.js +27 -0
- package/dist/handlers/testHandler.js.map +1 -0
- package/dist/handlers/updateHandler.js +84 -0
- package/dist/handlers/updateHandler.js.map +1 -0
- package/dist/handlers/versionHandler.js +61 -0
- package/dist/handlers/versionHandler.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +151 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/crypto.js +110 -0
- package/dist/lib/crypto.js.map +1 -0
- package/dist/lib/httpHelpers.js +61 -0
- package/dist/lib/httpHelpers.js.map +1 -0
- package/dist/lib/queryHelpers.js +81 -0
- package/dist/lib/queryHelpers.js.map +1 -0
- package/dist/models/aiConfig.js +255 -0
- package/dist/models/aiConfig.js.map +1 -0
- package/dist/models/conversation.js +209 -0
- package/dist/models/conversation.js.map +1 -0
- package/dist/models/jailbreakLog.js +68 -0
- package/dist/models/jailbreakLog.js.map +1 -0
- package/dist/models/message.js +174 -0
- package/dist/models/message.js.map +1 -0
- package/dist/models/pluginInstall.js +95 -0
- package/dist/models/pluginInstall.js.map +1 -0
- package/dist/models/rateLimitRecord.js +54 -0
- package/dist/models/rateLimitRecord.js.map +1 -0
- package/dist/models/versionCache.js +89 -0
- package/dist/models/versionCache.js.map +1 -0
- package/dist/services/effectivenessService.js +131 -0
- package/dist/services/effectivenessService.js.map +1 -0
- package/dist/services/exportService.js +152 -0
- package/dist/services/exportService.js.map +1 -0
- package/dist/services/migrationService.js +90 -0
- package/dist/services/migrationService.js.map +1 -0
- package/dist/services/openaiClient.js +412 -0
- package/dist/services/openaiClient.js.map +1 -0
- package/dist/services/promptService.js +467 -0
- package/dist/services/promptService.js.map +1 -0
- package/dist/services/rateLimitService.js +108 -0
- package/dist/services/rateLimitService.js.map +1 -0
- package/dist/services/telemetryService.js +173 -0
- package/dist/services/telemetryService.js.map +1 -0
- package/dist/services/updateService.js +388 -0
- package/dist/services/updateService.js.map +1 -0
- package/dist/services/versionService.js +289 -0
- package/dist/services/versionService.js.map +1 -0
- package/dist/types/hydrooj.js +7 -0
- package/dist/types/hydrooj.js.map +1 -0
- package/dist/types/mongo.js +7 -0
- package/dist/types/mongo.js.map +1 -0
- package/dist/utils/domainHelper.js +16 -0
- package/dist/utils/domainHelper.js.map +1 -0
- package/dist/utils/mongo.js +16 -0
- package/dist/utils/mongo.js.map +1 -0
- package/frontend/admin/ConfigPanel.tsx +1379 -0
- package/frontend/admin/VersionBadge.tsx +655 -0
- package/frontend/ai_helper.page.tsx +52 -0
- package/frontend/ai_helper_admin_config.page.tsx +47 -0
- package/frontend/ai_helper_analytics.page.tsx +52 -0
- package/frontend/ai_helper_conversation_detail.page.tsx +55 -0
- package/frontend/ai_helper_conversations.page.tsx +56 -0
- package/frontend/components/AIHelperDashboard.tsx +125 -0
- package/frontend/problem_detail.page.tsx +395 -0
- package/frontend/student/AIAssistantPanel.tsx +1839 -0
- package/frontend/student/AIChatPanel.tsx +944 -0
- package/frontend/student/ThreeColumnLayout.tsx +240 -0
- package/frontend/teacher/AnalyticsPage.tsx +614 -0
- package/frontend/teacher/ConversationDetail.tsx +504 -0
- package/frontend/teacher/ConversationList.tsx +568 -0
- package/frontend/teacher/ExportDialog.tsx +291 -0
- package/frontend/test.page.ts +88 -0
- package/frontend/utils/domainUtils.ts +37 -0
- package/index.js +6 -0
- package/jest.config.js +17 -0
- package/lib/mongodb.ts +60 -0
- package/locales/en.yaml +4 -0
- package/locales/zh.yaml +77 -0
- package/package.json +48 -0
- package/public/.gitkeep +0 -0
- package/public/README.md +1 -0
- package/src/__tests__/__mocks__/hydrooj.ts +27 -0
- package/src/__tests__/services/exportService.test.ts +156 -0
- package/src/__tests__/services/promptService.test.ts +141 -0
- package/src/__tests__/services/rateLimitService.test.ts +145 -0
- package/src/__tests__/utils/domainHelper.test.ts +47 -0
- package/src/constants/jailbreakRules.ts +28 -0
- package/src/constants/permissions.ts +43 -0
- package/src/handlers/adminConfigHandler.ts +363 -0
- package/src/handlers/adminHandler.ts +427 -0
- package/src/handlers/analyticsHandler.ts +517 -0
- package/src/handlers/dashboardHandler.ts +20 -0
- package/src/handlers/exportHandler.ts +134 -0
- package/src/handlers/studentHandler.ts +483 -0
- package/src/handlers/teacherHandler.ts +317 -0
- package/src/handlers/testHandler.ts +25 -0
- package/src/handlers/updateHandler.ts +85 -0
- package/src/handlers/versionHandler.ts +62 -0
- package/src/index.ts +198 -0
- package/src/lib/crypto.ts +125 -0
- package/src/lib/httpHelpers.ts +75 -0
- package/src/lib/queryHelpers.ts +108 -0
- package/src/models/aiConfig.ts +375 -0
- package/src/models/conversation.ts +328 -0
- package/src/models/jailbreakLog.ts +108 -0
- package/src/models/message.ts +246 -0
- package/src/models/pluginInstall.ts +138 -0
- package/src/models/rateLimitRecord.ts +81 -0
- package/src/models/versionCache.ts +127 -0
- package/src/services/effectivenessService.ts +161 -0
- package/src/services/exportService.ts +191 -0
- package/src/services/migrationService.ts +111 -0
- package/src/services/openaiClient.ts +548 -0
- package/src/services/promptService.ts +573 -0
- package/src/services/rateLimitService.ts +122 -0
- package/src/services/telemetryService.ts +218 -0
- package/src/services/updateService.ts +441 -0
- package/src/services/versionService.ts +351 -0
- package/src/types/hydrooj-extensions.d.ts +55 -0
- package/src/types/hydrooj.ts +38 -0
- package/src/types/mongo.ts +23 -0
- package/src/utils/domainHelper.ts +16 -0
- package/src/utils/mongo.ts +15 -0
- package/templates/ai-helper/admin_config.html +8 -0
- package/templates/ai-helper/analytics.html +8 -0
- package/templates/ai-helper/dashboard.html +8 -0
- package/templates/ai-helper/teacher_conversation_detail.html +8 -0
- package/templates/ai-helper/teacher_conversations.html +8 -0
- package/tests/integration/README.md +86 -0
- package/tests/integration/curl/01-admin-config-set.sh +56 -0
- package/tests/integration/curl/02-student-chat.sh +67 -0
- package/tests/integration/curl/03-teacher-list.sh +52 -0
- package/tests/integration/curl/04-teacher-detail.sh +37 -0
- package/tests/integration/curl/05-export.sh +49 -0
- package/tests/integration/curl/06-analytics.sh +43 -0
- package/tests/performance/README.md +85 -0
- package/tests/performance/data/prepare-sample-data.md +57 -0
- package/tests/performance/scripts/export-csv-k6.js +41 -0
- package/tests/performance/scripts/student-chat-k6.js +44 -0
- package/tests/performance/scripts/teacher-conversations-k6.js +33 -0
- package/tsconfig.json +42 -0
- package/tsconfig.vercel.json +27 -0
- package/types/hydrooj/index.d.ts +73 -0
- package/vercel.json +3 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"root": true,
|
|
3
|
+
"env": {
|
|
4
|
+
"node": true,
|
|
5
|
+
"es2021": true
|
|
6
|
+
},
|
|
7
|
+
"parser": "@typescript-eslint/parser",
|
|
8
|
+
"parserOptions": {
|
|
9
|
+
"ecmaVersion": 2021,
|
|
10
|
+
"sourceType": "module",
|
|
11
|
+
"project": "./tsconfig.json"
|
|
12
|
+
},
|
|
13
|
+
"plugins": ["@typescript-eslint"],
|
|
14
|
+
"extends": [
|
|
15
|
+
"eslint:recommended",
|
|
16
|
+
"plugin:@typescript-eslint/recommended"
|
|
17
|
+
],
|
|
18
|
+
"ignorePatterns": ["dist/", "node_modules/", "frontend/", "*.js", "src/__tests__/"],
|
|
19
|
+
"rules": {
|
|
20
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
21
|
+
"@typescript-eslint/no-unused-vars": ["warn", {
|
|
22
|
+
"argsIgnorePattern": "^_",
|
|
23
|
+
"varsIgnorePattern": "^_"
|
|
24
|
+
}],
|
|
25
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
26
|
+
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
27
|
+
"no-console": "off",
|
|
28
|
+
"prefer-const": "warn",
|
|
29
|
+
"no-var": "error"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
name: Sync Releases to Gitee
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
tag_name:
|
|
9
|
+
description: 'Tag name to sync (e.g., v1.5.5)'
|
|
10
|
+
required: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
sync-release:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Get release info
|
|
17
|
+
id: release
|
|
18
|
+
run: |
|
|
19
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
20
|
+
TAG_NAME="${{ github.event.inputs.tag_name }}"
|
|
21
|
+
# Fetch release info from GitHub API
|
|
22
|
+
RELEASE_INFO=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
|
23
|
+
"https://api.github.com/repos/${{ github.repository }}/releases/tags/${TAG_NAME}")
|
|
24
|
+
RELEASE_NAME=$(echo "$RELEASE_INFO" | jq -r '.name // .tag_name')
|
|
25
|
+
RELEASE_BODY=$(echo "$RELEASE_INFO" | jq -r '.body // ""')
|
|
26
|
+
PRERELEASE=$(echo "$RELEASE_INFO" | jq -r '.prerelease')
|
|
27
|
+
else
|
|
28
|
+
TAG_NAME="${{ github.event.release.tag_name }}"
|
|
29
|
+
RELEASE_NAME="${{ github.event.release.name }}"
|
|
30
|
+
RELEASE_BODY=$(cat << 'RELEASE_BODY_EOF'
|
|
31
|
+
${{ github.event.release.body }}
|
|
32
|
+
RELEASE_BODY_EOF
|
|
33
|
+
)
|
|
34
|
+
PRERELEASE="${{ github.event.release.prerelease }}"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT
|
|
38
|
+
echo "release_name=${RELEASE_NAME}" >> $GITHUB_OUTPUT
|
|
39
|
+
echo "prerelease=${PRERELEASE}" >> $GITHUB_OUTPUT
|
|
40
|
+
|
|
41
|
+
# Save body to file to handle multiline
|
|
42
|
+
echo "$RELEASE_BODY" > /tmp/release_body.txt
|
|
43
|
+
|
|
44
|
+
- name: Check if release exists on Gitee
|
|
45
|
+
id: check
|
|
46
|
+
run: |
|
|
47
|
+
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
48
|
+
"https://gitee.com/api/v5/repos/alture/hydro-ai-helper/releases/tags/${{ steps.release.outputs.tag_name }}?access_token=${{ secrets.GITEE_ACCESS_TOKEN }}")
|
|
49
|
+
|
|
50
|
+
if [ "$RESPONSE" = "200" ]; then
|
|
51
|
+
echo "exists=true" >> $GITHUB_OUTPUT
|
|
52
|
+
echo "Release already exists on Gitee, will update"
|
|
53
|
+
else
|
|
54
|
+
echo "exists=false" >> $GITHUB_OUTPUT
|
|
55
|
+
echo "Release does not exist on Gitee, will create"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
- name: Create or Update release on Gitee
|
|
59
|
+
run: |
|
|
60
|
+
RELEASE_BODY=$(cat /tmp/release_body.txt)
|
|
61
|
+
TAG_NAME="${{ steps.release.outputs.tag_name }}"
|
|
62
|
+
RELEASE_NAME="${{ steps.release.outputs.release_name }}"
|
|
63
|
+
PRERELEASE="${{ steps.release.outputs.prerelease }}"
|
|
64
|
+
|
|
65
|
+
# Convert prerelease to boolean
|
|
66
|
+
if [ "$PRERELEASE" = "true" ]; then
|
|
67
|
+
PRERELEASE_PARAM="true"
|
|
68
|
+
else
|
|
69
|
+
PRERELEASE_PARAM="false"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [ "${{ steps.check.outputs.exists }}" = "true" ]; then
|
|
73
|
+
# Get existing release ID
|
|
74
|
+
RELEASE_ID=$(curl -s \
|
|
75
|
+
"https://gitee.com/api/v5/repos/alture/hydro-ai-helper/releases/tags/${TAG_NAME}?access_token=${{ secrets.GITEE_ACCESS_TOKEN }}" \
|
|
76
|
+
| jq -r '.id')
|
|
77
|
+
|
|
78
|
+
# Update existing release
|
|
79
|
+
curl -X PATCH \
|
|
80
|
+
"https://gitee.com/api/v5/repos/alture/hydro-ai-helper/releases/${RELEASE_ID}" \
|
|
81
|
+
-H "Content-Type: application/json" \
|
|
82
|
+
-d "$(jq -n \
|
|
83
|
+
--arg token "${{ secrets.GITEE_ACCESS_TOKEN }}" \
|
|
84
|
+
--arg tag "$TAG_NAME" \
|
|
85
|
+
--arg name "$RELEASE_NAME" \
|
|
86
|
+
--arg body "$RELEASE_BODY" \
|
|
87
|
+
--argjson prerelease "$PRERELEASE_PARAM" \
|
|
88
|
+
'{
|
|
89
|
+
access_token: $token,
|
|
90
|
+
tag_name: $tag,
|
|
91
|
+
name: $name,
|
|
92
|
+
body: $body,
|
|
93
|
+
prerelease: $prerelease
|
|
94
|
+
}')"
|
|
95
|
+
|
|
96
|
+
echo "Release updated on Gitee"
|
|
97
|
+
else
|
|
98
|
+
# Create new release
|
|
99
|
+
curl -X POST \
|
|
100
|
+
"https://gitee.com/api/v5/repos/alture/hydro-ai-helper/releases" \
|
|
101
|
+
-H "Content-Type: application/json" \
|
|
102
|
+
-d "$(jq -n \
|
|
103
|
+
--arg token "${{ secrets.GITEE_ACCESS_TOKEN }}" \
|
|
104
|
+
--arg tag "$TAG_NAME" \
|
|
105
|
+
--arg name "$RELEASE_NAME" \
|
|
106
|
+
--arg body "$RELEASE_BODY" \
|
|
107
|
+
--arg branch "main" \
|
|
108
|
+
--argjson prerelease "$PRERELEASE_PARAM" \
|
|
109
|
+
'{
|
|
110
|
+
access_token: $token,
|
|
111
|
+
tag_name: $tag,
|
|
112
|
+
name: $name,
|
|
113
|
+
body: $body,
|
|
114
|
+
target_commitish: $branch,
|
|
115
|
+
prerelease: $prerelease
|
|
116
|
+
}')"
|
|
117
|
+
|
|
118
|
+
echo "Release created on Gitee"
|
|
119
|
+
fi
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Sync to Gitee
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
sync:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
|
|
18
|
+
- name: Setup SSH
|
|
19
|
+
run: |
|
|
20
|
+
mkdir -p ~/.ssh
|
|
21
|
+
echo "${{ secrets.GITEE_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
22
|
+
chmod 600 ~/.ssh/id_rsa
|
|
23
|
+
cat >> ~/.ssh/config << EOF
|
|
24
|
+
Host gitee.com
|
|
25
|
+
HostName gitee.com
|
|
26
|
+
User git
|
|
27
|
+
IdentityFile ~/.ssh/id_rsa
|
|
28
|
+
StrictHostKeyChecking no
|
|
29
|
+
ServerAliveInterval 60
|
|
30
|
+
ServerAliveCountMax 3
|
|
31
|
+
TCPKeepAlive yes
|
|
32
|
+
EOF
|
|
33
|
+
chmod 600 ~/.ssh/config
|
|
34
|
+
|
|
35
|
+
- name: Push to Gitee
|
|
36
|
+
run: |
|
|
37
|
+
git remote add gitee git@gitee.com:alture/hydro-ai-helper.git 2>/dev/null || true
|
|
38
|
+
|
|
39
|
+
# Retry logic for push
|
|
40
|
+
max_retries=3
|
|
41
|
+
retry_count=0
|
|
42
|
+
|
|
43
|
+
until git push gitee main --force; do
|
|
44
|
+
retry_count=$((retry_count + 1))
|
|
45
|
+
if [ $retry_count -ge $max_retries ]; then
|
|
46
|
+
echo "Failed after $max_retries attempts"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
echo "Retry $retry_count/$max_retries in 10 seconds..."
|
|
50
|
+
sleep 10
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
git push gitee --tags --force || true
|
package/.vercelignore
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 排除 HydroOJ 插件相关文件
|
|
2
|
+
src/
|
|
3
|
+
frontend/
|
|
4
|
+
dist/
|
|
5
|
+
specs/
|
|
6
|
+
.specify/
|
|
7
|
+
.claude/
|
|
8
|
+
.chatgpt/
|
|
9
|
+
|
|
10
|
+
# 排除开发文件
|
|
11
|
+
*.md
|
|
12
|
+
!README.md
|
|
13
|
+
tsconfig.json
|
|
14
|
+
tsconfig.vercel.json
|
|
15
|
+
.eslintrc.json
|
|
16
|
+
.gitignore
|
|
17
|
+
|
|
18
|
+
# 排除测试文件
|
|
19
|
+
__tests__/
|
|
20
|
+
*.test.ts
|
|
21
|
+
*.spec.ts
|
|
22
|
+
|
|
23
|
+
# 排除文档
|
|
24
|
+
docs/
|
|
25
|
+
assets/
|
|
26
|
+
DEPLOYMENT*.md
|
|
27
|
+
PHASE*.md
|
|
28
|
+
IMPLEMENTATION*.md
|
|
29
|
+
TROUBLESHOOTING.md
|
|
30
|
+
VERCEL*.md
|
|
31
|
+
QUICKSTART.md
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# 贡献指南
|
|
2
|
+
|
|
3
|
+
感谢您对 HydroOJ AI Helper 的关注!本文档将帮助您了解如何参与项目贡献。
|
|
4
|
+
|
|
5
|
+
## 开发环境配置
|
|
6
|
+
|
|
7
|
+
### 前置要求
|
|
8
|
+
|
|
9
|
+
- Node.js >= 18.0.0
|
|
10
|
+
- npm >= 8.0.0
|
|
11
|
+
- HydroOJ 开发环境(用于集成测试)
|
|
12
|
+
|
|
13
|
+
### 安装步骤
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 克隆仓库
|
|
17
|
+
git clone https://github.com/your-repo/hydro-ai-helper.git
|
|
18
|
+
cd hydro-ai-helper
|
|
19
|
+
|
|
20
|
+
# 安装依赖
|
|
21
|
+
npm install
|
|
22
|
+
|
|
23
|
+
# 编译 TypeScript
|
|
24
|
+
npm run build
|
|
25
|
+
|
|
26
|
+
# 运行代码检查
|
|
27
|
+
npm run lint
|
|
28
|
+
|
|
29
|
+
# 运行测试
|
|
30
|
+
npm test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 代码规范
|
|
34
|
+
|
|
35
|
+
### TypeScript 规范
|
|
36
|
+
|
|
37
|
+
- 使用 TypeScript 严格模式
|
|
38
|
+
- 所有公开 API 必须有类型定义
|
|
39
|
+
- 避免使用 `any` 类型,必要时使用类型断言并添加注释说明原因
|
|
40
|
+
|
|
41
|
+
### ESLint 规范
|
|
42
|
+
|
|
43
|
+
项目使用 ESLint 进行代码检查。提交前请确保:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm run lint
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
无任何错误或警告。
|
|
50
|
+
|
|
51
|
+
### 命名约定
|
|
52
|
+
|
|
53
|
+
- 文件名:使用 camelCase(如 `promptService.ts`)
|
|
54
|
+
- 类名:使用 PascalCase(如 `PromptService`)
|
|
55
|
+
- 函数/变量:使用 camelCase(如 `buildSystemPrompt`)
|
|
56
|
+
- 常量:使用 UPPER_SNAKE_CASE(如 `DEFAULT_RATE_LIMIT`)
|
|
57
|
+
- 接口:使用 PascalCase,无 `I` 前缀(如 `ChatRequest`)
|
|
58
|
+
|
|
59
|
+
### 目录结构
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
src/
|
|
63
|
+
├── handlers/ # HTTP 请求处理器
|
|
64
|
+
├── services/ # 业务逻辑服务
|
|
65
|
+
├── models/ # 数据模型
|
|
66
|
+
├── utils/ # 工具函数
|
|
67
|
+
├── types/ # 类型定义
|
|
68
|
+
├── constants/ # 常量定义
|
|
69
|
+
├── lib/ # 通用库函数
|
|
70
|
+
└── __tests__/ # 单元测试
|
|
71
|
+
├── services/
|
|
72
|
+
├── utils/
|
|
73
|
+
└── __mocks__/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 测试要求
|
|
77
|
+
|
|
78
|
+
### 单元测试
|
|
79
|
+
|
|
80
|
+
- 使用 Jest 作为测试框架
|
|
81
|
+
- 测试文件放在 `src/__tests__/` 目录下
|
|
82
|
+
- 测试文件命名:`*.test.ts`
|
|
83
|
+
|
|
84
|
+
运行测试:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# 运行所有测试
|
|
88
|
+
npm test
|
|
89
|
+
|
|
90
|
+
# 运行特定测试文件
|
|
91
|
+
npm test -- --testPathPattern="promptService"
|
|
92
|
+
|
|
93
|
+
# 生成覆盖率报告
|
|
94
|
+
npm test -- --coverage
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 集成测试
|
|
98
|
+
|
|
99
|
+
集成测试脚本位于 `tests/integration/` 目录,使用 curl 进行 API 测试。
|
|
100
|
+
|
|
101
|
+
## PR 提交流程
|
|
102
|
+
|
|
103
|
+
### 1. 创建分支
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git checkout -b feature/your-feature-name
|
|
107
|
+
# 或
|
|
108
|
+
git checkout -b fix/your-bug-fix
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 2. 开发与测试
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# 开发时使用 watch 模式
|
|
115
|
+
npm run dev
|
|
116
|
+
|
|
117
|
+
# 确保代码检查通过
|
|
118
|
+
npm run lint
|
|
119
|
+
|
|
120
|
+
# 确保测试通过
|
|
121
|
+
npm test
|
|
122
|
+
|
|
123
|
+
# 确保构建成功
|
|
124
|
+
npm run build
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 3. 提交规范
|
|
128
|
+
|
|
129
|
+
使用语义化提交信息:
|
|
130
|
+
|
|
131
|
+
- `feat:` 新功能
|
|
132
|
+
- `fix:` Bug 修复
|
|
133
|
+
- `docs:` 文档更新
|
|
134
|
+
- `style:` 代码格式调整(不影响逻辑)
|
|
135
|
+
- `refactor:` 代码重构
|
|
136
|
+
- `test:` 测试相关
|
|
137
|
+
- `chore:` 构建/工具链相关
|
|
138
|
+
|
|
139
|
+
示例:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
git commit -m "feat: add rate limit service for API throttling"
|
|
143
|
+
git commit -m "fix: handle edge case in prompt validation"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 4. 创建 Pull Request
|
|
147
|
+
|
|
148
|
+
- 标题简洁明了,说明改动内容
|
|
149
|
+
- 描述中说明改动原因和实现方式
|
|
150
|
+
- 关联相关 Issue(如有)
|
|
151
|
+
- 确保 CI 检查全部通过
|
|
152
|
+
|
|
153
|
+
## 问题反馈
|
|
154
|
+
|
|
155
|
+
如发现 Bug 或有功能建议,请通过 GitHub Issues 提交,并提供:
|
|
156
|
+
|
|
157
|
+
- 问题描述
|
|
158
|
+
- 复现步骤
|
|
159
|
+
- 预期行为
|
|
160
|
+
- 实际行为
|
|
161
|
+
- 环境信息(Node.js 版本、HydroOJ 版本等)
|
|
162
|
+
|
|
163
|
+
## 许可证
|
|
164
|
+
|
|
165
|
+
本项目采用 MIT 许可证。提交贡献即表示您同意将代码以 MIT 许可证发布。
|
package/README.md
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# HydroOJ AI 学习助手
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
一个以教学为优先的 AI 辅助学习插件,帮助学生在解题过程中获得思路引导而非直接答案。
|
|
16
|
+
|
|
17
|
+
## 特色功能
|
|
18
|
+
|
|
19
|
+
### 多轮对话与上下文理解
|
|
20
|
+
|
|
21
|
+
- **连续追问**:学生可以在同一对话中持续追问,AI 能够理解并引用之前的对话内容
|
|
22
|
+
- **对话持久化**:页面刷新后对话记录自动恢复,按题目隔离
|
|
23
|
+
- **智能截断**:对话历史超过 7 条时自动截取最近消息,防止 token 超限
|
|
24
|
+
|
|
25
|
+
### 选中答疑("我不理解"功能)
|
|
26
|
+
|
|
27
|
+
- **精准追问**:在 AI 回复中选中不理解的文字,弹出"我不理解"按钮
|
|
28
|
+
- **选中高亮保持**:点击按钮时选中状态保留,清晰标识追问内容
|
|
29
|
+
- **简洁回复**:针对选中内容的解释限制在 2 段以内,直击要点
|
|
30
|
+
- **支持历史消息**:可对任意一条 AI 历史回复使用选中答疑
|
|
31
|
+
|
|
32
|
+
### 差异化问题类型
|
|
33
|
+
|
|
34
|
+
| 类型 | 说明 | 回复风格 |
|
|
35
|
+
| -------- | ------------------------ | ---------------------- |
|
|
36
|
+
| 理解题意 | 对题目要求不太清楚 | 详细解释,循序渐进 |
|
|
37
|
+
| 理清思路 | 需要帮助梳理解题思路 | 结构化框架,有层次 |
|
|
38
|
+
| 分析错误 | 代码有问题,需要找出原因 | 简洁直接,快速定位 |
|
|
39
|
+
| 代码优化 | 已 AC 后寻求效率提升 | 复杂度分析,启发式引导 |
|
|
40
|
+
|
|
41
|
+
### 代码优化功能(v1.8.0)
|
|
42
|
+
|
|
43
|
+
- **AC 专属**:仅对已通过该题的用户显示"代码优化"选项
|
|
44
|
+
- **实时检测**:提交 AC 后自动在 AI 面板显示优化选项,无需刷新页面
|
|
45
|
+
- **代码加载确认**:选择优化时弹出确认框,可选择加载 AC 代码或使用当前代码
|
|
46
|
+
- **启发式引导**:AI 分析时间/空间复杂度,提供优化方向但不直接给出代码
|
|
47
|
+
- **服务端校验**:后端验证 AC 状态,防止绕过前端限制
|
|
48
|
+
|
|
49
|
+
### 统一管理入口(v1.6.0)
|
|
50
|
+
|
|
51
|
+
- **单一菜单**:控制面板中只有一个"AI 助手"入口,整合原有三个分散菜单
|
|
52
|
+
- **Tab 切换**:通过选项卡在对话记录、使用统计、AI 配置之间切换
|
|
53
|
+
- **URL 参数**:支持 `?tab=conversations|analytics|config` 直接跳转特定功能
|
|
54
|
+
- **浏览器导航**:Tab 切换支持前进/后退按钮
|
|
55
|
+
|
|
56
|
+
### 教师端数据分析
|
|
57
|
+
|
|
58
|
+
- **多维度统计**:按班级/学生/题目查看 AI 使用情况
|
|
59
|
+
- **可排序表格**:点击表头对任意列升序/降序排序
|
|
60
|
+
- **快捷跳转**:点击题目名称跳转详情页,点击对话数跳转筛选后的记录列表
|
|
61
|
+
- **数据导出**:支持 CSV 导出
|
|
62
|
+
|
|
63
|
+
### 多 API 端点与模型管理
|
|
64
|
+
|
|
65
|
+
- **多端点配置**:支持添加多个 API 端点,实现负载均衡和容灾
|
|
66
|
+
- **模型自动获取**:调用 `/models` 端点自动获取可用模型列表,无需手动输入
|
|
67
|
+
- **Fallback 机制**:选择多个模型按优先级排序,首选模型不可用时自动切换备选
|
|
68
|
+
- **拖拽排序**:拖拽模型卡片调整优先级顺序
|
|
69
|
+
- **API Key 加密**:使用 AES-256-GCM 加密存储 API Key
|
|
70
|
+
|
|
71
|
+
### 安全增强
|
|
72
|
+
|
|
73
|
+
- **越狱检测**:拦截试图绕过 AI 辅导限制的请求
|
|
74
|
+
- **白名单机制**:可信题目内容从服务端获取,避免误报
|
|
75
|
+
- **越狱记录**:支持分页查看越狱记录,便于管理员审计
|
|
76
|
+
|
|
77
|
+
### 现代化 UI
|
|
78
|
+
|
|
79
|
+
- **三列布局**:宽屏设备(≥1200px)自动切换 LeetCode 风格布局(题目 | 代码 | AI 对话)
|
|
80
|
+
- **响应式设计**:窄屏设备显示浮动对话面板
|
|
81
|
+
- **面板宽度可调**:拖拽 AI 面板左边缘调整宽度(300-900px)
|
|
82
|
+
- **统一主题**:紫色渐变主色调,圆角卡片设计
|
|
83
|
+
|
|
84
|
+
## 核心特性
|
|
85
|
+
|
|
86
|
+
**学生端**:题目页面浮动对话面板、自动读取题目、问题类型选择、可选附带代码、多轮对话、选中答疑、代码优化(AC 后)
|
|
87
|
+
|
|
88
|
+
**教师端**:查看学生对话记录、按时间/题目/班级/学生筛选、可排序统计表格、导出 CSV(支持脱敏)
|
|
89
|
+
|
|
90
|
+
**管理员端**:统一 AI 助手管理入口、配置多个 API 端点、自动获取模型列表、模型优先级与 Fallback、频率限制、System Prompt 自定义、越狱记录分页查看
|
|
91
|
+
|
|
92
|
+
## 安装
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# 克隆并构建
|
|
96
|
+
git clone https://github.com/AltureT/hydro-ai-helper.git
|
|
97
|
+
cd hydro-ai-helper
|
|
98
|
+
npm install
|
|
99
|
+
npm run build
|
|
100
|
+
|
|
101
|
+
# 安装到 HydroOJ
|
|
102
|
+
hydrooj addon add /path/to/hydro-ai-helper
|
|
103
|
+
pm2 restart hydrooj
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
验证:访问 `/ai-helper/hello` 返回 JSON 即表示成功。
|
|
107
|
+
|
|
108
|
+
## 配置
|
|
109
|
+
|
|
110
|
+
### 环境变量
|
|
111
|
+
|
|
112
|
+
设置 `ENCRYPTION_KEY`(32 字符)用于加密 API Key:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
export ENCRYPTION_KEY="your-32-character-secret-key!!!"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
生成随机密钥:`openssl rand -base64 24 | head -c 32`
|
|
119
|
+
|
|
120
|
+
### 管理员配置
|
|
121
|
+
|
|
122
|
+
登录后访问 **控制面板 → AI 助手**(`/ai-helper`),切换到"AI 配置" Tab:
|
|
123
|
+
|
|
124
|
+
#### API 端点配置
|
|
125
|
+
|
|
126
|
+
支持添加多个 API 端点,每个端点包含:
|
|
127
|
+
|
|
128
|
+
| 字段 | 说明 | 示例 |
|
|
129
|
+
| ------------ | -------------------- | --------------------------- |
|
|
130
|
+
| 端点名称 | 自定义名称 | `主服务`、`备用服务` |
|
|
131
|
+
| API Base URL | AI 服务地址 | `https://api.openai.com/v1` |
|
|
132
|
+
| API Key | API 密钥(加密存储) | `sk-...` |
|
|
133
|
+
| 启用状态 | 是否参与 AI 调用 | 开启/关闭 |
|
|
134
|
+
|
|
135
|
+
点击「获取模型」按钮自动获取该端点可用的模型列表。
|
|
136
|
+
|
|
137
|
+
#### 模型选择与优先级
|
|
138
|
+
|
|
139
|
+
从所有启用端点的模型中选择需要使用的模型,通过拖拽调整优先级顺序。当首选模型不可用时(限流、服务器错误等),系统自动尝试备选模型。
|
|
140
|
+
|
|
141
|
+
#### 其他配置
|
|
142
|
+
|
|
143
|
+
| 字段 | 说明 | 默认值 |
|
|
144
|
+
| ------------- | ------------------ | ------------------ |
|
|
145
|
+
| 频率限制 | 每用户每分钟请求数 | `5` |
|
|
146
|
+
| System Prompt | AI 系统提示词 | 内置教学辅导提示词 |
|
|
147
|
+
|
|
148
|
+
配置后点击「测试连接」验证,然后保存。
|
|
149
|
+
|
|
150
|
+
## 使用
|
|
151
|
+
|
|
152
|
+
### 学生
|
|
153
|
+
|
|
154
|
+
1. 访问题目详情页,右下角展开 AI 面板(宽屏自动显示右侧栏)
|
|
155
|
+
2. 选择问题类型(理解题意/理清思路/分析错误)
|
|
156
|
+
3. 可选:描述你的理解和尝试
|
|
157
|
+
4. 可选:附带当前代码
|
|
158
|
+
5. 发送后查看 AI 引导式回答
|
|
159
|
+
6. 如有不理解的地方,选中文字点击"我不理解"继续追问
|
|
160
|
+
7. AC 后可使用"代码优化"功能,获取效率提升建议
|
|
161
|
+
|
|
162
|
+
### 教师/管理员
|
|
163
|
+
|
|
164
|
+
访问 **控制面板 → AI 助手**(`/ai-helper`),通过 Tab 切换访问:
|
|
165
|
+
|
|
166
|
+
- **对话记录** Tab:查看学生对话记录,支持按时间/题目/班级/学生筛选
|
|
167
|
+
- **使用统计** Tab:查看 AI 使用统计数据,支持多维度分析
|
|
168
|
+
- **AI 配置** Tab(仅管理员):配置 API 端点、模型优先级、系统提示词等
|
|
169
|
+
|
|
170
|
+
支持 URL 参数直接跳转:`/ai-helper?tab=analytics`、`/ai-helper?tab=config`
|
|
171
|
+
|
|
172
|
+
数据导出:在对话列表页点击"导出数据"
|
|
173
|
+
|
|
174
|
+
### 示例截图
|
|
175
|
+
|
|
176
|
+
**学生端问答面板与题目联动示例:**
|
|
177
|
+
|
|
178
|
+
<img src="assets/screenshots/1.png" alt="学生端示例" width="800">
|
|
179
|
+
|
|
180
|
+
<img src="assets/screenshots/2.png" alt="学生端示例" width="400">
|
|
181
|
+
|
|
182
|
+
**后台管理:**
|
|
183
|
+
|
|
184
|
+
<img src="assets/screenshots/3.png" alt="后台管理示例" width="800">
|
|
185
|
+
|
|
186
|
+
<img src="assets/screenshots/4.png" alt="后台管理示例" width="800">
|
|
187
|
+
|
|
188
|
+
<img src="assets/screenshots/5.png" alt="后台管理示例" width="800">
|
|
189
|
+
|
|
190
|
+
<img src="assets/screenshots/6.png" alt="后台管理示例" width="400">
|
|
191
|
+
|
|
192
|
+
<img src="assets/screenshots/7.png" alt="后台管理示例" width="500">
|
|
193
|
+
|
|
194
|
+
## 项目结构
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
hydro-ai-helper/
|
|
198
|
+
├── src/ # 后端(TypeScript)
|
|
199
|
+
│ ├── models/ # 数据模型
|
|
200
|
+
│ ├── services/ # 业务逻辑
|
|
201
|
+
│ ├── handlers/ # 路由处理器
|
|
202
|
+
│ └── lib/ # 工具函数
|
|
203
|
+
├── frontend/ # 前端(React)
|
|
204
|
+
│ ├── student/ # 学生端组件
|
|
205
|
+
│ ├── teacher/ # 教师端组件
|
|
206
|
+
│ ├── admin/ # 管理员组件
|
|
207
|
+
│ └── components/ # 通用组件(如 Tab 容器)
|
|
208
|
+
└── dist/ # 编译输出
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 开发
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm run dev # 开发模式(watch)
|
|
215
|
+
npm run build # 构建
|
|
216
|
+
npm run lint # 代码检查
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 遥测与隐私
|
|
220
|
+
|
|
221
|
+
### 数据收集说明
|
|
222
|
+
|
|
223
|
+
为了更好地了解插件使用情况并改进功能,本插件会收集以下**匿名统计数据**:
|
|
224
|
+
|
|
225
|
+
- 插件安装数(通过随机 UUID 去重)
|
|
226
|
+
- 最近 7 天活跃用户数(聚合统计)
|
|
227
|
+
- 总对话数
|
|
228
|
+
- 插件版本信息
|
|
229
|
+
|
|
230
|
+
### 隐私保护措施
|
|
231
|
+
|
|
232
|
+
✅ **完全匿名**:使用随机 UUID,不收集任何可识别个人身份的信息
|
|
233
|
+
✅ **域名哈希**:域 ID 经过 SHA-256 哈希处理
|
|
234
|
+
✅ **仅聚合数据**:只统计用户数和对话数,不记录具体内容
|
|
235
|
+
✅ **自动清理**:90 天未上报的数据自动删除
|
|
236
|
+
✅ **用户可控**:可通过管理员配置关闭遥测功能
|
|
237
|
+
|
|
238
|
+
### 如何关闭遥测
|
|
239
|
+
|
|
240
|
+
如果你不希望上报统计数据,可以在数据库中设置:
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
// 连接到 MongoDB
|
|
244
|
+
use your_hydro_db
|
|
245
|
+
|
|
246
|
+
// 关闭遥测
|
|
247
|
+
db.ai_plugin_install.updateOne(
|
|
248
|
+
{ _id: 'install' },
|
|
249
|
+
{ $set: { telemetryEnabled: false } }
|
|
250
|
+
)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
关闭后,插件仍可正常使用,但不会上报任何数据。
|
|
254
|
+
|
|
255
|
+
### 数据用途
|
|
256
|
+
|
|
257
|
+
收集的数据仅用于:
|
|
258
|
+
- 在 GitHub README 显示安装数和活跃用户数徽章
|
|
259
|
+
- 了解插件使用趋势,优先开发最需要的功能
|
|
260
|
+
- 评估插件稳定性和性能
|
|
261
|
+
|
|
262
|
+
**我们承诺**:
|
|
263
|
+
- ❌ 不会出售或共享数据给第三方
|
|
264
|
+
- ❌ 不会收集学生的代码、题目内容或对话记录
|
|
265
|
+
- ❌ 不会追踪个人用户行为
|
|
266
|
+
|
|
267
|
+
## 关于本项目
|
|
268
|
+
|
|
269
|
+
本项目是 [HydroOJ](https://github.com/hydro-dev/Hydro) 开源在线评测系统的第三方插件,由 AI 辅助开发完成。如有问题或建议,欢迎提交 Issue。
|
|
270
|
+
|
|
271
|
+
## 许可证
|
|
272
|
+
|
|
273
|
+
MIT License
|