SkillSpace/openclaw/skills/patient-roleplay/scripts/scheduler.sh

187 lines
6.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# 患者模拟定时调度脚本
# 用途:按 cron 表达式定时触发患者模拟任务,支持批量患者数量和场景组合。
# 使用方式:
# bash scheduler.sh # 单次运行(使用默认配置)
# bash scheduler.sh --config <file> # 指定配置文件
# bash scheduler.sh --dry-run # 仅打印即将执行的计划,不实际运行
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
CONFIG_FILE="$SKILL_DIR/examples/schedule-config.yaml"
DRY_RUN=false
LOG_DIR="$SKILL_DIR/examples/logs"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
# ============================================================
# 解析命令行参数
# ============================================================
while [[ $# -gt 0 ]]; do
case "$1" in
--config)
CONFIG_FILE="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
*)
echo "未知参数: $1"
echo "用法: bash scheduler.sh [--config <file>] [--dry-run]"
exit 1
;;
esac
done
# ============================================================
# 加载配置文件
# ============================================================
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "[ERROR] 配置文件不存在: $CONFIG_FILE"
echo "请先在 examples/ 目录下创建 schedule-config.yaml"
exit 1
fi
# 从 YAML 读取配置(简化解析,仅支持单层)
read_yaml_value() {
local key="$1"
grep "^${key}:" "$CONFIG_FILE" | head -1 | sed "s/^${key}:[[:space:]]*//" | tr -d '"'
}
# ============================================================
# 读取配置
# ============================================================
PROFILE_COUNT=$(read_yaml_value "patient_count" || echo "5")
SCENARIOS=$(read_yaml_value "scenarios" || echo "all")
TIME_SLOT=$(read_yaml_value "time_slot" || echo "morning")
CRON_EXPR=$(read_yaml_value "cron" || echo "")
TARGET_AI_ENDPOINT=$(read_yaml_value "target_ai_endpoint" || echo "")
echo "========================================"
echo " 患者模拟定时调度"
echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"
echo " 配置: $CONFIG_FILE"
echo " 患者数量: $PROFILE_COUNT"
echo " 场景: $SCENARIOS"
echo " 时段: $TIME_SLOT"
echo " 目标 AI: $TARGET_AI_ENDPOINT"
echo "========================================"
if [[ "$DRY_RUN" == true ]]; then
echo ""
echo "[DRY RUN] 以下是将要执行的模拟计划(不会实际运行):"
echo ""
fi
# ============================================================
# 安装 cron如配置了 cron 表达式)
# ============================================================
install_cron() {
if [[ -z "$CRON_EXPR" ]]; then
return 0
fi
# ⚠️ 此操作会修改当前用户的 crontab。
# 仅添加标记为 "# patient-roleplay-scheduler" 的条目,
# 不会影响其他定时任务。可通过 crontab -e 手动移除。
local CRON_CMD="$CRON_EXPR cd $SCRIPT_DIR && bash scheduler.sh --config $CONFIG_FILE >> $LOG_DIR/cron-\$(date +\%Y\%m\%d).log 2>&1"
local CRON_MARKER="# patient-roleplay-scheduler"
# 删除旧条目
if crontab -l 2>/dev/null | grep -q "$CRON_MARKER"; then
crontab -l 2>/dev/null | grep -v "$CRON_MARKER" | crontab -
fi
# 添加新条目
(crontab -l 2>/dev/null || true; echo "$CRON_CMD $CRON_MARKER") | crontab -
echo "[CRON] 已安装定时任务: $CRON_EXPR"
}
# ============================================================
# 按真实患者就诊时间分布调整请求间隔
# ============================================================
get_interval_ms() {
case "$TIME_SLOT" in
morning)
# 上午 8-11 点就诊高峰:间隔 3-8 分钟
echo $((3000 + RANDOM % 5000))
;;
afternoon)
# 下午 2-5 点分散就诊:间隔 8-15 分钟
echo $((8000 + RANDOM % 7000))
;;
evening)
# 晚间较少就诊:间隔 20-30 分钟
echo $((20000 + RANDOM % 10000))
;;
*)
echo 5000
;;
esac
}
# ============================================================
# 执行单次患者模拟(占位——实际由 AI 代理执行)
# ============================================================
run_single_simulation() {
local profile_id="$1"
local scenario_id="$2"
local index="$3"
local INTERVAL_MS
INTERVAL_MS=$(get_interval_ms)
echo "[$(date '+%H:%M:%S')] 患者 #$index | 画像: $profile_id | 场景: $scenario_id"
if [[ "$DRY_RUN" == true ]]; then
echo " → (dry-run) 将等待 ${INTERVAL_MS}ms 后开始对话"
return 0
fi
# 实际模拟逻辑由 AI 代理在加载本技能后执行,
# 此处仅记录模拟启动事件。
# AI 代理应在此处被调用,传入 profile_id 和 scenario_id。
mkdir -p "$LOG_DIR"
echo "$(date -Iseconds) | $index | $profile_id | $scenario_id | started" >> "$LOG_DIR/sessions-$TIMESTAMP.log"
# 模拟真实就诊间隔
sleep "$((INTERVAL_MS / 1000))" 2>/dev/null || true
}
# ============================================================
# 主流程
# ============================================================
main() {
mkdir -p "$LOG_DIR"
# 安装 cron如需
install_cron
if [[ "$DRY_RUN" == true ]]; then
echo "模拟计划:共 $PROFILE_COUNT 名患者,场景范围:$SCENARIOS"
echo "时段分布参考:$TIME_SLOT"
echo "每次会话间隔:$(get_interval_ms)ms在真实运行中会随机变化"
return 0
fi
# 注:以下循环为调度框架。
# 实际的对话生成和 AI 交互由加载本技能后的 AI 代理执行。
for i in $(seq 1 "$PROFILE_COUNT"); do
# 从场景池中随机选取一个场景
SCENARIO_ID="scenario-auto-$((RANDOM % 5 + 1))"
PROFILE_ID="profile-auto-$((RANDOM % 5 + 1))"
run_single_simulation "$PROFILE_ID" "$SCENARIO_ID" "$i"
done
echo ""
echo "[完成] 共计划模拟 $PROFILE_COUNT 名患者"
echo "日志目录: $LOG_DIR"
}
main