209 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { SoupGameMessage } from "../../constant/message"
import db from "../../db"
import { SoupGame } from "../../db/soupGame"
import { Context } from "../../types"
import { isP2POrAtBot } from "../../utils/message"
/**
* 开启或者停止游戏
* @param ctx
* @param value
*/
const startOrStopGame = async (
ctx: Context,
value: boolean,
which: "auto" | "manual" = "manual"
) => {
const {
logger,
larkBody: { chatId, messageId },
attachService,
larkCard,
larkService,
} = ctx
const cardGender = larkCard.child("soupAgent")
if (!chatId) {
logger.error("chatId is required")
return
}
// 获取正在进行中的游戏
const activeGame = await db.soupGame.getActiveOneByChatId(chatId)
if (!activeGame) {
logger.info(`chatId: ${chatId} has no active game`)
}
// 停止游戏
if (!value) {
// 没有进行中的游戏是私聊或者at机器人回复停止游戏
if (!activeGame && isP2POrAtBot(ctx)) {
await larkService.message.replyCard(
messageId,
cardGender.genSuccessCard(SoupGameMessage.hasStopped)
)
return
}
// 没有进行中的游戏,且是正常对话,不响应
if (!activeGame) return
// 有进行中的游戏,关闭游戏
logger.info(`chatId: ${chatId} is closing the game`)
const res = await db.soupGame.close(activeGame.id)
if (!res) {
logger.error(`chatId: ${chatId} failed to close the game`)
await larkService.message.replyCard(
messageId,
cardGender.genErrorCard(SoupGameMessage.startFailed)
)
}
// 手动结束
if (which === "manual") {
await larkService.message.replyCard(
messageId,
cardGender.genCard("markdownSuccessCard", {
content: `
游戏结束!
**汤面:**${activeGame?.query}
**汤底:**${activeGame?.answer}`,
})
)
} else {
// 自动结束
await larkService.message.replyCard(
messageId,
cardGender.genCard("markdownSuccessCard", {
llmRes: `
恭喜您回答正确!游戏结束!
**汤面:**${activeGame?.query}
**汤底:**${activeGame?.answer}`,
})
)
}
return
}
// 开始游戏,有进行中的游戏
if (activeGame) {
logger.info(`chatId: ${chatId} has an active game`)
await larkService.message.replyCard(
messageId,
cardGender.genSuccessCard(SoupGameMessage.hasStarted)
)
return
}
logger.info(`chatId: ${chatId} is starting a new game`)
// 没有进行中的游戏,开始新游戏
const game = await attachService.startSoup()
if (!game) {
logger.error(`chatId: ${chatId} failed to start a new game`)
await larkService.message.replyCard(
messageId,
cardGender.genErrorCard(SoupGameMessage.startFailed)
)
return
}
// 写到数据库
const newSoupGame: SoupGame = {
...game,
chatId,
history: [],
active: true,
}
const res = await db.soupGame.create(newSoupGame)
if (!res) {
logger.error(`chatId: ${chatId} failed to create a new game`)
await larkService.message.replyCard(
messageId,
cardGender.genErrorCard(SoupGameMessage.startFailed)
)
return
}
logger.info(`chatId: ${chatId} created a new game`)
// 回复用户模型的消息
await larkService.message.replyCard(
messageId,
cardGender.genCard("markdownSuccessCard", {
content: `
游戏开始啦!
**题目:**${game.title}
**汤面:**${game.query}
艾特机器人说“结束游戏”即可结束游戏
`,
})
)
}
const chat2Soup = async (ctx: Context) => {
const {
larkBody: { msgText, chatId, messageId },
logger,
attachService,
larkCard,
larkService,
} = ctx
const cardGender = larkCard.child("soupAgent")
const activeGame = await db.soupGame.getActiveOneByChatId(chatId)
if (!activeGame) {
logger.info(`chatId: ${chatId} has no active game`)
return
}
const {
data: { message_id },
} = await larkService.message.reply(messageId, "text", "模型生成中...")
const res = await attachService.chat2Soup({
user_query: msgText,
soup_id: activeGame.title,
history: "",
})
if (!res) {
logger.error(`chatId: ${chatId} failed to get soup result`)
await larkService.message.replyCard(
messageId,
cardGender.genErrorCard(SoupGameMessage.chatFailed)
)
return
}
// 用户答对了
if (res.type === "END") {
await startOrStopGame(ctx, false, "auto")
return
}
// 继续游戏,更新历史记录
await db.soupGame.insertHistory(activeGame.id, [
...activeGame.history,
msgText,
])
// 回复用户模型的消息
await larkService.message.update(message_id, res.content, true)
}
/**
* 海龟汤游戏
* @param ctx
*/
const soupAgent = async (ctx: Context) => {
const {
larkBody: { msgText, chatId },
} = ctx
if (!chatId) return
if (msgText === "开始游戏" && isP2POrAtBot(ctx)) {
startOrStopGame(ctx, true)
return true
}
if (msgText === "结束游戏" || msgText === "停止游戏") {
startOrStopGame(ctx, false)
return true
}
const activeGame = await db.soupGame.getActiveOneByChatId(chatId)
if (!activeGame) return false
chat2Soup(ctx)
return true
}
export default soupAgent