update
This commit is contained in:
@@ -213,7 +213,7 @@ function decisionMaker(a::T)::Dict{Symbol, Any} where {T<:agent}
|
||||
systemmsg =
|
||||
"""
|
||||
You are an website-based polite sommelier working for an online wine store. You are currently talking with the user.
|
||||
Your task is to help the user choose the best wine that match the user preferences from your inventory.
|
||||
Your task is to help the user choose the best wine from your inventory that matches their tastes.
|
||||
|
||||
Definitions:
|
||||
"observation" is result of the preceding immediate action.
|
||||
@@ -224,11 +224,9 @@ function decisionMaker(a::T)::Dict{Symbol, Any} where {T<:agent}
|
||||
|
||||
You MUST follow the following guidelines:
|
||||
- Generally speaking, your inventory has some wines from France, the United States, Australia, Spain, and Italy but you won't know which wines are in stock until you check your inventory.
|
||||
- Use the "ask the user's preferences, then check inventory" strategy to help the user, as there are many wines in the inventory.
|
||||
- Check inventory before recommending or suggesting wines to the user.
|
||||
- Only recommending wine from your inventory.
|
||||
- Use the "get to know the user's preferences, then check inventory" strategy to help the user, as there are many wines in the inventory.
|
||||
- After recommending wine to the user, ask if there is anything else you can help with, but do not offer any additional services. If the user doesn't need anything else, say thank you and goodbye.
|
||||
- Do not offer the user to try wine as you are internet-based agent.
|
||||
- Do not ask the user about wine's flavors
|
||||
|
||||
You should follow the following guidelines as you see fit:
|
||||
- If the user interrupts, prioritize the user.
|
||||
@@ -248,14 +246,14 @@ function decisionMaker(a::T)::Dict{Symbol, Any} where {T<:agent}
|
||||
Good query example: black car, a stereo, 200 mile range, electric motor.
|
||||
Good query example: How many car brand are from Asia?
|
||||
- action_input: input to the action
|
||||
- recommending_wine: Are you recommending wines to the user? Can be "Yes" or "No"
|
||||
- mentioning_wine: Are you mentioning specific wine name to the user? Can be "Yes" or "No"
|
||||
|
||||
You should only respond in format as described below:
|
||||
thought: ...
|
||||
plan: ...
|
||||
action_name: ...
|
||||
action_input: ...
|
||||
recommending_wine: ...
|
||||
mentioning_wine: ...
|
||||
|
||||
Let's begin!
|
||||
"""
|
||||
@@ -270,6 +268,9 @@ function decisionMaker(a::T)::Dict{Symbol, Any} where {T<:agent}
|
||||
|
||||
chathistory = vectorOfDictToText(a.chathistory)
|
||||
checkinventory_flag = ""
|
||||
response = nothing # placeholder for show when error msg show up
|
||||
|
||||
for attempt in 1:10
|
||||
usermsg =
|
||||
"""
|
||||
Context: $context
|
||||
@@ -289,12 +290,11 @@ function decisionMaker(a::T)::Dict{Symbol, Any} where {T<:agent}
|
||||
"""
|
||||
<|start_header_id|>assistant<|end_header_id|>
|
||||
"""
|
||||
response = nothing # store for show when error msg show up
|
||||
for attempt in 1:10
|
||||
|
||||
try
|
||||
response = a.text2textInstructLLM(prompt)
|
||||
responsedict = GeneralUtils.textToDict(response,
|
||||
["thought", "plan", "action_name", "action_input", "recommending_wine"],
|
||||
["thought", "plan", "action_name", "action_input", "mentioning_wine"],
|
||||
rightmarker=":", symbolkey=true)
|
||||
|
||||
if responsedict[:action_name] ∉ ["CHATBOX", "CHECKINVENTORY"]
|
||||
@@ -308,7 +308,7 @@ function decisionMaker(a::T)::Dict{Symbol, Any} where {T<:agent}
|
||||
end
|
||||
|
||||
# check if there are more than 1 key per categories
|
||||
for i ∈ [:thought, :plan, :action_name, :action_input, :recommending_wine]
|
||||
for i ∈ [:thought, :plan, :action_name, :action_input, :mentioning_wine]
|
||||
matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i)
|
||||
if length(matchkeys) > 1
|
||||
error("DecisionMaker has more than one key per categories")
|
||||
@@ -316,18 +316,20 @@ function decisionMaker(a::T)::Dict{Symbol, Any} where {T<:agent}
|
||||
end
|
||||
|
||||
println("")
|
||||
println("--> Yiem decisionMaker ", @__FILE__, " ", @__LINE__)
|
||||
println("--> Yiem decisionMaker() ", @__FILE__, " ", @__LINE__)
|
||||
pprintln(responsedict)
|
||||
|
||||
# check if LLM recommend wine before checking inventory
|
||||
isMemEmpty = isempty(a.memory[:shortmem])
|
||||
if occursin("Yes", responsedict[:recommending_wine]) && isMemEmpty &&
|
||||
if occursin("Yes", responsedict[:mentioning_wine]) && isMemEmpty &&
|
||||
responsedict[:action_name] != "CHECKINVENTORY"
|
||||
checkinventory_flag = "You must check your inventory before recommending wine to the user."
|
||||
checkinventory_flag = "Note: You must check your inventory before recommending wine to the user."
|
||||
error( "You must check your inventory before recommending wine")
|
||||
else
|
||||
checkinventory_flag = ""
|
||||
end
|
||||
|
||||
delete!(responsedict, :recommending_wine)
|
||||
delete!(responsedict, :mentioning_wine)
|
||||
|
||||
return responsedict
|
||||
catch e
|
||||
@@ -1220,7 +1222,7 @@ function generatechat(memory::Dict, chathistory::Vector, text2textInstructLLM::F
|
||||
systemmsg =
|
||||
"""
|
||||
You are an website-based polite sommelier working for an online wine store.
|
||||
Your task is to help the user choose the best wine that match the user preferences from your inventory.
|
||||
Your task is to help the user choose the best wine from your inventory that matches their tastes.
|
||||
|
||||
At each round of conversation, the user will give you the current situation:
|
||||
Context: ...
|
||||
@@ -1228,27 +1230,32 @@ function generatechat(memory::Dict, chathistory::Vector, text2textInstructLLM::F
|
||||
Your current thoughts in your mind: ...
|
||||
|
||||
You must follow the following guidelines:
|
||||
- You won't know which wines are in stock until you check your inventory.
|
||||
- Only recommending (suggesting) wine from your inventory.
|
||||
- Your thoughts matter.
|
||||
- Do not offer the user to try wine as you are internet-based agent.
|
||||
- Do not ask the user about wine's flavors
|
||||
|
||||
You should then respond to the user with:
|
||||
- chat: what do you want to say to the user based on the current situation
|
||||
- mentioning_wine: Are you mentioning specific wine name to the user? Can be "Yes" or "No"
|
||||
|
||||
You should only respond in format as described below:
|
||||
chat: ...
|
||||
mentioning_wine: ...
|
||||
|
||||
Let's begin!
|
||||
"""
|
||||
|
||||
context_1 = length(memory[:shortmem]) > 0 ? vectorOfDictToText(memory[:shortmem], withkey=false) : "None"
|
||||
_chathistory = vectorOfDictToText(chathistory)
|
||||
chathistory = vectorOfDictToText(chathistory)
|
||||
checkinventory_flag = ""
|
||||
response = nothing # placeholder for show when error msg show up
|
||||
|
||||
for attempt in 1:5
|
||||
usermsg =
|
||||
"""
|
||||
Context: $context_1
|
||||
Your earlier conversation with the user: $_chathistory)
|
||||
Your earlier conversation with the user: $chathistory)
|
||||
Your thoughts: $(memory[:chatbox])
|
||||
$checkinventory_flag
|
||||
"""
|
||||
|
||||
_prompt =
|
||||
@@ -1264,11 +1271,9 @@ function generatechat(memory::Dict, chathistory::Vector, text2textInstructLLM::F
|
||||
<|start_header_id|>assistant<|end_header_id|>
|
||||
"""
|
||||
|
||||
for attempt in 1:5
|
||||
try
|
||||
response = text2textInstructLLM(prompt)
|
||||
responsedict = GeneralUtils.textToDict(response,
|
||||
["chat"],
|
||||
responsedict = GeneralUtils.textToDict(response,["chat", "mentioning_wine"],
|
||||
rightmarker=":", symbolkey=true)
|
||||
|
||||
for i ∈ [:chat]
|
||||
@@ -1285,6 +1290,21 @@ function generatechat(memory::Dict, chathistory::Vector, text2textInstructLLM::F
|
||||
end
|
||||
end
|
||||
|
||||
println("")
|
||||
println("--> generatechat() ", @__FILE__, " ", @__LINE__)
|
||||
pprintln(responsedict)
|
||||
|
||||
# check if LLM recommend wine before checking inventory
|
||||
isMemEmpty = isempty(memory[:shortmem])
|
||||
if occursin("Yes", responsedict[:mentioning_wine]) && isMemEmpty
|
||||
checkinventory_flag = "Note: You must check your inventory before recommending wine to the user."
|
||||
error( "You must check your inventory before recommending wine")
|
||||
else
|
||||
checkinventory_flag = ""
|
||||
end
|
||||
|
||||
delete!(responsedict, :mentioning_wine)
|
||||
|
||||
result = responsedict[:chat]
|
||||
|
||||
return result
|
||||
|
||||
@@ -324,32 +324,33 @@ function extractWineAttributes_1(a::T1, input::T2
|
||||
|
||||
systemmsg =
|
||||
"""
|
||||
As an helpful sommelier, your task is to fill out the user's preference form by copying the corresponding words from the user's query.
|
||||
As an helpful sommelier, your task is to fill out the user's preference form based on the corresponding words from the user's query.
|
||||
|
||||
At each round of conversation, the user will give you the current situation:
|
||||
User query: ...
|
||||
User's query: ...
|
||||
|
||||
The preference form requires the following information:
|
||||
wine_type, price, occasion, food_to_be_paired_with_wine, country, grape_variety, wine_notes.
|
||||
|
||||
You must follow the following guidelines:
|
||||
1) If specific information required in the preference form is not available in the query, use 'NA' to indicate this.
|
||||
1) If specific information required in the preference form is not available in the query or there isn't any, mark with 'NA' to indicate this.
|
||||
Additionally, words like 'any' or 'unlimited' mean no information is available.
|
||||
2) Use the conversion table to convert the descriptive word level of sweetness, intensity, tannin, and acidity into a corresponding integer.
|
||||
3) Do not generate other comments.
|
||||
|
||||
You should then respond to the user with the following points:
|
||||
- wine_type: Can be one of: red, white, sparkling, rose, dessert or fortified
|
||||
- reasoning: State your understanding of the current situation
|
||||
- wine_type: Can be one of: "red", "white", "sparkling", "rose", "dessert" or "fortified"
|
||||
- price: Must be an integer representing the cost of the wine.
|
||||
|
||||
- occasion: ...
|
||||
- food_to_be_paired_with_wine: food that will be served with wine
|
||||
- food_to_be_paired_with_wine: food that the user will be served with wine
|
||||
- country: wine's country of origin
|
||||
- grape variety: Name of grape used to make wine.
|
||||
- flavors: wine's flavor
|
||||
- flavors: Names of items that the wine tastes like.
|
||||
- aromas: wine's aroma
|
||||
|
||||
You should only respond in the form as described below:
|
||||
reasoning: ...
|
||||
wine_type: ...
|
||||
price: ...
|
||||
occasion: ...
|
||||
@@ -362,9 +363,11 @@ function extractWineAttributes_1(a::T1, input::T2
|
||||
Let's begin!
|
||||
"""
|
||||
|
||||
# chathistory = vectorOfDictToText(a.chathistory)
|
||||
|
||||
usermsg =
|
||||
"""
|
||||
User query: $input
|
||||
User's query: $input
|
||||
"""
|
||||
|
||||
_prompt =
|
||||
@@ -380,7 +383,7 @@ function extractWineAttributes_1(a::T1, input::T2
|
||||
<|start_header_id|>assistant<|end_header_id|>
|
||||
"""
|
||||
|
||||
attributes = ["wine_type", "price", "occasion", "food_to_be_paired_with_wine", "country", "grape_variety", "flavors", "aromas"]
|
||||
attributes = ["reasoning", "wine_type", "price", "occasion", "food_to_be_paired_with_wine", "country", "grape_variety", "flavors", "aromas"]
|
||||
|
||||
for attempt in 1:5
|
||||
try
|
||||
@@ -393,21 +396,23 @@ function extractWineAttributes_1(a::T1, input::T2
|
||||
end
|
||||
end
|
||||
|
||||
responsedict[:flavors] = replace(responsedict[:flavors], "notes"=>"") #BUG no method matching
|
||||
responsedict[:tasting_notes] = responsedict[:flavors]
|
||||
responsedict[:flavors] = replace(responsedict[:flavors], "notes"=>"")
|
||||
delete!(responsedict, :reasoning)
|
||||
delete!(responsedict, :tasting_notes)
|
||||
delete!(responsedict, :flavors)
|
||||
delete!(responsedict, :aromas)
|
||||
|
||||
result = ""
|
||||
for (k, v) in responsedict
|
||||
if !occursin("NA", v) && v != ""
|
||||
# some time LLM generate text with "(some comment)". this line removes it
|
||||
v = replace(v, r"\(.*?\)" => "")
|
||||
if !occursin("NA", v) && v != "" && !occursin("none", v) && !occursin("None", v)
|
||||
result *= "$k: $v, "
|
||||
end
|
||||
end
|
||||
|
||||
#[PENDING] remove halucination. "highend dry white wine" --> "wine_type: white, occasion: special occasion, food_to_be_paired_with_wine: seafood, fish, country: France, Italy, USA, grape_variety: Chardonnay, Sauvignon Blanc, Pinot Grigio\nwine_notes: citrus, green apple, floral"
|
||||
|
||||
|
||||
result = result[1:end-2] # remove the ending ", "
|
||||
|
||||
return result
|
||||
@@ -431,7 +436,7 @@ end
|
||||
function extractWineAttributes_2(a::T1, input::T2
|
||||
)::String where {T1<:agent, T2<:AbstractString}
|
||||
|
||||
converstiontable =
|
||||
conversiontable =
|
||||
"""
|
||||
Conversion Table:
|
||||
Intensity level:
|
||||
@@ -460,25 +465,27 @@ function extractWineAttributes_2(a::T1, input::T2
|
||||
4 to 5: May correspond to "high acidity" or a similar description.
|
||||
"""
|
||||
|
||||
# chathistory = vectorOfDictToText(a.chathistory)
|
||||
|
||||
systemmsg =
|
||||
"""
|
||||
As an helpful sommelier, your task is to fill the user's preference form based on the user query.
|
||||
As an helpful sommelier, your task is to fill out the user's preference form based on the corresponding words from the user's query.
|
||||
|
||||
At each round of conversation, the user will give you the current situation:
|
||||
Conversion Table: ...
|
||||
User query: ...
|
||||
User's query: ...
|
||||
|
||||
The preference form requires the following information:
|
||||
sweetness, acidity, tannin, intensity
|
||||
|
||||
You must follow the following guidelines:
|
||||
1) If specific information required in the preference form is not available in the query, use 'NA' to indicate this.
|
||||
1) If specific information required in the preference form is not available in the query or there isn't any, mark with 'NA' to indicate this.
|
||||
Additionally, words like 'any' or 'unlimited' mean no information is available.
|
||||
2) Use the conversion table to convert the descriptive word level of sweetness, intensity, tannin, and acidity into a corresponding integer.
|
||||
3) Do not generate other comments.
|
||||
|
||||
You should then respond to the user with the following points:
|
||||
- repeat: State the user query
|
||||
- reasoning: State your understanding of the current situation
|
||||
- sweetness: S where S are integers represent the range of sweetness levels
|
||||
Example: 1-2
|
||||
- acidity: D where D are integers represent the range of acidity level
|
||||
@@ -487,21 +494,25 @@ function extractWineAttributes_2(a::T1, input::T2
|
||||
Example: 1-3
|
||||
- intensity: I where I are integers represent the range of intensity level
|
||||
Example: 2-4
|
||||
- notes: Anything you want to add
|
||||
|
||||
You should only respond in the form as described below:
|
||||
repeat: ...
|
||||
reasoning: ...
|
||||
sweetness: ...
|
||||
acidity: ...
|
||||
tannin: ...
|
||||
intensity: ...
|
||||
notes: ...
|
||||
|
||||
Let's begin!
|
||||
"""
|
||||
|
||||
# chathistory = vectorOfDictToText(a.chathistory)
|
||||
|
||||
usermsg =
|
||||
"""
|
||||
Conversion Table: $converstiontable
|
||||
User query: $input
|
||||
$conversiontable
|
||||
User's query: $input
|
||||
"""
|
||||
|
||||
_prompt =
|
||||
@@ -517,7 +528,7 @@ function extractWineAttributes_2(a::T1, input::T2
|
||||
<|start_header_id|>assistant<|end_header_id|>
|
||||
"""
|
||||
|
||||
attributes = ["sweetness", "acidity", "tannin", "intensity"]
|
||||
attributes = ["reasoning", "sweetness", "acidity", "tannin", "intensity", "notes"]
|
||||
|
||||
for attempt in 1:5
|
||||
try
|
||||
@@ -530,6 +541,9 @@ function extractWineAttributes_2(a::T1, input::T2
|
||||
end
|
||||
end
|
||||
|
||||
delete!(responsedict, :reasoning)
|
||||
delete!(responsedict, :notes) # LLM traps. so it can add useless info here like comments.
|
||||
|
||||
# some time LLM think the user mentioning acidity and tannin but actually didn't
|
||||
for (k, v) in responsedict
|
||||
if k ∈ [:acidity, :tannin] && !occursin(string(k), input)
|
||||
@@ -545,9 +559,10 @@ function extractWineAttributes_2(a::T1, input::T2
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
result = ""
|
||||
for (k, v) in responsedict
|
||||
# some time LLM generate text with "(some comment)". this line removes it
|
||||
v = replace(v, r"\(.*?\)" => "")
|
||||
if !occursin("NA", v)
|
||||
result *= "$k: $v, "
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user