redcatbot/RedCat/DrugsDataExtractor.fs
2024-05-16 11:03:36 +02:00

128 lines
No EOL
4.1 KiB
Forth

module RedCat.DrugsDataExtractor
open System.Collections.Generic
open Newtonsoft.Json.Linq
open FuzzySharp
open System.IO
let drugsJson = File.ReadAllText(Path.Combine("/opt/redcatbot/", "drugs.json"))
let comboJson = File.ReadAllText(Path.Combine("/opt/redcatbot/", "combos.json"))
let DrugsJsonData = JObject.Parse(drugsJson)
let ComboJsonData = JObject.Parse(drugsJson)
let private tryExtractProps (propName: string) (jsonValue: JToken) =
match jsonValue["properties"][propName] with
| null -> None
| token -> token.ToString() |> Some
let private tryExtract (x: string) (jsonValue: JToken) =
match jsonValue[x] with
| null -> None
| token -> token.ToString() |> Some
let private tryExtractArray (fieldName: string) (jsonValue: JToken) =
match jsonValue[fieldName] with
| null -> None
| categories ->
categories.Values()
|> Seq.cast<JToken>
|> Seq.map(fun text -> text.ToString())
|> Seq.toList |> Some
let private DrugNamesWithAliases =
DrugsJsonData.Properties()
|> Seq.map(fun obj ->
match obj.Value |> tryExtractArray "aliases" with
| Some aliasesList -> aliasesList |> List.map(fun al -> (al, obj.Name))
| None -> [(obj.Name, obj.Name)])
|> Seq.concat
|> Map.ofSeq
let private DrugNames =
DrugNamesWithAliases |> Map.values |> Set.ofSeq
let private search (userInput: string) =
let clearString (inStr: string) = inStr.Replace("-", "").Replace(",", "")
let findCond (_in: KeyValuePair<string, string>) =
match (_in.Key, _in.Value) with
| _, drugName when drugName = userInput || clearString drugName = userInput ->
drugName |> Some
| someAlias, drugName when someAlias = userInput -> drugName |> Some
| _ -> None
let drugNameFound =
DrugNamesWithAliases
|> Seq.choose(findCond)
|> Seq.tryHead
drugNameFound
type DrugRecord = {
Name: string
Summary: string option
Categories: string list option
OnSet: string option
TotalDuration: string option
Dose: string option
}
type ComboRecord = {
DrugA: string
DrugB: string
Status: string option
Note: string option
}
type SearchResult =
| DrugRecord of DrugRecord
| ResponseText of string
let getComboRecord (userInputA: string) (userInputB: string) =
let getRecord (jsonValue: JToken) = {
DrugA = userInputA
DrugB = userInputB
Status = jsonValue |> tryExtract "status"
Note = jsonValue |> tryExtract "note"
}
let tryGetCombo drugA drugB =
match DrugsJsonData[drugA][drugB] with
| null -> None
| obj -> Some obj
match (search userInputA, search userInputB) with
| None, None -> Error $"Can't find both drugs {userInputA} and {userInputB}"
| Some _, None -> Error $"Can't find second drug {userInputB}"
| None, Some _ -> Error $"Can't find first drug {userInputA}"
| Some drugA, Some drugB ->
tryGetCombo drugA drugB
|> Option.bind(fun jsonValue -> (getRecord jsonValue) |> Some)
|> function
| None -> Error $"Can't find combo from {userInputA} and {userInputB}"
| Some combo -> combo |> Ok
let getSearchResponse (userInput: string) =
let matches =
Process.ExtractTop(userInput, DrugNames)
|> Seq.choose(fun e -> if e.Score > 62 then e.Value |> Some else None)
|> String.concat "\n- "
match matches with
| "" -> Error $"Can't find drug name: {userInput}"
| matches -> $"- {matches}" |> ResponseText |> Ok
let getDrugRecord (userInput: string) =
let getRecord (drugName: string) (jsonValue: JToken) = {
Name = drugName
Summary = jsonValue |> tryExtractProps "summary"
Categories = jsonValue |> tryExtractArray "categories"
OnSet = jsonValue |> tryExtractProps "onset"
TotalDuration = jsonValue |> tryExtractProps "duration"
Dose = jsonValue |> tryExtractProps "dose"
}
match search userInput with
| Some drugName -> getRecord drugName DrugsJsonData[drugName] |> DrugRecord |> Ok
| None -> getSearchResponse userInput