Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Another question structure #4

Merged
merged 3 commits into from
Feb 22, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
upload
  • Loading branch information
Exsper committed Feb 22, 2020
commit 03009ff8de0884974771a36d0b9efa1bcf69494d
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\test-Segment.js",
//"program": "${workspaceFolder}\\test.js",
//"program": "${workspaceFolder}\\test-Segment.js",
"program": "${workspaceFolder}\\test.js",
"console": "externalTerminal"
}
]
Expand Down
20 changes: 7 additions & 13 deletions builders/AorA.js → QuestionType/DoOrNotDo.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

const ReplyObject = require('../objects/ReplyObject');
/* #region AorA */

/**
* 寻找s1的末尾和s2的开头的重复部分
Expand All @@ -24,15 +25,9 @@ function LookForTheSame(s1, s2) {
return -1;
}

/**
* 根据含“不”的选择性询问生成对应回复
* @param {string} ask 接受的消息
* @return {ReplyObject} 所有可选项
*/
function AorA(ask) {
let reply = new ReplyObject(ask);
ask = reply.getNoneCQCodeAsk();

function DoOrNotDo(askObject) {
let ask = askObject.ask;
let reply = new ReplyObject(askObject);
// 排除不含“不”、含“不不”、过长或过短的消息
// if (!ask.includes("不") || ask.includes("不不") || ask.length > 30 || ask.length < 3) return reply.no();

Expand Down Expand Up @@ -85,7 +80,7 @@ function AorA(ask) {

// 细节处理
// 重复词有“!”视为恶意代码,不作回应(没人会用"学!code不学!code"聊天吧)
if (endString.includes("!") || endString.includes("!")) return reply.no();
if (doString.includes("!") || doString.includes("!")) return reply.no();
// 结束词包含疑问词/符号,取符号前的语句
if (endString.length > 0) {
const endStringRegex = /(.*?)(?=\?|?|!|!|,|,|\.|。|呢)+/;
Expand All @@ -105,6 +100,5 @@ function AorA(ask) {
return reply;
}

/* #endregion */

module.exports = AorA;
module.exports = DoOrNotDo;
53 changes: 53 additions & 0 deletions QuestionType/QuestionTypeHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict';

const DoOrNotDo = require('./DoOrNotDo');
const ThisOrThat = require('./ThisOrThat');
const TrueOrFalse = require('./TrueOrFalse');

class QuestionTypeHelper {

// 初步判断疑问句
static maybeIsQuestion(s) {
return (!!s.match(/(.+)[嘛嗎吗呢啊麽么呀呐吧\??]([\??])?/));
}

// 初步判断正反问句
static maybeIsPorN(s) { // 是Positive or negative
return (s.includes("不") && !s.includes("不不") && s.length >= 3);
}

// 初步判断选择问句
static maybeIsChoice(s) {
return (s.indexOf("还是") > 0);
}

// 反问句 需要排除
static isRhetorical(s) {
const keyWords = ["难道", "这么", "那么", "不是吗"];
return keyWords.some(function (item, index) {
if (s.includes(item)) return true;
})
}

// 特指问句 需要排除
static isSpecific(s) {
const keyWords = ["什么", "怎么", "谁", "多少", "哪", "几", "多"];
return keyWords.some(function (item, index) {
if (s.includes(item)) return true;
})
}

static getMethod(s) {
if (this.isRhetorical(s)) return false;
if (this.isSpecific(s)) return false;
if (this.maybeIsChoice(s)) return ThisOrThat;
if (this.maybeIsQuestion(s)) return TrueOrFalse;
if (this.maybeIsPorN(s)) return DoOrNotDo;
return false;
}

}



module.exports = QuestionTypeHelper;
44 changes: 44 additions & 0 deletions QuestionType/ThisOrThat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';

const ReplyObject = require('../objects/ReplyObject');

function ThisOrThat(askObject) {
let ask = askObject.ask;
let reply = new ReplyObject(askObject);

// 按“还是”分割
let arrDo = ask.split("还是");
// arrDo不应为undefined,应用该方法前ask应该已经被筛选过

// 如果有“是”,去掉是之前的词
let isIndex = arrDo[0].lastIndexOf("是");
if (isIndex >= 0 && isIndex < arrDo[0].length - 1) arrDo[0] = arrDo[0].substring(isIndex + 1);

// 重复词有“!”视为恶意代码,不作回应
let isCommand = arrDo.some(function (item, index) {
if (item.includes("!") || item.includes("!")) return true;
});
if (isCommand) return reply.no();

// 包含疑问词/符号,取符号前的do语句
const doStringRegex = /(.*?)(?=\?|?|,|,|\.|。|呢)+/;
arrDo.map((item, index) => {
let matchResult = item.match(doStringRegex);
if (matchResult instanceof Array) {
arrDo[index] = matchResult[0];
}
});

// 去除空值
arrDo = arrDo.filter(item => item.trim() !== "");
if (arrDo.length <= 0) return reply.no();

// 生成选项
reply.setChoices(arrDo);
reply.flipPosition();
return reply;
}

/* #endregion */

module.exports = ThisOrThat;
10 changes: 6 additions & 4 deletions builders/DoOrNot.js → QuestionType/TrueOrFalse.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

const ReplyObject = require('../objects/ReplyObject');
const path = require('path');

Expand Down Expand Up @@ -95,9 +97,9 @@ function isResultContainWord(result, word) {
}


function doOrNot(ask) {
let reply = new ReplyObject(ask);
ask = reply.getNoneCQCodeAsk();
function TrueOrFalse(askObject) {
let ask = askObject.ask;
let reply = new ReplyObject(askObject);

let result = segment.doSegment(ask, {
stripPunctuation: true // 去除标点
Expand Down Expand Up @@ -131,4 +133,4 @@ function doOrNot(ask) {
}


module.exports = doOrNot;
module.exports = TrueOrFalse;
32 changes: 4 additions & 28 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,19 @@
'use strict';
//for better includes..
//require('app-module-path/cwd');


const finder = require('./objects/findBuilder');
const sendMessageObject = require('./objects/sendMessageObject');


const run = require('./run');

// TODO
// 1. cq code

const sentMessageCollection = require('./objects/sentMessageCollection');
let smc = new sentMessageCollection();

let b = new finder();
// Koishi插件名
module.exports.name = 'SillyResponseBot';
// 插件处理和输出
module.exports.apply = (ctx) => {
ctx.middleware((meta, next) => {
let ask = meta.message;
ask = ask.trim();
if (ask.startsWith("!") || ask.startsWith("!")) {
try {
let str = ask.substring(1).trim();
const builder = b.returnBuilderIfMatched(str);
if (!builder) return next();
const r = builder(str);
if (!r.reply) return next();
let replyString = r.toString();
if (!replyString) return next();
let smo = new sendMessageObject(meta, r, replyString);
smo.recordAndSendMessage();
} catch (ex) {
console.log(ex);
return next();
}
} else {
return next();
}
run(meta, next, smc);
});
};

33 changes: 7 additions & 26 deletions objects/ReplyObject.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
'use strict';

const AskObject = require('./askObject');

function ReplyObject(ask) {
//initial vars
function ReplyObject(askObject) {

this.reply = true;
this.lastReply = "";
this.choices = [];
this.replies = [];

//should be the message sent in removed any hinting chars.
this.ask = ask;
this.askObject = new AskObject(this.ask);
this.askObject = askObject;

//set the default action to randomly pick an response in the choices array.
this.formatter = function() {
Expand All @@ -21,13 +15,8 @@ function ReplyObject(ask) {
};
}

ReplyObject.prototype.getNoneCQCodeAsk = function() {
return this.askObject.cutQRCode();
};


ReplyObject.prototype.setChoices = function(choices) {
this.choices = choices.map(str => this.askObject.reputQRCode(str));
this.choices = choices.map(str => this.askObject.reputCQCode(str));
return this;
};

Expand All @@ -37,20 +26,11 @@ ReplyObject.prototype.format = function(formatter) {
return this;
};

//get last response message
ReplyObject.prototype.getLastReply = function () {
return this.replies[this.replies.length - 1];
};

//get an string response as well as record them
ReplyObject.prototype.toString = function() {
if (typeof this.formatter === 'function') {
//forceed to be String
const reply = this.formatter().toString();

//save the reply for future use.
this.replies.push(reply);
return reply;
return this.formatter().toString();
} else {
//default action: return undefined
return undefined;
Expand All @@ -63,9 +43,10 @@ ReplyObject.prototype.no = function() {
no.reply = false;
return no;
};

// 人称代词转换
// 以后“是你吗” -> “不是我” 也用得到,现在暂时只回答“不是”
ReplyObject.prototype.flipPosition = function(str) {
ReplyObject.prototype.flipPosition = function() {
this.choices = this.choices.map(str => str.split("").map(char => (char === '我') ? '你' : (char === '你' ? '我' : char)).join(""));
};

Expand Down
52 changes: 26 additions & 26 deletions objects/askObject.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
'use strict';
// const { CQCode } = require('koishi-utils');

class askObject {
constructor(msg) {
this.ask = msg;

class AskObject {
constructor(meta) {
this.ask = meta.message.trim();

this.replaceObjects = [];
this.replaceTexts = [];
}

// 简体化
//const simplify = require('koishi-utils').simplify;
// 检查开头是否为! 或者为@bot
cutCommand(botQQ) {
if (this.ask.startsWith("!") || this.ask.startsWith("!")) {
this.ask = this.ask.substring(1).trim();
return true;
}
else if (botQQ) {
const atBot = `[CQ:at,qq=${botQQ}]`;
if (this.ask.startsWith(atBot)) {
this.ask = ask.substring(atBot.length).trim();
return true;
}
}
return false;
}

// html转意符换成普通字符
escape2Html(str) {
Expand All @@ -22,23 +35,8 @@ class askObject {
return str.replace(/\r?\n/g, "");
}

cutQRCode() {
// 不管[]内容是不是CQcode,反正总是要替换回来的,没有必要去来回转换,下面都白写了
/*
this.cqCodeObject = CQCode.parseAll(this.msg);
this.cqCodeObject.forEach((cqCode, i) => {
// 纯文本,处理特殊字符
if (cqCode.type === 'text') this.replacedMsg += this.removeReturn(this.escape2Html(cqCode.data.text));
// CQ对象,暂存并以其他文本替代,回复时再替换回来
else {
let replaceText = "[cqObjcet" + i + "]";
this.replacedMsg += replaceText;
this.replaceTexts.push(replaceText);
this.replaceObjects.push(cqCode);
}
});
return this.replacedMsg;
*/
// 将CQCode保存起来并用其他字符替换
cutCQCode() {
const _this = this;
let output = this.ask.replace(/\[(.+?)\]/g, function (matchString, group, index, orgString) {
let replacedIndex = _this.replaceObjects.indexOf(matchString);
Expand All @@ -52,10 +50,12 @@ class askObject {
return _this.replaceTexts[replacedIndex];
}
});
return this.removeReturn(this.escape2Html(output));
this.ask = this.removeReturn(this.escape2Html(output));
return this.ask;
}

reputQRCode(replymsg) {
// 将CQCode替换回去
reputCQCode(replymsg) {
const _this = this;
return replymsg.replace(/\[(cqObjcet[0-9]+)\]/g, function (matchString, group, index, orgString) {
let replacedIndex = _this.replaceTexts.indexOf(matchString);
Expand All @@ -66,4 +66,4 @@ class askObject {

}

module.exports = askObject;
module.exports = AskObject;
Loading