[add] 羽球配對功能
This commit is contained in:
parent
ce93877e8d
commit
570c0443d4
@ -14,16 +14,19 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/dateformat": "^5.0.0",
|
"@types/dateformat": "^5.0.0",
|
||||||
"@types/express": "^4.17.15",
|
"@types/express": "^4.17.15",
|
||||||
|
"@types/mysql": "^2.15.21",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@line/bot-sdk": "^7.5.2",
|
"@line/bot-sdk": "^7.5.2",
|
||||||
"dateformat": "^4.5.1",
|
"dateformat": "^4.5.1",
|
||||||
|
"dayjs": "^1.11.7",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"linebot": "^1.6.1",
|
"linebot": "^1.6.1",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
"nodemon": "^2.0.20",
|
"nodemon": "^2.0.20",
|
||||||
"openai": "^3.1.0",
|
"openai": "^3.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
319
src/Badminton.ts
Normal file
319
src/Badminton.ts
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
import * as line from "@line/bot-sdk";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import DBTools from "./DBTools";
|
||||||
|
import { NumberEx } from "./Engine/Number/NumberEx";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badminton
|
||||||
|
*/
|
||||||
|
export default class Badminton {
|
||||||
|
|
||||||
|
//#region Custom
|
||||||
|
|
||||||
|
public static async Run(msg: string[]): Promise<line.Message | line.Message[]> {
|
||||||
|
let message: line.Message | line.Message[] = null;
|
||||||
|
const instruction: string = msg[1];
|
||||||
|
switch (instruction) {
|
||||||
|
case "查詢參加人員": {
|
||||||
|
const text: string = await this.searchPlay(+msg[2]);
|
||||||
|
message = {
|
||||||
|
type: "text",
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "查詢對戰人員": {
|
||||||
|
message = await this.searchMatch(+msg[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case "查詢戰績": {
|
||||||
|
// const queryresp: any = await this.searchPlay(value);
|
||||||
|
// message.text = "Success";
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
case "輸入名單": {
|
||||||
|
message = await this.inputList(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async searchPlay(date: number): Promise<string> {
|
||||||
|
let resp: string = "";
|
||||||
|
const query: string = String.Format("SELECT * FROM `badminton` WHERE `time` = '{0}' LIMIT 1;", date);
|
||||||
|
const queryresp: any[] = await DBTools.Query(query);
|
||||||
|
if (queryresp.length > 0) {
|
||||||
|
resp = queryresp[0].personnel;
|
||||||
|
} else {
|
||||||
|
resp = "這天沒有對戰資料";
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async searchMatch(date: number): Promise<line.Message | line.Message[]> {
|
||||||
|
let resp: line.Message | line.Message[] = {
|
||||||
|
type: "text",
|
||||||
|
text: "這天沒有對戰資料"
|
||||||
|
};
|
||||||
|
const query: string = String.Format("SELECT * FROM `badminton` WHERE `time` = '{0}' LIMIT 1;", date);
|
||||||
|
const queryresp: any[] = await DBTools.Query(query);
|
||||||
|
if (queryresp.length > 0) {
|
||||||
|
const matchData_Str: string = queryresp[0].battlecombination;
|
||||||
|
if (matchData_Str) {
|
||||||
|
const matchData: any = JSON.parse(matchData_Str);
|
||||||
|
resp = this.getMatch_LineFlex(date.toString(), matchData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 輸入名單
|
||||||
|
* @param msg
|
||||||
|
*/
|
||||||
|
private static async inputList(msg: any[]): Promise<line.Message | line.Message[]> {
|
||||||
|
const date: number = +msg[2];
|
||||||
|
let personnelDatas: any[] = [];
|
||||||
|
for (let i: number = 3; i < msg.length; i++) {
|
||||||
|
const personnelData: any[] = JSON.parse(msg[i]);
|
||||||
|
personnelDatas.push(personnelData);
|
||||||
|
}
|
||||||
|
const personnel_str: string = JSON.stringify(personnelDatas);
|
||||||
|
const query: string = String.Format("INSERT INTO `badminton` (time,personnel) VALUES ({0},'{1}') ON DUPLICATE KEY UPDATE personnel='{2}';"
|
||||||
|
, date, personnel_str, personnel_str);
|
||||||
|
await DBTools.Query(query);
|
||||||
|
return await this.listMatch(date, personnelDatas, personnel_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async listMatch(date: number, personnelDatas: any[], personnel_str: string): Promise<line.Message | line.Message[]> {
|
||||||
|
let man: string[] = [];
|
||||||
|
let woman: string[] = [];
|
||||||
|
for (let i: number = 0; i < personnelDatas.length; i++) {
|
||||||
|
const personnelData: any[] = personnelDatas[i];
|
||||||
|
if (personnelData[0]) {
|
||||||
|
man.push(personnelData[1]);
|
||||||
|
} else {
|
||||||
|
woman.push(personnelData[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 打亂
|
||||||
|
man.sort(function (): number {
|
||||||
|
return (0.5 - Math.random());
|
||||||
|
});
|
||||||
|
woman.sort(function (): number {
|
||||||
|
return (0.5 - Math.random());
|
||||||
|
});
|
||||||
|
let diffCount: number = Math.abs(NumberEx.minus(man.length, woman.length));
|
||||||
|
if (man.length !== woman.length && diffCount >= 2) {
|
||||||
|
const needDiffCount: number = NumberEx.divide(diffCount, 2);
|
||||||
|
if (man.length > woman.length) {
|
||||||
|
for (let i: number = 0; i < needDiffCount; i++) {
|
||||||
|
woman.push(man.shift());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i: number = 0; i < needDiffCount; i++) {
|
||||||
|
man.push(woman.shift());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const totalRound: number = 3;
|
||||||
|
const totalCount: number = man.length > woman.length ? man.length : woman.length;
|
||||||
|
let lastmatch: Object = {};
|
||||||
|
let check: string[] = [];
|
||||||
|
let m_temp: number[] = [];
|
||||||
|
let w_temp: number[] = [];
|
||||||
|
for (let i: number = 0; i < totalCount; i++) {
|
||||||
|
m_temp.push(i);
|
||||||
|
w_temp.push(i);
|
||||||
|
}
|
||||||
|
for (let i: number = 0; i < totalRound; i++) {
|
||||||
|
const [match_num, check_temp] = this.getMatch(totalCount, check, m_temp, w_temp);
|
||||||
|
let match: string[][] = [];
|
||||||
|
check = check_temp;
|
||||||
|
for (let j: number = 0; j < match_num.length; j++) {
|
||||||
|
const [m, w] = match_num[j];
|
||||||
|
const man_str: string = man[m] ?? "那個";
|
||||||
|
const woman_str: string = woman[w] ?? "那個";
|
||||||
|
match.push([man_str, woman_str]);
|
||||||
|
}
|
||||||
|
lastmatch[i] = match;
|
||||||
|
}
|
||||||
|
// console.log(`manCount: ${man.length}, womanCount: ${woman.length}`);
|
||||||
|
const result: string = JSON.stringify(lastmatch);
|
||||||
|
const query: string = String.Format("INSERT INTO `badminton` (time,personnel,battlecombination) VALUES ({0},'{1}','{3}') ON DUPLICATE KEY UPDATE battlecombination='{2}';"
|
||||||
|
, date, personnel_str, result, result);
|
||||||
|
// console.log(`query: ${query}`);
|
||||||
|
await DBTools.Query(query);
|
||||||
|
let message: line.Message | line.Message[] = this.getMatch_LineFlex(date.toString(), lastmatch);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得名單
|
||||||
|
* @param totalCount
|
||||||
|
* @param check
|
||||||
|
* @param m_temp
|
||||||
|
* @param w_temp
|
||||||
|
* @param repeatCount
|
||||||
|
*/
|
||||||
|
private static getMatch(totalCount: number, check: string[], m_temp: number[], w_temp: number[]): [number[][], string[]] {
|
||||||
|
const repeatMaxCount: number = 10;
|
||||||
|
let check_temp: string[] = [].concat(check);
|
||||||
|
const match: number[][] = [];
|
||||||
|
let m: number[] = [].concat(m_temp);
|
||||||
|
let w: number[] = [].concat(w_temp);
|
||||||
|
// 打亂
|
||||||
|
m.sort(function (): number {
|
||||||
|
return (0.5 - Math.random());
|
||||||
|
});
|
||||||
|
w.sort(function (): number {
|
||||||
|
return (0.5 - Math.random());
|
||||||
|
});
|
||||||
|
for (let j: number = 0; j < totalCount; j++) {
|
||||||
|
for (let k: number = 0; k < repeatMaxCount; k++) {
|
||||||
|
const check_str: string = `m${m[0]}w${w[0]}`;
|
||||||
|
if (check.includes(check_str) && j !== totalCount - 1) {
|
||||||
|
w.sort(function (): number {
|
||||||
|
return (0.5 - Math.random());
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
check_temp.push(check_str);
|
||||||
|
match.push([m.shift(), w.shift()]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [match, check_temp];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得名單Line模板
|
||||||
|
* @param date
|
||||||
|
* @param matchs
|
||||||
|
*/
|
||||||
|
private static getMatch_LineFlex(date: string, matchs: Object): line.Message | line.Message[] {
|
||||||
|
const contents: any[] = [];
|
||||||
|
const dateTime_Str: string = `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`;
|
||||||
|
let dateTime: number = new Date(dateTime_Str).getTime();
|
||||||
|
let date_Str: string = dayjs(Math.floor(dateTime)).format("YYYY-MM-DD");
|
||||||
|
for (let i: number = 0, matchKey: string[] = Object.keys(matchs); i < matchKey.length; i++) {
|
||||||
|
const key: string = matchKey[i];
|
||||||
|
const match: string[] = matchs[key];
|
||||||
|
let boxs: any[] = [];
|
||||||
|
const bubble: any = {
|
||||||
|
"type": "bubble",
|
||||||
|
"size": "micro",
|
||||||
|
"body": {
|
||||||
|
"type": "box",
|
||||||
|
"layout": "vertical"
|
||||||
|
},
|
||||||
|
"styles": {
|
||||||
|
"footer": {
|
||||||
|
"separator": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const bubble_contents: Object = [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "勝皇羽球團",
|
||||||
|
"weight": "bold",
|
||||||
|
"color": "#1DB446",
|
||||||
|
"size": "sm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": date_Str,
|
||||||
|
"weight": "bold",
|
||||||
|
"size": "xl",
|
||||||
|
"margin": "sm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": `第${i + 1}輪`,
|
||||||
|
"weight": "bold",
|
||||||
|
"size": "xxl",
|
||||||
|
"margin": "sm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "separator",
|
||||||
|
"margin": "md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "box",
|
||||||
|
"layout": "horizontal",
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "一號隊友",
|
||||||
|
"size": "sm",
|
||||||
|
"flex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "二號隊友",
|
||||||
|
"size": "sm",
|
||||||
|
"align": "center"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"margin": "md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "separator",
|
||||||
|
"margin": "sm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "box",
|
||||||
|
"layout": "vertical",
|
||||||
|
"contents": boxs,
|
||||||
|
"spacing": "sm",
|
||||||
|
"margin": "md"
|
||||||
|
}];
|
||||||
|
for (let j: number = 0; j < match.length; j++) {
|
||||||
|
const box: any = {
|
||||||
|
"type": "box",
|
||||||
|
"layout": "horizontal",
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": match[j][0],
|
||||||
|
"size": "sm",
|
||||||
|
"flex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": match[j][1],
|
||||||
|
"size": "sm",
|
||||||
|
"align": "center"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
boxs.push(box);
|
||||||
|
}
|
||||||
|
bubble.body["contents"] = bubble_contents;
|
||||||
|
contents.push(bubble);
|
||||||
|
}
|
||||||
|
const messages: line.Message[] = [
|
||||||
|
{
|
||||||
|
"type": "flex",
|
||||||
|
"altText": "對戰組合名單",
|
||||||
|
"contents":
|
||||||
|
{
|
||||||
|
"type": "carousel",
|
||||||
|
"contents": contents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
}
|
44
src/DBTools.ts
Normal file
44
src/DBTools.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import mysql from "mysql";
|
||||||
|
import Tools from "./Tools";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DBTools
|
||||||
|
*/
|
||||||
|
export default class DBTools {
|
||||||
|
|
||||||
|
//#region Custom
|
||||||
|
|
||||||
|
public static async Query(query: string): Promise<any> {
|
||||||
|
const conn: mysql.Connection = this.connect();
|
||||||
|
|
||||||
|
let resp: any = null;
|
||||||
|
let run: boolean = true;
|
||||||
|
conn.query(query, function (err: mysql.MysqlError, rows: any, fields: mysql.FieldInfo[]): void {
|
||||||
|
if (err) {
|
||||||
|
console.error(`${query} Error: \n${err.message}`);
|
||||||
|
run = false;
|
||||||
|
}
|
||||||
|
resp = rows;
|
||||||
|
run = false;
|
||||||
|
});
|
||||||
|
while (run) {
|
||||||
|
await Tools.Sleep(100);
|
||||||
|
}
|
||||||
|
conn.end();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static connect(): mysql.Connection {
|
||||||
|
const conn: mysql.Connection = mysql.createConnection({
|
||||||
|
host: process.env.DB_HOST,
|
||||||
|
port: +process.env.DB_PORT,
|
||||||
|
user: process.env.DB_USER,
|
||||||
|
password: process.env.DB_PASSWORD,
|
||||||
|
database: process.env.DB_DATABASE
|
||||||
|
});
|
||||||
|
conn.connect();
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
}
|
116
src/Engine/CCExtensions/ArrayExtension.ts
Normal file
116
src/Engine/CCExtensions/ArrayExtension.ts
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
declare interface Array<T> {
|
||||||
|
/**
|
||||||
|
* 移除一個值並且回傳
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
ExRemoveAt(index: number): T;
|
||||||
|
/**
|
||||||
|
* 移除全部值(注意. 參考的也會被清空)
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* let bar: number[] = [1, 2, 3];
|
||||||
|
* let bar2: number[] = bar;
|
||||||
|
* bar.Clear();
|
||||||
|
* console.log(bar, bar2);
|
||||||
|
*
|
||||||
|
* // {
|
||||||
|
* // "bar": [],
|
||||||
|
* // "bar2": []
|
||||||
|
* // }
|
||||||
|
*/
|
||||||
|
Clear(): void;
|
||||||
|
/**
|
||||||
|
* 物件陣列排序,asc&key陣列長度請一樣
|
||||||
|
* PS. boolean 帶false是先true在false
|
||||||
|
* @link JavaScript Object 排序 http://www.eion.com.tw/Blogger/?Pid=1170#:~:text=JavaScript%20Object%20排序
|
||||||
|
* @param asc 是否升序排列(小到大)
|
||||||
|
* @param key 需排序的key(優先順序左到右)(沒有就放空)
|
||||||
|
*/
|
||||||
|
ObjectSort(asc?: boolean[], key?: string[]): any[];
|
||||||
|
/**
|
||||||
|
* 設計給Array<cc.Component.EventHandler>forHoldButton使用
|
||||||
|
* Add a non persistent listener to the UnityEvent.
|
||||||
|
* @param call Callback function.
|
||||||
|
*/
|
||||||
|
AddListener(call: Function): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.prototype.ExRemoveAt || Object.defineProperty(Array.prototype, "ExRemoveAt", {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (index: number): any {
|
||||||
|
let item: any = this.splice(index, 1);
|
||||||
|
return item[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Array.prototype.Clear || Object.defineProperty(Array.prototype, "Clear", {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (): void {
|
||||||
|
this.length = 0;
|
||||||
|
|
||||||
|
// let foo: number[] = [1, 2, 3];
|
||||||
|
// let bar: number[] = [1, 2, 3];
|
||||||
|
// let foo2: number[] = foo;
|
||||||
|
// let bar2: number[] = bar;
|
||||||
|
// foo = [];
|
||||||
|
// bar.length = 0;
|
||||||
|
// console.log(foo, bar, foo2, bar2);
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "foo": [],
|
||||||
|
// "bar": [],
|
||||||
|
// "foo2": [
|
||||||
|
// 1,
|
||||||
|
// 2,
|
||||||
|
// 3
|
||||||
|
// ],
|
||||||
|
// "bar2": []
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Array.prototype.ObjectSort || Object.defineProperty(Array.prototype, "ObjectSort", {
|
||||||
|
enumerable: false,
|
||||||
|
/**
|
||||||
|
* @param asc 是否升序排列(小到大)
|
||||||
|
* @param key 需排序的key(優先順序左到右)(沒有就放空)
|
||||||
|
*/
|
||||||
|
value: function (asc: boolean[] = [true], key?: string[]): any[] {
|
||||||
|
if (this.length === 0) {
|
||||||
|
return this;
|
||||||
|
} else if (!key || key.length === 0) {
|
||||||
|
console.error(`ObjectSort key error`);
|
||||||
|
return this;
|
||||||
|
} else if (asc.length !== key.length) {
|
||||||
|
console.error(`ObjectSort key asc error asc.length: ${asc.length}, key.length: ${key.length}`);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
for (let i: number = 0; i < key.length; i++) {
|
||||||
|
const keyname: string = key[i];
|
||||||
|
if (this[0][keyname] === undefined) {
|
||||||
|
console.error(`ObjectSort has not key[${i}]: ${keyname}`);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let count: number = key ? key.length : 1;
|
||||||
|
let arr: any[];
|
||||||
|
for (let i: number = count - 1; i >= 0; i--) {
|
||||||
|
arr = this.sort(function (a: any, b: any): 1 | -1 {
|
||||||
|
let mya: any = a;
|
||||||
|
let myb: any = b;
|
||||||
|
if (key) {
|
||||||
|
mya = a[key[i]];
|
||||||
|
myb = b[key[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加個等於數字相同不要再去排序到
|
||||||
|
if (asc[i]) {
|
||||||
|
return mya >= myb ? 1 : -1;
|
||||||
|
} else {
|
||||||
|
return mya <= myb ? 1 : -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
});
|
10
src/Engine/CCExtensions/CCExtension.ts.meta
Normal file
10
src/Engine/CCExtensions/CCExtension.ts.meta
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.0",
|
||||||
|
"uuid": "b373f805-9297-4af5-8ea6-0a250649b5b0",
|
||||||
|
"importer": "typescript",
|
||||||
|
"isPlugin": false,
|
||||||
|
"loadPluginInWeb": true,
|
||||||
|
"loadPluginInNative": true,
|
||||||
|
"loadPluginInEditor": false,
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
189
src/Engine/CCExtensions/NumberExtension.ts
Normal file
189
src/Engine/CCExtensions/NumberExtension.ts
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
|
||||||
|
declare interface Number {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金額每三位數(千)加逗號, 並且補到小數點第2位
|
||||||
|
* 輸出 41,038,560.00
|
||||||
|
* @param precision 補到小數點第幾位
|
||||||
|
* @param isPadZero 是否要補零
|
||||||
|
* */
|
||||||
|
ExFormatNumberWithComma(precision?: number, isPadZero?: boolean): string;
|
||||||
|
/**
|
||||||
|
* 基本4位數(9,999-999B-T)
|
||||||
|
* */
|
||||||
|
ExTransferToBMK(precision?: number,offset?: number): string;
|
||||||
|
/**
|
||||||
|
* 數字轉字串, 頭補0
|
||||||
|
* @param size
|
||||||
|
*/
|
||||||
|
Pad(size: number): string;
|
||||||
|
/**
|
||||||
|
* 四捨五入到小數點第X位 (同server計算規則)
|
||||||
|
* @param precision
|
||||||
|
*/
|
||||||
|
ExToNumRoundDecimal(precision: number): number;
|
||||||
|
/**
|
||||||
|
* 無條件捨去到小數點第X位
|
||||||
|
* @param precision
|
||||||
|
*/
|
||||||
|
ExToNumFloorDecimal(precision: number): number;
|
||||||
|
/**
|
||||||
|
* 無條件捨去強制保留X位小數,如:2,會在2後面補上00.即2.00
|
||||||
|
* @param precision 補到小數點第幾位
|
||||||
|
* @param isPadZero 是否要補零
|
||||||
|
*/
|
||||||
|
ExToStringFloorDecimal(precision: number, isPadZero?: boolean): string;
|
||||||
|
/**
|
||||||
|
* 取整數)
|
||||||
|
*/
|
||||||
|
ExToInt():number;
|
||||||
|
/**
|
||||||
|
* 小數轉整數(支援科學符號)
|
||||||
|
*/
|
||||||
|
Float2Fixed():number;
|
||||||
|
/**
|
||||||
|
* 數字長度(支援科學符號)
|
||||||
|
*/
|
||||||
|
DigitLength():number;
|
||||||
|
|
||||||
|
target: number;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Number.prototype.ExFormatNumberWithComma || Object.defineProperty(Number.prototype, 'ExFormatNumberWithComma', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (precision: number = 2, isPadZero: boolean = true) {
|
||||||
|
|
||||||
|
// let arr = String(this).split('.');
|
||||||
|
let arr = this.ExToStringFloorDecimal(precision, isPadZero).split('.');
|
||||||
|
let num = arr[0], result = '';
|
||||||
|
while (num.length > 3) {
|
||||||
|
result = ',' + num.slice(-3) + result;
|
||||||
|
num = num.slice(0, num.length - 3);
|
||||||
|
}
|
||||||
|
if (num.length > 0) result = num + result;
|
||||||
|
return arr[1] ? result + '.' + arr[1] : result;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
Number.prototype.ExTransferToBMK || Object.defineProperty(Number.prototype, 'ExTransferToBMK', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (precision: number=2,offset: number = 0) {
|
||||||
|
/**千 */
|
||||||
|
let MONEY_1K: number = 1000;
|
||||||
|
/**萬 */
|
||||||
|
// let MONEY_10K: number = 10000;
|
||||||
|
/**十萬 */
|
||||||
|
// let MONEY_100K: number = 100000;
|
||||||
|
/**百萬 */
|
||||||
|
let MONEY_1M: number = 1000000;
|
||||||
|
/**千萬 */
|
||||||
|
// let MONEY_10M: number = 10000000;
|
||||||
|
/**億 */
|
||||||
|
// let MONEY_100M: number = 100000000;
|
||||||
|
/**十億 */
|
||||||
|
let MONEY_1B: number = 1000000000;
|
||||||
|
/**百億 */
|
||||||
|
// let MONEY_10B: number = 10000000000;
|
||||||
|
/**千億 */
|
||||||
|
// let MONEY_100B: number = 100000000000;
|
||||||
|
/**兆 */
|
||||||
|
// let MONEY_1T: number = 1000000000000;
|
||||||
|
offset = Math.pow(10, offset);
|
||||||
|
// if (this >= MONEY_1T * offset) {
|
||||||
|
// //(3)1,000T
|
||||||
|
// //1T~
|
||||||
|
// return (~~(this / MONEY_1T)).ExFormatNumberWithComma(0) + "T";
|
||||||
|
// }
|
||||||
|
if (this >= MONEY_1B * offset) {
|
||||||
|
//1,000B~900,000B
|
||||||
|
//1B~900B
|
||||||
|
return (this / MONEY_1B).ExFormatNumberWithComma(3, false) + "B";
|
||||||
|
}
|
||||||
|
else if (this >= MONEY_1M * offset) {
|
||||||
|
//1,000M~900,000M
|
||||||
|
//1M~900M
|
||||||
|
return (this / MONEY_1M).ExFormatNumberWithComma(3, false) + "M";
|
||||||
|
}
|
||||||
|
else if (this >= MONEY_1K * offset) {
|
||||||
|
//1,000K~900,000K
|
||||||
|
//1K~90K
|
||||||
|
return (this / MONEY_1K).ExFormatNumberWithComma(3, false) + "K";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//0~9,000,000
|
||||||
|
//0~9,000
|
||||||
|
return this.ExFormatNumberWithComma(precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Number.prototype.Pad || Object.defineProperty(Number.prototype, 'Pad', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (size: number) {
|
||||||
|
let s = this + "";
|
||||||
|
while (s.length < size) s = "0" + s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Number.prototype.ExToNumRoundDecimal || Object.defineProperty(Number.prototype, 'ExToNumRoundDecimal', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (precision: number) {
|
||||||
|
return Math.round(Math.round(this * Math.pow(10, (precision || 0) + 1)) / 10) / Math.pow(10, (precision || 0));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Number.prototype.ExToInt || Object.defineProperty(Number.prototype, 'ExToInt',{
|
||||||
|
enumerable: false,
|
||||||
|
value: function (){
|
||||||
|
return ~~this;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Number.prototype.ExToNumFloorDecimal || Object.defineProperty(Number.prototype, 'ExToNumFloorDecimal', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (precision: number) {
|
||||||
|
let str = this.toPrecision(12);
|
||||||
|
let dotPos = str.indexOf('.');
|
||||||
|
return dotPos == -1 ? this : +`${str.substr(0, dotPos + 1 + precision)}`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Number.prototype.ExToStringFloorDecimal || Object.defineProperty(Number.prototype, 'ExToStringFloorDecimal', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function (precision: number, isPadZero: boolean = true) {
|
||||||
|
// 取小數點第X位
|
||||||
|
let f = this.ExToNumFloorDecimal(precision);
|
||||||
|
let s = f.toString();
|
||||||
|
// 補0
|
||||||
|
if (isPadZero) {
|
||||||
|
let rs = s.indexOf('.');
|
||||||
|
if (rs < 0) {
|
||||||
|
rs = s.length;
|
||||||
|
s += '.';
|
||||||
|
}
|
||||||
|
while (s.length <= rs + precision) {
|
||||||
|
s += '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Number.prototype.Float2Fixed || Object.defineProperty(Number.prototype, 'Float2Fixed', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function () {
|
||||||
|
if (this.toString().indexOf('e') === -1) {
|
||||||
|
return Number(this.toString().replace('.', ''));
|
||||||
|
}
|
||||||
|
const dLen = this.DigitLength();
|
||||||
|
return dLen > 0 ? +parseFloat((this * Math.pow(10, dLen)).toPrecision(12)) : this;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Number.prototype.DigitLength || Object.defineProperty(Number.prototype, 'DigitLength', {
|
||||||
|
enumerable: false,
|
||||||
|
value: function () {
|
||||||
|
const eSplit = this.toString().split(/[eE]/);
|
||||||
|
const len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
|
||||||
|
return len > 0 ? len : 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
84
src/Engine/Number/NumberEx.ts
Normal file
84
src/Engine/Number/NumberEx.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
export module NumberEx {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测数字是否越界,如果越界给出提示
|
||||||
|
* @param {*number} num 输入数
|
||||||
|
*/
|
||||||
|
function checkBoundary(num: number) {
|
||||||
|
if (_boundaryCheckingState) {
|
||||||
|
if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
|
||||||
|
console.warn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 精确乘法
|
||||||
|
*/
|
||||||
|
export function times(num1: number, num2: number, ...others: number[]): number {
|
||||||
|
if (others.length > 0) {
|
||||||
|
return times(times(num1, num2), others[0], ...others.slice(1));
|
||||||
|
}
|
||||||
|
const num1Changed = num1.Float2Fixed();
|
||||||
|
const num2Changed = num2.Float2Fixed();
|
||||||
|
const baseNum = num1.DigitLength() + num2.DigitLength();
|
||||||
|
const leftValue = num1Changed * num2Changed;
|
||||||
|
|
||||||
|
checkBoundary(leftValue);
|
||||||
|
|
||||||
|
return leftValue / Math.pow(10, baseNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 精确加法
|
||||||
|
*/
|
||||||
|
export function plus(num1: number, num2: number, ...others: number[]): number {
|
||||||
|
if (others.length > 0) {
|
||||||
|
return plus(plus(num1, num2), others[0], ...others.slice(1));
|
||||||
|
}
|
||||||
|
const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength()));
|
||||||
|
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 精确减法
|
||||||
|
*/
|
||||||
|
export function minus(num1: number, num2: number, ...others: number[]): number {
|
||||||
|
if (others.length > 0) {
|
||||||
|
return minus(minus(num1, num2), others[0], ...others.slice(1));
|
||||||
|
}
|
||||||
|
const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength()));
|
||||||
|
return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 精确除法
|
||||||
|
*/
|
||||||
|
export function divide(num1: number, num2: number, ...others: number[]): number {
|
||||||
|
if (others.length > 0) {
|
||||||
|
return divide(divide(num1, num2), others[0], ...others.slice(1));
|
||||||
|
}
|
||||||
|
const num1Changed = num1.Float2Fixed();
|
||||||
|
const num2Changed = num2.Float2Fixed();
|
||||||
|
checkBoundary(num1Changed);
|
||||||
|
checkBoundary(num2Changed);
|
||||||
|
return times((num1Changed / num2Changed), Math.pow(10, num2.DigitLength() - num1.DigitLength()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 四舍五入
|
||||||
|
*/
|
||||||
|
export function round(num: number, ratio: number): number {
|
||||||
|
const base = Math.pow(10, ratio);
|
||||||
|
return divide(Math.round(times(num, base)), base);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _boundaryCheckingState = false;
|
||||||
|
/**
|
||||||
|
* 是否进行边界检查
|
||||||
|
* @param flag 标记开关,true 为开启,false 为关闭
|
||||||
|
*/
|
||||||
|
function enableBoundaryChecking(flag = true) {
|
||||||
|
_boundaryCheckingState = flag;
|
||||||
|
}
|
||||||
|
}
|
90
src/Engine/Number/RandomEx.ts
Normal file
90
src/Engine/Number/RandomEx.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
|
||||||
|
export module RandomEx {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得隨機布林值
|
||||||
|
*/
|
||||||
|
export function GetBool() {
|
||||||
|
return GetInt() >= 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 取得隨機整數(回傳min ~ max - 1)
|
||||||
|
* @param min
|
||||||
|
* @param max
|
||||||
|
*/
|
||||||
|
export function GetInt(min: number = Number.MIN_VALUE, max: number = Number.MAX_VALUE): number {
|
||||||
|
return Math.floor(Math.random() * (max - min)) + min;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 取得隨機小數
|
||||||
|
* @param min
|
||||||
|
* @param max
|
||||||
|
*/
|
||||||
|
export function GetFloat(min: number = Number.MIN_VALUE, max: number = Number.MAX_VALUE): number {
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 隨機取得複數個不重複回傳
|
||||||
|
* @param num 取得數量
|
||||||
|
* @param items 陣列
|
||||||
|
*/
|
||||||
|
export function GetMultiNoRepeat(num: number, items: any[]): any[] {
|
||||||
|
let result: any[] = [];
|
||||||
|
for (let i: number = 0; i < num; i++) {
|
||||||
|
let ran: number = Math.floor(Math.random() * items.length);
|
||||||
|
let item = items.splice(ran, 1)[0];
|
||||||
|
if (result.indexOf(item) == -1) {
|
||||||
|
result.push(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根據權重取得複數個不重複回傳
|
||||||
|
* @param prize 獎項
|
||||||
|
* @param weights 機率
|
||||||
|
* @param count 數量
|
||||||
|
*/
|
||||||
|
export function GetMultiNoRepeatByWeight(prize: any[], weights: number[] = null, count: number = 1): any[] {
|
||||||
|
if (weights === null) {
|
||||||
|
weights = [];
|
||||||
|
for (let i: number = 0; i < prize.length; i++) {
|
||||||
|
weights.push(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let target: any[] = [];
|
||||||
|
for (let i: number = 0; i < count; i++) {
|
||||||
|
let results: number[] = RandomEx.GetPrizeByWeight(prize, weights);
|
||||||
|
prize.splice(results[0], 1);
|
||||||
|
weights.splice(results[0], 1);
|
||||||
|
target.push(results[1]);
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根據權重隨機取值
|
||||||
|
* @param prize 獎項
|
||||||
|
* @param weights 機率
|
||||||
|
*/
|
||||||
|
export function GetPrizeByWeight(prize: any[], weights: number[]): any[] {
|
||||||
|
if (prize.length !== weights.length) {
|
||||||
|
console.error(`GetWeight error -> prize.length:${prize.length} !== weights.length:${weights.length}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let totalWeight: number = 0;
|
||||||
|
for (let i: number = 0; i < weights.length; i++) {
|
||||||
|
totalWeight += weights[i];
|
||||||
|
}
|
||||||
|
let random: number = RandomEx.GetInt(0, totalWeight) + 1;
|
||||||
|
let nowWeight: number = weights[0];
|
||||||
|
for (let i: number = 0; i < weights.length; i++) {
|
||||||
|
if (nowWeight >= random) {
|
||||||
|
return [i, prize[i]];
|
||||||
|
}
|
||||||
|
nowWeight += weights[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/Engine/String.ts
Normal file
16
src/Engine/String.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
interface StringConstructor {
|
||||||
|
IsNullOrEmpty: (value: string) => boolean;
|
||||||
|
Format: (format: string, ...args: any[]) => string;
|
||||||
|
}
|
||||||
|
|
||||||
|
String.IsNullOrEmpty = function (value: string): boolean {
|
||||||
|
return value === undefined || value === null || value.trim() === "";
|
||||||
|
};
|
||||||
|
|
||||||
|
String.Format = function (format: string, ...args: any[]): string {
|
||||||
|
return format.replace(/{(\d+)}/g, (match, index) => {
|
||||||
|
let value: any = args[index];
|
||||||
|
if (value === null || value === undefined) { return ""; }
|
||||||
|
return "" + value;
|
||||||
|
});
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import * as line from "@line/bot-sdk";
|
import * as line from "@line/bot-sdk";
|
||||||
|
import Badminton from "./Badminton";
|
||||||
import OpenAI from "./OpenAI";
|
import OpenAI from "./OpenAI";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,8 +69,8 @@ export default class MessageClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async User(event: any): Promise<any> {
|
public async User(event: any): Promise<any> {
|
||||||
let userId = event.source.userId;
|
let userId: string = event.source.userId;
|
||||||
let replyMsg = event.message.text;
|
let replyMsg: string = event.message.text;
|
||||||
// let displayName = "";
|
// let displayName = "";
|
||||||
// let profile = await this.bot.getProfile(userId);
|
// let profile = await this.bot.getProfile(userId);
|
||||||
// if (profile) {
|
// if (profile) {
|
||||||
@ -77,61 +78,34 @@ export default class MessageClass {
|
|||||||
// }
|
// }
|
||||||
// 豬喵 特別功能
|
// 豬喵 特別功能
|
||||||
if ([process.env.toJianMiau, process.env.toZhuHan].includes(userId)) {
|
if ([process.env.toJianMiau, process.env.toZhuHan].includes(userId)) {
|
||||||
|
/** 訊息 */
|
||||||
|
let msg: string[] = event.message.text.split(" ");
|
||||||
|
|
||||||
|
if (userId === process.env.toJianMiau) {
|
||||||
|
// 建喵 指令功能
|
||||||
|
/** 指令 */
|
||||||
|
let instruction: string = msg[0];
|
||||||
|
switch (instruction) {
|
||||||
|
case "羽球": {
|
||||||
|
const messages: line.Message | line.Message[] = await Badminton.Run(msg);
|
||||||
|
if (messages) {
|
||||||
|
return this.bot.replyMessage(event.replyToken, messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
const response: string = await OpenAI.RunOpenAI(replyMsg);
|
||||||
|
replyMsg = response;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 豬涵 指令功能
|
||||||
const response: string = await OpenAI.RunOpenAI(replyMsg);
|
const response: string = await OpenAI.RunOpenAI(replyMsg);
|
||||||
replyMsg = response;
|
replyMsg = response;
|
||||||
}
|
}
|
||||||
// /** 訊息 */
|
}
|
||||||
// let Msg = event.message.text.split(" ");
|
|
||||||
|
|
||||||
// /** 指令 */
|
|
||||||
// let Instruction = Msg[0];
|
|
||||||
// switch (Instruction) {
|
|
||||||
// case "msg":
|
|
||||||
// case "Msg":
|
|
||||||
// case "MSG": {
|
|
||||||
// if (userId == process.env.toJianMiau) {
|
|
||||||
// replyMsg = "";
|
|
||||||
// if (Msg[1] === "豬涵") {
|
|
||||||
// if (Msg[2] === "豬涵") {
|
|
||||||
// Msg[2] = process.env.toZhuHantoZhuHan;
|
|
||||||
// } else if (Msg[2] === "建喵") {
|
|
||||||
// Msg[2] = process.env.toZhuHantoJianMiau;
|
|
||||||
// }
|
|
||||||
// for (let i = 3; i < Msg.length; i++) {
|
|
||||||
// replyMsg += Msg[i] + (i === Msg.length - 1 ? "" : " ");
|
|
||||||
// }
|
|
||||||
// let res_Msg = this.ZhuHanbot.push(Msg[2], replyMsg);
|
|
||||||
// } else {
|
|
||||||
// for (let i = 3; i < Msg.length; i++) {
|
|
||||||
// replyMsg += Msg[i] + (i === Msg.length - 1 ? "" : " ");
|
|
||||||
// }
|
|
||||||
// let res_Msg = this.bot.push(Msg[2], replyMsg);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let ToJM_message = "已發送訊息:";
|
|
||||||
// ToJM_message += `\nMyId: ${Msg[1]}`;
|
|
||||||
// ToJM_message += `\nuserId: ${Msg[2]}`;
|
|
||||||
// ToJM_message += `\nmessage: ${replyMsg}`;
|
|
||||||
// let res_reply = event.reply(ToJM_message).then(function (data) {
|
|
||||||
// // 當訊息成功回傳後的處理
|
|
||||||
// }).catch(function (error) {
|
|
||||||
// // 當訊息回傳失敗後的處理
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// default: {
|
|
||||||
// // 使用event.reply(要回傳的訊息)方法可將訊息回傳給使用者
|
|
||||||
// event.reply(replyMsg).then(function (data) {
|
|
||||||
// // 當訊息成功回傳後的處理
|
|
||||||
// }).catch(function (error) {
|
|
||||||
// // 當訊息回傳失敗後的處理
|
|
||||||
// });
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return this.bot.replyMessage(event.replyToken, {
|
return this.bot.replyMessage(event.replyToken, {
|
||||||
type: "text",
|
type: "text",
|
||||||
text: replyMsg
|
text: replyMsg
|
||||||
@ -142,6 +116,29 @@ export default class MessageClass {
|
|||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Group(event: any): Promise<any> {
|
||||||
|
let groupId: string = event.source.groupId;
|
||||||
|
// 羽球 特別功能
|
||||||
|
if ([process.env.toBadminton].includes(groupId)) {
|
||||||
|
/** 訊息 */
|
||||||
|
let msg: string[] = event.message.text.split(" ");
|
||||||
|
/** 指令 */
|
||||||
|
let instruction: string = msg[0];
|
||||||
|
switch (instruction) {
|
||||||
|
case "羽球": {
|
||||||
|
const messages: line.Message | line.Message[] = await Badminton.Run(msg);
|
||||||
|
if (messages) {
|
||||||
|
return this.bot.replyMessage(event.replyToken, messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Group(event) {
|
// Group(event) {
|
||||||
// switch (event.source.groupId) {
|
// switch (event.source.groupId) {
|
||||||
// case process.env.toYoutube: {
|
// case process.env.toYoutube: {
|
||||||
|
@ -8,13 +8,14 @@ export default class OpenAI {
|
|||||||
//#region Custom
|
//#region Custom
|
||||||
|
|
||||||
public static async RunOpenAI(msg: string): Promise<string> {
|
public static async RunOpenAI(msg: string): Promise<string> {
|
||||||
const configuration = new Configuration({
|
const configuration: Configuration = new Configuration({
|
||||||
apiKey: process.env.OPENAI_API_KEY,
|
apiKey: process.env.OPENAI_API_KEY,
|
||||||
});
|
});
|
||||||
const openai = new OpenAIApi(configuration);
|
const openai: OpenAIApi = new OpenAIApi(configuration);
|
||||||
|
// tslint:disable-next-line:typedef
|
||||||
const response = await openai.createCompletion({
|
const response = await openai.createCompletion({
|
||||||
model: "text-davinci-003",
|
model: "text-davinci-003",
|
||||||
prompt: msg,
|
prompt: "人類:" + msg,
|
||||||
temperature: 0.7,
|
temperature: 0.7,
|
||||||
max_tokens: 256,
|
max_tokens: 256,
|
||||||
top_p: 1,
|
top_p: 1,
|
||||||
@ -22,8 +23,8 @@ export default class OpenAI {
|
|||||||
presence_penalty: 0,
|
presence_penalty: 0,
|
||||||
});
|
});
|
||||||
let resptext: string = msg;
|
let resptext: string = msg;
|
||||||
const choices = response.data.choices;
|
const choices: CreateCompletionResponseChoicesInner[] = response.data.choices;
|
||||||
for (let i = 0; i < choices.length; i++) {
|
for (let i: number = 0; i < choices.length; i++) {
|
||||||
const choice: CreateCompletionResponseChoicesInner = choices[i];
|
const choice: CreateCompletionResponseChoicesInner = choices[i];
|
||||||
resptext += choice.text;
|
resptext += choice.text;
|
||||||
}
|
}
|
||||||
|
13
src/Tools.ts
Normal file
13
src/Tools.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Tools
|
||||||
|
*/
|
||||||
|
export default class Tools {
|
||||||
|
|
||||||
|
//#region Custom
|
||||||
|
|
||||||
|
public static Sleep(ms: number): Promise<any> {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
}
|
@ -3,8 +3,14 @@
|
|||||||
// 監聽檔案變化 "npm start"
|
// 監聽檔案變化 "npm start"
|
||||||
// 連線Debug "npm run dev"
|
// 連線Debug "npm run dev"
|
||||||
|
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import "dayjs/locale/zh-tw";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
|
import "./Engine/CCExtensions/ArrayExtension";
|
||||||
|
import "./Engine/CCExtensions/NumberExtension";
|
||||||
|
import "./Engine/String";
|
||||||
import LineBotClass from "./LineBotClass";
|
import LineBotClass from "./LineBotClass";
|
||||||
|
|
||||||
|
dayjs.locale("zh-tw");
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
new LineBotClass();
|
new LineBotClass();
|
Loading…
Reference in New Issue
Block a user