org.loklak.susi.SusiLog.java Source code

Java tutorial

Introduction

Here is the source code for org.loklak.susi.SusiLog.java

Source

/**
 *  SusiLog
 *  Copyright 24.07.2016 by Michael Peter Christen, @0rb1t3r
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program in the file lgpl21.txt
 *  If not, see <http://www.gnu.org/licenses/>.
 */

package org.loklak.susi;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import org.eclipse.jetty.util.ConcurrentHashSet;
import org.json.JSONException;
import org.json.JSONObject;
import org.loklak.tools.UTF8;
import org.loklak.tools.storage.JsonTray;

/**
 * Susis log is a kind of reflection about the conversation in the past
 */
public class SusiLog {

    private final static String[] failterms = new String[] { "You can ask me anything, but not that :)",
            "Oh sorry, I don't understand what you say. Please ask something else!", "Das weiss ich leider nicht.",
            "I don't know." };
    private final static String[] donotremoveunanswered = new String[] { "was ?(.*)", ".+ (?:.+ )+(.+)", "(.*)",
            "(.*) ?sorry ?(.*)", "(.*) ?you ?(.*)", "what ?(.*)", "you ?(.*)" };
    private final static Set<String> failset = new HashSet<>();
    private final static Set<String> dnruset = new HashSet<>();
    static {
        for (String t : failterms)
            failset.add(t);
        for (String t : donotremoveunanswered)
            dnruset.add(t);
    }

    private File root;
    private int rc;
    private Map<String, UserRecord> logs;
    private Map<String, Map<String, JsonTray>> rulesets;
    private Set<String> unanswered;

    public SusiLog(File storageLocation, int rememberLatestCount) {
        this.root = storageLocation;
        this.rc = rememberLatestCount;
        this.logs = new ConcurrentHashMap<>();
        this.rulesets = new ConcurrentHashMap<>();
        this.unanswered = null;
    }

    public Set<String> getUnanswered() {
        if (this.unanswered != null)
            return this.unanswered;
        this.unanswered = new ConcurrentHashSet<>();
        // debug
        for (String c : this.root.list()) {
            getInteractions(c).forEach(i -> {
                String query = i.getQuery().toLowerCase();
                String answer = i.getAnswer();
                if (query.length() > 0 && failset.contains(answer))
                    this.unanswered.add(query);
                //System.out.println("** DEBUG user " + c + "; q = " + query + "; a = " + answer);
            });
        }
        return this.unanswered;
    }

    public void removeUnanswered(String s) {
        if (this.unanswered == null)
            getUnanswered();
        boolean removed = this.unanswered.remove(s.toLowerCase());
        //if (removed) System.out.println("** removed unanswered " + s);
    }

    public void removeUnanswered(Pattern p) {
        if (this.unanswered == null)
            getUnanswered();
        if (dnruset.contains(p.pattern()))
            return;
        boolean removed = this.unanswered.remove(p.pattern());
        if (!removed) {
            Iterator<String> i = this.unanswered.iterator();
            while (i.hasNext()) {
                String s = i.next();
                if (p.matcher(s).matches()) {
                    i.remove();
                    removed = true;
                }
            }
        }
        if (removed)
            System.out.println("** removed unanswered " + p.pattern());
    }

    /**
     * get a list of interaction using the client key
     * @param client
     * @return a list of interactions, latest interaction is first in list
     */
    public ArrayList<SusiInteraction> getInteractions(String client) {
        UserRecord ur = this.logs.get(client);
        if (ur == null) {
            ur = new UserRecord(client);
            this.logs.put(client, ur);
        }
        return ur.conversation;
    }

    public SusiLog addInteraction(String client, SusiInteraction si) {
        UserRecord ur = this.logs.get(client);
        if (ur == null) {
            ur = new UserRecord(client);
            this.logs.put(client, ur);
        }
        ur.add(si);
        return this;
    }

    public class UserRecord {
        private ArrayList<SusiInteraction> conversation = null; // first entry always has the latest interaction
        private File logdump;

        public UserRecord(String client) {
            this.conversation = new ArrayList<>();
            File logpath = new File(root, client);
            logpath.mkdirs();
            this.logdump = new File(logpath, "log.txt");
            if (this.logdump.exists()) {
                try {
                    this.conversation = readLog(this.logdump, rc);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        public UserRecord add(SusiInteraction interaction) {
            if (this.conversation == null)
                return this;
            this.conversation.add(0, interaction);
            if (this.conversation.size() > rc)
                this.conversation.remove(this.conversation.size() - 1);
            try {
                Files.write(this.logdump.toPath(), UTF8.getBytes(interaction.getJSON().toString(0) + "\n"),
                        StandardOpenOption.APPEND, StandardOpenOption.CREATE);
            } catch (JSONException | IOException e) {
                e.printStackTrace();
            }
            return this;
        }
    }

    public static ArrayList<SusiInteraction> readLog(final File logdump, int count) throws IOException {
        List<String> lines = Files.readAllLines(logdump.toPath());
        ArrayList<SusiInteraction> conversation = new ArrayList<>();
        for (int i = lines.size() - 1; i >= 0; i--) {
            String line = lines.get(i);
            if (line.length() == 0)
                continue;
            SusiInteraction si = new SusiInteraction(new JSONObject(line));
            conversation.add(si);
            if (conversation.size() >= count)
                break;
        }
        return conversation;
    }

    public TreeMap<Long, List<SusiInteraction>> getAllLogs() {
        TreeMap<Long, List<SusiInteraction>> all = new TreeMap<>();
        String[] clients = this.root.list();
        for (String client : clients) {
            File logpath = new File(this.root, client);
            if (logpath.exists()) {
                File logdump = new File(logpath, "log.txt");
                if (logdump.exists())
                    try {
                        ArrayList<SusiInteraction> conversation = readLog(logdump, Integer.MAX_VALUE);
                        if (conversation.size() > 0) {
                            Date d = conversation.get(0).getQueryDate();
                            all.put(-d.getTime(), conversation);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }
        return all;
    }

    public Set<String> getRulesetNames(String client) {
        Map<String, JsonTray> rulesets = this.rulesets.get(client);
        if (rulesets == null) {
            Set<String> rules = new HashSet<String>();
            File rpath = new File(root, client);
            rpath.mkdirs();
            for (String s : rpath.list())
                if (s.endsWith(".json"))
                    rules.add(s.substring(0, s.length() - 5));
            return rules;
        }
        return rulesets.keySet();
    }

    public JsonTray getRuleset(String client, String name) throws IOException {
        Map<String, JsonTray> rulesets = this.rulesets.get(client);
        if (rulesets == null) {
            rulesets = new HashMap<>();
            this.rulesets.put(client, rulesets);
        }
        JsonTray jt = rulesets.get(name);
        if (jt == null) {
            File rpath = new File(root, client);
            rpath.mkdirs();
            jt = new JsonTray(new File(rpath, name + ".json"), null, 1000);
            rulesets.put(name, jt);
        }
        return jt;
    }
}