From a29e8049a70abc837305e43b871609d1dca9cd19 Mon Sep 17 00:00:00 2001 From: narawat lamaiin Date: Sat, 11 Jan 2025 16:57:57 +0700 Subject: [PATCH] update --- src/interface.jl | 55 ++++++++++++++++++++++++++-------------------- src/llmfunction.jl | 18 +++++++-------- src/util.jl | 2 +- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 06657c2..f09c56c 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -218,7 +218,7 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen winenames = df[:, :wine_name] for winename in winenames if !occursin(winename, chathistory) - println("\n~~~ Yiem decisionMaker() found wines from DB ", @__FILE__, " ", @__LINE__) + println("\n~~~ Yiem decisionMaker() found wines from DB ", Dates.now(), " ", @__FILE__, " ", @__LINE__) d = Dict( :understanding=> "I understand that the customer is looking for a wine that matches their intention and budget.", :reasoning=> "I checked the inventory and found wines that match the customer's criteria. I will present the wines to the customer.", @@ -271,7 +271,7 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen end if count > 1 errornote = "You must use only one function" - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) continue end @@ -281,16 +281,16 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen if responsedict[:action_name] ∉ ["CHATBOX", "CHECKINVENTORY", "ENDCONVERSATION"] errornote = "You must use the given functions" - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) continue end checkFlag = false for i ∈ [:understanding, :plan, :action_name] if length(responsedict[i]) == 0 - error("$i is empty ", @__FILE__, " ", @__LINE__) + error("$i is empty ", Dates.now(), " ", @__FILE__, " ", @__LINE__) errornote = "$i is empty" - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) checkFlag = true break end @@ -303,14 +303,14 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i) if length(matchkeys) > 1 errornote = "DecisionMaker has more than one key per categories" - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) checkFlag = true break end end checkFlag == true ? continue : nothing - println("\n~~~ Yiem decisionMaker() ", @__FILE__, " ", @__LINE__) + println("\n~~~ Yiem decisionMaker() ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(Dict(responsedict)) # check whether an agent recommend wines before checking inventory or recommend wines @@ -337,7 +337,7 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen isWineInEvent == false errornote = "Note: Before recommending a wine, ensure it's in your inventory. Check your stock first." - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) continue end end @@ -503,7 +503,7 @@ function evaluator(config::T1, state::T2 showerror(io, e) errorMsg = String(take!(io)) st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) - println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) + println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end end error("evaluator failed to generate an evaluation") @@ -633,7 +633,7 @@ function reflector(config::T1, state::T2)::String where {T1<:AbstractDict,T2<:Ab showerror(io, e) errorMsg = String(take!(io)) st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) - println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) + println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end end error("reflector failed to generate a thought") @@ -733,7 +733,7 @@ function conversation(a::sommelier, userinput::Dict) end end -function conversation(a::companion, userinput::Dict) +function conversation(a::companion, userinput::Dict; maximumMsg=30) chatresponse = nothing if userinput[:text] == "newtopic" @@ -754,7 +754,7 @@ function conversation(a::companion, userinput::Dict) ) chatresponse = generatechat(a) - addNewMessage(a, "assistant", chatresponse) + addNewMessage(a, "assistant", chatresponse; maximumMsg=30) push!(a.memory[:events], eventdict(; @@ -871,7 +871,7 @@ function think(a::T)::NamedTuple{(:actionname, :result),Tuple{String,String}} wh ) ) else - error("condition is not defined ", @__FILE__, " ", @__LINE__) + error("condition is not defined ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end @@ -928,6 +928,7 @@ function generatechat(a::sommelier, thoughtDict) - If the user interrupts, prioritize the user - Medium and full-bodied red wines should not be paired with spicy foods. + You should then respond to the user with: 1) Chat: Given the situation, How would you respond to the user to express your thoughts honestly and keep the conversation going smoothly? @@ -977,7 +978,7 @@ function generatechat(a::sommelier, thoughtDict) # sometime the model response like this "here's how I would respond: ..." if occursin("respond:", response) errornote = "You don't need to intro your response" - error("generatechat() response contain : ", @__FILE__, " ", @__LINE__) + error("generatechat() response contain : ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end response = GeneralUtils.remove_french_accents(response) response = replace(response, '*'=>"") @@ -989,7 +990,7 @@ function generatechat(a::sommelier, thoughtDict) for i ∈ [:chat] if length(JSON3.write(responsedict[i])) == 0 - error("$i is empty ", @__FILE__, " ", @__LINE__) + error("$i is empty ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end end @@ -1006,7 +1007,7 @@ function generatechat(a::sommelier, thoughtDict) error("Context: is in text. This is not allowed") end - println("\n~~~ generatechat() ", @__FILE__, " ", @__LINE__) + println("\n~~~ generatechat() ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(Dict(responsedict)) # check whether an agent recommend wines before checking inventory or recommend wines @@ -1044,7 +1045,7 @@ function generatechat(a::sommelier, thoughtDict) showerror(io, e) errorMsg = String(take!(io)) st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) - println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) + println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end end error("generatechat failed to generate a response") @@ -1137,6 +1138,12 @@ function generatequestion(a, text2textInstructLLM::Function; recent=nothing)::St - If you don't already know, find out the characteristics of wine the user is looking for, such as tannin, sweetness, intensity, acidity - If you don't already know, find out what food will be served with wine - If you haven't already, introduce the wines you found in the database to the user first + - Generally speaking, your inventory has some wines from France, the United States, Australia, Spain, and Italy, but you won't know exactly until you check your inventory. + - All wines in your inventory are always in stock. + - Engage in conversation to indirectly investigate the customer's intention, budget and preferences before checking your inventory. + - Do not ask the user about wine's flavor e.g. floral, citrusy, nutty or some thing similar as these terms cannot be used to search the database. + - Once the user has selected their wine, ask the user if they need any further assistance. Do not offer any additional services. If the user doesn't need any further assistance, say goodbye and invite them to come back next time. + - Medium and full-bodied red wines should not be paired with spicy foods. You should then respond to the user with: 1) Understanding: @@ -1251,17 +1258,17 @@ function generatequestion(a, text2textInstructLLM::Function; recent=nothing)::St # check for valid response q_atleast = length(a.memory[:events]) <= 2 ? 1 : 3 if q_number < q_atleast - error("too few questions only $q_number questions are generated ", @__FILE__, " ", @__LINE__) + error("too few questions only $q_number questions are generated ", Dates.now(), " ", @__FILE__, " ", @__LINE__) # check whether "A1" is in the response, if not error. elseif !occursin("A1:", response) - error("no answer found in the response ", @__FILE__, " ", @__LINE__) + error("no answer found in the response ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end responsedict = GeneralUtils.textToDict(response, ["Understanding", "Q1"], rightmarker=":", symbolkey=true, lowercasekey=true) response = "Q1: " * responsedict[:q1] - println("\n~~~ generatequestion ", @__FILE__, " ", @__LINE__) + println("\n~~~ generatequestion ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(response) return response catch e @@ -1269,7 +1276,7 @@ function generatequestion(a, text2textInstructLLM::Function; recent=nothing)::St showerror(io, e) errorMsg = String(take!(io)) st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) - println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) + println("\nAttempt $attempt. Error occurred: $errorMsg\n$st ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end end error("generatequestion failed to generate a response ", response) @@ -1345,7 +1352,7 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent:: # responsedict = GeneralUtils.textToDict(response, # ["summary", "presented", "selected"], # rightmarker=":", symbolkey=true) - println("\n~~~ generateSituationReport() ", @__FILE__, " ", @__LINE__) + println("\n~~~ generateSituationReport() ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(response) return Dict(:recap => response) @@ -1401,7 +1408,7 @@ function detectWineryName(a, text) try response = a.func[:text2textInstructLLM](prompt) - println("\n~~~ detectWineryName() ", @__FILE__, " ", @__LINE__) + println("\n~~~ detectWineryName() ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(response) responsedict = GeneralUtils.textToDict(response, ["winery_names"], @@ -1415,7 +1422,7 @@ function detectWineryName(a, text) showerror(io, e) errorMsg = String(take!(io)) st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) - println("\n Attempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) + println("\n Attempt $attempt. Error occurred: $errorMsg\n$st ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end end error("detectWineryName failed to generate a response") diff --git a/src/llmfunction.jl b/src/llmfunction.jl index fdea59f..70573a1 100644 --- a/src/llmfunction.jl +++ b/src/llmfunction.jl @@ -291,20 +291,20 @@ julia> result = checkinventory(agent, input) function checkinventory(a::T1, input::T2 ) where {T1<:agent, T2<:AbstractString} - println("\n~~~ checkinventory order: $input ", @__FILE__, " ", @__LINE__) + println("\n~~~ checkinventory order: $input ", Dates.now(), " ", @__FILE__, " ", @__LINE__) wineattributes_1 = extractWineAttributes_1(a, input) wineattributes_2 = extractWineAttributes_2(a, input) _inventoryquery = "retailer name: $(a.retailername), $wineattributes_1, $wineattributes_2" inventoryquery = "Retrieves winery, wine_name, vintage, region, country, wine_type, grape, serving_temperature, sweetness, intensity, tannin, acidity, tasting_notes, price and currency of wines that match the following criteria - {$_inventoryquery}" - println("~~~ checkinventory input: $inventoryquery ", @__FILE__, " ", @__LINE__) + println("~~~ checkinventory input: $inventoryquery ", Dates.now(), " ", @__FILE__, " ", @__LINE__) # add suppport for similarSQLVectorDB textresult, rawresponse = SQLLLM.query(inventoryquery, a.func[:executeSQL], a.func[:text2textInstructLLM], insertSQLVectorDB=a.func[:insertSQLVectorDB], similarSQLVectorDB=a.func[:similarSQLVectorDB]) - println("\n~~~ checkinventory result ", @__FILE__, " ", @__LINE__) + println("\n~~~ checkinventory result ", Dates.now(), " ", @__FILE__, " ", @__LINE__) println(textresult) return (result=textresult, rawresponse=rawresponse, success=true, errormsg=nothing) @@ -403,7 +403,7 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2< for word in attributes if !occursin(word, response) errornote = "$word attribute is missing in previous attempts" - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) checkFlag = true break end @@ -431,7 +431,7 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2< # check whether wine_price is in ranged number if !occursin('-', responsedict[:wine_price]) errornote = "wine_price must be a range number" - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) checkFlag = true break end @@ -454,7 +454,7 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2< for x in content #BUG why x is "0-1500" if !occursin("NA", responsedict[j]) && !occursin(x, input) errornote = "$x is not mentioned in the user query, you must only use the info from the query." - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) checkFlag == true break end @@ -624,7 +624,7 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2< value = responsedict[keyword] if value != "NA" && !occursin(value, input) errornote = "WARNING. Keyword $keyword: $value does not appear in the input. You must use information from the input only" - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) continue end @@ -640,7 +640,7 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2< if !occursin("keyword", string(k)) if v !== "NA" && (!occursin('-', v) || length(v) > 5) errornote = "WARNING: The non-range value {$k: $v} is not allowed. It should be specified in a range format, i.e. min-max." - println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) + println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__) continue end end @@ -859,7 +859,7 @@ end # state[:isterminal] = true # state[:reward] = 1 # end -# println("--> 5 Evaluator ", @__FILE__, " ", @__LINE__) +# println("--> 5 Evaluator ", Dates.now(), " ", @__FILE__, " ", @__LINE__) # pprintln(Dict(responsedict)) # return responsedict[:score] # catch e diff --git a/src/util.jl b/src/util.jl index 2d13228..1871423 100644 --- a/src/util.jl +++ b/src/util.jl @@ -106,7 +106,7 @@ function addNewMessage(a::T1, name::String, text::T2; error("name is not in agent.availableRole $(@__LINE__)") end - #[] summarize the oldest 10 message + #[WORKING] summarize the oldest 10 message if length(a.chathistory) > maximumMsg summarize(a.chathistory) else