update
This commit is contained in:
@@ -200,9 +200,8 @@ function decisionMaker(a::T; recent::Integer=10)::Dict{Symbol,Any} where {T<:age
|
||||
2) Plan: Based on the current situation, state a complete action plan to complete the task. Be specific.
|
||||
3) Action_name: (Typically corresponds to the execution of the first step in your plan) Can be one of the following function names:
|
||||
- CHATBOX which you can use to talk with the user. The input is your intentions for the dialogue. Be specific.
|
||||
- CHECKINVENTORY which you can use to check info about wine you want in your inventory. The input is a search term in verbal English.
|
||||
Bad query example 1: red wine that pair well with spicy food.
|
||||
Bad query example 2: white wine that goes well with party food.
|
||||
- CHECKINVENTORY which you can use to check info about wine you want in your inventory. The input is a search term is verbal english and it should includes - winery, wine name, vintage, region, country, wine type, grape varietal, tasting notes, wine price, occasion, food to be paired with wine, intensity, tannin, sweetness, acidity.
|
||||
Bad query example: red wine that pair well with spicy food.
|
||||
|
||||
- ENDCONVERSATION which you can use when the user has finished their conversation with you, so that you can properly end the conversation. Input is "NA".
|
||||
4) Action_input: input of the action
|
||||
@@ -264,6 +263,10 @@ function decisionMaker(a::T; recent::Integer=10)::Dict{Symbol,Any} where {T<:age
|
||||
response = nothing # placeholder for show when error msg show up
|
||||
|
||||
for attempt in 1:10
|
||||
if attempt > 1
|
||||
println("\nYiemAgent decisionMaker() attempt $attempt/10 ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
end
|
||||
|
||||
QandA = generatequestion(a, a.func[:text2textInstructLLM]; recent=3)
|
||||
|
||||
usermsg =
|
||||
@@ -298,17 +301,22 @@ function decisionMaker(a::T; recent::Integer=10)::Dict{Symbol,Any} where {T<:age
|
||||
end
|
||||
if count > 1
|
||||
errornote = "You must use only one function"
|
||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("\nYiemAgent decisionMaker() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
end
|
||||
|
||||
# check whether response has all header
|
||||
detected_kw = GeneralUtils.detect_keyword(header, response)
|
||||
kwvalue = [i for i in values(detected_kw)]
|
||||
zeroind = findall(x -> x == 0, kwvalue)
|
||||
missingkeys = [header[i] for i in zeroind]
|
||||
if 0 ∈ values(detected_kw)
|
||||
errornote = "\nYiemAgent decisionMaker() response does not have all header"
|
||||
errornote = "$missingkeys are missing from your previous response"
|
||||
println("\nYiemAgent decisionMaker() $errornote:\n $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
elseif sum(values(detected_kw)) > length(header)
|
||||
errornote = "\nYiemAgent decisionMaker() response has duplicated header"
|
||||
errornote = "Your response has duplicated points"
|
||||
println("\nYiemAgent decisionMaker() $errornote: $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
end
|
||||
|
||||
@@ -317,7 +325,7 @@ function decisionMaker(a::T; recent::Integer=10)::Dict{Symbol,Any} where {T<:age
|
||||
|
||||
if responsedict[:action_name] ∉ ["CHATBOX", "CHECKINVENTORY", "ENDCONVERSATION"]
|
||||
errornote = "You must use the given functions"
|
||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("\nYiemAgent decisionMaker() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
end
|
||||
|
||||
@@ -325,7 +333,7 @@ function decisionMaker(a::T; recent::Integer=10)::Dict{Symbol,Any} where {T<:age
|
||||
for i ∈ Symbol.(dictkey)
|
||||
if length(responsedict[i]) == 0
|
||||
errornote = "$i is empty"
|
||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("\nYiemAgent decisionMaker() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
checkFlag = true
|
||||
break
|
||||
end
|
||||
@@ -338,7 +346,7 @@ function decisionMaker(a::T; recent::Integer=10)::Dict{Symbol,Any} where {T<:age
|
||||
matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i)
|
||||
if length(matchkeys) > 1
|
||||
errornote = "DecisionMaker has more than one key per categories"
|
||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("\nYiemAgent decisionMaker() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
checkFlag = true
|
||||
break
|
||||
end
|
||||
@@ -372,7 +380,7 @@ function decisionMaker(a::T; recent::Integer=10)::Dict{Symbol,Any} where {T<:age
|
||||
isWineInEvent == false
|
||||
|
||||
errornote = "Note: Before recommending a wine, ensure it's in your inventory. Check your stock first."
|
||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("\nYiemAgent decisionMaker() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
end
|
||||
end
|
||||
@@ -1116,14 +1124,14 @@ function generatechat(a::sommelier, thoughtDict)
|
||||
You should only respond in format as described below:
|
||||
Dialogue: ...
|
||||
Here are some examples:
|
||||
Your ongoing conversation with the user: "user> hello, I need a new car\n"
|
||||
Additional info: "Car previously found in your inventory: 1) Toyota Camry 2020 2) Honda Civic 2021 3) Ford Mustang 2022"
|
||||
Your thoughts: "I should recommend the car we have to the user."
|
||||
Your thoughts: "I should recommend the car we have found in our inventory to the user."
|
||||
Your ongoing conversation with the user: "user> hello, I need a new car\n"
|
||||
Dialogue: "We have a variety of cars available, including the Toyota Camry 2020, the Honda Civic 2021, and the Ford Mustang 2022. Which one would you like to see?"
|
||||
|
||||
Let's begin!
|
||||
"""
|
||||
#[WORKING] remove "chat"
|
||||
|
||||
header = ["Dialogue:"]
|
||||
dictkey = ["dialogue"]
|
||||
|
||||
@@ -1145,6 +1153,7 @@ function generatechat(a::sommelier, thoughtDict)
|
||||
for attempt in 1:10
|
||||
|
||||
if attempt > 1 # use to prevent LLM generate the same respond over and over
|
||||
println("\nYiemAgent generatchat() attempt $attempt/10 ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
yourthought1 = paraphrase(a.func[:text2textInstructLLM], yourthought)
|
||||
else
|
||||
yourthought1 = yourthought
|
||||
@@ -1166,12 +1175,15 @@ function generatechat(a::sommelier, thoughtDict)
|
||||
|
||||
# put in model format
|
||||
prompt = GeneralUtils.formatLLMtext(_prompt; formatname="qwen")
|
||||
|
||||
response = a.func[:text2textInstructLLM](prompt)
|
||||
|
||||
# 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__, " $(Dates.now())")
|
||||
errornote = "You don't need to put 'response:' in your response"
|
||||
println("ERROR YiemAgent generatechat() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
elseif occursin("Your thoughts:", response) || occursin("your thoughts:", response)
|
||||
errornote = "You don't need to put 'Your thoughts:' in your response"
|
||||
println("ERROR YiemAgent generatechat() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
end
|
||||
response = GeneralUtils.remove_french_accents(response)
|
||||
response = replace(response, '*'=>"")
|
||||
@@ -1651,7 +1663,7 @@ function generatequestion(a, text2textInstructLLM::Function;
|
||||
# check whether response has all header
|
||||
detected_kw = GeneralUtils.detect_keyword(header, response)
|
||||
if 0 ∈ values(detected_kw)
|
||||
errornote = "\nYiemAgent generatequestion() response does not have all header"
|
||||
errornote = "\nresponse does not have all header"
|
||||
continue
|
||||
elseif sum(values(detected_kw)) > length(header)
|
||||
errornote = "\nYiemAgent generatequestion() response has duplicated header"
|
||||
@@ -1714,6 +1726,10 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent::
|
||||
errornote = ""
|
||||
response = nothing # store for show when error msg show up
|
||||
for attempt in 1:10
|
||||
if attempt > 1 # use to prevent LLM generate the same respond over and over
|
||||
println("\nYiemAgent generateSituationReport() attempt $attempt/10 ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
end
|
||||
|
||||
usermsg = """
|
||||
Total events: $(length(events))
|
||||
Events timeline: $timeline
|
||||
@@ -1738,11 +1754,11 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent::
|
||||
missingkeys = [header[i] for i in zeroind]
|
||||
if 0 ∈ values(detected_kw)
|
||||
errornote = "$missingkeys are missing in your previous attempt"
|
||||
println("\nYiemAgent generateSituationReport() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("\nERROR YiemAgent generateSituationReport() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
elseif sum(values(detected_kw)) > length(header)
|
||||
errornote = "Your previous response has duplicated events"
|
||||
println("\nYiemAgent generateSituationReport() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("\nERROR YiemAgent generateSituationReport() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
end
|
||||
|
||||
@@ -1757,8 +1773,8 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent::
|
||||
error("generateSituationReport failed to generate a response ", response)
|
||||
end
|
||||
|
||||
|
||||
function detectWineryName(a, text)
|
||||
|
||||
systemmsg =
|
||||
"""
|
||||
You are a sommelier of a wine store.
|
||||
@@ -1791,7 +1807,6 @@ function detectWineryName(a, text)
|
||||
usermsg = """
|
||||
Text: $text
|
||||
"""
|
||||
|
||||
_prompt =
|
||||
[
|
||||
Dict(:name => "system", :text => systemmsg),
|
||||
|
||||
@@ -389,6 +389,10 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<
|
||||
for attempt in 1:10
|
||||
#[WORKING] I should add generatequestion()
|
||||
|
||||
if attempt > 1
|
||||
println("\nYiemAgent extractWineAttributes_1() attempt $attempt/10 ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
end
|
||||
|
||||
usermsg =
|
||||
"""
|
||||
User's query: $input
|
||||
@@ -449,7 +453,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__, " $(Dates.now())")
|
||||
println("ERROR YiemAgent extractWineAttributes_1() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
checkFlag = true
|
||||
break
|
||||
end
|
||||
@@ -464,7 +468,7 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<
|
||||
# price range like 100-100 is not good
|
||||
if minprice == maxprice
|
||||
errornote = "wine_price with minimum equals to maximum is not valid"
|
||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
println("ERROR YiemAgent extractWineAttributes_1() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
checkFlag = true
|
||||
break
|
||||
end
|
||||
@@ -480,14 +484,14 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<
|
||||
content = [content]
|
||||
end
|
||||
|
||||
for x in content #check whether price are mentioned in the 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."
|
||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
checkFlag == true
|
||||
break
|
||||
end
|
||||
end
|
||||
# for x in content #check whether price are mentioned in the 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."
|
||||
# println("ERROR YiemAgent extractWineAttributes_1() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
# checkFlag == true
|
||||
# break
|
||||
# end
|
||||
# end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
18
src/util.jl
18
src/util.jl
@@ -268,7 +268,7 @@ end
|
||||
# Returns
|
||||
- `timeline::String`
|
||||
A formatted string representing the events with their subjects, actions, and optional outcomes
|
||||
Format: "{subject}> {actioninput} {outcome}\n" for each event
|
||||
Format: "{index}) {subject}> {actioninput} {outcome}\n" for each event
|
||||
|
||||
# Example
|
||||
|
||||
@@ -277,24 +277,32 @@ events = [
|
||||
Dict(:subject => "Assistant", :actioninput => "Hi there!", :outcome => "with a smile")
|
||||
]
|
||||
timeline = createTimeline(events)
|
||||
# User> Hello
|
||||
# Assistant> Hi there! with a smile
|
||||
# 1) User> Hello
|
||||
# 2) Assistant> Hi there! with a smile
|
||||
|
||||
"""
|
||||
function createTimeline(events::T1) where {T1<:AbstractVector}
|
||||
# Initialize empty timeline string
|
||||
timeline = ""
|
||||
|
||||
# Iterate through events with index
|
||||
for (i, event) in enumerate(events)
|
||||
# If no outcome exists, format without outcome
|
||||
if event[:outcome] === nothing
|
||||
timeline *= "$i) $(event[:subject])> $(event[:actioninput])\n"
|
||||
timeline *= "Event_$i) $(event[:subject])> $(event[:actioninput])\n"
|
||||
# If outcome exists, include it in formatting
|
||||
else
|
||||
timeline *= "$i) $(event[:subject])> $(event[:actioninput]) $(event[:outcome])\n"
|
||||
timeline *= "Event_$i) $(event[:subject])> $(event[:actioninput]) $(event[:outcome])\n"
|
||||
end
|
||||
end
|
||||
|
||||
# Return formatted timeline string
|
||||
return timeline
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
# """ Convert a single chat dictionary into LLM model instruct format.
|
||||
|
||||
# # Llama 3 instruct format example
|
||||
|
||||
@@ -95,10 +95,7 @@ function getEmbedding(text::T) where {T<:AbstractString}
|
||||
)
|
||||
)
|
||||
|
||||
#BUG it returns nothing from ollama
|
||||
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120, maxattempt=2)
|
||||
|
||||
|
||||
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120, maxattempt=3)
|
||||
embedding = response[:response][:embeddings]
|
||||
return embedding
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user