This commit is contained in:
narawat lamaiin
2024-05-31 11:47:43 +07:00
parent 3f38fdbb70
commit 3196842296
17 changed files with 5607 additions and 179 deletions

View File

@@ -0,0 +1,159 @@
using Revise
using YiemAgent, GeneralUtils, JSON3, DataStructures
thoughtDict = OrderedDict(
:Question=> "Hello, I would like a get a bottle of wine",
:Thought_1=> "The customer wants to buy a bottle of wine, but we need more information about their preferences.",
:Action_1=> Dict(
:name=> "chatbox",
:input=> "What occasion are you buying the wine for?",
),
:Observation_1=> "We are having a wedding pary this weekend.",
:Thought_2=> "A wedding party is a great occasion to have a good bottle of wine.",
:Action_2=> Dict(
:name=> "chatbox",
:input=> "What type of food will you be serving with the wine?",
),
:Observation_2=> "I think it is Thai dishes",
:Thought_3=> "Now that I know the occasion and food, I need to ask about the budget.",
:Action_3=> Dict(
:name=> "chatbox",
:input=> "What is your budget for this wine?",
),
:Observation_3=> "50 bucks",
:Thought_4=> "With a budget of \$50, we have a wide range of options. Now that I know it's a wedding party and Thai dishes, I need to ask about the type of wine they prefer.",
:Action_4=> Dict(
:name=> "chatbox",
:input=> "What type of wine are you looking for? (Red, White, Sparkling, Rose, Dessert, Fortified)",
),
:Observation_4=> "Sparkling please.",
:Thought_5=> "Now that I know the occasion, food, budget and preferred type of wine, it's time to check our inventory for the best matching wine.",
:Action_5=> Dict(
:name=> "winestock",
:input=> "wine with budget \$50, Thai dishes, sparkling, wedding party",
),
:Observation_5=> "I found the following wine in stock {1 : Zena Crown Vista, 2 : Schrader Cabernet Sauvignon}",
:Thought_6=> "Now that I have all the information, it's time to recommend a wine that fits their preferences.",
:Action_6=> Dict(
:name=> "recommendation",
:input=> "I recommend Zena Crown Vista for its sparkling and affordable price.",
),
:Observation_6=> "I don't like it. Do you have another option?",
)
_thoughtJsonStr = JSON3.write(thoughtDict)
thoughtJsonStr = _thoughtJsonStr[1:end-1] # remove } at the end
# @show thoughtJsonStr
_, latestThoughtIndice = GeneralUtils.findHighestIndexKey(thoughtDict, "Thought")
nextThoughtIndice = latestThoughtIndice + 1
_prompt =
"""
You are a helpful sommelier working for a wine store.
Your goal is to reccommend the best wine from your inventory that match the user preferences.
You must follow the following criteria:
1) Get to know what occasion the user is buying wine for
2) Get to know what food the user will have with wine
3) Get to know how much the user willing to spend
4) Get to know type of wine the user is looking for e.g. Red, White, Sparkling, Rose, Dessert, Fortified
5) Get to know what characteristics of wine the user is looking for
e.g. tannin, sweetness, intensity, acidity
6) Check your inventory for the best wine that match the user preference
7) Recommend wine to the user
You should only respond with interleaving Thought, Action, Observation steps.
Thought can reason about the current situation, and Action can be three types:
1) winestock[query], which you can use to find wine in your inventory. The more input data the better.
2) chatbox[text], which you can use to interact with the user.
3) recommendation[answer], which returns your wine reccommendation to the user.
You should only respond in JSON format as describe below:
{
"Thought": "your reasoning",
"Action": {"name": "action to take", "input": "Action input"},
"Observation": "result of the action"
}
Here are some examples:
{
"Question": "I would like to buy a sedan with 8 seats.",
"Thought_1": "Our showroom carries various vehicle model. But I'm not sure whether we have a models that fits the user demand, I need to check our inventory.",
"Action_1": {"name": "inventory", "input": "sedan with 8 seats."},
"Observation_1": "Several model has 8 seats. Available color are black, red green"
}
{
"Thought_2": "I have to ask the user what color he likes.",
"Action_2": {"name": "chatbox", "input": "Which color do you like?"}
"Observation_2": "I'll take black."
}
{
"Thought_3": "There is only one model that fits the user preference. It's Yiem model A",
"Action_3": {"name": "recommendation", "input": "I recommend a Yiem model A"}
}
Let's begin!
$(JSON3.write(thoughtDict))
{Thought_$nextThoughtIndice
"""
prompt = YiemAgent.formatLLMtext_llama3instruct("system", _prompt)
@show prompt
msgMeta = Dict(:requestResponse => nothing,
:msgPurpose => nothing,
:receiverId => nothing,
:getPost => nothing,
:msgId => "4c7111e0-c30e-44c3-8f85-1c8b3f03a8be",
:acknowledgestatus => nothing,
:replyToMsgId => nothing,
:msgFormatVersion => nothing,
:mqttServerInfo => Dict(:port => 1883, :broker => "mqtt.yiem.cc"),
:sendTopic => "/loadbalancer/requestingservice",
:receiverName => "text2textinstruct",
:replyTopic => nothing,
:senderName => "decisionMaker",
:senderSelfnote => nothing,
:senderId => "testingSessionID",
:timeStamp => "2024-05-04T08:06:23.561"
)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> prompt,
)
)
_response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
thoughtJsonStr = _response[:response][:text]

View File

@@ -0,0 +1,87 @@
using Revise # remove when this package is completed
using YiemAgent, GeneralUtils, JSON3, MQTTClient, Dates, UUIDs, DataStructures
using Base.Threads
# ---------------------------------------------- 100 --------------------------------------------- #
config = copy(JSON3.read("config.json"))
instanceInternalTopic = config[:serviceInternalTopic][:mqtttopic] * "/1"
client, connection = MakeConnection(config[:mqttServerInfo][:broker],
config[:mqttServerInfo][:port])
receiveUserMsgChannel = Channel{Dict}(4)
receiveInternalMsgChannel = Channel{Dict}(4)
msgMeta = GeneralUtils.generate_msgMeta(
"N/A",
replyTopic = config[:servicetopic][:mqtttopic] # ask frontend reply to this instance_chat_topic
)
agentConfig = Dict(
:mqttServerInfo=> config[:mqttServerInfo],
:receivemsg=> Dict(
:prompt=> config[:servicetopic][:mqtttopic], # topic to receive prompt i.e. frontend send msg to this topic
:internal=> instanceInternalTopic,
),
:externalservice=> config[:externalservice],
)
# Instantiate an agent
tools=Dict( # update input format
"askbox"=> Dict(
:description => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>",
:input => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""",
:output => "" ,
:func => nothing,
),
# "winestock"=> Dict(
# :description => "<winestock tool description>A handy tool for searching wine in your inventory that match the user preferences.</winestock tool description>",
# :input => """<input>Input is a JSON-formatted string that contains a detailed and precise search query.</input><input example>{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}</input example>""",
# :output => """<output>Output are wines that match the search query in JSON format.""",
# :func => ChatAgent.winestock,
# ),
"finalanswer"=> Dict(
:description => "<tool description>Useful for when you are ready to recommend wines to the user.</tool description>",
:input => """<input format>{\"finalanswer\": \"some text\"}.</input format><input example>{\"finalanswer\": \"I recommend Zena Crown Vista\"}</input example>""",
:output => "" ,
:func => nothing,
),
)
a = YiemAgent.sommelier(
receiveUserMsgChannel,
receiveInternalMsgChannel,
agentConfig,
name= "assistant",
id= "testingSessionID", # agent instance id
tools=tools,
)
input =
OrderedDict{Symbol, Any}(:question => "Hello, I would like a get a bottle of wine", :thought_1 => "It's great that the user is looking for a bottle of wine. To give them a personalized recommendation, I need to know more about their preferences.", :action_1 => Dict{Symbol, Any}(:name => "chatbox", :input => "What occasion are you planning to use this wine for?"), :observation_1 => "We are holding a wedding party", :thought_2 => "A wedding party is a great occasion for a special bottle of wine. I need to know what type of food will be served, and how much the user is willing to spend.", :action_2 => Dict{Symbol, Any}(:name => "chatbox", :input => "What type of food will you be serving at the wedding?"), :observation_2 => "It will be Thai dishes.", :thought_3 => "The type of wine that pairs well with Thai dishes is usually a crisp and refreshing white wine, but I also need to consider the budget and personal preferences.", :action_3 => Dict{Symbol, Any}(:name => "chatbox", :input => "How much are you willing to spend on this bottle of wine?"), :observation_3 => "I would spend up to 50 bucks.", :thought_4 => "I have a good idea of the occasion, food, and budget. Now I need to know what type of wine the user is looking for.", :action_4 => Dict{Symbol, Any}(:name => "chatbox", :input => "What type of wine are you usually looking for? Red, White, Sparkling, Rose, Dessert or Fortified?"), :observation_4 => "I like full-bodied Red wine with low tannin.", :thought_5 => "Now that I have all the necessary information, I can start searching for a suitable wine in our inventory.", :action_5 => Dict{Symbol, Any}(:name => "winestock", :input => "red wine with low tannins"), :observation_5 => "I found the following wines in our stock: \n{\n 1: El Enemigo Cabernet Franc 2019\n2: Tantara Chardonnay 2017\n\n}\n", :thought_6 => "Now that I have the information about the wine, it's time to make a recommendation.", :action_6 => Dict{Symbol, Any}(:name => "recommendbox", :input => "El Enemigo Cabernet Franc 2019"), :observation_6 => "I don't like the one you recommend. I want dry wine.")
result = YiemAgent.jsoncorrection(a, input)

View File

@@ -0,0 +1,112 @@
using Revise # remove when this package is completed
using YiemAgent, GeneralUtils, JSON3, MQTTClient, Dates, UUIDs
using Base.Threads
# ---------------------------------------------- 100 --------------------------------------------- #
config = copy(JSON3.read("config.json"))
instanceInternalTopic = config[:serviceInternalTopic][:mqtttopic] * "/1"
client, connection = MakeConnection(config[:mqttServerInfo][:broker],
config[:mqttServerInfo][:port])
receiveUserMsgChannel = Channel{Dict}(4)
receiveInternalMsgChannel = Channel{Dict}(4)
msgMeta = GeneralUtils.generate_msgMeta(
"N/A",
replyTopic = config[:servicetopic][:mqtttopic] # ask frontend reply to this instance_chat_topic
)
agentConfig = Dict(
:mqttServerInfo=> config[:mqttServerInfo],
:receivemsg=> Dict(
:prompt=> config[:servicetopic][:mqtttopic], # topic to receive prompt i.e. frontend send msg to this topic
:internal=> instanceInternalTopic,
),
:externalservice=> config[:externalservice],
)
# Instantiate an agent
tools=Dict( # update input format
"askbox"=> Dict(
:description => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>",
:input => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""",
:output => "" ,
:func => nothing,
),
# "winestock"=> Dict(
# :description => "<winestock tool description>A handy tool for searching wine in your inventory that match the user preferences.</winestock tool description>",
# :input => """<input>Input is a JSON-formatted string that contains a detailed and precise search query.</input><input example>{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}</input example>""",
# :output => """<output>Output are wines that match the search query in JSON format.""",
# :func => ChatAgent.winestock,
# ),
"finalanswer"=> Dict(
:description => "<tool description>Useful for when you are ready to recommend wines to the user.</tool description>",
:input => """<input format>{\"finalanswer\": \"some text\"}.</input format><input example>{\"finalanswer\": \"I recommend Zena Crown Vista\"}</input example>""",
:output => "" ,
:func => nothing,
),
)
a = YiemAgent.sommelier(
agentConfig,
name="assistant",
id="testingSessionID", # agent instance id
tools=tools,
)
# response = YiemAgent.conversation(a, Dict(:text=> "newtopic",) )
response = YiemAgent.conversation(a, Dict(:text=> "Hello, I would like a get a bottle of wine",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
) )
println("---> YiemAgent: ", response)
#BUG mcts do not start at current chat history
response = YiemAgent.conversation(a, Dict(:text=> "I'm having a graduation party this evening. I'll pay at most 30 bucks.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
) )
println("---> YiemAgent: ", response)
dummyinput = "price below 50, full-bodied red wine with sweetness level 2, low tannin level and medium acidity level, Thai dishes"
response = YiemAgent.winestock(a, dummyinput)
"""
Write me SQL command to search the database for wines that fits: {"wine_type": "red","sweetness": 2,"acidity": 3,"tannin": 1,"intensity": 5}
"""
mctsparam = Dict{Symbol, Any}()

View File

@@ -0,0 +1,190 @@
using Revise
using YiemAgent, GeneralUtils, JSON3, DataStructures
# ---------------------------------------------- 100 --------------------------------------------- #
msgMeta = Dict(:requestResponse => nothing,
:msgPurpose => nothing,
:receiverId => nothing,
:getPost => nothing,
:msgId => "4c7111e0-c30e-44c3-8f85-1c8b3f03a8be",
:acknowledgestatus => nothing,
:replyToMsgId => "dummyid",
:msgFormatVersion => nothing,
:mqttServerInfo => Dict(:port => 1883, :broker => "mqtt.yiem.cc"),
:sendTopic => "/testingSessionID",
:receiverName => "wineassistant",
:replyTopic => nothing,
:senderName => "test_1",
:senderSelfnote => nothing,
:senderId => nothing,
:timeStamp => "2024-05-04T08:06:23.561"
)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "We are holding a wedding party",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "It will be Thai dishes.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "I would spend up to 50 bucks.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "I like dry, full-bodied red wine with low tannin.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "What do you have?",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "Dry wine please.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "You did not gave me any choice.",
:select=> nothing,
:reward=> -1,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "You don't need to ask me. Just tell me already!",
:select=> nothing,
:reward=> -1,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "I like dry wine with fruity flavors.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "OK, I'll take it.",
:select=> 1,
:reward=> 1,
:isterminal=> true,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "Yes.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> "I like dry wine with medium acidity.",
:select=> nothing,
:reward=> 0,
:isterminal=> false,
)
)
result = GeneralUtils.sendMqttMsg(outgoingMsg)

View File

@@ -0,0 +1,130 @@
using Revise # remove when this package is completed
using YiemAgent, GeneralUtils, JSON3, MQTTClient, Dates, UUIDs, DataStructures
using Base.Threads
# ---------------------------------------------- 100 --------------------------------------------- #
config = copy(JSON3.read("config.json"))
instanceInternalTopic = config[:serviceInternalTopic][:mqtttopic] * "/1"
client, connection = MakeConnection(config[:mqttServerInfo][:broker],
config[:mqttServerInfo][:port])
receiveUserMsgChannel = Channel{Dict}(4)
receiveInternalMsgChannel = Channel{Dict}(4)
msgMeta = GeneralUtils.generate_msgMeta(
"N/A",
replyTopic = config[:servicetopic][:mqtttopic] # ask frontend reply to this instance_chat_topic
)
agentConfig = Dict(
:mqttServerInfo=> config[:mqttServerInfo],
:receivemsg=> Dict(
:prompt=> config[:servicetopic][:mqtttopic], # topic to receive prompt i.e. frontend send msg to this topic
:internal=> instanceInternalTopic,
),
:externalservice=> config[:externalservice],
)
# Instantiate an agent
tools=Dict( # update input format
"askbox"=> Dict(
:description => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>",
:input => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""",
:output => "" ,
:func => nothing,
),
# "winestock"=> Dict(
# :description => "<winestock tool description>A handy tool for searching wine in your inventory that match the user preferences.</winestock tool description>",
# :input => """<input>Input is a JSON-formatted string that contains a detailed and precise search query.</input><input example>{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}</input example>""",
# :output => """<output>Output are wines that match the search query in JSON format.""",
# :func => ChatAgent.winestock,
# ),
"finalanswer"=> Dict(
:description => "<tool description>Useful for when you are ready to recommend wines to the user.</tool description>",
:input => """<input format>{\"finalanswer\": \"some text\"}.</input format><input example>{\"finalanswer\": \"I recommend Zena Crown Vista\"}</input example>""",
:output => "" ,
:func => nothing,
),
)
a = YiemAgent.sommelier(
receiveUserMsgChannel,
receiveInternalMsgChannel,
agentConfig,
name= "assistant",
id= "testingSessionID", # agent instance id
tools=tools,
)
input =
OrderedDict{Symbol, Any}(
:question => "Hello, I would like a get a bottle of wine",
:thought_1 => "A customer wants to buy a bottle of wine. Before making a recommendation, I need to know more about their preferences.",
:action_1 => Dict{Symbol, Any}(
:name => "chatbox",
:input => "What is the occasion for which you're buying this wine?"
),
:observation_1 => "We are holding a wedding party",
:thought_2 => "A wedding party, that's a great occasion! The customer might be looking for a celebratory drink. Let me ask some more questions to narrow down the options.",
:action_2 => Dict{Symbol, Any}(
:name => "chatbox",
:input => "What type of food will you be serving at the wedding?"
),
:observation_2 => "It will be Thai dishes.",
:thought_3 => "With Thai food, I should recommend a wine that complements its spicy and savory flavors. And since it's a celebratory occasion, the customer might prefer a full-bodied wine.",
:action_3 => Dict{Symbol, Any}(
:name => "chatbox",
:input => "What is your budget for this bottle of wine?"
),
:observation_3 => "I would spend up to 50 bucks.",
:thought_4 => "Now that I have some more information, it's time to narrow down the options.",
:action_4 => Dict{Symbol, Any}(
:name => "winestock",
:input => "red wine with full body, pairs well with spicy food, budget \$50"),
:observation_4 => "I found the following wines in our stock: \n{\n 1: El Enemigo Cabernet Franc 2019\n2: Tantara Chardonnay 2017\n\n}\n",
:thought_5 => "Now that I have a list of potential wines, I need to know more about the customer's taste preferences.",
:action_5 => Dict{Symbol, Any}(
:name => "chatbox",
:input => "What type of wine characteristics are you looking for? (e.g. t.e.g. tannin level, sweetness, intensity, acidity)"
),
:observation_5 => "I like full-bodied Red wine with low tannin.",
:thought_6 => "Now that I have more information about the customer's preferences, it's time to make a recommendation.",
:action_6 => Dict{Symbol, Any}(
:name => "recommendbox",
:input => "El Enemigo Cabernet Franc 2019"
),
:observation_6 => "I don't like the one you recommend. I want dry wine."
)
result = YiemAgent.reflector(a, input)