让大模型输出更加规范化——指定插件

发布于:2025-07-18 ⋅ 阅读:(14) ⋅ 点赞:(0)

针对智能设备语音指导大模型自动定闹钟策略

目前没有很好的办法让大模型提高定时这种准确任务,那么我就希望代码解析推算出准确时间,并由大模型播报,通过制作插件嵌入大模型解决定闹钟幻觉的问题:

from runtime import Args
from typings.time_calculation.time_calculation import Input, Output
import re
import json
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from dateutil.parser import parse
import random

class SmartAlarmClock:
    def __init__(self, args):
        self.time_ranges = {
            '凌晨': (0, 6),
            '早上': (6, 8),
            '上午': (8, 11.5),
            '中午': (11.5, 13),
            '下午': (13, 18),
            '晚上': (18, 23)
        }
        self.chinese_num_map = {
            '零': 0, '一': 1, '二': 2, '两': 2, '三': 3, '四': 4,
            '五': 5, '六': 6, '七': 7, '八': 8, '九': 9,
            '十': 10
        }

    def _chinese_to_arabic(self, cn_num):
        """转换中文数字到阿拉伯数字(0-99)"""
        if cn_num in self.chinese_num_map:
            return self.chinese_num_map[cn_num]
        
        if '十' in cn_num:
            parts = cn_num.split('十')
            ten = 10 if parts[0] == '' else self.chinese_num_map.get(parts[0], 0) * 10
            unit = self.chinese_num_map.get(parts[1], 0) if len(parts) > 1 else 0
            return ten + unit
        return 0
    
    def get_current_time_period(self):
        """获取当前时间段名称"""
        now = datetime.now()
        current_hour = now.hour + now.minute / 60
        
        for period, (start, end) in self.time_ranges.items():
            if start <= current_hour < end:
                return period
        return '晚上'
    
    def parse_chinese_time(self, text):
        """解析中文时间表达式如'三点半'、'三点一刻'等"""
        pattern = r'([一二三四五六七八九十零]+)点(半|一刻|三刻|(\d+)分)?'
        match = re.search(pattern, text)
        if not match:
            return None
            
        hour_cn = match.group(1)
        hour = self.chinese_num_map.get(hour_cn, 0)
        if hour == 0:
            try:
                hour = int(hour_cn)
            except:
                return None
        
        minute_type = match.group(2)
        minute = 0
        if minute_type == '半':
            minute = 30
        elif minute_type == '一刻':
            minute = 15
        elif minute_type == '三刻':
            minute = 45
        elif match.group(3):
            minute = int(match.group(3))
        
        return hour, minute
    
    def parse_time_expression(self, text, args):
        """解析用户的时间表达式"""
        now = datetime.now()
        text = text.replace(' ', '')
        
        # 初始化默认时间为当前时间
        alarm_time = now.replace(second=0, microsecond=0)
        days_later = 0
        month = now.month
        day = now.day
        year = now.year

        delta_match = re.search(
            r'('
            r'(\d+|半)(?:个?)?(小时|分钟|钟头|个小时|钟)?(?:\s*半)?'
            r'|(半钟头)'
            r'|(\d+\s*个\s*半\s*(?:小时|钟头|钟))'
            r'|(([一二三四五六七八九十两\d]+)刻钟?)'
            r')(后|以后)', 
            text
        )

        if delta_match:
            num = 0
            unit = ''
            
            if delta_match.group(4):
                num = 0.5
                unit = '小时'
            elif delta_match.group(5):
                match = re.search(r'(\d+)\s*个\s*半', delta_match.group(5))
                if match:
                    num = int(match.group(1)) + 0.5
                    if any(word in delta_match.group(5) for word in ['小时', '钟头', '钟']):
                        unit = '小时'
                    else:
                        unit = '分钟'
            elif delta_match.group(6):
                num_str = delta_match.group(7)
                if num_str.isdigit():
                    num = int(num_str)
                else:
                    num = self._chinese_to_arabic(num_str)
                unit = '分钟'
                num = num * 15
            else:
                num_str = delta_match.group(2)
                unit = delta_match.group(3) if delta_match.group(3) else ''
                
                if num_str == '半':
                    num = 0.5
                    if not unit:
                        if '钟头' in delta_match.group(0):
                            unit = '小时'
                        else:
                            unit = 'minutes'
                else:
                    num = int(num_str)
            
            if unit in ['小时', '个钟头', '个小时', '钟']:
                delta = timedelta(hours=num)
            elif unit == '分钟':
                delta = timedelta(minutes=num)
            else:
                delta = timedelta(minutes=num if num != 0.5 else 30)
            
            alarm_time = now + delta
            if alarm_time.day != now.day:
                alarm_time = alarm_time.replace(hour=0, minute=0, second=0, microsecond=0)
            return alarm_time
        
        # 处理日期部分
        if '大后天' in text or '大大后天' in text:
            days_later = text.count('大') + 2
        elif '后天' in text:
            days_later = 2
        elif '明天' in text:
            days_later = 1
        
        date_match = re.search(r'(\d{1,2})[月号](\d{1,2})?[号日]?', text)
        if date_match:
            if date_match.group(2):
                month = int(date_match.group(1))
                day = int(date_match.group(2))
            else:
                day = int(date_match.group(1))
                if day < now.day:
                    month += 1
                    if month > 12:
                        month = 1
                        year += 1
        
        # 应用日期调整
        if days_later > 0:
            alarm_time += timedelta(days=days_later)
        else:
            try:
                alarm_time = alarm_time.replace(year=year, month=month, day=day)
            except ValueError:
                import calendar
                last_day = calendar.monthrange(year, month)[1]
                alarm_time = alarm_time.replace(year=year, month=month, day=last_day)
        
        # 处理时间段
        period_hour_adjust = 0
        for period, (start, end) in self.time_ranges.items():
            if period in text:
                if period in ['下午', '晚上']:
                    period_hour_adjust = 12
                break
        
        # 提取具体时间
        hour = minute = 0
        
        chinese_time = self.parse_chinese_time(text)
        if chinese_time:
            hour, minute = chinese_time
        else:
            time_match = re.search(r'(\d{1,2})[:点](\d{1,2})?', text)
            if time_match:
                hour = int(time_match.group(1))
                minute = int(time_match.group(2)) if time_match.group(2) else 0
        
        # 应用时间段调整
        if hour != 0:
            # 处理时间段调整
            if (period_hour_adjust == 12 and hour < 12) or hour >= 13:
                hour += period_hour_adjust
            
            hour = hour % 24
            
            # 设置时间
            alarm_time = alarm_time.replace(hour=hour, minute=minute)
            
            # 检查是否需要调整到第二天
            if alarm_time <= now:
                # 如果用户没有明确指定时间段,且时间小于当前时间
                if period_hour_adjust == 0 and days_later == 0 and not date_match:
                    # 如果是上午时间(0-12点),尝试调整为下午
                    if hour < 12:
                        alarm_time = alarm_time.replace(hour=hour+12)
                        # 如果调整后时间仍然过去,则设置为第二天
                        if alarm_time <= now:
                            alarm_time += timedelta(days=1)
                            alarm_time = alarm_time.replace(hour=hour)  # 恢复原始小时数
                    else:
                        # 下午时间已经过去,设置为第二天
                        alarm_time += timedelta(days=1)
        
        return alarm_time
    
    def generate_response(self, alarm_time, reminder_text):
        """生成响应JSON"""
        now = datetime.now()
        if alarm_time is None:
            return json.dumps({
                "status": "error",
                "message": "时间已过,无法设置过去的闹钟。"
            }, ensure_ascii=False)
        
        # 计算日期差值
        delta_days = (alarm_time.date() - now.date()).days
        
        # 确定日期显示方式
        if delta_days == 1:
            date_display = "明天"
        elif delta_days == 2:
            date_display = "后天"
        elif delta_days == 3:
            date_display = "大后天"
        elif delta_days > 3:
            date_display = f"{alarm_time.year}{alarm_time.month}{alarm_time.day}日"
        else:  # 当天
            date_display = "今天"
        
        time_str = alarm_time.strftime("%H:%M")
        time_str12 = alarm_time.strftime("%I:%M")
        hour = alarm_time.hour + alarm_time.minute / 60
        period = '凌晨'
        for p, (start, end) in self.time_ranges.items():
            if start <= hour < end:
                period = p
                break
        
        response_template = [
            f"收到!主人请放心, 将在{date_display} {period}{time_str12}准时提醒您{reminder_text}。",
            f"好的主人!您去忙吧,{date_display} {period}{time_str12},我会准时提醒您{reminder_text}。",
            f"好的,我会在{date_display} {period}{time_str12}提醒您{reminder_text}。",
            f"没问题包在我身上!,我会在{date_display} {period}{time_str12}准时提醒您{reminder_text}。"
        ]
        
        # JSON模板仍使用原始日期格式
        JSON_template = str({
            "intention": "F", 
            "date": alarm_time.strftime("%m/%d"), 
            "time": time_str
        })
        
        return json.dumps({
            "status": "success",
            "date": alarm_time.strftime("%m/%d"),
            "time": time_str,
            "period": period,
            "message": response_template[random.randint(0, 3)] + JSON_template
        }, ensure_ascii=False)
    
    def process_request(self, user_input, args):
        """处理用户输入"""
        reminder_match = re.search(r'提醒我(.+)$|提醒(.+)$', user_input)
        reminder_text = reminder_match.group(1) or reminder_match.group(2) if reminder_match else "提醒您"
        
        alarm_time = self.parse_time_expression(user_input, args=args)
        
        return self.generate_response(alarm_time, reminder_text)

def handler(args: Args[Input])->Output:
    alarm = SmartAlarmClock(args=args)
    response = alarm.process_request(args.input.user_description, args)
    return {"response": response}

插件输入输出参数配置:

在这里插入图片描述

结果展示

在这里插入图片描述

以上就是最终定时结果


网站公告

今日签到

点亮在社区的每一天
去签到