This commit is contained in:
narawat lamaiin
2025-01-11 16:57:57 +07:00
parent 944d9eaf2b
commit a29e8049a7
3 changed files with 41 additions and 34 deletions

View File

@@ -218,7 +218,7 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen
winenames = df[:, :wine_name] winenames = df[:, :wine_name]
for winename in winenames for winename in winenames
if !occursin(winename, chathistory) 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( d = Dict(
:understanding=> "I understand that the customer is looking for a wine that matches their intention and budget.", :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.", :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 end
if count > 1 if count > 1
errornote = "You must use only one function" errornote = "You must use only one function"
println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
continue continue
end 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"] if responsedict[:action_name] ["CHATBOX", "CHECKINVENTORY", "ENDCONVERSATION"]
errornote = "You must use the given functions" errornote = "You must use the given functions"
println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
continue continue
end end
checkFlag = false checkFlag = false
for i [:understanding, :plan, :action_name] for i [:understanding, :plan, :action_name]
if length(responsedict[i]) == 0 if length(responsedict[i]) == 0
error("$i is empty ", @__FILE__, " ", @__LINE__) error("$i is empty ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
errornote = "$i is empty" errornote = "$i is empty"
println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
checkFlag = true checkFlag = true
break break
end end
@@ -303,14 +303,14 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen
matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i) matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i)
if length(matchkeys) > 1 if length(matchkeys) > 1
errornote = "DecisionMaker has more than one key per categories" 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 checkFlag = true
break break
end end
end end
checkFlag == true ? continue : nothing checkFlag == true ? continue : nothing
println("\n~~~ Yiem decisionMaker() ", @__FILE__, " ", @__LINE__) println("\n~~~ Yiem decisionMaker() ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
pprintln(Dict(responsedict)) pprintln(Dict(responsedict))
# check whether an agent recommend wines before checking inventory or recommend wines # 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 isWineInEvent == false
errornote = "Note: Before recommending a wine, ensure it's in your inventory. Check your stock first." 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 continue
end end
end end
@@ -503,7 +503,7 @@ function evaluator(config::T1, state::T2
showerror(io, e) showerror(io, e)
errorMsg = String(take!(io)) errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) 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
end end
error("evaluator failed to generate an evaluation") 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) showerror(io, e)
errorMsg = String(take!(io)) errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) 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
end end
error("reflector failed to generate a thought") error("reflector failed to generate a thought")
@@ -733,7 +733,7 @@ function conversation(a::sommelier, userinput::Dict)
end end
end end
function conversation(a::companion, userinput::Dict) function conversation(a::companion, userinput::Dict; maximumMsg=30)
chatresponse = nothing chatresponse = nothing
if userinput[:text] == "newtopic" if userinput[:text] == "newtopic"
@@ -754,7 +754,7 @@ function conversation(a::companion, userinput::Dict)
) )
chatresponse = generatechat(a) chatresponse = generatechat(a)
addNewMessage(a, "assistant", chatresponse) addNewMessage(a, "assistant", chatresponse; maximumMsg=30)
push!(a.memory[:events], push!(a.memory[:events],
eventdict(; eventdict(;
@@ -871,7 +871,7 @@ function think(a::T)::NamedTuple{(:actionname, :result),Tuple{String,String}} wh
) )
) )
else else
error("condition is not defined ", @__FILE__, " ", @__LINE__) error("condition is not defined ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
end end
@@ -928,6 +928,7 @@ function generatechat(a::sommelier, thoughtDict)
- If the user interrupts, prioritize the user - If the user interrupts, prioritize the user
- Medium and full-bodied red wines should not be paired with spicy foods. - Medium and full-bodied red wines should not be paired with spicy foods.
You should then respond to the user with: 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? 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: ..." # sometime the model response like this "here's how I would respond: ..."
if occursin("respond:", response) if occursin("respond:", response)
errornote = "You don't need to intro your 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 end
response = GeneralUtils.remove_french_accents(response) response = GeneralUtils.remove_french_accents(response)
response = replace(response, '*'=>"") response = replace(response, '*'=>"")
@@ -989,7 +990,7 @@ function generatechat(a::sommelier, thoughtDict)
for i [:chat] for i [:chat]
if length(JSON3.write(responsedict[i])) == 0 if length(JSON3.write(responsedict[i])) == 0
error("$i is empty ", @__FILE__, " ", @__LINE__) error("$i is empty ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
end end
end end
@@ -1006,7 +1007,7 @@ function generatechat(a::sommelier, thoughtDict)
error("Context: is in text. This is not allowed") error("Context: is in text. This is not allowed")
end end
println("\n~~~ generatechat() ", @__FILE__, " ", @__LINE__) println("\n~~~ generatechat() ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
pprintln(Dict(responsedict)) pprintln(Dict(responsedict))
# check whether an agent recommend wines before checking inventory or recommend wines # check whether an agent recommend wines before checking inventory or recommend wines
@@ -1044,7 +1045,7 @@ function generatechat(a::sommelier, thoughtDict)
showerror(io, e) showerror(io, e)
errorMsg = String(take!(io)) errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) 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
end end
error("generatechat failed to generate a response") 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 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 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 - 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: You should then respond to the user with:
1) Understanding: 1) Understanding:
@@ -1251,17 +1258,17 @@ function generatequestion(a, text2textInstructLLM::Function; recent=nothing)::St
# check for valid response # check for valid response
q_atleast = length(a.memory[:events]) <= 2 ? 1 : 3 q_atleast = length(a.memory[:events]) <= 2 ? 1 : 3
if q_number < q_atleast 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. # check whether "A1" is in the response, if not error.
elseif !occursin("A1:", response) 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 end
responsedict = GeneralUtils.textToDict(response, responsedict = GeneralUtils.textToDict(response,
["Understanding", "Q1"], ["Understanding", "Q1"],
rightmarker=":", symbolkey=true, lowercasekey=true) rightmarker=":", symbolkey=true, lowercasekey=true)
response = "Q1: " * responsedict[:q1] response = "Q1: " * responsedict[:q1]
println("\n~~~ generatequestion ", @__FILE__, " ", @__LINE__) println("\n~~~ generatequestion ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
pprintln(response) pprintln(response)
return response return response
catch e catch e
@@ -1269,7 +1276,7 @@ function generatequestion(a, text2textInstructLLM::Function; recent=nothing)::St
showerror(io, e) showerror(io, e)
errorMsg = String(take!(io)) errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) 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
end end
error("generatequestion failed to generate a response ", response) error("generatequestion failed to generate a response ", response)
@@ -1345,7 +1352,7 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent::
# responsedict = GeneralUtils.textToDict(response, # responsedict = GeneralUtils.textToDict(response,
# ["summary", "presented", "selected"], # ["summary", "presented", "selected"],
# rightmarker=":", symbolkey=true) # rightmarker=":", symbolkey=true)
println("\n~~~ generateSituationReport() ", @__FILE__, " ", @__LINE__) println("\n~~~ generateSituationReport() ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
pprintln(response) pprintln(response)
return Dict(:recap => response) return Dict(:recap => response)
@@ -1401,7 +1408,7 @@ function detectWineryName(a, text)
try try
response = a.func[:text2textInstructLLM](prompt) response = a.func[:text2textInstructLLM](prompt)
println("\n~~~ detectWineryName() ", @__FILE__, " ", @__LINE__) println("\n~~~ detectWineryName() ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
pprintln(response) pprintln(response)
responsedict = GeneralUtils.textToDict(response, ["winery_names"], responsedict = GeneralUtils.textToDict(response, ["winery_names"],
@@ -1415,7 +1422,7 @@ function detectWineryName(a, text)
showerror(io, e) showerror(io, e)
errorMsg = String(take!(io)) errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) 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
end end
error("detectWineryName failed to generate a response") error("detectWineryName failed to generate a response")

View File

@@ -291,20 +291,20 @@ julia> result = checkinventory(agent, input)
function checkinventory(a::T1, input::T2 function checkinventory(a::T1, input::T2
) where {T1<:agent, T2<:AbstractString} ) 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_1 = extractWineAttributes_1(a, input)
wineattributes_2 = extractWineAttributes_2(a, input) wineattributes_2 = extractWineAttributes_2(a, input)
_inventoryquery = "retailer name: $(a.retailername), $wineattributes_1, $wineattributes_2" _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}" 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 # add suppport for similarSQLVectorDB
textresult, rawresponse = SQLLLM.query(inventoryquery, a.func[:executeSQL], textresult, rawresponse = SQLLLM.query(inventoryquery, a.func[:executeSQL],
a.func[:text2textInstructLLM], a.func[:text2textInstructLLM],
insertSQLVectorDB=a.func[:insertSQLVectorDB], insertSQLVectorDB=a.func[:insertSQLVectorDB],
similarSQLVectorDB=a.func[:similarSQLVectorDB]) similarSQLVectorDB=a.func[:similarSQLVectorDB])
println("\n~~~ checkinventory result ", @__FILE__, " ", @__LINE__) println("\n~~~ checkinventory result ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
println(textresult) println(textresult)
return (result=textresult, rawresponse=rawresponse, success=true, errormsg=nothing) 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 for word in attributes
if !occursin(word, response) if !occursin(word, response)
errornote = "$word attribute is missing in previous attempts" errornote = "$word attribute is missing in previous attempts"
println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
checkFlag = true checkFlag = true
break break
end 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 # check whether wine_price is in ranged number
if !occursin('-', responsedict[:wine_price]) if !occursin('-', responsedict[:wine_price])
errornote = "wine_price must be a range number" errornote = "wine_price must be a range number"
println("Attempt $attempt $errornote ", @__FILE__, " ", @__LINE__) println("Attempt $attempt $errornote ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
checkFlag = true checkFlag = true
break break
end 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" for x in content #BUG why x is "0-1500"
if !occursin("NA", responsedict[j]) && !occursin(x, input) 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." 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 checkFlag == true
break break
end end
@@ -624,7 +624,7 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2<
value = responsedict[keyword] value = responsedict[keyword]
if value != "NA" && !occursin(value, input) 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" 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 continue
end end
@@ -640,7 +640,7 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2<
if !occursin("keyword", string(k)) if !occursin("keyword", string(k))
if v !== "NA" && (!occursin('-', v) || length(v) > 5) 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." 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 continue
end end
end end
@@ -859,7 +859,7 @@ end
# state[:isterminal] = true # state[:isterminal] = true
# state[:reward] = 1 # state[:reward] = 1
# end # end
# println("--> 5 Evaluator ", @__FILE__, " ", @__LINE__) # println("--> 5 Evaluator ", Dates.now(), " ", @__FILE__, " ", @__LINE__)
# pprintln(Dict(responsedict)) # pprintln(Dict(responsedict))
# return responsedict[:score] # return responsedict[:score]
# catch e # catch e

View File

@@ -106,7 +106,7 @@ function addNewMessage(a::T1, name::String, text::T2;
error("name is not in agent.availableRole $(@__LINE__)") error("name is not in agent.availableRole $(@__LINE__)")
end end
#[] summarize the oldest 10 message #[WORKING] summarize the oldest 10 message
if length(a.chathistory) > maximumMsg if length(a.chathistory) > maximumMsg
summarize(a.chathistory) summarize(a.chathistory)
else else