This commit is contained in:
narawat lamaiin
2024-05-28 23:48:50 +07:00
parent fcf8d855b8
commit 3f38fdbb70
7 changed files with 202 additions and 452 deletions

View File

@@ -223,12 +223,18 @@ function virtualWineUserChatbox(a::T1, input::T2, virtualCustomerChatHistory
}
Here are some examples:
sommelier: "What's your budget?
you:
{
"text": "My budget is 30 USD.",
"select": null,
"reward": 0,
"isterminal": false
}
sommelier: "The first option is Zena Crown and the second one is Buano Red."
you:
{
"text": "I like the 2nd option.",
"select": 2,
@@ -307,12 +313,12 @@ function virtualWineUserChatbox(a::T1, input::T2, virtualCustomerChatHistory
responseJsonStr = jsoncorrection(a, _responseJsonStr, expectedJsonExample)
responseDict = copy(JSON3.read(responseJsonStr))
text = responseDict[:text]
select = responseDict[:select] == "null" ? nothing : responseDict[:select]
reward = responseDict[:reward]
isterminal = 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 != "" && select != "" && reward != "" && isterminal != ""
if text != ""
# pass test
else
error("virtual customer not answer correctly")
@@ -332,58 +338,6 @@ function virtualWineUserChatbox(a::T1, input::T2, virtualCustomerChatHistory
error("virtualWineUserChatbox failed to get a response")
end
# function virtualWineUserChatbox(a::T1, input::T2
# )::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent, T2<:AbstractString}
# # put in model format
# virtualWineCustomer = a.config[:externalservice][:virtualWineCustomer_1]
# llminfo = virtualWineCustomer[:llminfo]
# prompt =
# if llminfo[:name] == "llama3instruct"
# formatLLMtext_llama3instruct("assistant", input)
# else
# error("llm model name is not defied yet $(@__LINE__)")
# end
# # send formatted input to user using GeneralUtils.sendReceiveMqttMsg
# msgMeta = GeneralUtils.generate_msgMeta(
# virtualWineCustomer[:mqtttopic],
# senderName= "virtualWineUserChatbox",
# senderId= a.id,
# receiverName= "virtualWineCustomer",
# 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,
# )
# )
# attempt = 0
# for attempt in 1:5
# try
# result = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
# response = result[:response]
# return (response[:text], response[:select], response[:reward], response[:isterminal])
# catch e
# io = IOBuffer()
# showerror(io, e)
# errorMsg = String(take!(io))
# st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
# println("")
# @warn "Error occurred: $errorMsg\n$st"
# println("")
# end
# end
# error("virtualWineUserChatbox failed to get a response")
# end
""" Search wine in stock.
# Arguments
@@ -411,6 +365,150 @@ julia> result = winestock(agent, input)
function winestock(a::T1, input::T2
)::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent, T2<:AbstractString}
systemmsg =
"""
As an attentive sommelier, your mission is to determine the user's preferred levels of sweetness, intensity, tannin, and acidity for a wine based on their input.
You'll achieve this by referring to the provided conversion table.
Conversion Table:
Intensity level:
Level 1: May correspond to "light-bodied" or a similar description.
Level 2: May correspond to "med-light" or a similar description.
Level 3: May correspond to "medium" or a similar description.
Level 4: May correspond to "med-full" or a similar description.
Level 5: May correspond to "full" or a similar description.
Sweetness level:
Level 1: May correspond to "dry", "no-sweet" or a similar description.
Level 2: May correspond to "off-dry", "less-sweet" or a similar description.
Level 3: May correspond to "semi-sweet" or a similar description.
Level 4: May correspond to "sweet" or a similar description.
Level 5: May correspond to "very sweet" or a similar description.
Tannin level:
Level 1: May correspond to "low tannin" or a similar description.
Level 2: May correspond to "semi-low tannin" or a similar description.
Level 3: May correspond to "medium tannin" or a similar description.
Level 4: May correspond to "semi-high tannin" or a similar description.
Level 5: May correspond to "high tannin" or a similar description.
Acidity level:
Level 1: May correspond to "low acidity" or a similar description.
Level 2: May correspond to "semi-low acidity" or a similar description.
Level 3: May correspond to "medium acidity" or a similar description.
Level 4: May correspond to "semi-high acidity" or a similar description.
Level 5: May correspond to "high acidity" or a similar description.
You should only respond in JSON format as describe below:
{
"sweetness": "sweetness level",
"acidity": "acidity level",
"tannin": "tannin level",
"intensity": "intensity level"
}
Here are some examples:
user: red wines, price < 50, body=full-bodied, tannins=1, off dry, acidity=medium, intensity=intense, Thai dishes
assistant:
{
"wine_attributes":
{
"sweetness": 2,
"acidity": 3,
"tannin": 1,
"intensity": 5
}
}
Let's begin!
"""
usermsg =
"""
$input
"""
chathistory =
[
Dict(:name=> "system", :text=> systemmsg),
Dict(:name=> "user", :text=> usermsg)
]
# put in model format
prompt = formatLLMtext(chathistory, "llama3instruct")
prompt *=
"""
<|start_header_id|>assistant<|end_header_id|>
{
"""
pprint(prompt)
externalService = a.config[:externalservice][:text2textinstruct]
# send formatted input to user using GeneralUtils.sendReceiveMqttMsg
msgMeta = GeneralUtils.generate_msgMeta(
externalService[:mqtttopic],
senderName= "virtualWineUserChatbox",
senderId= a.id,
receiverName= "text2textinstruct",
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,
)
)
attempt = 0
for attempt in 1:5
try
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
_responseJsonStr = response[:response][:text]
expectedJsonExample =
"""
Here is an expected JSON format:
{
"wine_attributes":
{
"...": "...",
"...": "...",
}
}
"""
responseJsonStr = jsoncorrection(a, _responseJsonStr, expectedJsonExample)
responseDict = copy(JSON3.read(responseJsonStr))
return (text, select, reward, isterminal)
catch e
io = IOBuffer()
showerror(io, e)
errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
println("")
@warn "Error occurred: $errorMsg\n$st"
println("")
end
end
error("virtualWineUserChatbox failed to get a response")
winesStr =
"""
1: El Enemigo Cabernet Franc 2019
@@ -425,6 +523,23 @@ function winestock(a::T1, input::T2
"""
return result, nothing, 0, false
end
# function winestock(a::T1, input::T2
# )::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent, T2<:AbstractString}
# winesStr =
# """
# 1: El Enemigo Cabernet Franc 2019
# 2: Tantara Chardonnay 2017
# """
# result =
# """
# I found the following wines in our stock:
# {
# $winesStr
# }
# """
# return result, nothing, 0, false
# end
""" Attemp to correct LLM response's incorrect JSON response.
@@ -446,13 +561,14 @@ julia>
# Signature
"""
function jsoncorrection(a::T1, input::T2,
correctJsonExample::T3) where {T1<:agent, T2<:AbstractString, T3<:AbstractString}
function jsoncorrection(a::T1, input::T2, correctJsonExample::T3;
maxattempt::Integer=3
) where {T1<:agent, T2<:AbstractString, T3<:AbstractString}
incorrectjson = deepcopy(input)
correctjson = nothing
for attempt in 1:5
for attempt in 1:maxattempt
try
d = copy(JSON3.read(incorrectjson))
correctjson = incorrectjson