From 9c22cf2e3169d938ac56b0c4484365ce12bcc525 Mon Sep 17 00:00:00 2001 From: narawat Date: Wed, 24 Jun 2026 20:46:24 +0700 Subject: [PATCH] use Dict string key --- src/interface.jl | 170 ++++++++++++++++++++++----------------------- src/llmfunction.jl | 107 ++++++++++++++-------------- src/type.jl | 66 +++++++++--------- src/util.jl | 111 +++++++++++++++-------------- 4 files changed, 226 insertions(+), 228 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 2ddbbca..d672e60 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -64,29 +64,29 @@ end # Example ```jldoctest julia> config = Dict( - :mqttServerInfo => Dict( - :description => "mqtt server info", - :port => 1883, - :broker => "mqtt.yiem.cc" - ), - :externalservice => Dict( - "text"2textinstruct => Dict( - :mqtttopic => "/loadbalancer/requestingservice", - :description => "text to text service with instruct LLM", - :llminfo => Dict( - "name" => "llama3instruct" - ) - ), - ) - ) + "mqttServerInfo" => Dict( + "description" => "mqtt server info", + "port" => 1883, + "broker" => "mqtt.yiem.cc" + ), + "externalservice" => Dict( + "text2textinstruct" => Dict( + "mqtttopic" => "/loadbalancer/requestingservice", + "description" => "text to text service with instruct LLM", + "llminfo" => Dict( + "name" => "llama3instruct" + ) + ), + ) + ) julia> output_thoughtDict = Dict( - :thought_1 => "The customer wants to buy a bottle of wine. This is a good start!", - :action_1 => Dict{String, Any}( - :action=>"CHATBOX", - :input=>"What occasion are you buying the wine for?" + "thought_1" => "The customer wants to buy a bottle of wine. This is a good start!", + "action_1" => Dict{String, Any}( + "action"=>"CHATBOX", + "input"=>"What occasion are you buying the wine for?" ), - :observation_1 => "" + "observation_1" => "" ) ``` - [] update docstring @@ -123,7 +123,7 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10 # end recentevents_ind = GeneralUtils.recentElementsIndex( - length(a.memory[:events]), recentevents; includelatest=true) + length(a.memory["events"]), recentevents; includelatest=true) requiredKeys = ["plan", "actionname", "actioninput"] @@ -203,8 +203,8 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10 # check whether the wine is in event isWineInEvent = false for winename in mentioned_winery - for event in a.memory[:events] - if event[:observation] !== nothing && occursin(winename, event[:observation]) + for event in a.memory["events"] + if event["observation"] !== nothing && occursin(winename, event["observation"]) isWineInEvent = true break end @@ -237,19 +237,19 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10 end # store for later training - responsedict[:system] = systemmsg - responsedict[:unformatPrompt] = unformatPrompt - responsedict[:prompt] = prompt - responsedict[:context] = context - responsedict[:think] = think - responsedict[:response] = response - # responsedict[:QandA] = QandA + responsedict["system"] = systemmsg + responsedict["unformatPrompt"] = unformatPrompt + responsedict["prompt"] = prompt + responsedict["context"] = context + responsedict["think"] = think + responsedict["response"] = response + # responsedict["QandA"] = QandA # check whether there is a file path exists before writing to it - if !haskey(a.memory["shortmem"], :decisionlog) - a.memory["shortmem"][:decisionlog] = [responsedict] + if !haskey(a.memory["shortmem"], "decisionlog") + a.memory["shortmem"]["decisionlog"] = [responsedict] else - push!(a.memory["shortmem"][:decisionlog], responsedict) + push!(a.memory["shortmem"]["decisionlog"], responsedict) end # # 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)") - responsedict[:prompt] = prompt + responsedict["prompt"] = prompt return responsedict end 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) # add user activity to events memory - push!(a.memory[:events], + push!(a.memory["events"], eventdict(; event_description="the user talks to the assistant.", timestamp=Dates.now(), @@ -544,7 +544,7 @@ function conversation(a::Union{companion, virtualcustomer}, userinput::Dict; addNewMessage(a, "assistant", chatresponse; maximumMsg=maximumMsg) - push!(a.memory[:events], + push!(a.memory["events"], eventdict(; event_description="the assistant talks to the user.", timestamp=Dates.now(), @@ -592,18 +592,18 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh end # this section allow LLM functions above to have different return values. - result = haskey(response, :result) ? response[:result] : nothing - rawresponse = haskey(response, :rawresponse) ? response[:rawresponse] : nothing - select = haskey(response, :select) ? response[:select] : nothing - reward::Integer = haskey(response, :reward) ? response[:reward] : 0 - isterminal::Bool = haskey(response, :isterminal) ? response[:isterminal] : false - errormsg::Union{AbstractString,Nothing} = haskey(response, :errormsg) ? response[:errormsg] : nothing - success::Bool = haskey(response, :success) ? response[:success] : false + result = haskey(response, "result") ? response["result"] : nothing + rawresponse = haskey(response, "rawresponse") ? response["rawresponse"] : nothing + select = haskey(response, "select") ? response["select"] : nothing + reward::Integer = haskey(response, "reward") ? response["reward"] : 0 + isterminal::Bool = haskey(response, "isterminal") ? response["isterminal"] : false + errormsg::Union{AbstractString,Nothing} = haskey(response, "errormsg") ? response["errormsg"] : nothing + success::Bool = haskey(response, "success") ? response["success"] : false # # manage memory (pass msg to generatechat) # if actionname ∈ ["CHATBOX", "PRESENTBOX", "ENDCONVERSATION"] # chatresponse = generatechat(a, thoughtDict) - # push!(a.memory[:events], + # push!(a.memory["events"], # eventdict(; # event_description="the assistant talks to the user.", # timestamp=Dates.now(), @@ -615,7 +615,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh # ) # result = chatresponse if actionname ∈ ["CHATBOX"] - push!(a.memory[:events], + push!(a.memory["events"], eventdict(; event_description="an assistant talks to the user.", timestamp=Dates.now(), @@ -628,7 +628,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh result = actioninput elseif actionname ∈ ["ENDCONVERSATION"] chatresponse = generatechat(a, thoughtDict) - push!(a.memory[:events], + push!(a.memory["events"], eventdict(; event_description="an assistant talks to the user to end conversation.", timestamp=Dates.now(), @@ -641,7 +641,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh result = chatresponse elseif actionname ∈ ["PRESENTBOX"] chatresponse = presentbox(a, thoughtDict) - push!(a.memory[:events], + push!(a.memory["events"], eventdict(; event_description="the assistant presents wines to the user.", timestamp=Dates.now(), @@ -656,12 +656,12 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh elseif actionname == "CHECKWINE" if rawresponse !== nothing vd = GeneralUtils.dfToVectorDict(rawresponse) # comes in dataframe format - # 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? - 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"]["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? + if length(a.memory["shortmem"]["db_search_result"]) != 0 + a.memory["shortmem"]["db_search_result"] = vcat(a.memory["shortmem"]["db_search_result"], vd) else - a.memory["shortmem"][:db_search_result] = vd + a.memory["shortmem"]["db_search_result"] = vd end # # add to scratchpad @@ -680,7 +680,7 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh # """ end - push!(a.memory[:events], + push!(a.memory["events"], eventdict(; event_description= "the assistant searched the database.", timestamp= Dates.now(), @@ -803,7 +803,7 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10, recentev end # 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" println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())") 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 # outside its inventory # 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" mentioned_winery = String.(strip.(split(mentioned_winery, ","))) # check whether the wine is in event isWineInEvent = false for winename in mentioned_winery - for event in a.memory[:events] - if event[:observation] !== nothing && occursin(winename, event[:observation]) + for event in a.memory["events"] + if event["observation"] !== nothing && occursin(winename, event["observation"]) isWineInEvent = true break end @@ -850,7 +850,7 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10, recentev end end - result = responsedict[:dialogue] + result = responsedict["dialogue"] return result end error("presentbox() failed to generate a response") @@ -913,10 +913,10 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10) """ requiredKeys = [:dialogue] - # a.memory["shortmem"][:available_wine] is a vector of dictionary + # a.memory["shortmem"]["available_wine"] is a vector of dictionary # context = - # if length(a.memory["shortmem"][:available_wine]) != 0 - # "Wines previously found in your inventory: $(availableWineToText(a.memory["shortmem"][:available_wine]))" + # if length(a.memory["shortmem"]["available_wine"]) != 0 + # "Wines previously found in your inventory: $(availableWineToText(a.memory["shortmem"]["available_wine"]))" # else # "N/A" # end @@ -1003,8 +1003,8 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10) # check whether the wine is in event isWineInEvent = false for winename in mentioned_winery - for event in a.memory[:events] - if event[:observation] !== nothing && occursin(winename, event[:observation]) + for event in a.memory["events"] + if event["observation"] !== nothing && occursin(winename, event["observation"]) isWineInEvent = true break end @@ -1018,7 +1018,7 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10) continue end end - result = responsedict[:dialogue] + result = responsedict["dialogue"] return result end @@ -1088,15 +1088,15 @@ function generatechat(a::virtualcustomer; converPartnerName::Union{String, Nothing}=nothing, maxattempt=10, recentEventNum=10 ) - recent_ind = GeneralUtils.recentElementsIndex(length(a.memory[:events]), recentEventNum; includelatest=true) - recentEventsDict = createEventsLog(a.memory[:events]; index=recent_ind) + recent_ind = GeneralUtils.recentElementsIndex(length(a.memory["events"]), recentEventNum; includelatest=true) + recentEventsDict = createEventsLog(a.memory["events"]; index=recent_ind) response = nothing # placeholder for show when error msg show up errornote = "N/A" header = ["Dialogue:", "Role:"] dictkey = ["dialogue", "role"] llmkwargs=Dict( - :num_ctx => 32768, - :temperature => 0.5, + "num_ctx" => 32768, + "temperature" => 0.5, ) for attempt in 1:maxattempt @@ -1141,15 +1141,15 @@ function generatechat(a::virtualcustomer; responsedict = GeneralUtils.textToDict(response, header; dictKey=dictkey, symbolkey=true) - 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." + 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." println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())") continue end # check if the dialogue is the same as the previous one - 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." + 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." println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())") continue end @@ -1157,7 +1157,7 @@ function generatechat(a::virtualcustomer; # check whether LLM just repeat the previous dialogue dublicate = false 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." println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())") dublicate = true @@ -1170,7 +1170,7 @@ function generatechat(a::virtualcustomer; # println("\n$prompt", @__FILE__, ":", @__LINE__, " $(Dates.now())") # println("\n $response") - return responsedict[:dialogue] + return responsedict["dialogue"] end error("generatechat failed to generate a response") end @@ -1285,12 +1285,12 @@ function generatequestion(a, text2textInstructLLM::Function, timeline)::String dictkey = ["q1"] # context = - # if length(a.memory["shortmem"][:available_wine]) != 0 - # "Available wines you've found in your inventory so far: $(availableWineToText(a.memory["shortmem"][:available_wine]))" + # if length(a.memory["shortmem"]["available_wine"]) != 0 + # "Available wines you've found in your inventory so far: $(availableWineToText(a.memory["shortmem"]["available_wine"]))" # else # "N/A" # 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) # recentevents = a.memory[:events][recent_ind] @@ -1357,8 +1357,8 @@ function generatequestion(a, text2textInstructLLM::Function, timeline)::String # check whether the wine is in event isWineInEvent = false for winename in mentioned_winery - for event in a.memory[:events] - if event[:observation] !== nothing && occursin(winename, event[:observation]) + for event in a.memory["events"] + if event["observation"] !== nothing && occursin(winename, event["observation"]) isWineInEvent = true break end @@ -1402,7 +1402,7 @@ function generatequestion(a, text2textInstructLLM::Function, timeline)::String responsedict = GeneralUtils.textToDict(response, header; dictKey=dictkey, symbolkey=true) - response = "Q1: " * responsedict[:q1] + response = "Q1: " * responsedict["q1"] println("\nYiemAgent generatequestion() ", @__FILE__, ":", @__LINE__, " $(Dates.now())") try pprintln(response) catch e println(response) end @@ -1446,11 +1446,11 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent:: Let's begin! """ - header = ["Event_$i:" for i in eachindex(a.memory[:events])] - dictkey = lowercase.(["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"])]) - ind = GeneralUtils.nonRecentElementsIndex(length(a.memory[:events]), skiprecent) - events = a.memory[:events][ind] + ind = GeneralUtils.nonRecentElementsIndex(length(a.memory["events"]), skiprecent) + events = a.memory["events"][ind] timeline = createTimeline(events) errornote = "N/A" @@ -1570,7 +1570,7 @@ function detectWineryName(a, text) responsedict = GeneralUtils.textToDict(response, header; dictKey=dictkey, symbolkey=true) - result = responsedict[:winery_names] + result = responsedict["winery_names"] return result end diff --git a/src/llmfunction.jl b/src/llmfunction.jl index 13233d2..273509b 100644 --- a/src/llmfunction.jl +++ b/src/llmfunction.jl @@ -37,10 +37,10 @@ function virtualWineUserRecommendbox(a::T1, input )::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent} # put in model format - virtualWineCustomer = a.config[:externalservice][:virtualWineCustomer_1] - llminfo = virtualWineCustomer[:llminfo] + virtualWineCustomer = a.config["externalservice"]["virtualWineCustomer_1"] + llminfo = virtualWineCustomer["llminfo"] prompt = - if llminfo[:name] == "llama3instruct" + if llminfo["name"] == "llama3instruct" formatLLMtext_llama3instruct("assistant", input) else 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 msgMeta = GeneralUtils.generate_msgMeta( - virtualWineCustomer[:mqtttopic], + virtualWineCustomer["mqtttopic"], senderName= "virtualWineUserRecommendbox", senderId= a.id, receiverName= "virtualWineCustomer", - mqttBroker= a.config[:mqttServerInfo][:broker], - mqttBrokerPort= a.config[:mqttServerInfo][:port], + mqttBroker= a.config["mqttServerInfo"]["broker"], + mqttBrokerPort= a.config["mqttServerInfo"]["port"], msgId = "dummyid" #CHANGE remove after testing finished ) outgoingMsg = Dict( - :msgMeta=> msgMeta, - :payload=> Dict( - :text=> prompt, + "msgMeta"=> msgMeta, + "payload"=> Dict( + "text"=> prompt, ) ) 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 @@ -171,26 +171,26 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor 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 chathistory::Vector{Dict{String, Any}} = Vector{Dict{String, Any}}() for i in virtualCustomerChatHistory newdict = Dict() - newdict[:name] = - if i[:name] == "user" + newdict["name"] = + if i["name"] == "user" "you" - elseif i[:name] == "assistant" + elseif i["name"] == "assistant" "sommelier" else - i[:name] + i["name"] end - newdict[:text] = i[:text] + newdict["text"] = i["text"] push!(chathistory, newdict) end - push!(chathistory, Dict(:name=> "assistant", :text=> input)) + push!(chathistory, Dict("name"=> "assistant", "text"=> input)) # put in model format prompt = formatLLMtext(chathistory, "llama3instruct") @@ -201,23 +201,23 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor """ pprint(prompt) - externalService = config[:externalservice][:text2textinstruct] + externalService = config["externalservice"]["text2textinstruct"] # send formatted input to user using GeneralUtils.sendReceiveMqttMsg msgMeta = GeneralUtils.generate_msgMeta( - externalService[:mqtttopic], + externalService["mqtttopic"], senderName= "virtualWineUserChatbox", senderId= string(uuid4()), receiverName= "text2textinstruct", - mqttBroker= config[:mqttServerInfo][:broker], - mqttBrokerPort= config[:mqttServerInfo][:port], + mqttBroker= config["mqttServerInfo"]["broker"], + mqttBrokerPort= config["mqttServerInfo"]["port"], msgId = string(uuid4()) #CHANGE remove after testing finished ) outgoingMsg = Dict( - :msgMeta=> msgMeta, - :payload=> Dict( - :text=> prompt, + "msgMeta"=> msgMeta, + "payload"=> Dict( + "text"=> prompt, ) ) @@ -225,7 +225,7 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor for attempt in 1:5 try response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120) - _responseJsonStr = response[:response][:text] + _responseJsonStr = response["response"]["text"] expectedJsonExample = """ Here is an expected JSON format: @@ -239,10 +239,10 @@ function virtualWineUserChatbox(config::T1, input::T2, virtualCustomerChatHistor responseJsonStr = jsoncorrection(config, _responseJsonStr, expectedJsonExample) responseDict = copy(JSON.parsefile(responseJsonStr)) - text::AbstractString = responseDict[:text] - select::Union{Nothing, Number} = responseDict[:select] == "null" ? nothing : responseDict[:select] - reward::Number = responseDict[:reward] - isterminal::Bool = responseDict[:isterminal] + text::AbstractString = responseDict["text"] + select::Union{Nothing, Number} = responseDict["select"] == "null" ? nothing : responseDict["select"] + reward::Number = responseDict["reward"] + isterminal::Bool = responseDict["isterminal"] if text != "" # pass test @@ -455,8 +455,8 @@ function extractWineAttributes_1(a::T1, input::T2; maxattempt=10 unformatPrompt = [ - Dict(:name=> "system", :text=> systemmsg), - Dict(:name=> "user", :text=> usermsg) + Dict("name"=> "system", "text"=> systemmsg), + Dict("name"=> "user", "text"=> usermsg) ] # put in model format @@ -544,21 +544,20 @@ function extractWineAttributes_1(a::T1, input::T2; maxattempt=10 if j ∉ removekeys # in case j is wine_price it needs to be checked differently because its value is ranged if j == :wine_price - if responsedict[:wine_price] != "N/A" - # check whether wine_price is in ranged number - 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." +if responsedict["wine_price"] != "N/A" + 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." println("\nERROR YiemAgent extractWineAttributes_1() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())") checkFlag = true break end # # check whether max wine_price is in the input - # pricerange = split(responsedict[:wine_price], '-') + # pricerange = split(responsedict["wine_price"], '-') # minprice = pricerange[1] # maxprice = pricerange[end] # if !occursin(maxprice, input) - # responsedict[:wine_price] = "N/A" + # responsedict["wine_price"] = "N/A" # end # # price range like 100-100 is not good # if minprice == maxprice @@ -735,7 +734,7 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2< unformatPrompt = [ - Dict(:name=> "system", :text=> systemmsg), + Dict("name"=> "system", "text"=> systemmsg), ] # put in model format @@ -883,8 +882,8 @@ function paraphrase(text2textInstructLLM::Function, text::String) _prompt = [ - Dict(:name => "system", :text => systemmsg), - Dict(:name => "user", :text => usermsg) + Dict("name" => "system", "text" => systemmsg), + Dict("name" => "user", "text" => usermsg) ] # put in model format @@ -935,7 +934,7 @@ function paraphrase(text2textInstructLLM::Function, text::String) println("\nparaphrase() ", @__FILE__, ":", @__LINE__, " $(Dates.now())") pprintln(Dict(responsedict)) - result = responsedict[:paraphrase] + result = responsedict["paraphrase"] return result catch e @@ -1004,10 +1003,10 @@ function jsoncorrection(config::T1, input::T2, correctJsonExample::T3; """ # apply LLM specific instruct format - externalService = config[:externalservice][:text2textinstruct] - llminfo = externalService[:llminfo] +externalService = config["externalservice"]["text2textinstruct"] + llminfo = externalService["llminfo"] prompt = - if llminfo[:name] == "llama3instruct" + if llminfo["name"] == "llama3instruct" formatLLMtext_llama3instruct("system", _prompt) else 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 msgMeta = GeneralUtils.generate_msgMeta( - externalService[:mqtttopic], + externalService["mqtttopic"], senderName= "jsoncorrection", senderId= string(uuid4()), receiverName= "text2textinstruct", - mqttBroker= config[:mqttServerInfo][:broker], - mqttBrokerPort= config[:mqttServerInfo][:port], + mqttBroker= config["mqttServerInfo"]["broker"], + mqttBrokerPort= config["mqttServerInfo"]["port"], ) outgoingMsg = Dict( - :msgMeta=> msgMeta, - :payload=> Dict( - :text=> prompt, - :kwargs=> Dict( - :max_tokens=> 512, - :stop=> ["<|eot_id|>"], + "msgMeta"=> msgMeta, + "payload"=> Dict( + "text"=> prompt, + "kwargs"=> Dict( + "max_tokens"=> 512, + "stop"=> ["<|eot_id|>"], ) ) ) diff --git a/src/type.jl b/src/type.jl index 001eb43..54e9253 100644 --- a/src/type.jl +++ b/src/type.jl @@ -38,7 +38,7 @@ function companion( name::String= "Assistant", id::String= GeneralUtils.uuid4snakecase(), maxHistoryMsg::Integer= 20, - chathistory::Vector{Dict{Symbol, String}} = Vector{Dict{Symbol, String}}(), + chathistory::Vector{Dict{String, String}} = Vector{Dict{String, String}}(), llmFormatName::String= "granite3", systemmsg::String= """ @@ -55,7 +55,7 @@ function companion( tools = Dict( # update input format "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 NO "system" message in chathistory because I want to add it at the inference time chathistory= [ - Dict(:name=>"user", :text=> "Wassup!", :timestamp=> Dates.now()), - Dict(:name=>"assistant", :text=> "Hi I'm your assistant.", :timestamp=> Dates.now()), + Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()), + Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()), ] """ memory = Dict{String, Any}( - :events=> Vector{Dict{String, Any}}(), - :state=> Dict{String, Any}(), # state of the agent - :recap=> OrderedDict{String, Any}(), # recap summary of the conversation + "events"=> Vector{Dict{String, Any}}(), + "state"=> Dict{String, Any}(), # state of the agent + "recap"=> OrderedDict{String, Any}(), # recap summary of the conversation ) newAgent = companion( @@ -116,7 +116,7 @@ end Retailer name associated with the sommelier. Default: `"retailer_name"` - `maxHistoryMsg::Integer` Maximum history messages. Default: `20` - - `chathistory::Vector{Dict{Symbol, String}}` + - `chathistory::Vector{Dict{String, String}}` Chat history. Default: empty vector. - `llmFormatName::String` LLM format name. Default: `"granite3"` @@ -146,20 +146,20 @@ function sommelier( id::String= string(uuid4()), retailername::String= "retailer_name", maxHistoryMsg::Integer= 20, - chathistory::Vector{Dict{Symbol, String}} = Vector{Dict{Symbol, String}}(), + chathistory::Vector{Dict{String, String}} = Vector{Dict{String, String}}(), llmFormatName::String= "granite3" ) tools = Dict( # update input format "chatbox"=> Dict( - :description => "Useful for when you need to ask the user for more context. Do not ask the user their own question.", - :input => """Input is a text in JSON format.{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}""", - :output => "" , + "description" => "Useful for when you need to ask the user for more context. Do not ask the user their own question.", + "input" => """Input is a text in JSON format.{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}""", + "output" => "" , ), "winestock"=> Dict( - :description => "A handy tool for searching wine in your inventory that match the user preferences.", - :input => """Input is a JSON-formatted string that contains a detailed and precise search query.{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}""", - :output => """Output are wines that match the search query in JSON format.""", + "description" => "A handy tool for searching wine in your inventory that match the user preferences.", + "input" => """Input is a JSON-formatted string that contains a detailed and precise search query.{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}""", + "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 NO "system" message in chathistory because I want to add it at the inference time chathistory= [ - Dict(:name=>"user", :text=> "Wassup!", :timestamp=> Dates.now()), - Dict(:name=>"assistant", :text=> "Hi I'm your assistant.", :timestamp=> Dates.now()), + Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()), + Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()), ] """ memory = Dict{String, Any}( - :shortmem=> OrderedDict{String, Any}( - :db_search_result=> Any[], - :scratchpad=> "", #[PENDING] should be a dict e.g. Dict(:database_search_result=>Dict(:wines=> "", :search_query=> "")) + "shortmem"=> OrderedDict{String, Any}( + "db_search_result"=> Any[], + "scratchpad"=> "", #PENDING should be a dict e.g. Dict("database_search_result"=>Dict("wines"=> "", "search_query"=> "")) ), - :events=> Vector{Dict{String, Any}}(), - :state=> Dict{String, Any}( + "events"=> Vector{Dict{String, Any}}(), + "state"=> Dict{String, Any}( ), - :recap=> OrderedDict{String, Any}(), + "recap"=> OrderedDict{String, Any}(), ) @@ -297,7 +297,7 @@ function virtualcustomer( name::String= "Assistant", id::String= string(uuid4()), maxHistoryMsg::Integer= 20, - chathistory::Vector{Dict{Symbol, String}} = Vector{Dict{Symbol, String}}(), + chathistory::Vector{Dict{String, String}} = Vector{Dict{String, String}}(), llmFormatName::String= "granite3", systemmsg::String= """ @@ -314,9 +314,9 @@ function virtualcustomer( tools = Dict( # update input format "chatbox"=> Dict( - :description => "Useful for when you need to ask the user for more context. Do not ask the user their own question.", - :input => """Input is a text in JSON format.{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}""", - :output => "" , + "description" => "Useful for when you need to ask the user for more context. Do not ask the user their own question.", + "input" => """Input is a text in JSON format.{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}""", + "output" => "" , ), ) @@ -324,17 +324,17 @@ function virtualcustomer( 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 chathistory= [ - Dict(:name=>"user", :text=> "Wassup!", :timestamp=> Dates.now()), - Dict(:name=>"assistant", :text=> "Hi I'm your assistant.", :timestamp=> Dates.now()), + Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()), + Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()), ] """ memory = Dict{String, Any}( - :shortmem=> OrderedDict{String, Any}( + "shortmem"=> OrderedDict{String, Any}( ), - :events=> Vector{Dict{String, Any}}(), - :state=> Dict{String, Any}( + "events"=> Vector{Dict{String, Any}}(), + "state"=> Dict{String, Any}( ), - :recap=> OrderedDict{String, Any}(), + "recap"=> OrderedDict{String, Any}(), ) newAgent = virtualcustomer( diff --git a/src/util.jl b/src/util.jl index 689809f..353f637 100644 --- a/src/util.jl +++ b/src/util.jl @@ -26,16 +26,16 @@ julia> client, connection = MakeConnection("test.mosquitto.org", 1883) julia> connect(client, connection) julia> msgMeta = GeneralUtils.generate_msgMeta("testtopic") julia> agentConfig = Dict( - :receiveprompt=>Dict( - :mqtttopic=> "testtopic/receive", - ), - :receiveinternal=>Dict( - :mqtttopic=> "testtopic/internal", - ), - :text2text=>Dict( - :mqtttopic=> "testtopic/text2text", - ), - ) + "receiveprompt"=>Dict( + "mqtttopic"=> "testtopic/receive", + ), + "receiveinternal"=>Dict( + "mqtttopic"=> "testtopic/internal", + ), + "text2text"=>Dict( + "mqtttopic"=> "testtopic/text2text", + ), + ) julia> a = YiemAgent.sommelier( client, msgMeta, @@ -52,9 +52,9 @@ julia> YiemAgent.clearhistory(a) """ function clearhistory(a::T) where {T<:agent} empty!(a.chathistory) - empty!(a.memory[:shortmem]) - empty!(a.memory[:events]) - a.memory[:chatbox] = "" + empty!(a.memory["shortmem"]) + empty!(a.memory["events"]) + a.memory["chatbox"] = "" end @@ -129,7 +129,7 @@ This function takes in a vector of dictionaries and outputs a single string wher julia> using Revise 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) "John> Hello\nJane> Goodbye\n" ``` @@ -233,17 +233,17 @@ function eventdict(; ) d = Dict{String, Any}( - :event_description=> event_description, - :timestamp=> timestamp, - :subject=> subject, - :thought=> thought, - :actionname=> actionname, - :actioninput=> actioninput, - :location=> location, - :equipment_used=> equipment_used, - :material_used=> material_used, - :observation=> observation, - :note=> note, + "event_description"=> event_description, + "timestamp"=> timestamp, + "subject"=> subject, + "thought"=> thought, + "actionname"=> actionname, + "actioninput"=> actioninput, + "location"=> location, + "equipment_used"=> equipment_used, + "material_used"=> material_used, + "observation"=> observation, + "note"=> note, ) return d @@ -268,8 +268,8 @@ end # Example events = [ - Dict(:subject => "User", :actioninput => "Hello", :observation => nothing), - Dict(:subject => "Assistant", :actioninput => "Hi there!", :observation => "with a smile") + Dict("subject" => "User", "actioninput" => "Hello", "observation" => nothing), + Dict("subject" => "Assistant", "actioninput" => "Hi there!", "observation" => "with a smile") ] timeline = createTimeline(events) # 1) User> Hello @@ -293,16 +293,15 @@ function createTimeline(events::T1; eventindex::Union{UnitRange, Nothing}=nothin for i in ind event = events[i] # If no outcome exists, format without outcome - # if event[:actionname] == "CHATBOX" - # timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput])\n" - # elseif event[:actionname] == "CHECKINVENTORY" && event[:observation] === nothing - # 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" - timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput]), observation: $(event[:observation])\n" +# if event["actionname"] == "CHATBOX" + # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"])\n" + # elseif event["actionname"] == "CHECKINVENTORY" && event["observation"] === nothing + # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: Not done yet.\n" + if event["actionname"] == "CHECKWINE" + timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: $(event["observation"])\\n" else - timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput])\n" - end + timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"])\\n" + end end # Return formatted timeline string @@ -325,11 +324,11 @@ end # for i in ind # event = events[i] # # If no outcome exists, format without outcome -# if event[:observation] === nothing -# timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput]), observation: Not done yet.\n" -# # If outcome exists, include it in formatting -# else -# timeline *= "Event_$i $(event[:subject])> actionname: $(event[:actionname]), actioninput: $(event[:actioninput]), observation: $(event[:observation])\n" +# if event["observation"] === nothing + # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: Not done yet.\n" + # # If outcome exists, include it in formatting + # else + # timeline *= "Event_$i $(event["subject"])> actionname: $(event["actionname"]), actioninput: $(event["actioninput"]), observation: $(event["observation"])\\n" # end # end @@ -341,7 +340,7 @@ end function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing ) where {T1<:AbstractVector} # Initialize empty log array - log = Dict{Symbol, String}[] + log = Dict{String, String}[] # Determine which indices to use - either provided range or full length ind = @@ -355,20 +354,20 @@ function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing for i in ind event = events[i] # If no outcome exists, format without outcome - if event[:observation] === nothing - subject = event[:subject] - actionname = event[:actionname] - actioninput = event[:actioninput] + if event["observation"] === nothing + subject = event["subject"] + actionname = event["actionname"] + actioninput = event["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) else - subject = event[:subject] - actionname = event[:actionname] - actioninput = event[:actioninput] - observation = event[:observation] + subject = event["subject"] + actionname = event["actionname"] + actioninput = event["actioninput"] + observation = event["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) end end @@ -380,7 +379,7 @@ end function createChatLog(chatdict::T1; index::Union{UnitRange, Nothing}=nothing ) where {T1<:AbstractVector} # Initialize empty log array - log = Dict{Symbol, String}[] + log = Dict{String, String}[] # Determine which indices to use - either provided range or full length ind = @@ -393,9 +392,9 @@ function createChatLog(chatdict::T1; index::Union{UnitRange, Nothing}=nothing # Iterate through events and format each one for i in ind event = chatdict[i] - subject = event[:name] - text = event[:text] - d = Dict{Symbol, String}(:name=>subject, :text=>text) + subject = event["name"] + text = event["text"] + d = Dict{String, String}("name"=>subject, "text"=>text) push!(log, d) end