UNPKG

wechaty-qnamaker

Version:
137 lines (110 loc) 3.61 kB
import { log } from 'wechaty' import { Args, CommandContext, Vorpal, } from 'wechaty-vorpal' import { matchers, } from 'wechaty-plugin-contrib' import { QnAMakerOptions } from './qnamaker' import { normalizeConfig } from './normalize-config' import { asker } from './asker' import { QnASearchResult, QueryDTO, } from '@azure/cognitiveservices-qnamaker-runtime/esm/models' function Faq (config: Partial<QnAMakerOptions> | Partial<QnAMakerOptions>[]) { log.verbose('WechatyQnAMaker', 'Faq(%s)', JSON.stringify(config)) const normalizedConfigList: QnAMakerOptions[] = [] if (!Array.isArray(config)) { normalizedConfigList.push(normalizeConfig(config)) } else { normalizedConfigList.push( ...config.map(c => normalizeConfig(c)) ) } return function FaqExtension (vorpal: Vorpal) { log.verbose('WechatyQnAMaker', 'FaqExtension(vorpal)') vorpal .command('faq <question...>', 'Get an answer from Frequent Asked Questions (FAQ)') .option('-v --verbose', 'Show verbose informations') .option('-n --number <number>', 'Show maximum <number> related answers. (default: 1)') .action(faqAction(normalizedConfigList)) } } interface FaqOptions { verbose? : boolean, number? : number, } const faqAction = (configList : QnAMakerOptions[]) => { log.verbose('WechatyQnAMaker', 'Faq() faqAction("%s")', JSON.stringify(configList)) const askerDictList = configList.map(config => ({ ask : asker(config), matchLanguage : (typeof config.language === 'undefined') ? () => true // match all language by default : matchers.languageMatcher(config.language), })) const askAll = async ( question : string, dto : QueryDTO = {}, ) => { const resultList = await Promise.all( askerDictList .filter(dict => dict.matchLanguage(question)) .map(dict => dict.ask(question, dto)) ) return resultList .flat() .filter(i => i.score) .sort((a, b) => b.score! - a.score!) } return async function faqActionExector ( this: CommandContext, args: Args ): Promise<void> { log.verbose('WechatyQnAMaker', 'Faq() faqAction() faqActionExecutor("%s")', JSON.stringify(args)) const options: FaqOptions = args.options let question: string if (Array.isArray(args.question)) { question = args.question.join(' ') } else { question = args.question } const queryDto: QueryDTO = { scoreThreshold : 1, top : options.number, } const searchResultList = await askAll(question, queryDto) if (searchResultList.length <= 0) { this.log('Sorry, I did not find any answer in my KB (Knowledge Base) for your question: "' + question + '".') return } log.verbose('WechatyQnAMaker', 'Faq() faqAction() faqActionExecutor() found %s answers', searchResultList.length) searchResultList.forEach((result, idx) => { if (!result.answer) { return } if (idx > (options.number ?? 0)) { return } this.log( toReply(result, idx + 1, options.verbose) ) }) } } function toReply ( result : QnASearchResult, index : number, verbose = false, ): string { if (!verbose) { return result.answer! } const list = [ `A${index}:(score:${Math.floor(result.score || 0)}) ${result.answer}`, ] if (result.questions) { list.unshift('') list.unshift(`Q${index}: ` + result.questions[0]) } return list.join('\n') } export { Faq }