init
This commit is contained in:
commit
25efc510e5
7 changed files with 37304 additions and 0 deletions
16
RedCat.sln
Normal file
16
RedCat.sln
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RedCat", "RedCat\RedCat.fsproj", "{712648D9-AF68-4847-AF7F-B976AC1AB1D2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{712648D9-AF68-4847-AF7F-B976AC1AB1D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{712648D9-AF68-4847-AF7F-B976AC1AB1D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{712648D9-AF68-4847-AF7F-B976AC1AB1D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{712648D9-AF68-4847-AF7F-B976AC1AB1D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
128
RedCat/DrugsDataExtractor.fs
Normal file
128
RedCat/DrugsDataExtractor.fs
Normal file
|
@ -0,0 +1,128 @@
|
|||
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
|
74
RedCat/Program.fs
Normal file
74
RedCat/Program.fs
Normal file
|
@ -0,0 +1,74 @@
|
|||
module RedCat.Program
|
||||
|
||||
open Microsoft.Extensions.Logging
|
||||
open Funogram.Api
|
||||
open Funogram.Telegram
|
||||
open Funogram.Telegram.Bot
|
||||
|
||||
open RedCat.DrugsDataExtractor
|
||||
open RedCat.RecordFormatter
|
||||
|
||||
let private factory = LoggerFactory.Create(fun builder ->
|
||||
builder.AddSimpleConsole(fun opts -> opts.TimestampFormat <- "[MM-dd HH:mm:ss.fff] ") |> ignore)
|
||||
|
||||
let NewConsoleOnlyLogger (loggerName: string) =
|
||||
factory.CreateLogger(loggerName)
|
||||
|
||||
let logger = NewConsoleOnlyLogger "RedCatLog"
|
||||
type BotCommands =
|
||||
| Start
|
||||
| Combo of string * string
|
||||
| Info of string
|
||||
| Dose of string
|
||||
| Search of string
|
||||
|
||||
let parseCommand (cmd: BotCommands) =
|
||||
match cmd with
|
||||
| Start -> "Utilizzo: !info lsd"
|
||||
| Combo (userInputA, userInputB) ->
|
||||
match getComboRecord userInputA userInputB with
|
||||
| Ok comboRecord -> formatComboRecord comboRecord
|
||||
| Error errMsg ->
|
||||
logger.LogError errMsg
|
||||
$"Non trovo informazioni relative alla combo {userInputA} e {userInputB}"
|
||||
| Info userInput ->
|
||||
match getDrugRecord userInput with
|
||||
| Ok (DrugRecord drugData) -> formatDrugInfoResponse drugData
|
||||
| Ok (ResponseText suggestionsResponse) ->
|
||||
$"Non trovo informazioni relative a '{userInput}'.\nForse stavi cercando:\n{suggestionsResponse}"
|
||||
| Error _ -> $"Non trovo informazioni relative a '{userInput}'"
|
||||
| Dose userInput -> "Not implemented yet"
|
||||
| Search userInput ->
|
||||
match getSearchResponse userInput with
|
||||
| Ok (ResponseText rt) -> $"Possibili risultati: \n{rt}"
|
||||
| Error _ -> $"Non trovo informazioni relative a '{userInput}'"
|
||||
| _ -> failwith "Shouldn't happen here"
|
||||
|
||||
let sendMsg (ctx: UpdateContext) (cmd: BotCommands) =
|
||||
match ctx.Update.Message with
|
||||
| Some { MessageId = messageId; Chat = chat } ->
|
||||
let msg = cmd |> parseCommand
|
||||
Api.sendMessageReply chat.Id msg messageId
|
||||
|> api ctx.Config
|
||||
|> Async.Ignore
|
||||
|> Async.Start
|
||||
| _ -> ()
|
||||
|
||||
let updateArrived (ctx: UpdateContext) =
|
||||
processCommands ctx [|
|
||||
cmd "!start" (fun _ -> sendMsg ctx Start)
|
||||
cmdScan "!info %s" (fun userInput _ -> sendMsg ctx (Info (formatDrugInput userInput)))
|
||||
cmdScan "!search %s" (fun userInput _ -> sendMsg ctx (Search (formatDrugInput userInput)))
|
||||
//cmdScan "!combo %s %s" (fun (drugA, drugB) _ -> sendMsg ctx (Combo(drugA,drugB)))
|
||||
//cmdScan "!dose %s" (fun drug _ -> sendMsg ctx (Dose drug))
|
||||
|] |> ignore
|
||||
|
||||
[<EntryPoint>]
|
||||
let main _ =
|
||||
async {
|
||||
let config = { Config.defaultConfig
|
||||
with Token = "1171254969:AAGraSaWhTxAoJVLnSEkh8DfrpqdqOmf1aM" }
|
||||
let! _ = Api.deleteWebhookBase () |> api config
|
||||
return! startBot config updateArrived None
|
||||
} |> Async.RunSynchronously
|
||||
0
|
53
RedCat/RecordFormatter.fs
Normal file
53
RedCat/RecordFormatter.fs
Normal file
|
@ -0,0 +1,53 @@
|
|||
module RedCat.RecordFormatter
|
||||
|
||||
open RedCat.DrugsDataExtractor
|
||||
|
||||
|
||||
let formatDrugInput (drugRawName: string) =
|
||||
drugRawName.ToLower().Replace(" ", "").Replace("-", "").Replace(",", "")
|
||||
|
||||
let formatDrugInfoResponse (drugData: DrugRecord) =
|
||||
let toPrettyString (drugInfo: string option) =
|
||||
match drugInfo with
|
||||
| Some s when drugInfo = drugData.Summary -> $"📜 {s}" |> Some
|
||||
| Some s when drugInfo = drugData.Dose -> $"🍽️ {s}" |> Some
|
||||
| Some s when drugInfo = drugData.TotalDuration -> $"⏳ Durata: {s}" |> Some
|
||||
| Some s when drugInfo = drugData.OnSet -> $"🤯 Inizio effetti: {s}" |> Some
|
||||
| _ -> None
|
||||
|
||||
let formattedCategories =
|
||||
drugData.Categories
|
||||
|> Option.bind(fun catgs -> catgs |> String.concat " | " |> Some)
|
||||
|
||||
let mainResponseText =
|
||||
[drugData.Summary; drugData.Dose; drugData.TotalDuration; drugData.OnSet]
|
||||
|> List.choose toPrettyString
|
||||
|> String.concat "\n\n"
|
||||
|
||||
match formattedCategories with
|
||||
| None -> $"~{drugData.Name} \n\n{mainResponseText}"
|
||||
| Some categories -> $"~{drugData.Name} [ {categories} ]\n\n{mainResponseText}"
|
||||
|
||||
let formatComboRecord (comboData: ComboRecord) =
|
||||
let translate (s: string) =
|
||||
match s with
|
||||
| "Dangerous" -> "❌ Molto pericoloso alla vita e alla salute"
|
||||
| "Unsafe" -> "‼️ Pericoloso"
|
||||
| "Caution" -> "⚠️ Attenzione"
|
||||
| "Low Risk & Synergy" -> "➕➕ Rischio basso e amplificazione effetto ➕➕"
|
||||
| "Low Risk & Decrease" -> "➖➖ Rischio basso e diminuzione effetto ➖➖"
|
||||
| "Low Risk & No Synergy" -> "🟰🟰 Rischio basso e interazione assente 🟰🟰"
|
||||
| _ -> failwith "Shouldn't happen here"
|
||||
|
||||
let toPrettyString (comboInfo: string option) =
|
||||
match comboInfo with
|
||||
| Some s when comboInfo = comboData.Status -> $"{translate s}" |> Some
|
||||
| Some s when comboInfo = comboData.Note -> $"{s}" |> Some
|
||||
| _ -> None
|
||||
|
||||
let comboText =
|
||||
[comboData.Status; comboData.Note]
|
||||
|> List.choose toPrettyString
|
||||
|> String.concat "\n"
|
||||
|
||||
$"[{comboData.DrugA}] ~ [{comboData.DrugB}]\n\n{comboText}"
|
26
RedCat/RedCat.fsproj
Normal file
26
RedCat/RedCat.fsproj
Normal file
|
@ -0,0 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="DrugsDataExtractor.fs" />
|
||||
<Compile Include="RecordFormatter.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Funogram" Version="2.0.8" />
|
||||
<PackageReference Include="Funogram.Telegram" Version="6.9.0" />
|
||||
<PackageReference Include="FuzzySharp" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
2543
RedCat/combos.json
Normal file
2543
RedCat/combos.json
Normal file
File diff suppressed because it is too large
Load diff
34464
RedCat/drugs.json
Normal file
34464
RedCat/drugs.json
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue