|
1 | 1 | (ns unmo.core
|
2 | 2 | (:gen-class)
|
3 |
| - (:require [unmo.responder :refer [response]] |
4 |
| - [unmo.dictionary :refer [study save-dictionary load-dictionary]] |
5 |
| - [unmo.morph :refer [analyze]] |
6 |
| - [unmo.version :refer [unmo-version]] |
7 |
| - [bigml.sampling [simple :as simple]])) |
| 3 | + (:require [clojure.java.io :as io] |
| 4 | + [clojure.string :as str] |
| 5 | + [fipp.edn :as fipp] |
| 6 | + [unmo.dictionary :as dict] |
| 7 | + [unmo.morph :as morph] |
| 8 | + [unmo.responder :as resp] |
| 9 | + [unmo.version :as ver])) |
8 | 10 |
|
9 |
| -(def ^{:private true |
10 |
| - :doc "デフォルトで使用される辞書ファイル名"} |
11 |
| - dictionary-file |
12 |
| - "dict.clj") |
| 11 | +(def dictionary-file "dict.edn") |
| 12 | + |
| 13 | +(def responders {:what resp/response-what |
| 14 | + :random resp/response-random |
| 15 | + :pattern resp/response-pattern |
| 16 | + :template resp/response-template |
| 17 | + :markov resp/response-markov}) |
| 18 | + |
| 19 | +(defn save-dictionary |
| 20 | + "Saves the result of pprint the map dictionary to the specified filename." |
| 21 | + [dictionary filename] |
| 22 | + (let [data (with-out-str |
| 23 | + (binding [*print-length* false] |
| 24 | + (fipp/pprint dictionary)))] |
| 25 | + (spit filename data :encoding "UTF-8"))) |
| 26 | + |
| 27 | +(defn load-dictionary |
| 28 | + "Returns a dictionary map read from the specified filename." |
| 29 | + [filename] |
| 30 | + (if (.exists (io/as-file filename)) |
| 31 | + (-> filename (slurp :encoding "UTF-8") read-string) |
| 32 | + {})) |
13 | 33 |
|
14 | 34 | (defn- rand-responder
|
15 |
| - "確率によって変動するResponderを返す。 |
| 35 | + "Returns the one of keywords, :what :random :pattern :template :markov, |
| 36 | + which is determined by the probability. |
| 37 | +
|
16 | 38 | :what 10%
|
17 | 39 | :random 20%
|
18 | 40 | :pattern 30%
|
19 | 41 | :template 20%
|
20 | 42 | :markov 20%"
|
21 | 43 | []
|
22 |
| - (-> [:what :random :pattern :template :markov] |
23 |
| - (simple/sample :weigh {:what 0.1 |
24 |
| - :random 0.2 |
25 |
| - :pattern 0.3 |
26 |
| - :template 0.2 |
27 |
| - :markov 0.2}) |
28 |
| - (first))) |
29 |
| - |
30 |
| -(defn- format-response |
31 |
| - "Responder からの結果を整形して返す。" |
32 |
| - [{:keys [responder response error]}] |
33 |
| - (let [responder-name (-> responder (name) (clojure.string/capitalize))] |
34 |
| - (if error |
35 |
| - (str responder-name "> 警告: " (:message error)) |
36 |
| - (str responder-name "> " response)))) |
| 44 | + (let [n (rand-int 100)] |
| 45 | + (cond (< 0 n 10) :what |
| 46 | + (< 11 n 30) :random |
| 47 | + (< 31 n 60) :pattern |
| 48 | + (< 61 n 80) :template |
| 49 | + :else :markov))) |
37 | 50 |
|
38 | 51 | (defn- dialogue
|
39 |
| - "ユーザーからの発言、形態素解析結果、辞書を受け取り、AIの思考結果を整形した文字列を返す。" |
| 52 | + "Takes an input, its morphological analysis results, a dictionary, and |
| 53 | + returns a sentence generated by the responder. If the responder returned nil, |
| 54 | + calls :what responder and returns the result sentence." |
40 | 55 | ([input parts dictionary]
|
41 | 56 | (dialogue input parts dictionary (rand-responder)))
|
42 |
| - ([input parts dictionary responder] |
43 |
| - (let [res (-> {:input input |
44 |
| - :dictionary dictionary |
45 |
| - :parts parts |
46 |
| - :responder responder} |
47 |
| - (response))] |
48 |
| - (case (get-in res [:error :type]) |
49 |
| - :fatal (format-response res) |
50 |
| - nil (format-response res) |
51 |
| - (recur input parts dictionary :random))))) |
52 | 57 |
|
53 |
| -(defn -main |
54 |
| - "標準入力からユーザーの発言を受け取り、Responder の結果を表示して繰り返す。" |
55 |
| - [& args] |
56 |
| - (println (format "Unmo version %s launched." unmo-version)) |
| 58 | + ([input parts dictionary res-key] |
| 59 | + (if-let [res ((res-key responders) {:input input |
| 60 | + :dictionary dictionary |
| 61 | + :parts parts})] |
| 62 | + (str (str/capitalize (name res-key)) "> " res) |
| 63 | + (dialogue input parts dictionary :what)))) |
| 64 | + |
| 65 | +(defn -main [& args] |
| 66 | + (morph/start) |
| 67 | + (println (format "Unmo version %s launched." ver/unmo-version)) |
57 | 68 | (print "> ")
|
58 | 69 | (flush)
|
59 | 70 |
|
60 |
| - (loop [input (read-line) |
| 71 | + (loop [input (read-line) |
61 | 72 | dictionary (load-dictionary dictionary-file)]
|
62 |
| - (if (clojure.string/blank? input) |
63 |
| - (do (println "Saving dictionary...") |
| 73 | + (if (str/blank? input) |
| 74 | + (do (println "Shutting down...") |
| 75 | + (morph/stop) |
64 | 76 | (save-dictionary dictionary dictionary-file)
|
65 | 77 | (println "Quit."))
|
66 |
| - (let [parts (analyze input) |
67 |
| - res (dialogue input parts dictionary)] |
| 78 | + (let [parts (morph/analyze input) |
| 79 | + res (dialogue input parts dictionary)] |
68 | 80 | (println res)
|
69 | 81 | (print "> ")
|
70 | 82 | (flush)
|
71 |
| - (recur (read-line) (study dictionary input parts)))))) |
| 83 | + (recur (read-line) (dict/study dictionary input parts)))))) |
0 commit comments