use Dict string key

This commit is contained in:
2026-06-24 20:46:24 +07:00
parent de20764610
commit 9c22cf2e31
4 changed files with 226 additions and 228 deletions

View File

@@ -64,29 +64,29 @@ end
# Example # Example
```jldoctest ```jldoctest
julia> config = Dict( julia> config = Dict(
:mqttServerInfo => Dict( "mqttServerInfo" => Dict(
:description => "mqtt server info", "description" => "mqtt server info",
:port => 1883, "port" => 1883,
:broker => "mqtt.yiem.cc" "broker" => "mqtt.yiem.cc"
), ),
:externalservice => Dict( "externalservice" => Dict(
"text"2textinstruct => Dict( "text2textinstruct" => Dict(
:mqtttopic => "/loadbalancer/requestingservice", "mqtttopic" => "/loadbalancer/requestingservice",
:description => "text to text service with instruct LLM", "description" => "text to text service with instruct LLM",
:llminfo => Dict( "llminfo" => Dict(
"name" => "llama3instruct" "name" => "llama3instruct"
) )
), ),
) )
) )
julia> output_thoughtDict = Dict( julia> output_thoughtDict = Dict(
:thought_1 => "The customer wants to buy a bottle of wine. This is a good start!", "thought_1" => "The customer wants to buy a bottle of wine. This is a good start!",
:action_1 => Dict{String, Any}( "action_1" => Dict{String, Any}(
:action=>"CHATBOX", "action"=>"CHATBOX",
:input=>"What occasion are you buying the wine for?" "input"=>"What occasion are you buying the wine for?"
), ),
:observation_1 => "" "observation_1" => ""
) )
``` ```
- [] update docstring - [] update docstring
@@ -123,7 +123,7 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
# end # end
recentevents_ind = GeneralUtils.recentElementsIndex( recentevents_ind = GeneralUtils.recentElementsIndex(
length(a.memory[:events]), recentevents; includelatest=true) length(a.memory["events"]), recentevents; includelatest=true)
requiredKeys = ["plan", "actionname", "actioninput"] requiredKeys = ["plan", "actionname", "actioninput"]
@@ -203,8 +203,8 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
# check whether the wine is in event # check whether the wine is in event
isWineInEvent = false isWineInEvent = false
for winename in mentioned_winery for winename in mentioned_winery
for event in a.memory[:events] for event in a.memory["events"]
if event[:observation] !== nothing && occursin(winename, event[:observation]) if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true isWineInEvent = true
break break
end end
@@ -237,19 +237,19 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
end end
# store for later training # store for later training
responsedict[:system] = systemmsg responsedict["system"] = systemmsg
responsedict[:unformatPrompt] = unformatPrompt responsedict["unformatPrompt"] = unformatPrompt
responsedict[:prompt] = prompt responsedict["prompt"] = prompt
responsedict[:context] = context responsedict["context"] = context
responsedict[:think] = think responsedict["think"] = think
responsedict[:response] = response responsedict["response"] = response
# responsedict[:QandA] = QandA # responsedict["QandA"] = QandA
# check whether there is a file path exists before writing to it # check whether there is a file path exists before writing to it
if !haskey(a.memory["shortmem"], :decisionlog) if !haskey(a.memory["shortmem"], "decisionlog")
a.memory["shortmem"][:decisionlog] = [responsedict] a.memory["shortmem"]["decisionlog"] = [responsedict]
else else
push!(a.memory["shortmem"][:decisionlog], responsedict) push!(a.memory["shortmem"]["decisionlog"], responsedict)
end end
# # save to filename ./log/decisionlog.txt # # save to filename ./log/decisionlog.txt
@@ -275,7 +275,7 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
# println("\nYiemAgent decisionMaker() saved to disk is done. agent $(a.id)") # println("\nYiemAgent decisionMaker() saved to disk is done. agent $(a.id)")
responsedict[:prompt] = prompt responsedict["prompt"] = prompt
return responsedict return responsedict
end end
error("DecisionMaker failed to generate a thought ", response) error("DecisionMaker failed to generate a thought ", response)
@@ -531,7 +531,7 @@ function conversation(a::Union{companion, virtualcustomer}, userinput::Dict;
addNewMessage(a, "user", userinput["text"]; maximumMsg=maximumMsg) addNewMessage(a, "user", userinput["text"]; maximumMsg=maximumMsg)
# add user activity to events memory # add user activity to events memory
push!(a.memory[:events], push!(a.memory["events"],
eventdict(; eventdict(;
event_description="the user talks to the assistant.", event_description="the user talks to the assistant.",
timestamp=Dates.now(), timestamp=Dates.now(),
@@ -544,7 +544,7 @@ function conversation(a::Union{companion, virtualcustomer}, userinput::Dict;
addNewMessage(a, "assistant", chatresponse; maximumMsg=maximumMsg) addNewMessage(a, "assistant", chatresponse; maximumMsg=maximumMsg)
push!(a.memory[:events], push!(a.memory["events"],
eventdict(; eventdict(;
event_description="the assistant talks to the user.", event_description="the assistant talks to the user.",
timestamp=Dates.now(), timestamp=Dates.now(),
@@ -592,18 +592,18 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh
end end
# this section allow LLM functions above to have different return values. # this section allow LLM functions above to have different return values.
result = haskey(response, :result) ? response[:result] : nothing result = haskey(response, "result") ? response["result"] : nothing
rawresponse = haskey(response, :rawresponse) ? response[:rawresponse] : nothing rawresponse = haskey(response, "rawresponse") ? response["rawresponse"] : nothing
select = haskey(response, :select) ? response[:select] : nothing select = haskey(response, "select") ? response["select"] : nothing
reward::Integer = haskey(response, :reward) ? response[:reward] : 0 reward::Integer = haskey(response, "reward") ? response["reward"] : 0
isterminal::Bool = haskey(response, :isterminal) ? response[:isterminal] : false isterminal::Bool = haskey(response, "isterminal") ? response["isterminal"] : false
errormsg::Union{AbstractString,Nothing} = haskey(response, :errormsg) ? response[:errormsg] : nothing errormsg::Union{AbstractString,Nothing} = haskey(response, "errormsg") ? response["errormsg"] : nothing
success::Bool = haskey(response, :success) ? response[:success] : false success::Bool = haskey(response, "success") ? response["success"] : false
# # manage memory (pass msg to generatechat) # # manage memory (pass msg to generatechat)
# if actionname ∈ ["CHATBOX", "PRESENTBOX", "ENDCONVERSATION"] # if actionname ∈ ["CHATBOX", "PRESENTBOX", "ENDCONVERSATION"]
# chatresponse = generatechat(a, thoughtDict) # chatresponse = generatechat(a, thoughtDict)
# push!(a.memory[:events], # push!(a.memory["events"],
# eventdict(; # eventdict(;
# event_description="the assistant talks to the user.", # event_description="the assistant talks to the user.",
# timestamp=Dates.now(), # timestamp=Dates.now(),
@@ -615,7 +615,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh
# ) # )
# result = chatresponse # result = chatresponse
if actionname ["CHATBOX"] if actionname ["CHATBOX"]
push!(a.memory[:events], push!(a.memory["events"],
eventdict(; eventdict(;
event_description="an assistant talks to the user.", event_description="an assistant talks to the user.",
timestamp=Dates.now(), timestamp=Dates.now(),
@@ -628,7 +628,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh
result = actioninput result = actioninput
elseif actionname ["ENDCONVERSATION"] elseif actionname ["ENDCONVERSATION"]
chatresponse = generatechat(a, thoughtDict) chatresponse = generatechat(a, thoughtDict)
push!(a.memory[:events], push!(a.memory["events"],
eventdict(; eventdict(;
event_description="an assistant talks to the user to end conversation.", event_description="an assistant talks to the user to end conversation.",
timestamp=Dates.now(), timestamp=Dates.now(),
@@ -641,7 +641,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh
result = chatresponse result = chatresponse
elseif actionname ["PRESENTBOX"] elseif actionname ["PRESENTBOX"]
chatresponse = presentbox(a, thoughtDict) chatresponse = presentbox(a, thoughtDict)
push!(a.memory[:events], push!(a.memory["events"],
eventdict(; eventdict(;
event_description="the assistant presents wines to the user.", event_description="the assistant presents wines to the user.",
timestamp=Dates.now(), timestamp=Dates.now(),
@@ -656,12 +656,12 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh
elseif actionname == "CHECKWINE" elseif actionname == "CHECKWINE"
if rawresponse !== nothing if rawresponse !== nothing
vd = GeneralUtils.dfToVectorDict(rawresponse) # comes in dataframe format vd = GeneralUtils.dfToVectorDict(rawresponse) # comes in dataframe format
# a.memory["shortmem"][:found_wine] = vd # used by decisionMaker() as a short note # a.memory["shortmem"]["found_wine"] = vd # used by decisionMaker() as a short note
#[PENDING] a.memory["shortmem"][:available_wine] should be OrderedDict instead of vector dict so that no duplicate item are listed? #[PENDING] a.memory["shortmem"]["available_wine"] should be OrderedDict instead of vector dict so that no duplicate item are listed?
if length(a.memory["shortmem"][:db_search_result]) != 0 if length(a.memory["shortmem"]["db_search_result"]) != 0
a.memory["shortmem"][:db_search_result] = vcat(a.memory["shortmem"][:db_search_result], vd) a.memory["shortmem"]["db_search_result"] = vcat(a.memory["shortmem"]["db_search_result"], vd)
else else
a.memory["shortmem"][:db_search_result] = vd a.memory["shortmem"]["db_search_result"] = vd
end end
# # add to scratchpad # # add to scratchpad
@@ -680,7 +680,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh
# """ # """
end end
push!(a.memory[:events], push!(a.memory["events"],
eventdict(; eventdict(;
event_description= "the assistant searched the database.", event_description= "the assistant searched the database.",
timestamp= Dates.now(), timestamp= Dates.now(),
@@ -803,7 +803,7 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10, recentev
end end
# check if Context: is in dialogue # check if Context: is in dialogue
if occursin("Context:", responsedict[:dialogue]) if occursin("Context:", responsedict["dialogue"])
errornote = "Your previous response contains 'Context:' which is not allowed" errornote = "Your previous response contains 'Context:' which is not allowed"
println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue continue
@@ -815,15 +815,15 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10, recentev
# check whether an agent recommend wines before checking inventory or recommend wines # check whether an agent recommend wines before checking inventory or recommend wines
# outside its inventory # outside its inventory
# ask LLM whether there are any winery mentioned in the response # ask LLM whether there are any winery mentioned in the response
mentioned_winery = detectWineryName(a, responsedict[:dialogue]) mentioned_winery = detectWineryName(a, responsedict["dialogue"])
if mentioned_winery != "None" if mentioned_winery != "None"
mentioned_winery = String.(strip.(split(mentioned_winery, ","))) mentioned_winery = String.(strip.(split(mentioned_winery, ",")))
# check whether the wine is in event # check whether the wine is in event
isWineInEvent = false isWineInEvent = false
for winename in mentioned_winery for winename in mentioned_winery
for event in a.memory[:events] for event in a.memory["events"]
if event[:observation] !== nothing && occursin(winename, event[:observation]) if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true isWineInEvent = true
break break
end end
@@ -850,7 +850,7 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10, recentev
end end
end end
result = responsedict[:dialogue] result = responsedict["dialogue"]
return result return result
end end
error("presentbox() failed to generate a response") error("presentbox() failed to generate a response")
@@ -913,10 +913,10 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10)
""" """
requiredKeys = [:dialogue] requiredKeys = [:dialogue]
# a.memory["shortmem"][:available_wine] is a vector of dictionary # a.memory["shortmem"]["available_wine"] is a vector of dictionary
# context = # context =
# if length(a.memory["shortmem"][:available_wine]) != 0 # if length(a.memory["shortmem"]["available_wine"]) != 0
# "Wines previously found in your inventory: $(availableWineToText(a.memory["shortmem"][:available_wine]))" # "Wines previously found in your inventory: $(availableWineToText(a.memory["shortmem"]["available_wine"]))"
# else # else
# "N/A" # "N/A"
# end # end
@@ -1003,8 +1003,8 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10)
# check whether the wine is in event # check whether the wine is in event
isWineInEvent = false isWineInEvent = false
for winename in mentioned_winery for winename in mentioned_winery
for event in a.memory[:events] for event in a.memory["events"]
if event[:observation] !== nothing && occursin(winename, event[:observation]) if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true isWineInEvent = true
break break
end end
@@ -1018,7 +1018,7 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10)
continue continue
end end
end end
result = responsedict[:dialogue] result = responsedict["dialogue"]
return result return result
end end
@@ -1088,15 +1088,15 @@ function generatechat(a::virtualcustomer;
converPartnerName::Union{String, Nothing}=nothing, maxattempt=10, recentEventNum=10 converPartnerName::Union{String, Nothing}=nothing, maxattempt=10, recentEventNum=10
) )
recent_ind = GeneralUtils.recentElementsIndex(length(a.memory[:events]), recentEventNum; includelatest=true) recent_ind = GeneralUtils.recentElementsIndex(length(a.memory["events"]), recentEventNum; includelatest=true)
recentEventsDict = createEventsLog(a.memory[:events]; index=recent_ind) recentEventsDict = createEventsLog(a.memory["events"]; index=recent_ind)
response = nothing # placeholder for show when error msg show up response = nothing # placeholder for show when error msg show up
errornote = "N/A" errornote = "N/A"
header = ["Dialogue:", "Role:"] header = ["Dialogue:", "Role:"]
dictkey = ["dialogue", "role"] dictkey = ["dialogue", "role"]
llmkwargs=Dict( llmkwargs=Dict(
:num_ctx => 32768, "num_ctx" => 32768,
:temperature => 0.5, "temperature" => 0.5,
) )
for attempt in 1:maxattempt for attempt in 1:maxattempt
@@ -1141,15 +1141,15 @@ function generatechat(a::virtualcustomer;
responsedict = GeneralUtils.textToDict(response, header; responsedict = GeneralUtils.textToDict(response, header;
dictKey=dictkey, symbolkey=true) dictKey=dictkey, symbolkey=true)
if responsedict[:role] == "no" if responsedict["role"] == "no"
errornote = "In your previous attempt you said $(responsedict[:dialogue]) which you, as a customer of a wine store, are not supposed to speak." errornote = "In your previous attempt you said $(responsedict["dialogue"]) which you, as a customer of a wine store, are not supposed to speak."
println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue continue
end end
# check if the dialogue is the same as the previous one # check if the dialogue is the same as the previous one
if length(responsedict[:dialogue]) != 0 && responsedict[:dialogue] == a.chathistory[end]["text"] if length(responsedict["dialogue"]) != 0 && responsedict["dialogue"] == a.chathistory[end]["text"]
errornote = "In your previous attempt you said $(responsedict[:dialogue]) which was the same as the previous one." errornote = "In your previous attempt you said $(responsedict["dialogue"]) which was the same as the previous one."
println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue continue
end end
@@ -1157,7 +1157,7 @@ function generatechat(a::virtualcustomer;
# check whether LLM just repeat the previous dialogue # check whether LLM just repeat the previous dialogue
dublicate = false dublicate = false
for msg in a.chathistory for msg in a.chathistory
if msg["text"] == responsedict[:dialogue] if msg["text"] == responsedict["dialogue"]
errornote = "In your previous attempt, you repeated the earlier dialogue. Please try again." errornote = "In your previous attempt, you repeated the earlier dialogue. Please try again."
println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
dublicate = true dublicate = true
@@ -1170,7 +1170,7 @@ function generatechat(a::virtualcustomer;
# println("\n$prompt", @__FILE__, ":", @__LINE__, " $(Dates.now())") # println("\n$prompt", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# println("\n $response") # println("\n $response")
return responsedict[:dialogue] return responsedict["dialogue"]
end end
error("generatechat failed to generate a response") error("generatechat failed to generate a response")
end end
@@ -1285,12 +1285,12 @@ function generatequestion(a, text2textInstructLLM::Function, timeline)::String
dictkey = ["q1"] dictkey = ["q1"]
# context = # context =
# if length(a.memory["shortmem"][:available_wine]) != 0 # if length(a.memory["shortmem"]["available_wine"]) != 0
# "Available wines you've found in your inventory so far: $(availableWineToText(a.memory["shortmem"][:available_wine]))" # "Available wines you've found in your inventory so far: $(availableWineToText(a.memory["shortmem"]["available_wine"]))"
# else # else
# "N/A" # "N/A"
# end # end
database_search_result = a.memory["shortmem"][:db_search_result] database_search_result = a.memory["shortmem"]["db_search_result"]
# recent_ind = GeneralUtils.recentElementsIndex(length(a.memory[:events]), recent) # recent_ind = GeneralUtils.recentElementsIndex(length(a.memory[:events]), recent)
# recentevents = a.memory[:events][recent_ind] # recentevents = a.memory[:events][recent_ind]
@@ -1357,8 +1357,8 @@ function generatequestion(a, text2textInstructLLM::Function, timeline)::String
# check whether the wine is in event # check whether the wine is in event
isWineInEvent = false isWineInEvent = false
for winename in mentioned_winery for winename in mentioned_winery
for event in a.memory[:events] for event in a.memory["events"]
if event[:observation] !== nothing && occursin(winename, event[:observation]) if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true isWineInEvent = true
break break
end end
@@ -1402,7 +1402,7 @@ function generatequestion(a, text2textInstructLLM::Function, timeline)::String
responsedict = GeneralUtils.textToDict(response, header; responsedict = GeneralUtils.textToDict(response, header;
dictKey=dictkey, symbolkey=true) dictKey=dictkey, symbolkey=true)
response = "Q1: " * responsedict[:q1] response = "Q1: " * responsedict["q1"]
println("\nYiemAgent generatequestion() ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nYiemAgent generatequestion() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
try pprintln(response) catch e println(response) end try pprintln(response) catch e println(response) end
@@ -1446,11 +1446,11 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent::
Let's begin! Let's begin!
""" """
header = ["Event_$i:" for i in eachindex(a.memory[:events])] header = ["Event_$i:" for i in eachindex(a.memory["events"])]
dictkey = lowercase.(["Event_$i" for i in eachindex(a.memory[:events])]) dictkey = lowercase.(["Event_$i" for i in eachindex(a.memory["events"])])
ind = GeneralUtils.nonRecentElementsIndex(length(a.memory[:events]), skiprecent) ind = GeneralUtils.nonRecentElementsIndex(length(a.memory["events"]), skiprecent)
events = a.memory[:events][ind] events = a.memory["events"][ind]
timeline = createTimeline(events) timeline = createTimeline(events)
errornote = "N/A" errornote = "N/A"
@@ -1570,7 +1570,7 @@ function detectWineryName(a, text)
responsedict = GeneralUtils.textToDict(response, header; responsedict = GeneralUtils.textToDict(response, header;
dictKey=dictkey, symbolkey=true) dictKey=dictkey, symbolkey=true)
result = responsedict[:winery_names] result = responsedict["winery_names"]
return result return result
end end

View File

@@ -37,10 +37,10 @@ function virtualWineUserRecommendbox(a::T1, input
)::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent} )::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent}
# put in model format # put in model format
virtualWineCustomer = a.config[:externalservice][:virtualWineCustomer_1] virtualWineCustomer = a.config["externalservice"]["virtualWineCustomer_1"]
llminfo = virtualWineCustomer[:llminfo] llminfo = virtualWineCustomer["llminfo"]
prompt = prompt =
if llminfo[:name] == "llama3instruct" if llminfo["name"] == "llama3instruct"
formatLLMtext_llama3instruct("assistant", input) formatLLMtext_llama3instruct("assistant", input)
else else
error("llm model name is not defied yet $(@__LINE__)") error("llm model name is not defied yet $(@__LINE__)")
@@ -48,26 +48,26 @@ function virtualWineUserRecommendbox(a::T1, input
# send formatted input to user using GeneralUtils.sendReceiveMqttMsg # send formatted input to user using GeneralUtils.sendReceiveMqttMsg
msgMeta = GeneralUtils.generate_msgMeta( msgMeta = GeneralUtils.generate_msgMeta(
virtualWineCustomer[:mqtttopic], virtualWineCustomer["mqtttopic"],
senderName= "virtualWineUserRecommendbox", senderName= "virtualWineUserRecommendbox",
senderId= a.id, senderId= a.id,
receiverName= "virtualWineCustomer", receiverName= "virtualWineCustomer",
mqttBroker= a.config[:mqttServerInfo][:broker], mqttBroker= a.config["mqttServerInfo"]["broker"],
mqttBrokerPort= a.config[:mqttServerInfo][:port], mqttBrokerPort= a.config["mqttServerInfo"]["port"],
msgId = "dummyid" #CHANGE remove after testing finished msgId = "dummyid" #CHANGE remove after testing finished
) )
outgoingMsg = Dict( outgoingMsg = Dict(
:msgMeta=> msgMeta, "msgMeta"=> msgMeta,
:payload=> Dict( "payload"=> Dict(
:text=> prompt, "text"=> prompt,
) )
) )
result = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120) result = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
response = result[:response] response = result["response"]
return (response[:text], response[:select], response[:reward], response[:isterminal]) return (response["text"], response["select"], response["reward"], response["isterminal"])
end end
@@ -171,26 +171,26 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor
Let's begin! Let's begin!
""" """
pushfirst!(virtualCustomerChatHistory, Dict(:name=> "system", :text=> systemmsg)) pushfirst!(virtualCustomerChatHistory, Dict("name"=> "system", "text"=> systemmsg))
# replace the :user key in chathistory to allow the virtual wine customer AI roleplay # replace the :user key in chathistory to allow the virtual wine customer AI roleplay
chathistory::Vector{Dict{String, Any}} = Vector{Dict{String, Any}}() chathistory::Vector{Dict{String, Any}} = Vector{Dict{String, Any}}()
for i in virtualCustomerChatHistory for i in virtualCustomerChatHistory
newdict = Dict() newdict = Dict()
newdict[:name] = newdict["name"] =
if i[:name] == "user" if i["name"] == "user"
"you" "you"
elseif i[:name] == "assistant" elseif i["name"] == "assistant"
"sommelier" "sommelier"
else else
i[:name] i["name"]
end end
newdict[:text] = i[:text] newdict["text"] = i["text"]
push!(chathistory, newdict) push!(chathistory, newdict)
end end
push!(chathistory, Dict(:name=> "assistant", :text=> input)) push!(chathistory, Dict("name"=> "assistant", "text"=> input))
# put in model format # put in model format
prompt = formatLLMtext(chathistory, "llama3instruct") prompt = formatLLMtext(chathistory, "llama3instruct")
@@ -201,23 +201,23 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor
""" """
pprint(prompt) pprint(prompt)
externalService = config[:externalservice][:text2textinstruct] externalService = config["externalservice"]["text2textinstruct"]
# send formatted input to user using GeneralUtils.sendReceiveMqttMsg # send formatted input to user using GeneralUtils.sendReceiveMqttMsg
msgMeta = GeneralUtils.generate_msgMeta( msgMeta = GeneralUtils.generate_msgMeta(
externalService[:mqtttopic], externalService["mqtttopic"],
senderName= "virtualWineUserChatbox", senderName= "virtualWineUserChatbox",
senderId= string(uuid4()), senderId= string(uuid4()),
receiverName= "text2textinstruct", receiverName= "text2textinstruct",
mqttBroker= config[:mqttServerInfo][:broker], mqttBroker= config["mqttServerInfo"]["broker"],
mqttBrokerPort= config[:mqttServerInfo][:port], mqttBrokerPort= config["mqttServerInfo"]["port"],
msgId = string(uuid4()) #CHANGE remove after testing finished msgId = string(uuid4()) #CHANGE remove after testing finished
) )
outgoingMsg = Dict( outgoingMsg = Dict(
:msgMeta=> msgMeta, "msgMeta"=> msgMeta,
:payload=> Dict( "payload"=> Dict(
:text=> prompt, "text"=> prompt,
) )
) )
@@ -225,7 +225,7 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor
for attempt in 1:5 for attempt in 1:5
try try
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120) response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
_responseJsonStr = response[:response][:text] _responseJsonStr = response["response"]["text"]
expectedJsonExample = expectedJsonExample =
""" """
Here is an expected JSON format: Here is an expected JSON format:
@@ -239,10 +239,10 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor
responseJsonStr = jsoncorrection(config, _responseJsonStr, expectedJsonExample) responseJsonStr = jsoncorrection(config, _responseJsonStr, expectedJsonExample)
responseDict = copy(JSON.parsefile(responseJsonStr)) responseDict = copy(JSON.parsefile(responseJsonStr))
text::AbstractString = responseDict[:text] text::AbstractString = responseDict["text"]
select::Union{Nothing, Number} = responseDict[:select] == "null" ? nothing : responseDict[:select] select::Union{Nothing, Number} = responseDict["select"] == "null" ? nothing : responseDict["select"]
reward::Number = responseDict[:reward] reward::Number = responseDict["reward"]
isterminal::Bool = responseDict[:isterminal] isterminal::Bool = responseDict["isterminal"]
if text != "" if text != ""
# pass test # pass test
@@ -455,8 +455,8 @@ function extractWineAttributes_1(a::T1, input::T2; maxattempt=10
unformatPrompt = unformatPrompt =
[ [
Dict(:name=> "system", :text=> systemmsg), Dict("name"=> "system", "text"=> systemmsg),
Dict(:name=> "user", :text=> usermsg) Dict("name"=> "user", "text"=> usermsg)
] ]
# put in model format # put in model format
@@ -544,21 +544,20 @@ function extractWineAttributes_1(a::T1, input::T2; maxattempt=10
if j removekeys if j removekeys
# in case j is wine_price it needs to be checked differently because its value is ranged # in case j is wine_price it needs to be checked differently because its value is ranged
if j == :wine_price if j == :wine_price
if responsedict[:wine_price] != "N/A" if responsedict["wine_price"] != "N/A"
# check whether wine_price is in ranged number if !occursin("to", responsedict["wine_price"])
if !occursin("to", responsedict[:wine_price]) errornote = "In your previous attempt, the 'wine_price' was set to $(responsedict["wine_price"]) which is not a correct format. Please adjust it accordingly."
errornote = "In your previous attempt, the 'wine_price' was set to $(responsedict[:wine_price]) which is not a correct format. Please adjust it accordingly."
println("\nERROR YiemAgent extractWineAttributes_1() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nERROR YiemAgent extractWineAttributes_1() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
checkFlag = true checkFlag = true
break break
end end
# # check whether max wine_price is in the input # # check whether max wine_price is in the input
# pricerange = split(responsedict[:wine_price], '-') # pricerange = split(responsedict["wine_price"], '-')
# minprice = pricerange[1] # minprice = pricerange[1]
# maxprice = pricerange[end] # maxprice = pricerange[end]
# if !occursin(maxprice, input) # if !occursin(maxprice, input)
# responsedict[:wine_price] = "N/A" # responsedict["wine_price"] = "N/A"
# end # end
# # price range like 100-100 is not good # # price range like 100-100 is not good
# if minprice == maxprice # if minprice == maxprice
@@ -735,7 +734,7 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2<
unformatPrompt = unformatPrompt =
[ [
Dict(:name=> "system", :text=> systemmsg), Dict("name"=> "system", "text"=> systemmsg),
] ]
# put in model format # put in model format
@@ -883,8 +882,8 @@ function paraphrase(text2textInstructLLM::Function, text::String)
_prompt = _prompt =
[ [
Dict(:name => "system", :text => systemmsg), Dict("name" => "system", "text" => systemmsg),
Dict(:name => "user", :text => usermsg) Dict("name" => "user", "text" => usermsg)
] ]
# put in model format # put in model format
@@ -935,7 +934,7 @@ function paraphrase(text2textInstructLLM::Function, text::String)
println("\nparaphrase() ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nparaphrase() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
pprintln(Dict(responsedict)) pprintln(Dict(responsedict))
result = responsedict[:paraphrase] result = responsedict["paraphrase"]
return result return result
catch e catch e
@@ -1004,10 +1003,10 @@ function jsoncorrection(config::T1, input::T2, correctJsonExample::T3;
""" """
# apply LLM specific instruct format # apply LLM specific instruct format
externalService = config[:externalservice][:text2textinstruct] externalService = config["externalservice"]["text2textinstruct"]
llminfo = externalService[:llminfo] llminfo = externalService["llminfo"]
prompt = prompt =
if llminfo[:name] == "llama3instruct" if llminfo["name"] == "llama3instruct"
formatLLMtext_llama3instruct("system", _prompt) formatLLMtext_llama3instruct("system", _prompt)
else else
error("llm model name is not defied yet $(@__LINE__)") error("llm model name is not defied yet $(@__LINE__)")
@@ -1015,21 +1014,21 @@ function jsoncorrection(config::T1, input::T2, correctJsonExample::T3;
# send formatted input to user using GeneralUtils.sendReceiveMqttMsg # send formatted input to user using GeneralUtils.sendReceiveMqttMsg
msgMeta = GeneralUtils.generate_msgMeta( msgMeta = GeneralUtils.generate_msgMeta(
externalService[:mqtttopic], externalService["mqtttopic"],
senderName= "jsoncorrection", senderName= "jsoncorrection",
senderId= string(uuid4()), senderId= string(uuid4()),
receiverName= "text2textinstruct", receiverName= "text2textinstruct",
mqttBroker= config[:mqttServerInfo][:broker], mqttBroker= config["mqttServerInfo"]["broker"],
mqttBrokerPort= config[:mqttServerInfo][:port], mqttBrokerPort= config["mqttServerInfo"]["port"],
) )
outgoingMsg = Dict( outgoingMsg = Dict(
:msgMeta=> msgMeta, "msgMeta"=> msgMeta,
:payload=> Dict( "payload"=> Dict(
:text=> prompt, "text"=> prompt,
:kwargs=> Dict( "kwargs"=> Dict(
:max_tokens=> 512, "max_tokens"=> 512,
:stop=> ["<|eot_id|>"], "stop"=> ["<|eot_id|>"],
) )
) )
) )

View File

@@ -38,7 +38,7 @@ function companion(
name::String= "Assistant", name::String= "Assistant",
id::String= GeneralUtils.uuid4snakecase(), id::String= GeneralUtils.uuid4snakecase(),
maxHistoryMsg::Integer= 20, maxHistoryMsg::Integer= 20,
chathistory::Vector{Dict{Symbol, String}} = Vector{Dict{Symbol, String}}(), chathistory::Vector{Dict{String, String}} = Vector{Dict{String, String}}(),
llmFormatName::String= "granite3", llmFormatName::String= "granite3",
systemmsg::String= systemmsg::String=
""" """
@@ -55,7 +55,7 @@ function companion(
tools = Dict( # update input format tools = Dict( # update input format
"CHATBOX"=> Dict( "CHATBOX"=> Dict(
:description => "- CHATBOX which you can use to talk with the user. The input is your intentions for the dialogue. Be specific.", "description" => "- CHATBOX which you can use to talk with the user. The input is your intentions for the dialogue. Be specific.",
), ),
) )
@@ -63,14 +63,14 @@ function companion(
Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3 Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
NO "system" message in chathistory because I want to add it at the inference time NO "system" message in chathistory because I want to add it at the inference time
chathistory= [ chathistory= [
Dict(:name=>"user", :text=> "Wassup!", :timestamp=> Dates.now()), Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()),
Dict(:name=>"assistant", :text=> "Hi I'm your assistant.", :timestamp=> Dates.now()), Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()),
] ]
""" """
memory = Dict{String, Any}( memory = Dict{String, Any}(
:events=> Vector{Dict{String, Any}}(), "events"=> Vector{Dict{String, Any}}(),
:state=> Dict{String, Any}(), # state of the agent "state"=> Dict{String, Any}(), # state of the agent
:recap=> OrderedDict{String, Any}(), # recap summary of the conversation "recap"=> OrderedDict{String, Any}(), # recap summary of the conversation
) )
newAgent = companion( newAgent = companion(
@@ -116,7 +116,7 @@ end
Retailer name associated with the sommelier. Default: `"retailer_name"` Retailer name associated with the sommelier. Default: `"retailer_name"`
- `maxHistoryMsg::Integer` - `maxHistoryMsg::Integer`
Maximum history messages. Default: `20` Maximum history messages. Default: `20`
- `chathistory::Vector{Dict{Symbol, String}}` - `chathistory::Vector{Dict{String, String}}`
Chat history. Default: empty vector. Chat history. Default: empty vector.
- `llmFormatName::String` - `llmFormatName::String`
LLM format name. Default: `"granite3"` LLM format name. Default: `"granite3"`
@@ -146,20 +146,20 @@ function sommelier(
id::String= string(uuid4()), id::String= string(uuid4()),
retailername::String= "retailer_name", retailername::String= "retailer_name",
maxHistoryMsg::Integer= 20, maxHistoryMsg::Integer= 20,
chathistory::Vector{Dict{Symbol, String}} = Vector{Dict{Symbol, String}}(), chathistory::Vector{Dict{String, String}} = Vector{Dict{String, String}}(),
llmFormatName::String= "granite3" llmFormatName::String= "granite3"
) )
tools = Dict( # update input format tools = Dict( # update input format
"chatbox"=> Dict( "chatbox"=> Dict(
:description => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>", "description" => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>",
:input => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""", "input" => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""",
:output => "" , "output" => "" ,
), ),
"winestock"=> Dict( "winestock"=> Dict(
:description => "<winestock tool description>A handy tool for searching wine in your inventory that match the user preferences.</winestock tool description>", "description" => "<winestock tool description>A handy tool for searching wine in your inventory that match the user preferences.</winestock tool description>",
:input => """<input>Input is a JSON-formatted string that contains a detailed and precise search query.</input><input example>{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}</input example>""", "input" => """<input>Input is a JSON-formatted string that contains a detailed and precise search query.</input><input example>{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}</input example>""",
:output => """<output>Output are wines that match the search query in JSON format.""", "output" => """<output>Output are wines that match the search query in JSON format.""",
), ),
) )
@@ -167,19 +167,19 @@ function sommelier(
Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3 Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
NO "system" message in chathistory because I want to add it at the inference time NO "system" message in chathistory because I want to add it at the inference time
chathistory= [ chathistory= [
Dict(:name=>"user", :text=> "Wassup!", :timestamp=> Dates.now()), Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()),
Dict(:name=>"assistant", :text=> "Hi I'm your assistant.", :timestamp=> Dates.now()), Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()),
] ]
""" """
memory = Dict{String, Any}( memory = Dict{String, Any}(
:shortmem=> OrderedDict{String, Any}( "shortmem"=> OrderedDict{String, Any}(
:db_search_result=> Any[], "db_search_result"=> Any[],
:scratchpad=> "", #[PENDING] should be a dict e.g. Dict(:database_search_result=>Dict(:wines=> "", :search_query=> "")) "scratchpad"=> "", #PENDING should be a dict e.g. Dict("database_search_result"=>Dict("wines"=> "", "search_query"=> ""))
), ),
:events=> Vector{Dict{String, Any}}(), "events"=> Vector{Dict{String, Any}}(),
:state=> Dict{String, Any}( "state"=> Dict{String, Any}(
), ),
:recap=> OrderedDict{String, Any}(), "recap"=> OrderedDict{String, Any}(),
) )
@@ -297,7 +297,7 @@ function virtualcustomer(
name::String= "Assistant", name::String= "Assistant",
id::String= string(uuid4()), id::String= string(uuid4()),
maxHistoryMsg::Integer= 20, maxHistoryMsg::Integer= 20,
chathistory::Vector{Dict{Symbol, String}} = Vector{Dict{Symbol, String}}(), chathistory::Vector{Dict{String, String}} = Vector{Dict{String, String}}(),
llmFormatName::String= "granite3", llmFormatName::String= "granite3",
systemmsg::String= systemmsg::String=
""" """
@@ -314,9 +314,9 @@ function virtualcustomer(
tools = Dict( # update input format tools = Dict( # update input format
"chatbox"=> Dict( "chatbox"=> Dict(
:description => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>", "description" => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>",
:input => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""", "input" => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""",
:output => "" , "output" => "" ,
), ),
) )
@@ -324,17 +324,17 @@ function virtualcustomer(
Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3 Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
NO "system" message in chathistory because I want to add it at the inference time NO "system" message in chathistory because I want to add it at the inference time
chathistory= [ chathistory= [
Dict(:name=>"user", :text=> "Wassup!", :timestamp=> Dates.now()), Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()),
Dict(:name=>"assistant", :text=> "Hi I'm your assistant.", :timestamp=> Dates.now()), Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()),
] ]
""" """
memory = Dict{String, Any}( memory = Dict{String, Any}(
:shortmem=> OrderedDict{String, Any}( "shortmem"=> OrderedDict{String, Any}(
), ),
:events=> Vector{Dict{String, Any}}(), "events"=> Vector{Dict{String, Any}}(),
:state=> Dict{String, Any}( "state"=> Dict{String, Any}(
), ),
:recap=> OrderedDict{String, Any}(), "recap"=> OrderedDict{String, Any}(),
) )
newAgent = virtualcustomer( newAgent = virtualcustomer(

View File

@@ -26,16 +26,16 @@ julia> client, connection = MakeConnection("test.mosquitto.org", 1883)
julia> connect(client, connection) julia> connect(client, connection)
julia> msgMeta = GeneralUtils.generate_msgMeta("testtopic") julia> msgMeta = GeneralUtils.generate_msgMeta("testtopic")
julia> agentConfig = Dict( julia> agentConfig = Dict(
:receiveprompt=>Dict( "receiveprompt"=>Dict(
:mqtttopic=> "testtopic/receive", "mqtttopic"=> "testtopic/receive",
), ),
:receiveinternal=>Dict( "receiveinternal"=>Dict(
:mqtttopic=> "testtopic/internal", "mqtttopic"=> "testtopic/internal",
), ),
:text2text=>Dict( "text2text"=>Dict(
:mqtttopic=> "testtopic/text2text", "mqtttopic"=> "testtopic/text2text",
), ),
) )
julia> a = YiemAgent.sommelier( julia> a = YiemAgent.sommelier(
client, client,
msgMeta, msgMeta,
@@ -52,9 +52,9 @@ julia> YiemAgent.clearhistory(a)
""" """
function clearhistory(a::T) where {T<:agent} function clearhistory(a::T) where {T<:agent}
empty!(a.chathistory) empty!(a.chathistory)
empty!(a.memory[:shortmem]) empty!(a.memory["shortmem"])
empty!(a.memory[:events]) empty!(a.memory["events"])
a.memory[:chatbox] = "" a.memory["chatbox"] = ""
end end
@@ -129,7 +129,7 @@ This function takes in a vector of dictionaries and outputs a single string wher
julia> using Revise julia> using Revise
julia> using GeneralUtils julia> using GeneralUtils
julia> vecd = [Dict(:name => "John", :text => "Hello"), Dict(:name => "Jane", :text => "Goodbye")] julia> vecd = [Dict("name" => "John", "text" => "Hello"), Dict("name" => "Jane", "text" => "Goodbye")]
julia> GeneralUtils.vectorOfDictToText(vecd, withkey=true) julia> GeneralUtils.vectorOfDictToText(vecd, withkey=true)
"John> Hello\nJane> Goodbye\n" "John> Hello\nJane> Goodbye\n"
``` ```
@@ -233,17 +233,17 @@ function eventdict(;
) )
d = Dict{String, Any}( d = Dict{String, Any}(
:event_description=> event_description, "event_description"=> event_description,
:timestamp=> timestamp, "timestamp"=> timestamp,
:subject=> subject, "subject"=> subject,
:thought=> thought, "thought"=> thought,
:actionname=> actionname, "actionname"=> actionname,
:actioninput=> actioninput, "actioninput"=> actioninput,
:location=> location, "location"=> location,
:equipment_used=> equipment_used, "equipment_used"=> equipment_used,
:material_used=> material_used, "material_used"=> material_used,
:observation=> observation, "observation"=> observation,
:note=> note, "note"=> note,
) )
return d return d
@@ -268,8 +268,8 @@ end
# Example # Example
events = [ events = [
Dict(:subject => "User", :actioninput => "Hello", :observation => nothing), Dict("subject" => "User", "actioninput" => "Hello", "observation" => nothing),
Dict(:subject => "Assistant", :actioninput => "Hi there!", :observation => "with a smile") Dict("subject" => "Assistant", "actioninput" => "Hi there!", "observation" => "with a smile")
] ]
timeline = createTimeline(events) timeline = createTimeline(events)
# 1) User> Hello # 1) User> Hello
@@ -293,16 +293,15 @@ function createTimeline(events::T1; eventindex::Union{UnitRange, Nothing}=nothin
for i in ind for i in ind
event = events[i] event = events[i]
# If no outcome exists, format without outcome # If no outcome exists, format without outcome
# if event[:actionname] == "CHATBOX" # if event["actionname"] == "CHATBOX"
# timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput])\n" # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"])\n"
# elseif event[:actionname] == "CHECKINVENTORY" && event[:observation] === nothing # elseif event["actionname"] == "CHECKINVENTORY" && event["observation"] === nothing
# timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput]), observation: Not done yet.\n" # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: Not done yet.\n"
# If outcome exists, include it in formatting if event["actionname"] == "CHECKWINE"
if event[:actionname] == "CHECKWINE" timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: $(event["observation"])\\n"
timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput]), observation: $(event[:observation])\n"
else else
timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput])\n" timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"])\\n"
end end
end end
# Return formatted timeline string # Return formatted timeline string
@@ -325,11 +324,11 @@ end
# for i in ind # for i in ind
# event = events[i] # event = events[i]
# # If no outcome exists, format without outcome # # If no outcome exists, format without outcome
# if event[:observation] === nothing # if event["observation"] === nothing
# timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput]), observation: Not done yet.\n" # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: Not done yet.\n"
# # If outcome exists, include it in formatting # # If outcome exists, include it in formatting
# else # else
# timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput]), observation: $(event[:observation])\n" # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: $(event["observation"])\\n"
# end # end
# end # end
@@ -341,7 +340,7 @@ end
function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing
) where {T1<:AbstractVector} ) where {T1<:AbstractVector}
# Initialize empty log array # Initialize empty log array
log = Dict{Symbol, String}[] log = Dict{String, String}[]
# Determine which indices to use - either provided range or full length # Determine which indices to use - either provided range or full length
ind = ind =
@@ -355,20 +354,20 @@ function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing
for i in ind for i in ind
event = events[i] event = events[i]
# If no outcome exists, format without outcome # If no outcome exists, format without outcome
if event[:observation] === nothing if event["observation"] === nothing
subject = event[:subject] subject = event["subject"]
actionname = event[:actionname] actionname = event["actionname"]
actioninput = event[:actioninput] actioninput = event["actioninput"]
str = "actionname: $actionname, actioninput: $actioninput" str = "actionname: $actionname, actioninput: $actioninput"
d = Dict{Symbol, String}(:name=>subject, :text=>str) d = Dict{String, String}("name"=>subject, "text"=>str)
push!(log, d) push!(log, d)
else else
subject = event[:subject] subject = event["subject"]
actionname = event[:actionname] actionname = event["actionname"]
actioninput = event[:actioninput] actioninput = event["actioninput"]
observation = event[:observation] observation = event["observation"]
str = "actionname: $actionname, actioninput: $actioninput, observation: $observation" str = "actionname: $actionname, actioninput: $actioninput, observation: $observation"
d = Dict{Symbol, String}(:name=>subject, :text=>str) d = Dict{String, String}("name"=>subject, "text"=>str)
push!(log, d) push!(log, d)
end end
end end
@@ -380,7 +379,7 @@ end
function createChatLog(chatdict::T1; index::Union{UnitRange, Nothing}=nothing function createChatLog(chatdict::T1; index::Union{UnitRange, Nothing}=nothing
) where {T1<:AbstractVector} ) where {T1<:AbstractVector}
# Initialize empty log array # Initialize empty log array
log = Dict{Symbol, String}[] log = Dict{String, String}[]
# Determine which indices to use - either provided range or full length # Determine which indices to use - either provided range or full length
ind = ind =
@@ -393,9 +392,9 @@ function createChatLog(chatdict::T1; index::Union{UnitRange, Nothing}=nothing
# Iterate through events and format each one # Iterate through events and format each one
for i in ind for i in ind
event = chatdict[i] event = chatdict[i]
subject = event[:name] subject = event["name"]
text = event[:text] text = event["text"]
d = Dict{Symbol, String}(:name=>subject, :text=>text) d = Dict{String, String}("name"=>subject, "text"=>text)
push!(log, d) push!(log, d)
end end