Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
435beaffbb | ||
|
|
3f504976ea | ||
|
|
81dfb4fc3e | ||
|
|
a71feea4fd | ||
|
|
9f620e84f8 | ||
|
|
a1cfb045ba | ||
|
|
e106a8bfdc | ||
|
|
e6bcf0db15 | ||
|
|
943faf0ba9 |
+93
-23
@@ -4,7 +4,7 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
description: '部署环境'
|
||||
description: '部署环境(本仓库仅 main 分支;dev/prod 均从 main 部署)'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
@@ -19,67 +19,137 @@ env:
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
KUBECONFIG: /tmp/kubeconfig
|
||||
steps:
|
||||
- name: Validate branch ↔ environment
|
||||
run: |
|
||||
set -euo pipefail
|
||||
REF="${{ gitea.ref }}"
|
||||
BRANCH="${REF#refs/heads/}"
|
||||
if [[ "$REF" == refs/tags/* ]]; then
|
||||
echo "ERROR: 请从分支触发部署,不要用 tag。当前 ref=$REF"
|
||||
exit 1
|
||||
fi
|
||||
ENV="${{ inputs.environment }}"
|
||||
echo "branch=$BRANCH environment=$ENV sha=${{ gitea.sha }}"
|
||||
# lpt-ai 仅维护 main:dev/prod 都从 main 出包,靠 environment 区分 namespace/镜像 tag
|
||||
case "$BRANCH" in
|
||||
main|master)
|
||||
echo "OK: lpt-ai 从 $BRANCH 部署到 $ENV"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: lpt-ai 只能从 main/master 部署,当前分支是 '$BRANCH'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case "$ENV" in
|
||||
dev|prod) ;;
|
||||
*)
|
||||
echo "ERROR: 未知 environment=$ENV"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Checkout code
|
||||
run: |
|
||||
git clone $REPO_URL .
|
||||
git checkout ${{ gitea.sha }}
|
||||
set -euo pipefail
|
||||
git clone "$REPO_URL" .
|
||||
git checkout "${{ gitea.sha }}"
|
||||
|
||||
- name: Login to Docker Registry
|
||||
run: |
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login $REGISTRY -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||
set -euo pipefail
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "$REGISTRY" -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||
|
||||
- name: Build & Push Docker image
|
||||
run: |
|
||||
TAG=${{ gitea.sha }}-$(date +%s)
|
||||
docker build -t $REGISTRY/$APP:$TAG -t $REGISTRY/$APP:${{ inputs.environment }} .
|
||||
docker push $REGISTRY/$APP:$TAG
|
||||
docker push $REGISTRY/$APP:${{ inputs.environment }}
|
||||
echo "IMAGE_TAG=$TAG" >> $GITHUB_ENV
|
||||
set -euo pipefail
|
||||
ENV="${{ inputs.environment }}"
|
||||
TAG="${{ gitea.sha }}-$(date +%s)"
|
||||
echo "Building $REGISTRY/$APP:$TAG (env tag=$ENV)"
|
||||
docker build -t "$REGISTRY/$APP:$TAG" -t "$REGISTRY/$APP:$ENV" .
|
||||
docker push "$REGISTRY/$APP:$TAG"
|
||||
docker push "$REGISTRY/$APP:$ENV"
|
||||
if [ -n "${GITHUB_ENV:-}" ]; then
|
||||
echo "IMAGE_TAG=$TAG" >> "$GITHUB_ENV"
|
||||
fi
|
||||
if [ -n "${GITEA_ENV:-}" ]; then
|
||||
echo "IMAGE_TAG=$TAG" >> "$GITEA_ENV"
|
||||
fi
|
||||
echo "$TAG" > image_tag.txt
|
||||
if [ -n "${{ runner.temp }}" ]; then
|
||||
echo "$TAG" > "${{ runner.temp }}/image_tag.txt" || true
|
||||
fi
|
||||
echo "IMAGE_TAG=$TAG"
|
||||
|
||||
- name: Setup kubectl
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -sLO "https://dl.k8s.io/release/v1.30.0/bin/linux/amd64/kubectl"
|
||||
chmod +x kubectl
|
||||
mv kubectl /usr/local/bin/
|
||||
mkdir -p ~/.kube
|
||||
echo "${{ secrets.KUBECONFIG_B64 }}" | base64 -d > ~/.kube/config
|
||||
echo "${{ secrets.KUBECONFIG_B64 }}" | base64 -d > /tmp/kubeconfig
|
||||
chmod 600 /tmp/kubeconfig
|
||||
|
||||
- name: Create/Update imagePullSecret
|
||||
run: |
|
||||
set -euo pipefail
|
||||
kubectl create secret docker-registry regcred \
|
||||
--docker-server=$REGISTRY \
|
||||
--docker-server="$REGISTRY" \
|
||||
--docker-username="${{ secrets.REGISTRY_USERNAME }}" \
|
||||
--docker-password="${{ secrets.REGISTRY_PASSWORD }}" \
|
||||
-n lpt-${{ inputs.environment }} \
|
||||
-n "lpt-${{ inputs.environment }}" \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
- name: Deploy to K8s
|
||||
run: |
|
||||
kubectl set image deployment/$APP $APP=$REGISTRY/$APP:$IMAGE_TAG -n lpt-${{ inputs.environment }} --record
|
||||
kubectl rollout status deployment/$APP -n lpt-${{ inputs.environment }} --timeout=5m
|
||||
set -euo pipefail
|
||||
ENV="${{ inputs.environment }}"
|
||||
IMAGE_TAG="${IMAGE_TAG:-}"
|
||||
if [ -z "$IMAGE_TAG" ] && [ -f image_tag.txt ]; then
|
||||
IMAGE_TAG="$(cat image_tag.txt)"
|
||||
fi
|
||||
if [ -z "$IMAGE_TAG" ] && [ -f "${{ runner.temp }}/image_tag.txt" ]; then
|
||||
IMAGE_TAG="$(cat "${{ runner.temp }}/image_tag.txt")"
|
||||
fi
|
||||
if [ -z "$IMAGE_TAG" ]; then
|
||||
echo "ERROR: IMAGE_TAG 为空,无法部署"
|
||||
exit 1
|
||||
fi
|
||||
echo "Deploying $REGISTRY/$APP:$IMAGE_TAG -> namespace lpt-$ENV"
|
||||
kubectl set image "deployment/$APP" \
|
||||
"$APP=$REGISTRY/$APP:$IMAGE_TAG" \
|
||||
-n "lpt-$ENV" --record
|
||||
kubectl rollout status "deployment/$APP" \
|
||||
-n "lpt-$ENV" --timeout=5m
|
||||
|
||||
- name: Debug on failure
|
||||
if: failure()
|
||||
run: |
|
||||
ENV="${{ inputs.environment }}"
|
||||
echo "=== Deployment Status ==="
|
||||
kubectl get deployment $APP -n lpt-${{ inputs.environment }}
|
||||
kubectl get deployment "$APP" -n "lpt-$ENV" || true
|
||||
echo ""
|
||||
echo "=== Pod Status ==="
|
||||
kubectl get pods -n lpt-${{ inputs.environment }} -l app=$APP
|
||||
kubectl get pods -n "lpt-$ENV" -l "app=$APP" || true
|
||||
echo ""
|
||||
echo "=== Recent Events ==="
|
||||
kubectl get events -n lpt-${{ inputs.environment }} --sort-by='.lastTimestamp' | tail -20
|
||||
kubectl get events -n "lpt-$ENV" --sort-by='.lastTimestamp' | tail -20 || true
|
||||
echo ""
|
||||
echo "=== Pod Describe (latest) ==="
|
||||
POD=$(kubectl get pods -n lpt-${{ inputs.environment }} -l app=$APP --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[-1].metadata.name}')
|
||||
kubectl describe pod $POD -n lpt-${{ inputs.environment }} || true
|
||||
POD=$(kubectl get pods -n "lpt-$ENV" -l "app=$APP" --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[-1].metadata.name}' 2>/dev/null || true)
|
||||
if [ -n "${POD:-}" ]; then
|
||||
kubectl describe pod "$POD" -n "lpt-$ENV" || true
|
||||
echo ""
|
||||
echo "=== Pod Logs (latest) ==="
|
||||
kubectl logs $POD -n lpt-${{ inputs.environment }} --tail=50 || true
|
||||
kubectl logs "$POD" -n "lpt-$ENV" --tail=50 || true
|
||||
fi
|
||||
|
||||
- name: Rollback on failure
|
||||
if: failure()
|
||||
run: |
|
||||
kubectl rollout undo deployment/$APP -n lpt-${{ inputs.environment }}
|
||||
kubectl rollout status deployment/$APP -n lpt-${{ inputs.environment }}
|
||||
set -euo pipefail
|
||||
ENV="${{ inputs.environment }}"
|
||||
kubectl rollout undo "deployment/$APP" -n "lpt-$ENV" || true
|
||||
kubectl rollout status "deployment/$APP" -n "lpt-$ENV" || true
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
# LPT AI 服务(lpt-ai)
|
||||
|
||||
> TypeScript + Fastify 独立 AI 服务,集成 SiliconFlow LLM,为后端提供异步 AI 任务。
|
||||
|
||||
## Git 提交规范
|
||||
|
||||
- 提交信息必须简短且使用中文,不要使用英文长句。
|
||||
- 格式:`类型: 简述`,例如 `feat: 新增思维导图生成任务`、`fix: 修复任务队列TTL清理`、`docs: 补充环境变量说明`。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- 运行时:Node.js 20+
|
||||
- 框架:Fastify 5
|
||||
- LLM:SiliconFlow OpenAI 兼容接口(Qwen/Qwen2.5-32B-Instruct)
|
||||
- 运行时依赖:除 fastify 外无其他外部依赖
|
||||
|
||||
## 项目结构
|
||||
|
||||
```text
|
||||
lpt-ai/src/
|
||||
├── index.ts → 服务入口(加载 .env,启动 Fastify)
|
||||
├── routes/ai.ts → AI 路由(health, tasks, fetch-title)
|
||||
├── llm/
|
||||
│ ├── client.ts → LLM 客户端(SiliconFlow 接口)
|
||||
│ ├── prompts.ts → Prompt 模板(3 种任务类型)
|
||||
│ └── prompts.test.ts
|
||||
├── task-queue.ts → 异步任务队列
|
||||
└── admin/
|
||||
├── index.ts → 管理面板路由
|
||||
├── routes.ts
|
||||
└── store.ts → 日志存储
|
||||
```
|
||||
|
||||
## API 端点(5 个)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/health` | 健康检查(返回 LLM 可用状态和模型名) |
|
||||
| POST | `/ai/tasks` | 提交异步任务(返回 taskId) |
|
||||
| GET | `/ai/tasks/:taskId` | 轮询任务结果 |
|
||||
| POST | `/fetch-title` | 抓取网页标题 |
|
||||
| GET | `/admin` | 管理面板(查看最近 200 条日志) |
|
||||
|
||||
## 支持的任务类型
|
||||
|
||||
| 类型 | 说明 | 温度 | Max Tokens |
|
||||
|------|------|------|------------|
|
||||
| `aggregate-report` | 残片聚合为学习报告 | 0.3 | 2048 |
|
||||
| `generate-mind-map` | 从报告/残片生成思维导图大纲 | 0.3 | 4096 |
|
||||
| `compare-recall` | 用户回忆 vs 标准导图语义对比 | 0.2 | 4096 |
|
||||
|
||||
## 任务队列设计
|
||||
|
||||
- 异步任务模式:submit + poll,避免 LLM 长耗时(10-60s)超时。
|
||||
- 单线程 Worker:`setImmediate` 链,同一时刻只处理一个 LLM 调用,防止 API 限流。
|
||||
- TTL 清理:5 分钟一次,移除完成超过 1 小时的记录。
|
||||
- 异常隔离:单个任务失败不影响后续任务。
|
||||
- 管理面板日志:复用 `logStore`,记录最近 200 条请求/响应。
|
||||
|
||||
## LLM 配置
|
||||
|
||||
```env
|
||||
LLM_API_URL=https://api.siliconflow.cn/v1/chat/completions
|
||||
LLM_API_KEY= # 必填,未配置时 /health 返回 llmAvailable: false
|
||||
LLM_MODEL=Qwen/Qwen2.5-32B-Instruct
|
||||
LLM_TIMEOUT_MS=60000 # 单次 LLM 调用超时
|
||||
PORT=5199
|
||||
```
|
||||
|
||||
## 降级策略
|
||||
|
||||
- LLM API Key 未配置 → `/health` 返回 `llmAvailable: false`。
|
||||
- 后端(lpt-be)检测到 AI 不可用 → 自动切换到内置规则引擎(`BuiltinMindMapGenerator`)。
|
||||
- Java 后端是唯一调用方;本服务不直接暴露给前端,不做鉴权(部署在内网)。
|
||||
|
||||
## 启动命令
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # 开发模式(tsx watch,热重载)
|
||||
npm run build # 编译 TypeScript
|
||||
npm run start # 生产模式
|
||||
npm run test # 测试
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
- 多阶段构建:`node:20-alpine` 编译 → `node:20-alpine` 运行。
|
||||
- 暴露端口:5199。
|
||||
- 健康检查:`curl http://localhost:5199/health`。
|
||||
|
||||
## 关联项目
|
||||
|
||||
| 项目 | 路径 | 端口 | 说明 |
|
||||
|------|------|------|------|
|
||||
| lpt-be | `../lpt-be/` | 5157 | Spring Boot 后端,通过 `lpt.ai-service.url` 调用本服务 |
|
||||
| lpt-fe | `../lpt-fe/` | 5158 | Vue 3 前端,不直接调用本服务 |
|
||||
|
||||
## 调用关系
|
||||
|
||||
```text
|
||||
lpt-be (5157) ──HTTP POST /ai/tasks──→ lpt-ai (5199)
|
||||
lpt-be (5157) ──HTTP GET /ai/tasks/:id──→ lpt-ai (5199)
|
||||
```
|
||||
@@ -85,7 +85,7 @@ curl http://localhost:5199/ai/tasks/550e8400-e29b-41d4-a716-446655440000
|
||||
| type | 说明 | params 字段 |
|
||||
|------|------|------------|
|
||||
| `aggregate-report` | 聚合学习残片为报告 | `taskName`, `expectation`, `fragments[]` |
|
||||
| `generate-mind-map` | 生成思维导图大纲 | `taskName`, `reports[]`, `fragments[]`, `applications[]` |
|
||||
| `generate-mind-map` | 生成思维导图大纲 | `taskName`, `reports[]`, `applications[]` |
|
||||
| `compare-recall` | 对比用户回忆与标准导图 | `taskName`, `standardOutline`, `recallOutline` |
|
||||
|
||||
## 架构位置
|
||||
|
||||
-131
@@ -1,131 +0,0 @@
|
||||
# Kubernetes Configuration for LPT Project
|
||||
|
||||
This directory contains the shared Kubernetes configuration files for the LPT (Learning Progress Tracker) project.
|
||||
|
||||
## Files
|
||||
|
||||
### ConfigMap
|
||||
- **`configmap.yaml`** - Shared environment variables for all services
|
||||
- LLM API configuration (URL, model, timeout)
|
||||
- Database connection string
|
||||
- Service URLs
|
||||
|
||||
### Secrets (Templates)
|
||||
- **`lpt-secrets.yaml`** - Application secrets template
|
||||
- LLM API key
|
||||
- MySQL root password
|
||||
- **⚠️ DO NOT commit real secrets!** Use the template to create secrets manually.
|
||||
|
||||
- **`regcred-secret.yaml`** - Docker registry authentication template
|
||||
- Used for pulling images from private registry (192.168.123.199:5000)
|
||||
- **⚠️ Managed by Gitea Actions workflow** - DO NOT commit real credentials!
|
||||
|
||||
### Service-Specific Configurations
|
||||
Each service has its own `k8s/` directory with deployment and service configs:
|
||||
- **`lpt-fe/k8s/`** - Frontend deployment (Nginx + Vue 3)
|
||||
- **`lpt-be/k8s/`** - Backend deployment (Spring Boot)
|
||||
- **`lpt-ai/k8s/`** - AI service deployment (Python FastAPI)
|
||||
|
||||
## Deployment
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1. **Create namespace**:
|
||||
```bash
|
||||
kubectl create namespace lpt-dev
|
||||
```
|
||||
|
||||
2. **Apply shared ConfigMap**:
|
||||
```bash
|
||||
kubectl apply -f k8s/configmap.yaml
|
||||
```
|
||||
|
||||
3. **Create secrets** (replace with actual values):
|
||||
```bash
|
||||
# Application secrets
|
||||
kubectl create secret generic lpt-secrets \
|
||||
--from-literal=llm-api-key=<YOUR_LLM_API_KEY> \
|
||||
--from-literal=mysql-root-password=<YOUR_MYSQL_ROOT_PASSWORD> \
|
||||
--namespace=lpt-dev
|
||||
|
||||
# Registry credentials (for manual creation, or use Gitea workflow)
|
||||
kubectl create secret docker-registry regcred \
|
||||
--docker-server=192.168.123.199:5000 \
|
||||
--docker-username=admin \
|
||||
--docker-password=<REGISTRY_PASSWORD> \
|
||||
--namespace=lpt-dev
|
||||
```
|
||||
|
||||
4. **Deploy services**:
|
||||
```bash
|
||||
# Frontend
|
||||
kubectl apply -f lpt-fe/k8s/
|
||||
|
||||
# Backend
|
||||
kubectl apply -f lpt-be/k8s/
|
||||
|
||||
# AI Service
|
||||
kubectl apply -f lpt-ai/k8s/
|
||||
```
|
||||
|
||||
### CI/CD Workflow
|
||||
|
||||
The Gitea Actions workflows (`.gitea/workflows/deploy.yml` in each service) automatically:
|
||||
1. Build Docker images
|
||||
2. Push to private registry (192.168.123.199:5000)
|
||||
3. Create/update `regcred` secret with credentials from Gitea secrets
|
||||
4. Update deployment image tags
|
||||
|
||||
**Required Gitea Secrets** (per repository):
|
||||
- `REGISTRY_USERNAME`: Docker registry username (admin)
|
||||
- `REGISTRY_PASSWORD`: Docker registry password
|
||||
|
||||
## Verification
|
||||
|
||||
Check deployment status:
|
||||
```bash
|
||||
kubectl get all -n lpt-dev
|
||||
kubectl get configmap -n lpt-dev
|
||||
kubectl get secret -n lpt-dev
|
||||
```
|
||||
|
||||
View logs:
|
||||
```bash
|
||||
kubectl logs -f deployment/lpt-fe -n lpt-dev
|
||||
kubectl logs -f deployment/lpt-be -n lpt-dev
|
||||
kubectl logs -f deployment/lpt-ai -n lpt-dev
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ lpt-fe:3000 │ (NodePort 30080)
|
||||
│ Vue 3 + Nginx │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ lpt-be:8080 │ (NodePort 30088)
|
||||
│ Spring Boot │
|
||||
└────────┬────────┘
|
||||
│
|
||||
├─────────► MySQL (external)
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ lpt-ai:5199 │ (ClusterIP)
|
||||
│ FastAPI │
|
||||
└─────────────────┘
|
||||
│
|
||||
▼
|
||||
LLM API (external)
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Namespace**: All resources use `lpt-dev` namespace
|
||||
- **Registry**: Private Docker registry at `192.168.123.199:5000`
|
||||
- **Image Pull**: All deployments use `imagePullSecrets: [name: regcred]`
|
||||
- **ConfigMap**: Shared config is mounted as environment variables
|
||||
- **Secrets**: Sensitive data (API keys, passwords) stored in `lpt-secrets`
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: lpt-config
|
||||
namespace: lpt-dev
|
||||
data:
|
||||
# LPT AI Service
|
||||
LLM_API_URL: https://api.siliconflow.cn/v1/chat/completions
|
||||
LLM_MODEL: Qwen/Qwen2.5-32B-Instruct
|
||||
LLM_TIMEOUT_MS: "60000"
|
||||
LPT_AI-SERVICE_URL: http://lpt-ai:5199
|
||||
PORT: "5199"
|
||||
|
||||
# Spring Boot Database
|
||||
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/learning_progress_tracker?allowPublicKeyRetrieval=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
|
||||
@@ -1,33 +0,0 @@
|
||||
# LPT Application Secrets
|
||||
#
|
||||
# This file is a TEMPLATE - DO NOT commit real secrets to git!
|
||||
#
|
||||
# To create this secret:
|
||||
# kubectl create secret generic lpt-secrets \
|
||||
# --from-literal=llm-api-key=<YOUR_LLM_API_KEY> \
|
||||
# --from-literal=mysql-root-password=<YOUR_MYSQL_ROOT_PASSWORD> \
|
||||
# --namespace=lpt-dev
|
||||
#
|
||||
# Or use kubectl apply with stringData:
|
||||
# kubectl apply -f - <<EOF
|
||||
# apiVersion: v1
|
||||
# kind: Secret
|
||||
# metadata:
|
||||
# name: lpt-secrets
|
||||
# namespace: lpt-dev
|
||||
# type: Opaque
|
||||
# stringData:
|
||||
# llm-api-key: "your-actual-api-key"
|
||||
# mysql-root-password: "your-actual-mysql-password"
|
||||
# EOF
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: lpt-secrets
|
||||
namespace: lpt-dev
|
||||
type: Opaque
|
||||
data:
|
||||
# Base64 encoded values - use stringData for plain text when applying
|
||||
# llm-api-key: <base64-encoded-api-key>
|
||||
# mysql-root-password: <base64-encoded-password>
|
||||
@@ -1,26 +0,0 @@
|
||||
# Docker Registry Secret for pulling images from private registry
|
||||
#
|
||||
# This file is a TEMPLATE - the actual secret is managed by Gitea Actions workflow
|
||||
# and should NOT be committed with real credentials.
|
||||
#
|
||||
# To create this secret manually:
|
||||
# kubectl create secret docker-registry regcred \
|
||||
# --docker-server=192.168.123.199:5000 \
|
||||
# --docker-username=admin \
|
||||
# --docker-password=<REGISTRY_PASSWORD> \
|
||||
# --namespace=lpt-dev
|
||||
#
|
||||
# Or use the workflow which reads from Gitea secrets:
|
||||
# - REGISTRY_USERNAME
|
||||
# - REGISTRY_PASSWORD
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: regcred
|
||||
namespace: lpt-dev
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
data:
|
||||
# .dockerconfigjson: <base64-encoded-docker-config>
|
||||
# This is generated by the workflow - DO NOT commit real values here
|
||||
.dockerconfigjson: ""
|
||||
@@ -32,15 +32,14 @@ describe("aggregateReportPrompt", () => {
|
||||
});
|
||||
|
||||
describe("generateMindMapPrompt", () => {
|
||||
it("要求输出缩进大纲且包含全部输入", () => {
|
||||
it("要求输出缩进大纲且只包含学习报告", () => {
|
||||
const messages = generateMindMapPrompt(
|
||||
"Java 并发",
|
||||
"并发编程学习",
|
||||
["报告一"],
|
||||
["残片一", "残片二"],
|
||||
);
|
||||
expect(messages[0].content).toContain("缩进");
|
||||
expect(messages[1].content).toContain("报告一");
|
||||
expect(messages[1].content).toContain("残片二");
|
||||
expect(messages[1].content).not.toContain("学习残片");
|
||||
});
|
||||
});
|
||||
|
||||
+2
-6
@@ -50,20 +50,19 @@ export function aggregateReportPrompt(
|
||||
}
|
||||
|
||||
/**
|
||||
* 从学习报告和残片生成标准思维导图(预留,用于替代 Java 端 BuiltinMindMapGenerator)。
|
||||
* 从学习报告生成标准思维导图(预留,用于替代 Java 端 BuiltinMindMapGenerator)。
|
||||
* 输出为缩进大纲文本,与后端 MindMapTreeTool.parseOutline 格式一致。
|
||||
*/
|
||||
export function generateMindMapPrompt(
|
||||
taskName: string,
|
||||
taskDescription: string,
|
||||
reports: string[],
|
||||
fragments: string[],
|
||||
): ChatMessage[] {
|
||||
return [
|
||||
{
|
||||
role: "system",
|
||||
content: [
|
||||
"你是一名知识结构整理助手。请阅读某个学习任务的全部学习报告和残片,",
|
||||
"你是一名知识结构整理助手。请阅读某个学习任务的全部学习报告,",
|
||||
"将其中的知识点整理成一份思维导图大纲。要求:",
|
||||
"1. 第一行是导图根标题(任务主题);",
|
||||
"2. 之后每行一个节点,用两个空格的缩进表示层级;",
|
||||
@@ -81,9 +80,6 @@ export function generateMindMapPrompt(
|
||||
"",
|
||||
"学习报告:",
|
||||
...reports.map((r, i) => `${i + 1}. ${r}`),
|
||||
"",
|
||||
"学习残片:",
|
||||
...fragments.map((f, i) => `${i + 1}. ${f}`),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n"),
|
||||
|
||||
@@ -160,12 +160,10 @@ function buildMessages(task: TaskRecord) {
|
||||
}
|
||||
case "generate-mind-map": {
|
||||
const reports = p.reports as string[] | undefined;
|
||||
const fragments = p.fragments as string[] | undefined;
|
||||
return generateMindMapPrompt(
|
||||
p.taskName as string,
|
||||
(p.taskDescription as string) ?? "",
|
||||
reports ?? [],
|
||||
fragments ?? [],
|
||||
);
|
||||
}
|
||||
case "compare-recall": {
|
||||
|
||||
Reference in New Issue
Block a user