Недавно (2020 г.) меня попросили помочь провести семинар, посвященный юридическому сообществу. На семинаре был изучен потенциал чат-ботов и механизмов правил. В качестве быстрой демонстрации я создал простого чат-бота. Мой чат-бот сосредоточен на предоставлении Пользователю помощи в получении цифровых доказательств из разных стран. В разных странах разные процедуры. Например, многие страны упрощают этот процесс с помощью двустороннего договора, такого как Договор о взаимной правовой помощи или сокращенно MLAT. Для ряда европейских стран существует еще одно двустороннее соглашение, известное как Соглашение о европейской судебной сети (EJN). Таким образом, при отсутствии двустороннего соглашения вы должны обратиться за советом в Службу уголовного преследования Великобритании (CPS). Очевидно, что если вы находитесь в Великобритании и цифровые доказательства также находятся в Великобритании, то никаких особых действий не требуется (обратите внимание, этот пост написан с точки зрения Великобритании).

Давайте создадим чат-бот, чтобы помочь Пользователю выяснить, существует ли двустороннее соглашение, и если есть, определить правильное. Наш чат-бот будет направлять Пользователя, и когда Пользователь отправит двухбуквенный код страны, чат-бот сможет проинформировать Пользователя о соответствующем действии. Например, если двухбуквенный код страны соответствует стране внутри EJN, чат-бот ответит соответствующим образом.

REPL.IT

Прежде чем мы перейдем к коду, давайте посмотрим на онлайн-REPL. Онлайн-REPL — это удобный инструмент для тестирования несложных фрагментов кода. Несложным, не зависящим от внешних библиотек.

REPL.IT — один из таких онлайн-REPL:



Представленный код достаточно прост для работы в онлайн-REPL.

Чат-бот

Введите Листинг 1. в нужный REPL.

Листинг 1.

;;UK only
(def UK #{"UK"})

;;EU EJN countries
(def EJN #{"CH" "SI" "IT" "FI" "MK" "LI" "GR" "DK" "ME" "IS" "AT" "LT" "BG" "PT" "HR" "HU" "SE" "RO" "CY" "TR" "AL" "FR" "DE" "NO" "BE" "CZ" "NL" "EE" "LU" "IE" "LV" "SK" "ES" "RS" "MT" "PL"})
;;MLAT bilateral countries
(def MLAT #{"AU" "MY" "DZ" "UY" "GY" "SA" "BH" "JO" "VN" "PA" "LY" "AR" "BR" "CN" "PY" "PH" "BB" "CA" "TH" "KZ" "EC" "AG" "CL" "US" "UA" "GD" "IN" "HK" "CO" "NG" "AE" "MX"})
;;Positive responses
(def Positive #{"yeah" "Y" "yes" "OK" "y" "ok" "Yes" "Yeah"})
;;Negative responses
(def Negative #{"n" "nope" "not" "Nope" "Not" "N" "no" "No"})
;;Indifferent responses
(def Indifferent #{"Not sure" "maybe" "Don't understand" "dont understand" "Possibly" "possibly" "not sure" "Maybe"})
;;FUNCTIONS
(defn start []
(println "Do you wish to obtain digital evidence and want to know what authority is required?")
(let [x (read-line) ]
(cond
(contains? Positive x) (Country)
(contains? Negative x) "Perhaps try a different ChatBot!"
(contains? Indifferent x) "Sounds like a training issue, this ChatBot is here to help you get the right authority for digital evidence"
:else (start))))
(defn Country []
(println "Do you know what country the evidence is located?")
(let [x (read-line) ]
(cond
(contains? Positive x) (CountryCode)
(contains? Negative x) "You need to do some more investigation, come back when you have identified the country of location holding the digital evidence"
(contains? Indifferent x) "You need to do some more investigation, come back when you have identified the country of location holding the digital evidence"
:else (start))))
(defn CountryCode []
(println "Do you know the two-letter code for the specific country?")
(let [x (read-line) ]
(cond
(contains? Positive x) (results)
(contains? Negative x) "Try looking up the country code here: https://www.iban.com/country-codes"
(contains? Indifferent x) "Try looking up the country code here: https://www.iban.com/country-codes"
:else (start))))
(defn results []
(println "Just type in the two-letter Contry code in uppercase")(let [x (read-line) ]
(cond
(contains? UK x) "It's in the UK, no special procedures or authorities required"
(contains? EJN x) "This is in the EU judicicial network, follow the European Judicial procedure"
(contains? MLAT x) "This is outside both the UK and EJN.  You will have to follow the MLAT procedure"
:else "Unfortunately, this is outside of MLAT.  Please seek advice from the Crown Prosecution Service (CPS)")))

Чтобы запустить чат-бота, просто запустите функцию (старт)

Разберем код:

Наборы

Напомним, набор — это набор уникальных значений. Наши наборы содержат либо двухбуквенный код страны, либо тип ответа. Например, положительные ответы включают «да», «да» и «хорошо».

Функции

Все представленные функции имеют аналогичный формат. То есть они используют условие, которое представлено ключевым словом условие. Этот простой, но мощный формат следует логической системе утверждения истины. Этот формат начинается с задания Пользователю вопроса. Ответ оценивается:

(println "Do you wish to obtain digital evidence and want to know what authority is required?")
(let [x (read-line) ]
(cond
(contains? Positive x) (Country)

Таким образом, ответ считывается и сохраняется в x, а затем сравнивается с положительным набором. Если ответ находится в Положительном наборе, эта функция останавливается и вызывается функция Страна. . В противном случае он переходит на следующую строку:

(contains? Negative x) "Perhaps try a different ChatBot!"

Если ни одно из условий не выполняется, последняя строка, начинающаяся с :else, вызывается и выполняется. :

:else (start)

С точки зрения наших элементов программирования, начальные строки кода каждой функции являются примерами последовательности и выборки. Однако во всех функциях, кроме одной, последний :else вызывает функцию (start). При вызове этой функции запуска эти сегменты кода демонстрируют повторение.

Улучшения

Одной из первых выявленных проблем является то, что наш чат-бот запрашивает двухбуквенные коды стран в верхнем регистре. Мы можем улучшить нашу функцию результатов, автоматически преобразовывая пользовательский ввод в верхний регистр следующим образом:

(defn results []
(println “Just type in the two-letter Country code”)
(let [x (clojure.string/upper-case (read-line)) ]
(cond

Это также может быть применено ко всем пользовательским вводам и позволит нам упростить наши наборы. Другими словами, наши наборы должны содержать только слова или аббревиатуры в верхнем регистре.

Чтобы упростить пользователю задачу, мы могли бы позволить ему вводить либо полное название страны, либо двухбуквенный код. Мы также можем включить распространенные ошибки или опечатки. Например, набор для Великобритании может выглядеть примерно так:

;;UK only
(def UK #{"UK" "UNITED KINGDOM" "GREAT BRITAIN" "BRITAIN" "BRITISH ISLES" "BRIRAIN" "BRITIAN"})

У пользователя может быть ряд запросов, поэтому мы можем захотеть контролировать завершение программы. Например, вы можете создать ряд функций, которые будут вызываться из функции results следующим образом:

(defn results []
(println "Just type in the two-letter Contry code in uppercase")(let [x (read-line) ]
(cond
(contains? UK x) (uk_ending)
(contains? EJN x) (ejn_ending)
(contains? MLAT x) (mlat_ending)
:else (ending))))

Все эти функции могут иметь аналогичный формат, чтобы дать Пользователю возможность выполнить дополнительные запросы.


:else (ending))))
.
.
.
(defn ending []
(println "Unfortunately, this is outside of MLAT.  Please seek advice from the Crown Prosecution Service (CPS). Would you like to continue with another inquiry?")
(let [x  (read-line) ]
(cond
(contains? Positive x) (start)
(contains? Negative x) "Bye"
(contains? Indifferent x) "Bye for now, just type (start) if you wish to continue"
:else "Didn't understand your response.  Type (start) to continue")))

РЕЗЮМЕ

Надеюсь, вы видите потенциал этого шаблона или шаблона. Например, вместо того, чтобы быть чат-ботом и читать ответы пользователей, данные можно вводить и обрабатывать. Чтобы продемонстрировать, программа может использовать шаблон cond для получения показаний температуры и проверки ряда условий:

(defn thermo_reg []
(let [ current_temp @temperature ]
(cond
(>= current_temp 25) (run_aircon)
(<= current_temp 10) (run_heater)
:else (get_new_temp_reading))))

;;demo of above template but using println statements and randomly generated test data.
(def current_temp (atom (rand-int 30))) 
  
(defn thermo_reg [] 
(cond 
(>= @current_temp 25) (println "run_aircon") 
(<= @current_temp 10) (println "run_heater") 
:else  (println "Just Right"))) 
  
(reset! current_temp (rand-int 30)) (thermo_reg)
run_heater

(reset! current_temp (rand-int 30)) (thermo_reg)
run_aircon

(reset! current_temp (rand-int 30)) (thermo_reg)
Just Right

(reset! current_temp (rand-int 30)) (thermo_reg)
run_aircon

(reset! current_temp (rand-int 30)) (thermo_reg)
Just Right

(reset! current_temp (rand-int 30)) (thermo_reg)
Just Right

(reset! current_temp (rand-int 30)) (thermo_reg)
run_heater

Встроенная функция rand-int генерирует случайное целое число. Число 30 просто определяет диапазон. Другими словами, (rand-int 30) генерирует случайное число от 0 до 30.

Поэкспериментируйте с кодом в этом посте и подумайте, как можно применить этот шаблон.

"Предыдущий"