Java 电报机器人-根据最后一个机器人问题处理来自用户的响应
我希望我的电报机器人根据机器人提出的最后一个问题处理用户输入。基本上,这就是流程:Java 电报机器人-根据最后一个机器人问题处理来自用户的响应,java,telegram,telegram-bot,Java,Telegram,Telegram Bot,我希望我的电报机器人根据机器人提出的最后一个问题处理用户输入。基本上,这就是流程: 用户调用/验证命令 机器人请求电子邮件 用户发送他的电子邮件 Bot会回复一条消息,告诉用户将代码发送到用户的电子邮件进行确认,并要求用户在聊天室中键入代码 用户输入代码 Bot验证用户代码,用户通过身份验证并开始接收通知 问题是:我如何知道用户在这个流中回答特定的bot问题 我考虑了两种方法: 使用强制回复选项发送消息,以便用户必须回复机器人问题。这会将用户响应的消息发回给我,这样我就可以比较bot消息字
- 用户调用/验证命令
- 机器人请求电子邮件
- 用户发送他的电子邮件
- Bot会回复一条消息,告诉用户将代码发送到用户的电子邮件进行确认,并要求用户在聊天室中键入代码
- 用户输入代码
- Bot验证用户代码,用户通过身份验证并开始接收通知
- 使用强制回复选项发送消息,以便用户必须回复机器人问题。这会将用户响应的消息发回给我,这样我就可以比较bot消息字符串,看看答案是什么
- 将最后一条bot消息存储在某个位置,然后当消息到达时,检查最后一条bot消息是什么,并假设用户消息是响应
有更好的办法吗?我将Java与一起使用。通常为了具体说明向电报机器人发送的内容,您将使用命令与机器人进行通信(电报命令以/开头,每个命令在服务器端都有一个特定的命令处理程序),不幸的是,到目前为止,无法将额外的参数与命令一起发送到电报机器人,您可以使用下面对话中提到的解决方法之一: 如果您不熟悉使用java的bot命令,请参考以下示例:
我希望这有帮助 开发电报机器人程序时最常用的任务之一。
有一个解决方案,您需要为Laravel安装shapoapps/multibot\u驱动程序包(composer需要shapoapps/multibot\u驱动程序)
此软件包有一个会话管理器,类似于网页用户的会话。在每个用户消息之后,您将用户输入记录到服务器端的会话中。当收到每个新请求(消息)时,您从会话读取数据并构建逻辑。
这里是文档-因为很难找到可以引导我找到解决方案的想法(在Java中),为了未来的Java Google用户,我将在这里分享我的想法。我正在与Spring Boot/Data一起使用 实现此流的最佳方法是在数据库中保存状态。为此,使用消息独特的聊天ID来区分一个聊天室和另一个聊天室 以下是Java实现的相关部分(该逻辑几乎适用于任何语言): 保存与系统用户有关的电报聊天信息的实体
@Entity
@Table(name = "user_bot")
public class UserBot implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "chat_id", unique = true, nullable = false, length = 255)
private String chatId;
@Column(name = "bot_verification_code", length = 6)
private String botVerificationCode;
@Enumerated
@Column(name = "last_bot_state", columnDefinition = "SMALLINT DEFAULT NULL")
private BotState lastBotState;
@Column(columnDefinition = "TINYINT(1)")
private boolean verified;
@JoinColumn(name = "user_id", referencedColumnName = "id")
@ManyToOne(fetch = FetchType.EAGER)
private User user;
}
表示所有可能的bot响应(状态)的枚举
接收消息并作出相应响应的服务
@Service
public class TelegramBotService extends TelegramLongPollingBot {
@Autowired
private CodeUtils codeUtils;
@Autowired
private UserBotRepository userBotRepository;
@Autowired
private UserRepository userRepository;
@Value("${telegram.bot.username}")
private String botUsername;
@Value("${telegram.bot.token}")
private String botToken;
@PostConstruct
public void registerBot() {
TelegramBotsApi botsApi = new TelegramBotsApi();
try {
botsApi.registerBot(this);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
@Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
String receivedMessage = update.getMessage().getText();
SendMessage sendMessage = null;
// TODO: futuramente, tratar casos onde um usuário chama um comando sem ainda estar autenticado
switch (receivedMessage) {
case "/autenticar":
sendMessage = handleAuthentication(update);
break;
default:
// Quando nenhum comando atender, será um texto a ser checado de acordo com o estado anterior
sendMessage = checkState(update);
}
try {
execute(sendMessage);
} catch (TelegramApiException e) {
codeUtils.log(e.getMessage(), this);
}
}
}
private SendMessage handleAuthentication(Update update) {
SendMessage sendMessage = new SendMessage()
.setChatId(update.getMessage().getChatId())
.setText(BotState.AUTH_STEP_1.toString());
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
if (userBot == null) {
userBot = new UserBot();
userBot.setChatId(update.getMessage().getChatId().toString());
userBot.setLastBotState(BotState.AUTH_STEP_1);
} else if (userBot.isVerified()) {
// Um texto simples enviado no sendMessage indica o fim de um fluxo
sendMessage.setText("Este aparelho já está autenticado no sistema.");
userBot.setLastBotState(null);
}
userBotRepository.save(userBot);
return sendMessage;
}
// Checa o estado anterior do bot em relação ao chatId recebido
private SendMessage checkState(Update update) {
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
SendMessage sendMessage = null;
if (userBot == null || userBot.getLastBotState() == null)
return sendDefaultMessage(update);
switch (Optional.ofNullable(userBot.getLastBotState()).orElse(BotState.NO_STATE)) {
case AUTH_STEP_1:
sendMessage = sendCode(update);
break;
case AUTH_STEP_2:
sendMessage = validateCode(update);
break;
default:
sendMessage = sendDefaultMessage(update);
}
return sendMessage;
}
// Grava o código no banco e envia para o e-mail do usuário
private SendMessage sendCode(Update update) {
User user = userRepository.findByEmail(update.getMessage().getText().toLowerCase());
SendMessage sendMessage = new SendMessage(update.getMessage().getChatId(), "");
if (user == null)
sendMessage.setText("Não encontrei nenhum usuário no sistema com este e-mail :(");
else {
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
String verificationCode = Integer.toString(new Random().nextInt(899999) + 100000);
String text = "Este é um e-mail automático de verificação de identidade. Informe este código para o bot do Telegram: " + verificationCode;
codeUtils.sendEmail(new String[]{user.getEmail()}, "CCR Laudos - Código de Verificação", text);
// Associa a conversação ao usuário, mas a validade depende da flag verified
userBot.setUser(user);
userBot.setBotVerificationCode(verificationCode);
userBot.setLastBotState(BotState.AUTH_STEP_2);
userBotRepository.save(userBot);
sendMessage.setText(BotState.AUTH_STEP_2.toString());
}
return sendMessage;
}
// Checa se o código informado foi o mesmo passado por e-mail para o usuário a fim de autenticá-lo
private SendMessage validateCode(Update update) {
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
SendMessage sendMessage = new SendMessage(update.getMessage().getChatId(), "");
if (update.getMessage().getText().equals(userBot.getBotVerificationCode())) {
userBot.setVerified(true);
sendMessage.setText("O aparelho foi autenticado com sucesso. Você passará a receber notificações do sistema.");
} else {
userBot.setUser(null);
sendMessage.setText("Código inválido.");
}
userBotRepository.save(userBot);
return sendMessage;
}
private SendMessage sendDefaultMessage(Update update) {
String markdownMessage = "Não entendi \ud83e\udd14 \n"
+ "Que tal tentar um comando digitando */* ?";
return new SendMessage(update.getMessage().getChatId(), markdownMessage).setParseMode(ParseMode.MARKDOWN);
}
@Override
public String getBotUsername() {
return this.botUsername;
}
@Override
public String getBotToken() {
return this.botToken;
}
}
实现的流程是:
就这样!希望它能帮助别人。我正在使用Java:(是的,在发送命令时不可能使用参数。但我想做的是模仿BotFather在创建机器人时所做的流程。
@Service
public class TelegramBotService extends TelegramLongPollingBot {
@Autowired
private CodeUtils codeUtils;
@Autowired
private UserBotRepository userBotRepository;
@Autowired
private UserRepository userRepository;
@Value("${telegram.bot.username}")
private String botUsername;
@Value("${telegram.bot.token}")
private String botToken;
@PostConstruct
public void registerBot() {
TelegramBotsApi botsApi = new TelegramBotsApi();
try {
botsApi.registerBot(this);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
@Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
String receivedMessage = update.getMessage().getText();
SendMessage sendMessage = null;
// TODO: futuramente, tratar casos onde um usuário chama um comando sem ainda estar autenticado
switch (receivedMessage) {
case "/autenticar":
sendMessage = handleAuthentication(update);
break;
default:
// Quando nenhum comando atender, será um texto a ser checado de acordo com o estado anterior
sendMessage = checkState(update);
}
try {
execute(sendMessage);
} catch (TelegramApiException e) {
codeUtils.log(e.getMessage(), this);
}
}
}
private SendMessage handleAuthentication(Update update) {
SendMessage sendMessage = new SendMessage()
.setChatId(update.getMessage().getChatId())
.setText(BotState.AUTH_STEP_1.toString());
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
if (userBot == null) {
userBot = new UserBot();
userBot.setChatId(update.getMessage().getChatId().toString());
userBot.setLastBotState(BotState.AUTH_STEP_1);
} else if (userBot.isVerified()) {
// Um texto simples enviado no sendMessage indica o fim de um fluxo
sendMessage.setText("Este aparelho já está autenticado no sistema.");
userBot.setLastBotState(null);
}
userBotRepository.save(userBot);
return sendMessage;
}
// Checa o estado anterior do bot em relação ao chatId recebido
private SendMessage checkState(Update update) {
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
SendMessage sendMessage = null;
if (userBot == null || userBot.getLastBotState() == null)
return sendDefaultMessage(update);
switch (Optional.ofNullable(userBot.getLastBotState()).orElse(BotState.NO_STATE)) {
case AUTH_STEP_1:
sendMessage = sendCode(update);
break;
case AUTH_STEP_2:
sendMessage = validateCode(update);
break;
default:
sendMessage = sendDefaultMessage(update);
}
return sendMessage;
}
// Grava o código no banco e envia para o e-mail do usuário
private SendMessage sendCode(Update update) {
User user = userRepository.findByEmail(update.getMessage().getText().toLowerCase());
SendMessage sendMessage = new SendMessage(update.getMessage().getChatId(), "");
if (user == null)
sendMessage.setText("Não encontrei nenhum usuário no sistema com este e-mail :(");
else {
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
String verificationCode = Integer.toString(new Random().nextInt(899999) + 100000);
String text = "Este é um e-mail automático de verificação de identidade. Informe este código para o bot do Telegram: " + verificationCode;
codeUtils.sendEmail(new String[]{user.getEmail()}, "CCR Laudos - Código de Verificação", text);
// Associa a conversação ao usuário, mas a validade depende da flag verified
userBot.setUser(user);
userBot.setBotVerificationCode(verificationCode);
userBot.setLastBotState(BotState.AUTH_STEP_2);
userBotRepository.save(userBot);
sendMessage.setText(BotState.AUTH_STEP_2.toString());
}
return sendMessage;
}
// Checa se o código informado foi o mesmo passado por e-mail para o usuário a fim de autenticá-lo
private SendMessage validateCode(Update update) {
UserBot userBot = userBotRepository.findByChatId(update.getMessage().getChatId().toString());
SendMessage sendMessage = new SendMessage(update.getMessage().getChatId(), "");
if (update.getMessage().getText().equals(userBot.getBotVerificationCode())) {
userBot.setVerified(true);
sendMessage.setText("O aparelho foi autenticado com sucesso. Você passará a receber notificações do sistema.");
} else {
userBot.setUser(null);
sendMessage.setText("Código inválido.");
}
userBotRepository.save(userBot);
return sendMessage;
}
private SendMessage sendDefaultMessage(Update update) {
String markdownMessage = "Não entendi \ud83e\udd14 \n"
+ "Que tal tentar um comando digitando */* ?";
return new SendMessage(update.getMessage().getChatId(), markdownMessage).setParseMode(ParseMode.MARKDOWN);
}
@Override
public String getBotUsername() {
return this.botUsername;
}
@Override
public String getBotToken() {
return this.botToken;
}
}