update
This commit is contained in:
372
src/interface.jl
372
src/interface.jl
@@ -97,7 +97,7 @@ julia> output_thoughtDict = Dict(
|
|||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
function decisionMaker(a::T; recent::Integer=10, maxattempt=10
|
function decisionMaker(a::T; recentevents::Integer=10, maxattempt=10
|
||||||
) where {T<:agent}
|
) where {T<:agent}
|
||||||
|
|
||||||
# lessonDict = copy(JSON3.read("lesson.json"))
|
# lessonDict = copy(JSON3.read("lesson.json"))
|
||||||
@@ -125,35 +125,42 @@ function decisionMaker(a::T; recent::Integer=10, maxattempt=10
|
|||||||
# """
|
# """
|
||||||
# end
|
# end
|
||||||
|
|
||||||
recent_ind = GeneralUtils.recentElementsIndex(length(a.chathistory), recent; includelatest=true)
|
recentevents_ind = GeneralUtils.recentElementsIndex(length(a.memory[:events]), recentevents;
|
||||||
recentevents = a.memory[:events][recent_ind]
|
includelatest=true)
|
||||||
recentchat = createChatLog(a.chathistory[recent_ind]; index=recent_ind)
|
timeline = createTimeline(a.memory[:events]; eventindex=recentevents_ind)
|
||||||
|
|
||||||
|
recentchat_ind = GeneralUtils.recentElementsIndex(length(a.chathistory), recentevents;
|
||||||
|
includelatest=true)
|
||||||
|
recentchat = createChatLog(a.chathistory; index=recentchat_ind)
|
||||||
# recentEventsDict = createEventsLog(recentevents; index=recent_ind)
|
# recentEventsDict = createEventsLog(recentevents; index=recent_ind)
|
||||||
|
|
||||||
|
#BUG timeline only cover event 1-9 out of 10 events while recentchat cover 1-9 because
|
||||||
|
# recent_ind is based on chathistory. i should ind based on events. The reason is events always
|
||||||
|
# have more than chathistory due to CHECKINVENTORY() function which store in events BUT NOT in
|
||||||
|
# chathistory
|
||||||
|
|
||||||
timeline = createTimeline(recentevents; eventindex=recent_ind)
|
|
||||||
|
|
||||||
# recap as caching
|
# # recap as caching
|
||||||
# query similar result from vectorDB
|
# # query similar result from vectorDB
|
||||||
recapkeys = keys(a.memory[:recap])
|
# recapkeys = keys(a.memory[:recap])
|
||||||
_recapkeys_vec = [i for i in recapkeys]
|
# _recapkeys_vec = [i for i in recapkeys]
|
||||||
|
|
||||||
# select recent keys
|
# # select recent keys
|
||||||
_recentRecapKeys =
|
# _recentRecapKeys =
|
||||||
if length(a.memory[:recap]) <= 3 # 1st message is a user's hello msg
|
# if length(a.memory[:recap]) <= 3 # 1st message is a user's hello msg
|
||||||
_recapkeys_vec
|
# _recapkeys_vec
|
||||||
elseif length(a.memory[:recap]) > 3
|
# elseif length(a.memory[:recap]) > 3
|
||||||
l = length(a.memory[:recap])
|
# l = length(a.memory[:recap])
|
||||||
_recapkeys_vec[l-2:l]
|
# _recapkeys_vec[l-2:l]
|
||||||
end
|
# end
|
||||||
|
|
||||||
# get recent recap
|
# # get recent recap
|
||||||
_recentrecap = OrderedDict()
|
# _recentrecap = OrderedDict()
|
||||||
for (k, v) in a.memory[:recap]
|
# for (k, v) in a.memory[:recap]
|
||||||
if k ∈ _recentRecapKeys
|
# if k ∈ _recentRecapKeys
|
||||||
_recentrecap[k] = v
|
# _recentrecap[k] = v
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
# recentrecap = GeneralUtils.dictToString_noKey(_recentrecap)
|
# recentrecap = GeneralUtils.dictToString_noKey(_recentrecap)
|
||||||
# similarDecision = a.func[:similarSommelierDecision](recentrecap)
|
# similarDecision = a.func[:similarSommelierDecision](recentrecap)
|
||||||
@@ -415,7 +422,7 @@ function decisionMaker(a::T; recent::Integer=10, maxattempt=10
|
|||||||
|
|
||||||
#[WORKING]
|
#[WORKING]
|
||||||
evaluationdict = evaluator(a, timeline, responsedict, context)
|
evaluationdict = evaluator(a, timeline, responsedict, context)
|
||||||
if evaluationdict[:good_decision] == "no"
|
if evaluationdict[:approved] == "no"
|
||||||
mentor_comment = evaluationdict[:suggestion]
|
mentor_comment = evaluationdict[:suggestion]
|
||||||
errornote = "Your previous attempt was not good enough. Please try again. Here is the mentor's suggestion: $mentor_comment"
|
errornote = "Your previous attempt was not good enough. Please try again. Here is the mentor's suggestion: $mentor_comment"
|
||||||
println("\nERROR YiemAgent decisionMaker() - $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
println("\nERROR YiemAgent decisionMaker() - $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
@@ -851,7 +858,7 @@ function evaluator(a::T1, timeline, decisiondict, evaluateecontext
|
|||||||
- Do not generate additional thoughts or actions.
|
- Do not generate additional thoughts or actions.
|
||||||
2) decision_evaluation:
|
2) decision_evaluation:
|
||||||
- Examine how the trainee's decisions align with the store's policies and guidelines before proceeding.
|
- Examine how the trainee's decisions align with the store's policies and guidelines before proceeding.
|
||||||
3) good_decision: Decide whether the decision make sense under the circumstances. Can be "yes" or "no"
|
3) approved: Decide whether to let the trainee proceed or not. Can be "yes" or "no"
|
||||||
4) suggestion: Based store policy and guidelines, provide a suggestion for the immediate decision step only.
|
4) suggestion: Based store policy and guidelines, provide a suggestion for the immediate decision step only.
|
||||||
|
|
||||||
</You should then respond to the user with>
|
</You should then respond to the user with>
|
||||||
@@ -859,14 +866,14 @@ function evaluator(a::T1, timeline, decisiondict, evaluateecontext
|
|||||||
{
|
{
|
||||||
"trajectory_evaluation": "..."
|
"trajectory_evaluation": "..."
|
||||||
"decision_evaluation": "..."
|
"decision_evaluation": "..."
|
||||||
"good_decision": "..."
|
"approved": "..."
|
||||||
"suggestion": "..."
|
"suggestion": "..."
|
||||||
}
|
}
|
||||||
</You should only respond in format as described below>
|
</You should only respond in format as described below>
|
||||||
|
|
||||||
Let's begin!
|
Let's begin!
|
||||||
"""
|
"""
|
||||||
requiredKeys = [:trajectory_evaluation, :decision_evaluation, :good_decision, :suggestion]
|
requiredKeys = [:trajectory_evaluation, :decision_evaluation, :approved, :suggestion]
|
||||||
errornote = "N/A"
|
errornote = "N/A"
|
||||||
|
|
||||||
for attempt in 1:10
|
for attempt in 1:10
|
||||||
@@ -1116,7 +1123,7 @@ julia>
|
|||||||
"""
|
"""
|
||||||
function think(a::T)::NamedTuple{(:actionname, :result),Tuple{String,String}} where {T<:agent}
|
function think(a::T)::NamedTuple{(:actionname, :result),Tuple{String,String}} where {T<:agent}
|
||||||
# a.memory[:recap] = generateSituationReport(a, a.func[:text2textInstructLLM]; skiprecent=0)
|
# a.memory[:recap] = generateSituationReport(a, a.func[:text2textInstructLLM]; skiprecent=0)
|
||||||
thoughtDict = decisionMaker(a; recent=5)
|
thoughtDict = decisionMaker(a; recentevents=5)
|
||||||
|
|
||||||
actionname = thoughtDict[:action_name]
|
actionname = thoughtDict[:action_name]
|
||||||
actioninput = thoughtDict[:action_input]
|
actioninput = thoughtDict[:action_input]
|
||||||
@@ -1230,30 +1237,39 @@ function think(a::T)::NamedTuple{(:actionname, :result),Tuple{String,String}} wh
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10)
|
function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10, recentevents::Integer=10)
|
||||||
|
recentchat_ind = GeneralUtils.recentElementsIndex(length(a.chathistory), recentevents;
|
||||||
|
includelatest=true)
|
||||||
|
recentchat = createChatLog(a.chathistory; index=recentchat_ind)
|
||||||
systemmsg =
|
systemmsg =
|
||||||
"""
|
"""
|
||||||
Your profile:
|
<Your role>
|
||||||
Your name is $(a.name). You are a helpful English-speaking assistant, acting as a polite, website-based sommelier for $(a.retailername)'s wine store.
|
Your name is $(a.name). You are a helpful English-speaking assistant, acting as a polite, website-based sommelier for $(a.retailername)'s wine store.
|
||||||
Situation:
|
</Your role>
|
||||||
You have checked the inventory and found wines.
|
<Situation>
|
||||||
Your mission:
|
You have checked the inventory and found wines that may match what the user wants
|
||||||
Present the wines to the customer in a way that keep the conversation smooth and engaging.
|
</Situation>
|
||||||
At each round of conversation, you will be given the following information:
|
<Your mission>
|
||||||
|
Present the wines to the user in a way that keep the conversation smooth and engaging.
|
||||||
|
</Your mission>
|
||||||
|
<At each round of conversation, you will be given the following information>
|
||||||
|
Name of the wines that needs to be introduced: name of wines you are going to introduce to the user
|
||||||
Database search result: the result of a database search using SQL commands you have found so far
|
Database search result: the result of a database search using SQL commands you have found so far
|
||||||
Chat history: your ongoing conversation with the user
|
</At each round of conversation, you will be given the following information>
|
||||||
Wine name: name of wines you are going to introduce.
|
<You should follow the following guidelines>
|
||||||
You should follow the following guidelines:
|
|
||||||
- Provide detailed introductions of the wines you've found to the user.
|
- Provide detailed introductions of the wines you've found to the user.
|
||||||
- Explain how the wine could match the user's intention and what its effects might mean for the user's experience.
|
- Explain how the wine could match the user's intention and what its effects might mean for the user's experience.
|
||||||
- If multiple wines are available, highlight their differences and provide a comprehensive comparison of how each option aligns with the user's intention and what the potential effects of each option could mean for the user's experience.
|
- If multiple wines are available, highlight their differences and provide a comprehensive comparison of how each option aligns with the user's intention and what the potential effects of each option could mean for the user's experience.
|
||||||
- Provide your personal recommendation and provide a brief explanation of why you recommend it.
|
- Provide your personal recommendation and provide a brief explanation of why you recommend it.
|
||||||
You should then respond to the user with:
|
</You should follow the following guidelines>
|
||||||
|
<You should then respond to the user with>
|
||||||
dialogue: Your presentation to the user
|
dialogue: Your presentation to the user
|
||||||
You should only respond in format as described below:
|
</You should then respond to the user with>
|
||||||
|
<You should only respond in format as described below>
|
||||||
{
|
{
|
||||||
"dialogue": "..."
|
"dialogue": "..."
|
||||||
}
|
}
|
||||||
|
</You should only respond in format as described below>
|
||||||
|
|
||||||
Let's begin!
|
Let's begin!
|
||||||
"""
|
"""
|
||||||
@@ -1265,7 +1281,7 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10)
|
|||||||
"N/A"
|
"N/A"
|
||||||
end
|
end
|
||||||
|
|
||||||
chathistory = chatHistoryToText(a.chathistory)
|
# chathistory = chatHistoryToText(a.chathistory)
|
||||||
errornote = "N/A"
|
errornote = "N/A"
|
||||||
response = nothing # placeholder for show when error msg show up
|
response = nothing # placeholder for show when error msg show up
|
||||||
|
|
||||||
@@ -1279,9 +1295,8 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10)
|
|||||||
context =
|
context =
|
||||||
"""
|
"""
|
||||||
<context>
|
<context>
|
||||||
|
Name of the wines that needs to be introduced: $(thoughtDict[:action_input])
|
||||||
Database search result: $database_search_result
|
Database search result: $database_search_result
|
||||||
Chat history: $chathistory
|
|
||||||
Wine name: $(thoughtDict[:action_input])
|
|
||||||
P.S. $errornote
|
P.S. $errornote
|
||||||
</context>
|
</context>
|
||||||
"""
|
"""
|
||||||
@@ -1291,6 +1306,7 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10)
|
|||||||
Dict(:name => "system", :text => systemmsg),
|
Dict(:name => "system", :text => systemmsg),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
unformatPrompt = vcat(unformatPrompt, recentchat)
|
||||||
# put in model format
|
# put in model format
|
||||||
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
|
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
|
||||||
# add info
|
# add info
|
||||||
@@ -1400,6 +1416,176 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10)
|
|||||||
end
|
end
|
||||||
error("presentbox() failed to generate a response")
|
error("presentbox() failed to generate a response")
|
||||||
end
|
end
|
||||||
|
# function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10)
|
||||||
|
# systemmsg =
|
||||||
|
# """
|
||||||
|
# Your profile:
|
||||||
|
# Your name is $(a.name). You are a helpful English-speaking assistant, acting as a polite, website-based sommelier for $(a.retailername)'s wine store.
|
||||||
|
# Situation:
|
||||||
|
# You have checked the inventory and found wines.
|
||||||
|
# Your mission:
|
||||||
|
# Present the wines to the customer in a way that keep the conversation smooth and engaging.
|
||||||
|
# At each round of conversation, you will be given the following information:
|
||||||
|
# Database search result: the result of a database search using SQL commands you have found so far
|
||||||
|
# Chat history: your ongoing conversation with the user
|
||||||
|
# Name of the wines that needs to be introduced: name of wines you are going to introduce to the user.
|
||||||
|
# You should follow the following guidelines:
|
||||||
|
# - Provide detailed introductions of the wines you've found to the user.
|
||||||
|
# - Explain how the wine could match the user's intention and what its effects might mean for the user's experience.
|
||||||
|
# - If multiple wines are available, highlight their differences and provide a comprehensive comparison of how each option aligns with the user's intention and what the potential effects of each option could mean for the user's experience.
|
||||||
|
# - Provide your personal recommendation and provide a brief explanation of why you recommend it.
|
||||||
|
# You should then respond to the user with:
|
||||||
|
# dialogue: Your presentation to the user
|
||||||
|
# You should only respond in format as described below:
|
||||||
|
# {
|
||||||
|
# "dialogue": "..."
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Let's begin!
|
||||||
|
# """
|
||||||
|
# requiredKeys = [:dialogue]
|
||||||
|
# database_search_result =
|
||||||
|
# if length(a.memory[:shortmem][:db_search_result]) != 0
|
||||||
|
# availableWineToText(a.memory[:shortmem][:db_search_result])
|
||||||
|
# else
|
||||||
|
# "N/A"
|
||||||
|
# end
|
||||||
|
|
||||||
|
# chathistory = chatHistoryToText(a.chathistory)
|
||||||
|
# errornote = "N/A"
|
||||||
|
# response = nothing # placeholder for show when error msg show up
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# # yourthought = "$(thoughtDict[:thought]) $(thoughtDict[:plan])"
|
||||||
|
# # yourthought1 = nothing
|
||||||
|
|
||||||
|
# for attempt in 1:maxtattempt
|
||||||
|
|
||||||
|
# context =
|
||||||
|
# """
|
||||||
|
# <context>
|
||||||
|
# Database search result: $database_search_result
|
||||||
|
# Chat history: $chathistory
|
||||||
|
# Name of the wines that needs to be introduced: $(thoughtDict[:action_input])
|
||||||
|
# P.S. $errornote
|
||||||
|
# </context>
|
||||||
|
# """
|
||||||
|
|
||||||
|
# unformatPrompt =
|
||||||
|
# [
|
||||||
|
# Dict(:name => "system", :text => systemmsg),
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# # put in model format
|
||||||
|
# prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
|
||||||
|
# # add info
|
||||||
|
# prompt = prompt * context
|
||||||
|
|
||||||
|
# response = a.func[:text2textInstructLLM](prompt; senderId=a.id)
|
||||||
|
# response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
|
||||||
|
# response = GeneralUtils.remove_french_accents(response)
|
||||||
|
# # response = replace(response, '$'=>"USD")
|
||||||
|
# think, response = GeneralUtils.extractthink(response)
|
||||||
|
|
||||||
|
# response = replace(response, '*'=>"")
|
||||||
|
# response = replace(response, '$' => "USD")
|
||||||
|
# response = replace(response, '`' => "")
|
||||||
|
# response = replace(response, "<|eot_id|>"=>"")
|
||||||
|
|
||||||
|
# responsedict = nothing
|
||||||
|
# try
|
||||||
|
# responsedict = copy(JSON3.read(response))
|
||||||
|
# catch
|
||||||
|
# println("\nERROR YiemAgent presentbox() failed to parse response: $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# continue
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # check whether all answer's key points are in responsedict
|
||||||
|
# _responsedictKey = keys(responsedict)
|
||||||
|
# responsedictKey = [i for i in _responsedictKey] # convert into a list
|
||||||
|
# is_requiredKeys_in_responsedictKey = [i ∈ responsedictKey for i in requiredKeys]
|
||||||
|
|
||||||
|
# if length(is_requiredKeys_in_responsedictKey) > length(requiredKeys)
|
||||||
|
# errornote = "Your previous attempt has more key points than answer's required key points."
|
||||||
|
# println("\nERROR YiemAgent presentbox() $errornote --> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# continue
|
||||||
|
# elseif !all(is_requiredKeys_in_responsedictKey)
|
||||||
|
# zeroind = findall(x -> x == 0, is_requiredKeys_in_responsedictKey)
|
||||||
|
# missingkeys = [requiredKeys[i] for i in zeroind]
|
||||||
|
# errornote = "$missingkeys are missing from your previous response"
|
||||||
|
# println("\nERROR YiemAgent presentbox() $errornote --> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# continue
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # # check whether response has not-allowed words
|
||||||
|
# # notallowed = ["respond:", "user>", "user:"]
|
||||||
|
# # detected_kw = GeneralUtils.detect_keyword(notallowed, response)
|
||||||
|
# # # list all keys that have 1 value in detected_kw dictionary
|
||||||
|
# # k = [key for (key, value) in detected_kw if value == 1]
|
||||||
|
# # if length(k) > 0
|
||||||
|
# # errornote = "In your previous attempt, you have $k in your response which is not allowed."
|
||||||
|
# # println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# # continue
|
||||||
|
# # end
|
||||||
|
|
||||||
|
# # # check whether response has all header
|
||||||
|
# # detected_kw = GeneralUtils.detect_keyword(header, response)
|
||||||
|
# # if 0 ∈ values(detected_kw)
|
||||||
|
# # errornote = "$missingkeys are missing from your previous response"
|
||||||
|
# # println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# # continue
|
||||||
|
# # elseif sum(values(detected_kw)) > length(header)
|
||||||
|
# # errornote = "\nYour previous attempt has duplicated points according to the required response format"
|
||||||
|
# # println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# # continue
|
||||||
|
# # end
|
||||||
|
|
||||||
|
# # responsedict = GeneralUtils.textToDict(response, header;
|
||||||
|
# # dictKey=dictkey, symbolkey=true)
|
||||||
|
|
||||||
|
# # check if Context: is in dialogue
|
||||||
|
# if occursin("Context:", responsedict[:dialogue])
|
||||||
|
# errornote = "Your previous response contains 'Context:' which is not allowed"
|
||||||
|
# println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# continue
|
||||||
|
# end
|
||||||
|
|
||||||
|
# println("\nYiemAgent presentbox() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# pprintln(Dict(responsedict))
|
||||||
|
|
||||||
|
# # check whether an agent recommend wines before checking inventory or recommend wines
|
||||||
|
# # outside its inventory
|
||||||
|
# # ask LLM whether there are any winery mentioned in the response
|
||||||
|
# mentioned_winery = detectWineryName(a, responsedict[:dialogue])
|
||||||
|
# if mentioned_winery != "None"
|
||||||
|
# mentioned_winery = String.(strip.(split(mentioned_winery, ",")))
|
||||||
|
|
||||||
|
# # check whether the wine is in event
|
||||||
|
# isWineInEvent = false
|
||||||
|
# for winename in mentioned_winery
|
||||||
|
# for event in a.memory[:events]
|
||||||
|
# if event[:outcome] !== nothing && occursin(winename, event[:outcome])
|
||||||
|
# isWineInEvent = true
|
||||||
|
# break
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # if wine is mentioned but not in timeline or shortmem,
|
||||||
|
# # then the agent is not supposed to recommend the wine
|
||||||
|
# if isWineInEvent == false
|
||||||
|
# errornote = "Your previous response recommended wines that is not in your inventory which is not allowed"
|
||||||
|
# println("\nERROR YiemAgent presentbox() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# continue
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# result = responsedict[:dialogue]
|
||||||
|
# return result
|
||||||
|
# end
|
||||||
|
# error("presentbox() failed to generate a response")
|
||||||
|
# end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1547,7 +1733,7 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10)
|
|||||||
response = replace(response, '$' => "USD")
|
response = replace(response, '$' => "USD")
|
||||||
response = replace(response, '`' => "")
|
response = replace(response, '`' => "")
|
||||||
response = replace(response, "<|eot_id|>"=>"")
|
response = replace(response, "<|eot_id|>"=>"")
|
||||||
response = GeneralUtils.remove_french_accents(response)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1612,35 +1798,39 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function generatechat(a::companion; converPartnerName::Union{String, Nothing}=nothing, maxattempt=10)
|
function generatechat(a::companion; recentevents::Integer=10,
|
||||||
|
converPartnerName::Union{String, Nothing}=nothing, maxattempt=10)
|
||||||
|
|
||||||
|
recentchat_ind = GeneralUtils.recentElementsIndex(length(a.chathistory), recentevents;
|
||||||
|
includelatest=true);
|
||||||
|
recentchat = createChatLog(a.chathistory; index=recentchat_ind)
|
||||||
|
|
||||||
response = nothing # placeholder for show when error msg show up
|
response = nothing # placeholder for show when error msg show up
|
||||||
errornote = "N/A"
|
errornote = "N/A"
|
||||||
llmkwargs=Dict(
|
|
||||||
:num_ctx => 32768,
|
|
||||||
:temperature => 0.5,
|
|
||||||
)
|
|
||||||
for attempt in 1:maxattempt
|
for attempt in 1:maxattempt
|
||||||
if attempt > 1
|
if attempt > 1
|
||||||
println("\nYiemAgent generatechat() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
println("\nYiemAgent generatechat() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
end
|
end
|
||||||
|
|
||||||
systemmsg = a.systemmsg * "\nP.S. $errornote\n"
|
context =
|
||||||
_prompt =
|
"""
|
||||||
[
|
<context>
|
||||||
Dict(:name => "system", :text => systemmsg),
|
P.S. $errornote
|
||||||
]
|
</context>
|
||||||
for i in a.chathistory
|
"""
|
||||||
tempdict = Dict{Symbol, String}()
|
|
||||||
for j in keys(i)
|
|
||||||
if j ∉ [:timestamp]
|
|
||||||
tempdict[j] = i[j]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
_prompt = vcat(_prompt, tempdict)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
unformatPrompt =
|
||||||
|
[
|
||||||
|
Dict(:name => "system", :text => a.systemmsg),
|
||||||
|
]
|
||||||
|
|
||||||
|
unformatPrompt = vcat(unformatPrompt, recentchat)
|
||||||
# put in model format
|
# put in model format
|
||||||
_prompt = GeneralUtils.formatLLMtext(_prompt, a.llmFormatName)
|
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
|
||||||
|
# add info
|
||||||
|
prompt = prompt * context
|
||||||
|
|
||||||
|
|
||||||
# replace user and assistant with partner name
|
# replace user and assistant with partner name
|
||||||
prompt = replace(_prompt, "|>user"=>"|>$(converPartnerName)")
|
prompt = replace(_prompt, "|>user"=>"|>$(converPartnerName)")
|
||||||
@@ -1664,6 +1854,58 @@ function generatechat(a::companion; converPartnerName::Union{String, Nothing}=no
|
|||||||
end
|
end
|
||||||
error("generatechat failed to generate a response")
|
error("generatechat failed to generate a response")
|
||||||
end
|
end
|
||||||
|
# function generatechat(a::companion; converPartnerName::Union{String, Nothing}=nothing, maxattempt=10)
|
||||||
|
# response = nothing # placeholder for show when error msg show up
|
||||||
|
# errornote = "N/A"
|
||||||
|
# llmkwargs=Dict(
|
||||||
|
# :num_ctx => 32768,
|
||||||
|
# :temperature => 0.5,
|
||||||
|
# )
|
||||||
|
# for attempt in 1:maxattempt
|
||||||
|
# if attempt > 1
|
||||||
|
# println("\nYiemAgent generatechat() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# end
|
||||||
|
|
||||||
|
# systemmsg = a.systemmsg * "\nP.S. $errornote\n"
|
||||||
|
# _prompt =
|
||||||
|
# [
|
||||||
|
# Dict(:name => "system", :text => systemmsg),
|
||||||
|
# ]
|
||||||
|
# for i in a.chathistory
|
||||||
|
# tempdict = Dict{Symbol, String}()
|
||||||
|
# for j in keys(i)
|
||||||
|
# if j ∉ [:timestamp]
|
||||||
|
# tempdict[j] = i[j]
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# _prompt = vcat(_prompt, tempdict)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # put in model format
|
||||||
|
# _prompt = GeneralUtils.formatLLMtext(_prompt, a.llmFormatName)
|
||||||
|
|
||||||
|
# # replace user and assistant with partner name
|
||||||
|
# prompt = replace(_prompt, "|>user"=>"|>$(converPartnerName)")
|
||||||
|
# prompt = replace(prompt, "|>assistant"=>"|>$(a.name)")
|
||||||
|
|
||||||
|
# response = a.func[:text2textInstructLLM](prompt; llmkwargs=llmkwargs, senderId=a.id)
|
||||||
|
# response = replace(response, "<|im_start|>"=> "")
|
||||||
|
# response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
|
||||||
|
# think, response = GeneralUtils.extractthink(response)
|
||||||
|
|
||||||
|
# # check whether LLM just repeat the previous dialogue
|
||||||
|
# for msg in a.chathistory
|
||||||
|
# if msg[:text] == response
|
||||||
|
# errornote = "In your previous attempt, you repeated the previous dialogue. Please try again."
|
||||||
|
# println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
|
# continue
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# return response
|
||||||
|
# end
|
||||||
|
# error("generatechat failed to generate a response")
|
||||||
|
# end
|
||||||
|
|
||||||
|
|
||||||
# modify it to work with customer object
|
# modify it to work with customer object
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ function checkinventory(a::T1, input::T2
|
|||||||
|
|
||||||
println("\ncheckinventory result ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
println("\ncheckinventory result ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
println(textresult)
|
println(textresult)
|
||||||
|
#[PENDING] if there is no wine id, it is not a valid result
|
||||||
return (result=textresult, rawresponse=rawresponse, success=true, errormsg=nothing)
|
return (result=textresult, rawresponse=rawresponse, success=true, errormsg=nothing)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
49
src/util.jl
49
src/util.jl
@@ -297,20 +297,53 @@ function createTimeline(events::T1; eventindex::Union{UnitRange, Nothing}=nothin
|
|||||||
1:length(events)
|
1:length(events)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Iterate through events and format each one
|
#[WORKING] Iterate through events and format each one
|
||||||
for (i, event) in zip(ind, events)
|
for i in ind
|
||||||
|
event = events[i]
|
||||||
# If no outcome exists, format without outcome
|
# If no outcome exists, format without outcome
|
||||||
if event[:outcome] === nothing
|
# if event[:actionname] == "CHATBOX"
|
||||||
timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput]), observation: Not done yet.\n"
|
# timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput])\n"
|
||||||
|
# elseif event[:actionname] == "CHECKINVENTORY" && event[:outcome] === nothing
|
||||||
|
# timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput]), observation: Not done yet.\n"
|
||||||
# If outcome exists, include it in formatting
|
# If outcome exists, include it in formatting
|
||||||
else
|
if event[:actionname] == "CHECKINVENTORY"
|
||||||
timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput]), observation: $(event[:outcome])\n"
|
timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput]), observation: $(event[:outcome])\n"
|
||||||
|
else
|
||||||
|
timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput])\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return formatted timeline string
|
# Return formatted timeline string
|
||||||
return timeline
|
return timeline
|
||||||
end
|
end
|
||||||
|
# function createTimeline(events::T1; eventindex::Union{UnitRange, Nothing}=nothing
|
||||||
|
# ) where {T1<:AbstractVector}
|
||||||
|
# # Initialize empty timeline string
|
||||||
|
# timeline = ""
|
||||||
|
|
||||||
|
# # Determine which indices to use - either provided range or full length
|
||||||
|
# ind =
|
||||||
|
# if eventindex !== nothing
|
||||||
|
# [eventindex...]
|
||||||
|
# else
|
||||||
|
# 1:length(events)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # Iterate through events and format each one
|
||||||
|
# for i in ind
|
||||||
|
# event = events[i]
|
||||||
|
# # If no outcome exists, format without outcome
|
||||||
|
# if event[:outcome] === nothing
|
||||||
|
# timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput]), observation: Not done yet.\n"
|
||||||
|
# # If outcome exists, include it in formatting
|
||||||
|
# else
|
||||||
|
# timeline *= "Event_$i $(event[:subject])> action_name: $(event[:actionname]), action_input: $(event[:actioninput]), observation: $(event[:outcome])\n"
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # Return formatted timeline string
|
||||||
|
# return timeline
|
||||||
|
# end
|
||||||
|
|
||||||
|
|
||||||
function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing
|
function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing
|
||||||
@@ -327,7 +360,8 @@ function createEventsLog(events::T1; index::Union{UnitRange, Nothing}=nothing
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Iterate through events and format each one
|
# Iterate through events and format each one
|
||||||
for (i, event) in zip(ind, events)
|
for i in ind
|
||||||
|
event = events[i]
|
||||||
# If no outcome exists, format without outcome
|
# If no outcome exists, format without outcome
|
||||||
if event[:outcome] === nothing
|
if event[:outcome] === nothing
|
||||||
subject = event[:subject]
|
subject = event[:subject]
|
||||||
@@ -362,7 +396,8 @@ function createChatLog(chatdict::T1; index::Union{UnitRange, Nothing}=nothing
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Iterate through events and format each one
|
# Iterate through events and format each one
|
||||||
for (i, event) in zip(ind, chatdict)
|
for i in ind
|
||||||
|
event = chatdict[i]
|
||||||
subject = event[:name]
|
subject = event[:name]
|
||||||
text = event[:text]
|
text = event[:text]
|
||||||
d = Dict{Symbol, String}(:name=>subject, :text=>text)
|
d = Dict{Symbol, String}(:name=>subject, :text=>text)
|
||||||
|
|||||||
Reference in New Issue
Block a user