def multiple_save_info(cls, question: str, session_id: str, context_id: str, std_question_id: int, collection: str, partition: str, qa: QA, qa_manager: QAManager, **kwargs): """ 多轮问答保存信息至session的info中 @param {str} question - 客户反馈的信息文本(提问回答) @param {str} session_id - 客户的session id @param {str} context_id - 上下文临时id @param {int} std_question_id - 上下文中对应的提问问题id @param {str} collection - 提问答案参数指定的问题分类 @param {str} partition - 提问答案参数指定的场景标签 @param {QA} qa - 服务器的问答处理模块实例对象 @param {QAManager} qa_manager - 服务器的问答数据管理实例对象 @param {kwargs} - 扩展传入参数 ask {list} - 问题列表,注意最后的问题必须有tips或to参数 [ {'info_key': '保存的key值', 'next_tips': '下一个问题'}, ..., {'info_key': '保存的key值', 'tips': '处理完成提示', 'to': 跳转到指定问题id}, ] @param {str, object} - 按照不同的处理要求返回内容 'answer', [str, ...] - 直接返回回复内容,第二个参数为回复内容 'to', int - 跳转到指定问题处理,第二个参数为std_question_id 'again', [str, ...] - 再获取一次答案,第二个参数为提示内容,如果第2个参数为None代表使用原来的参数再提问一次 'break', [collection, partition] - 跳出问题(让问题继续走匹配流程),可以返回[collection, partition]变更分类和场景 默认为'again' """ _step = qa.get_cache_value(session_id, 'multiple_save_info', {}).get(context_id, 0) _ask = kwargs.get('ask')[_step] # 保存值 _info_key = _ask.get('info_key') _info = dict() _info[_info_key] = question qa.update_session_info(session_id, _info) # 处理下一个问题 _to = _ask.get('to', None) _tips = _ask.get('tips', None) _next_tips = _ask.get('next_tips', None) if _to is not None or _tips is not None: # 最后一个问题 qa.del_cache(session_id, 'multiple_save_info') if _to is None: return 'answer', [ _tips, ] else: return 'to', _to else: # 还有下一个问题 qa.add_cache(session_id, 'multiple_save_info', {context_id: _step + 1}) return 'again', [ _next_tips, ]
def weather(cls, question: str, session_id: str, context_id: str, std_question_id: int, collection: str, partition: str, qa: QA, qa_manager: QAManager, **kwargs): """ 查询天气 @param {str} question - 客户反馈的信息文本(提问回答) @param {str} session_id - 客户的session id @param {str} context_id - 上下文临时id @param {int} std_question_id - 上下文中对应的提问问题id @param {str} collection - 提问答案参数指定的问题分类 @param {str} partition - 提问答案参数指定的场景标签 @param {QA} qa - 服务器的问答处理模块实例对象 @param {QAManager} qa_manager - 服务器的问答数据管理实例对象 @param {kwargs} - 扩展传入参数 time {list} - nlp分词的时间词语列表 addr {list} - nlp分词的地址词语列表 @returns {str, object} - 按照不同的处理要求返回内容 'answer', [str, ...] - 直接返回回复内容,第二个参数为回复内容 'to', int - 跳转到指定问题处理,第二个参数为std_question_id 'again', [str, ...] - 再获取一次答案,第二个参数为提示内容,如果第2个参数为None代表使用原来的参数再提问一次 'break', [collection, partition] - 跳出问题(让问题继续走匹配流程),可以返回[collection, partition]变更分类和场景 默认为'again' """ _match_city_code = '' _match_day = 0 # 0代表当前,1代表明天,2代表后天 # 检查是不是第二次的选项 _cache_info = qa.get_cache_value(session_id, 'weather', default=None, context_id=context_id) if _cache_info is not None: if question.isdigit(): if question not in _cache_info['addr_dict'].keys(): # 回答不在选项范围 return 'again', [ '亲, 您输入的序号不对, 请输入正确的序号选择城市', ] else: _match_day = _cache_info['day'] _match_city_code = _cache_info['addr_dict'][question] else: # 不是选项,是文字 return 'answer', [ WEATHER_ERROR, ] else: # 尝试获取日期 for _word in kwargs.get('time', []): if _word in ['明天']: _match_day = 1 elif _word in ['后天']: _match_day = 2 # 尝试获取地址 with redis.Redis(connection_pool=qa.redis_pool) as _redis: _match_addr = cls._search_city(kwargs.get('addr', []), _redis) if len(_match_addr) == 0: # 没有匹配到地址,尝试获取客户info中的地址 _addr = qa.get_info_by_key(session_id, 'addr', default='') if _addr == '' and WEATHER_TRY_USE_IP_ADDR: # 尝试通过IP地址获取地址 _addr = cls._get_addr_by_ip( qa.get_info_by_key(session_id, 'ip', default=''), qa) if _addr != '': _addrs_with_class = qa.nlp.cut_sentence(_addr) _addrs = [item[0] for item in _addrs_with_class] _match_addr = cls._search_city(_addrs, _redis) _len = len(_match_addr) if _len == 1: _match_city_code = _match_addr[0][1][0] elif _len > 1: # 匹配到多个,进行提问让客户选择 _tips = ['找到了多个地址,您想查询哪个地址的天气?请输入序号进行选择: '] _index = 1 _cache_info = dict() _cache_info['day'] = _match_day _cache_info['addr_dict'] = dict() for item in _match_addr: # 加入到上下文 _cache_info['addr_dict'][str(_index)] = item[1][0] # 获取详细地址 _tips.append( '%d.%s' % (_index, cls._get_city_full_name(item[0], _redis))) _index += 1 # 添加到cache中 qa.add_cache(session_id, 'weather', _cache_info, context_id=context_id) # 重新提问 return 'again', _tips if _match_city_code == '': # 没有找到地址,直接返回退出 return 'answer', [ WEATHER_ERROR, ] # 查询天气, 先查本地缓存 _today = datetime.datetime.now().strftime('%Y-%m-%d') with redis.Redis(connection_pool=qa.redis_pool) as _redis: _json = _redis.get('api_tool_ask:weather:cache:%s:%s' % (_match_city_code, _today)) if _json is None: # 要进行查询 _api_back = NetTool.restful_api_call( 'http://t.weather.sojson.com/api/weather/city/%s' % _match_city_code, back_type='text', logger=qa.logger) if _api_back['is_success']: _json = _api_back['back_object'] _wdata = json.loads(_json) if _wdata['status'] == 200: # 存入缓存,一天到期 _redis.set('api_tool_ask:weather:cache:%s:%s' % (_match_city_code, _today), _json, ex=86400) else: return 'answer', [ WEATHER_ERROR, ] else: # 获取失败 return 'answer', [ WEATHER_ERROR, ] else: _wdata = json.loads(_json) # 返回结果 _end_str = '' # 结束语 if _match_day == 0: _end_str = '湿度%s, PM2.5: %s, 空气质量%s, %s, ' % ( _wdata['data']['shidu'], _wdata['data']['pm25'], _wdata['data']['quality'], _wdata['data']['ganmao']) _answer = '亲, %s%s的天气%s, 吹%s%s, %s, %s, %s%s' % ( _wdata['cityInfo']['city'], _wdata['data']['forecast'][_match_day]['ymd'], _wdata['data']['forecast'][_match_day]['type'], _wdata['data']['forecast'][_match_day]['fl'], _wdata['data']['forecast'][_match_day]['fx'], _wdata['data']['forecast'][_match_day]['high'], _wdata['data']['forecast'][_match_day]['low'], _end_str, _wdata['data']['forecast'][_match_day]['notice']) return 'answer', [ _answer, ]