This commit is contained in:
narawat lamaiin
2025-04-01 21:17:15 +07:00
parent b8fd772a28
commit c21f943b12
4 changed files with 64 additions and 40 deletions

View File

@@ -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),

View File

@@ -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

View File

@@ -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

View File

@@ -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