feat: 提醒到期 → LLM生成自然提醒语 → 推送
- Gateway ReminderScheduler 到期时调用 ai-core /api/v1/internal/reminder-trigger - ai-core 用 LLM 生成温柔俏皮的提醒语,通过 messagePusher 推送 - Thinker 新增 TriggerReminderMessage 方法 - 环境变量: AI_CORE_URL (Gateway 已有) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"html"
|
||||
"io"
|
||||
"git.yeij.top/AskaEth/Cyrene/pkg/logger"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -242,7 +244,7 @@ func (h *ReminderHandler) Delete(c *gin.Context) {
|
||||
// ========== 提醒调度器 ==========
|
||||
|
||||
// StartReminderScheduler 启动提醒调度器,每 30 秒检查一次到期提醒
|
||||
func StartReminderScheduler(s *store.ReminderStore, hub *ws.Hub) {
|
||||
func StartReminderScheduler(s *store.ReminderStore, hub *ws.Hub, aiCoreURL, internalToken string) {
|
||||
go func() {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
defer ticker.Stop()
|
||||
@@ -250,13 +252,13 @@ func StartReminderScheduler(s *store.ReminderStore, hub *ws.Hub) {
|
||||
logger.Println("[ReminderScheduler] 提醒调度器已启动 (检查间隔: 30秒)")
|
||||
|
||||
for range ticker.C {
|
||||
checkAndNotify(s, hub)
|
||||
checkAndNotify(s, hub, aiCoreURL, internalToken)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// checkAndNotify 检查到期提醒并推送通知
|
||||
func checkAndNotify(s *store.ReminderStore, hub *ws.Hub) {
|
||||
// checkAndNotify 检查到期提醒并推送通知 + 触发 LLM 生成自然提醒语
|
||||
func checkAndNotify(s *store.ReminderStore, hub *ws.Hub, aiCoreURL, internalToken string) {
|
||||
reminders, err := s.GetDueReminders()
|
||||
if err != nil {
|
||||
logger.Printf("[ReminderScheduler] 获取到期提醒失败: %v", err)
|
||||
@@ -297,7 +299,12 @@ func checkAndNotify(s *store.ReminderStore, hub *ws.Hub) {
|
||||
// 2. 通过 Hub 向用户推送
|
||||
hub.SendToUser(r.UserID, data)
|
||||
|
||||
// 3. 标记为已通知
|
||||
// 3. 触发 LLM 生成自然提醒语
|
||||
if aiCoreURL != "" && internalToken != "" {
|
||||
go triggerLLMReminder(aiCoreURL, internalToken, r)
|
||||
}
|
||||
|
||||
// 4. 标记为已通知
|
||||
if err := s.MarkNotified(r.ID); err != nil {
|
||||
logger.Printf("[ReminderScheduler] 标记已通知失败: id=%s err=%v", r.ID, err)
|
||||
}
|
||||
@@ -339,3 +346,38 @@ func calculateNextRemindAt(current time.Time, repeatType string) time.Time {
|
||||
return current
|
||||
}
|
||||
}
|
||||
|
||||
func triggerLLMReminder(aiCoreURL, internalToken string, r store.Reminder) {
|
||||
body := map[string]string{
|
||||
"title": r.Title,
|
||||
"description": r.Description,
|
||||
"user_id": r.UserID,
|
||||
"session_id": r.SessionID,
|
||||
}
|
||||
reqBody, _ := json.Marshal(body)
|
||||
req, err := http.NewRequest("POST", aiCoreURL+"/api/v1/internal/reminder-trigger", bytes.NewReader(reqBody))
|
||||
if err != nil {
|
||||
logger.Printf("[ReminderScheduler] 创建LLM请求失败: %v", err)
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-Internal-Token", internalToken)
|
||||
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Printf("[ReminderScheduler] LLM提醒生成请求失败: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
logger.Printf("[ReminderScheduler] LLM提醒生成返回 %d: %s", resp.StatusCode, string(bodyBytes))
|
||||
return
|
||||
}
|
||||
|
||||
logger.Printf("[ReminderScheduler] LLM提醒已触发: title=%s user=%s", r.Title, r.UserID)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user