在控制台中编程简单的 Chatterbot?

Programming Simple Chatterbot in console?

大家好,我是业余码农,请多多关照

我不想进入 swing/switch 对话框编程,因此我希望它尽可能简单。但同样,我不希望我的代码包含很多 if an else 语句。我正在寻找更多使聊天机器人更流畅的方法。我尝试搜索和理解字符串和数组,但我仍然不知道如何将其实现到我的编码中。

这是我第一次尝试制作一个简单的聊天机器人

    import java.util.Scanner;

public class ChatBot {

    public static void main(String[] args) {
        System.out.println("");
        Scanner sc = new Scanner(System.in);
        System.out.println("Hello I'm your therapist for today! What's your name? \n");
        String n = sc.nextLine();
        System.out.println("Okay " + n + ", How are you?");

        while (true) {
            System.out.println(" ");
            String inputs = sc.nextLine();
            inputs = inputs.toUpperCase();

            if (inputs.indexOf("FINE") >= 0) {
                System.out.println("That's good to know " + n);
            }

            else if (inputs.indexOf("HI") >= 0) {
                System.out.println("Hello " + n);
            }

            else if (inputs.indexOf("HELP") >= 0) {
                System.out.println("If you seek help, listen to your heart! <3");
            }

            else if (inputs.indexOf("HELP ME") >= 1) {
                System.out.println("I will try my best helping you, what's your problem?");
            }

            // what if bot doesn't know the answer to fyour question/response?
            // The chatbot gives a random respond to unknown questions by the user
            // here the number of random responses are given 4, but in java we start at 0
            // I have made the number to 4, so that the responses can be from between 0 to 3
            // Also I have added Math.random utility and declared it to a double value
            // The "r" is now my random, and I make a new integar to calculate random
            // response
            // by calculating the r times num variables and thereby getting a random value.
            // that random value is declared to "rResponse" and therefore I have assigned
            // the
            // String response to answer/reply depending on the random number that's
            // generated
            // between 0-3
            else {
                final int num = 4;
                double r = Math.random();
                int rResponse = (int) (r * num);
                String response = "";

                if (rResponse == 0) {
                    response = "Hmmm...";
                }

                else if (rResponse == 1) {
                    response = "Okay?...";
                }

                else if (rResponse == 2) {
                    response = "I don't get it...";
                }

                else if (rResponse == 3) {
                    response = "I dont quite follow, I'm sorry. Try another question";
                }
                System.out.println(response);

            }
        }

    }

}

总之,我的问题在

                else if (inputs.indexOf("HELP ME") >= 1) {
                    System.out.println("I will try my best helping you, what's your problem?"); }
else if (inputs.indexOf("HELP") >= 0) {
                System.out.println("If you seek help, listen to your heart! <3"); }

这段代码是我无法让它响应我希望机器人单独回答的两个不同用户输入的事实。例如,当你说“帮助我”而不是“帮助”时,我希望它有不同的反应。

是否有任何建议或方法可以让我以不同的方式执行此操作?

此外,如果有人可以让我知道如何用另一种方法重做所有这些,通过使用 arraylist?还是二维数组?如果它对像我这样的初学者来说不是太硬核。没有执行所有这些 if 和 else 语句的简单方法是什么?

提前致谢。

在这种情况下,您应该转向 equals:

else if ("HELP ME".equals(inputs)) {
                System.out.println("I will try my best helping you, what's your problem?"); 
} else if ("HELP".equals(inputs)) {
     System.out.println("If you seek help, listen to your heart! <3"); 
}

与常量字符串比较的一般做法是将字符串常量放在第一位,然后将变量放在第二位,以防止 NPE(NullPointerException),以防 inputs 为空。

回到你的问题,我认为你可以使用 HashMap 来避免 if-else 语句:

HashMap<> handlers = new HashMap<String, Runnable>();
handlers.add("FINE", () -> {
    System.out.println("That's good to know " + n);
});

.... add other handlers.

do while {
   
    Get your handler from  handlers and call run on it.
    If no handler not found, try randome response.
}

它比 indexOfequals 操作更有效。

顺便说一句,Spring Shell 是编写 shell 应用程序的良好入门。

我假设您了解 classes、方法和字段。如果你不这样做,这个解释就没有任何意义。

我们将使用 classes 和 java.util.List 接口构建一个树数据结构。

第一步是构建一个 getter / setter class 来保存响应和下一个问题的 List 索引。

这是class。

public class Response {
    
    private final String response;
    
    private final int responseQuestion;

    public Response(String response, int responseQuestion) {
        this.response = response.toLowerCase();
        this.responseQuestion = responseQuestion;
    }
    
    public boolean doesResponseMatch(String responseString) {
        return responseString.toLowerCase().contains(getResponse());
    }

    public String getResponse() {
        return response;
    }

    public int getResponseQuestion() {
        return responseQuestion;
    }

}

doesResponseMatch 方法确定用户键入的 responseString 是否包含响应 String

我们将响应保存为小写 String 并将用户 responseString 转换为小写,以便包含测试与大小写无关。

剩下的class是典型的getter/setterclass.

下一步是创建一个 class,其中包含一个问题、一个 List 个可能的回答和一个默认回答。如果 none 个可能的响应匹配,则使用默认响应。

public class Question {
    
    private final String question;
    
    private final Response defaultResponse;
    
    private List<Response> possibleResponses;

    public Question(String question, Response defaultResponse) {
        this.question = question;
        this.defaultResponse = defaultResponse;
        this.possibleResponses = new ArrayList<>();
    }
    
    public void addPossibleResponse(Response response) {
        this.possibleResponses.add(response);
    }
    
    public Response getPossibleResponse(String responseString) {
        for (Response response : this.possibleResponses) {
            if (response.doesResponseMatch(responseString)) {
                return response;
            }
        }
        
        return this.defaultResponse;
    }

    public String getQuestion() {
        return question;
    }
    
}

getPossibleResponse 方法returns匹配响应,如果没有匹配,则默认响应。

问题可以包含零个、一个或多个匹配的回答。每个响应都可以指向不同的问题索引。

我们用一个java.util.ArrayList来容纳List。由于我们要一次添加所有问题,因此数组列表是保存树的合适结构。

下一步是创建一个 class 来保存我们的树结构,这将是 Question 个实例的 List

public class ResponseTree {
    
    private List<Question> questions;
    
    public ResponseTree() {
        this.questions = new ArrayList<>();
        addQuestionFactory();
    }
    
    private void addQuestionFactory() {
        Response defaultResponse = new Response("", 0);
        String question = "I don't understand your response.";
        addQuestion(question, defaultResponse);
        
        // Add your additional questions / responses here.
        // Using a List means we can point to any question by it's 
        // location number from 0 to List size() - 1.
        // This is a tree structure, stored in a List.
    }
    
    private void addQuestion(String question, Response defaultResponse) {
        this.questions.add(new Question(question, defaultResponse));
    }
}

addQuestionFactory 是一个单独的方法,因为它会增长以包含您要回答的所有聊天机器人问题。我已经包含了明显的第一个问题。

您可以通过编写聊天机器人的其余部分来测试此代码。任何回应都将由第一个问题回答。编写完聊天机器人的其余部分后,您可以向工厂方法添加问题和响应。

通过使用 classes,我们创建了一个如下所示的树结构:

Tree (List)
    Question
        String
        List of possible responses
        Default response

Response
    String
    Index pointer

通过使用 classes,我们可以隐藏一些复杂性并使我们的代码更易于理解。