async def sched_list(session: CommandSession): job_id_prefix = scheduler.make_job_id(PLUGIN_NAME, context_id(session.ctx)) jobs = await scheduler.get_jobs( scheduler.make_job_id(PLUGIN_NAME, context_id(session.ctx))) if not jobs: await session.send(f'你还没有添加过计划任务') return for job in jobs: await session.send(format_job(job.id[len(job_id_prefix):], job)) await asyncio.sleep(0.8) await session.send_expr(f'以上是所有的 {len(jobs)} 个计划任务')
async def _(session: CommandSession): count = await note_count(context_id(session.ctx)) if count == 0: await session.send_expr(expr.LIST_EMPTY) return all_notes = await Note.query.where( Note.context_id == context_id(session.ctx)).gino.all() for n in all_notes: await session.send(f'ID:{n.id}\r\n内容:{n.content}') await asyncio.sleep(0.8) await session.send_expr(expr.LIST_COMPLETE, count=count)
async def note_add(session: CommandSession): content = session.get('content', prompt_expr=expr.ADD_WHAT_CONTENT) new_note = await Note.create(content=content, context_id=context_id(session.ctx)) await session.send_expr(expr.ADD_SUCCESS, id=new_note.id, content=new_note.content)
async def _(session: NLPSession): confidence = None # by default we don't return result if session.ctx['to_me']: # if the user is talking to us, we may consider reply to him/her confidence = 60.0 ctx_id = context_id(session.ctx) if ctx_id in tuling_sessions: ne_type = tuling_sessions[ctx_id] lex_result = await nlp.lexer(session.msg_text) # we only mind the first paragraph words = lex_result[0] if lex_result else [] for w in words: if ne_type == w['ne']: # if there is a tuling session existing, # and the user's input is exactly what tuling wants, # we are sure that the user is replying tuling confidence = 100.0 - len(words) * 5.0 break if confidence: return NLPResult(confidence, 'tuling', { 'message': session.msg, 'one_time': True })
async def call_tuling_api( session: BaseSession, text: Optional[str], image: Optional[Union[List[str], str]]) -> List[str]: url = 'http://openapi.tuling123.com/openapi/api/v2' payload = { 'reqType': 0, 'perception': {}, 'userInfo': { 'apiKey': session.bot.config.TULING123_API_KEY, 'userId': context_id(session.ctx, use_hash=True) } } group_unique_id = context_id(session.ctx, mode='group', use_hash=True) if group_unique_id: payload['userInfo']['groupId'] = group_unique_id if image and not isinstance(image, str): image = image[0] if text: payload['perception']['inputText'] = {'text': text} payload['reqType'] = 0 elif image: payload['perception']['inputImage'] = {'url': image} payload['reqType'] = 1 else: return [] try: resp = await requests.post(url, json=payload) if resp.ok: resp_payload = await resp.json() if resp_payload.get('results'): return_list = [] for result in resp_payload['results']: res_type = result.get('resultType') if res_type in ('text', 'url'): return_list.append(result['values'][res_type]) return return_list return [] except (requests.RequestException, json.JSONDecodeError, KeyError): return []
async def call_tuling_api(session: CommandSession, text: str) -> Optional[str]: # 调用图灵机器人的 API 获取回复 if not text: return None url = 'http://openapi.tuling123.com/openapi/api/v2' # 构造请求数据 payload = { 'reqType': 0, 'perception': { 'inputText': { 'text': text } }, 'userInfo': { 'apiKey': session.bot.config.TULING_API_KEY, 'userId': context_id(session.ctx, use_hash=True) } } group_unique_id = context_id(session.ctx, mode='group', use_hash=True) if group_unique_id: payload['userInfo']['groupId'] = group_unique_id try: # 使用 aiohttp 库发送最终的请求 async with aiohttp.ClientSession() as sess: async with sess.post(url, json=payload) as response: if response.status != 200: # 如果 HTTP 响应状态码不是 200,说明调用失败 return None resp_payload = json.loads(await response.text()) if resp_payload['results']: for result in resp_payload['results']: if result['resultType'] == 'text': # 返回文本类型的回复 return result['values']['text'] except (aiohttp.ClientError, json.JSONDecodeError, KeyError): # 抛出上面任何异常,说明调用失败 return None
async def _(session: NLPSession): data = { 'timestamp': [session.ctx['time']], 'ctx_id': [context_id(session.ctx)], 'self_id': [session.ctx['self_id']], 'message': [str(session.ctx['message'])] } # we don't want to block the processing of message, # so just make sure it will append in the future asyncio.ensure_future(append_message(data))
async def sched_remove(session: CommandSession): parser = ArgumentParser() parser.add_argument('name') args = await parse_args(session, parser, argv=session.get_optional('argv'), help_msg=sched_remove_help) ok = await scheduler.remove_job( scheduler.make_job_id(PLUGIN_NAME, context_id(session.ctx), args.name)) if ok: await session.send(f'成功删除计划任务 {args.name}') else: await session.send(f'没有找到计划任务 {args.name},请检查你的输入是否正确')
async def sched_get(session: CommandSession): parser = ArgumentParser() parser.add_argument('name') args = await parse_args(session, parser, argv=session.get_optional('argv'), help_msg=sched_get_help) job = await scheduler.get_job( scheduler.make_job_id(PLUGIN_NAME, context_id(session.ctx), args.name)) if not job: await session.send(f'没有找到计划任务 {args.name},请检查你的输入是否正确') return await session.send('找到计划任务如下') await session.send(format_job(args.name, job))
async def note_remove(session: CommandSession): ctx_id = context_id(session.ctx) count = await note_count(ctx_id) if count == 0: await session.send_expr(expr.LIST_EMPTY) return id_ = session.get('id', prompt_expr=expr.DEL_WHICH_ID) note_ = await Note.query.where((Note.context_id == ctx_id) & (Note.id == id_)).gino.first() if note_ is None: await session.send_expr(expr.DEL_ID_NOT_EXISTS, id=id_) else: await note_.delete() await session.send_expr(expr.DEL_SUCCESS, id=id_, content=note_.content)
async def tuling(session: CommandSession): message = session.get('message', prompt_expr=expr.I_AM_READY) ctx_id = context_id(session.ctx) if ctx_id in tuling_sessions: del tuling_sessions[ctx_id] tmp_msg = Message(message) text = tmp_msg.extract_plain_text() images = [s.data['url'] for s in tmp_msg if s.type == 'image' and 'url' in s.data] # call tuling api replies = await call_tuling_api(session, text, images) logger.debug(f'Got tuling\'s replies: {replies}') if replies: for reply in replies: await session.send(escape(reply)) await asyncio.sleep(0.8) else: await session.send_expr(expr.I_DONT_UNDERSTAND) one_time = session.get_optional('one_time', False) if one_time: # tuling123 may opened a session, we should recognize the # situation that tuling123 want more information from the user. # for simplification, we only recognize named entities, # and since we will also check the user's input later, # here we can allow some ambiguity. ne_type = tuling_ne_type(replies, { 'LOC': ('哪里', '哪儿', re.compile(r'哪\S城市'), '位置'), 'TIME': ('什么时候',), }) if ne_type: logger.debug(f'One time call, ' f'and there is a tuling session for {ne_type}') tuling_sessions[ctx_id] = ne_type else: session.pause()
async def sched_add(session: CommandSession): parser = ArgumentParser() parser.add_argument('-S', '--second') parser.add_argument('-M', '--minute') parser.add_argument('-H', '--hour') parser.add_argument('-d', '--day') parser.add_argument('-m', '--month') parser.add_argument('-w', '--day-of-week') parser.add_argument('-f', '--force', action='store_true', default=False) parser.add_argument('-v', '--verbose', action='store_true', default=False) parser.add_argument('--name', required=True) parser.add_argument('commands', nargs='+') args = await parse_args(session, parser, argv=session.get_optional('argv'), help_msg=sched_add_help) if not re.match(r'[_a-zA-Z][_a-zA-Z0-9]*', args.name): await session.send('计划任务名必须仅包含字母、数字、下划线,且以字母或下划线开头') return parsed_commands: List[ScheduledCommand] = [] invalid_commands: List[str] = [] if args.verbose: parsed_commands.append( ScheduledCommand(('echo', ), f'开始执行计划任务 {args.name}……')) for cmd_str in args.commands: cmd, current_arg = parse_command(session.bot, cmd_str) if cmd: tmp_session = CommandSession(session.bot, session.ctx, cmd, current_arg=current_arg) if await cmd.run(tmp_session, dry=True): parsed_commands.append(ScheduledCommand(cmd.name, current_arg)) continue invalid_commands.append(cmd_str) if invalid_commands: invalid_commands_joined = '\n'.join( [f'- {c}' for c in invalid_commands]) await session.send(f'计划任务添加失败,' f'因为下面的 {len(invalid_commands)} 个命令无法被运行' f'(命令不存在或权限不够):\n' f'{invalid_commands_joined}') return trigger_args = { k: v for k, v in args.__dict__.items() if k in {'second', 'minute', 'hour', 'day', 'month', 'day_of_week'} } try: job = await scheduler.add_scheduled_commands( parsed_commands, job_id=scheduler.make_job_id(PLUGIN_NAME, context_id(session.ctx), args.name), ctx=session.ctx, trigger='cron', **trigger_args, replace_existing=args.force) except scheduler.JobIdConflictError: # a job with same name exists await session.send(f'计划任务 {args.name} 已存在,' f'若要覆盖请使用 --force 参数') return await session.send(f'计划任务 {args.name} 添加成功') await session.send(format_job(args.name, job))