From 8fc3afe3483f7519daab553a94a84c3c9bb7ce52 Mon Sep 17 00:00:00 2001 From: tonaerospace Date: Thu, 20 Mar 2025 16:15:38 +0700 Subject: [PATCH] update --- src/interface.jl | 61 +++++++++++++++++----------- src/llmfunction.jl | 68 ++++++++++++++++++-------------- test/config.json | 62 +++++++++++++++++++---------- test/{runtest.jl => runtests.jl} | 6 +-- 4 files changed, 120 insertions(+), 77 deletions(-) rename test/{runtest.jl => runtests.jl} (98%) diff --git a/src/interface.jl b/src/interface.jl index 0b91c06..7d7b626 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -318,9 +318,10 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen continue end - responsedict = GeneralUtils.textToDict(response, - ["Understanding", "Reasoning", "Plan", "Action_name", "Action_input"], - rightmarker=":", symbolkey=true, lowercasekey=true) + header = ["Understanding:", "Reasoning:", "Plan:", "Action_name:", "Action_input:"] + dictkey = ["understanding", "reasoning", "plan", "action_name", "action_input"] + responsedict = GeneralUtils.textToDict(response, header; + dictKey=dictkey, symbolkey=true) if responsedict[:action_name] ∉ ["CHATBOX", "CHECKINVENTORY", "ENDCONVERSATION"] errornote = "You must use the given functions" @@ -999,6 +1000,9 @@ function generatechat(a::sommelier, thoughtDict) Let's begin! """ + header = ["Chat:"] + dictkey = ["chat"] + # a.memory[:shortmem][:available_wine] is a vector of dictionary context = if length(a.memory[:shortmem][:available_wine]) != 0 @@ -1054,22 +1058,27 @@ function generatechat(a::sommelier, thoughtDict) response = replace(response, '`' => "") response = replace(response, "<|eot_id|>"=>"") response = GeneralUtils.remove_french_accents(response) - responsedict = GeneralUtils.textToDict(response, ["Chat"], - rightmarker=":", symbolkey=true, lowercasekey=true) - for i ∈ [:chat] - if length(JSON3.write(responsedict[i])) == 0 - error("$i is empty ", Dates.now(), " ", @__FILE__, " ", @__LINE__) - end + # check whether response has all header + detected_kw = GeneralUtils.detect_keyword(header, response) + if sum(values(detected_kw)) < length(header) + errornote = "\nSQL decisionMaker() response does not have all header" + continue + elseif sum(values(detected_kw)) > length(header) + errornote = "\nSQL decisionMaker() response has duplicated header" + continue end - # check if there are more than 1 key per categories - for i ∈ [:chat] - matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i) - if length(matchkeys) > 1 - error("generatechat has more than one key per categories") - end - end + responsedict = GeneralUtils.textToDict(response, header; + dictKey=dictkey, symbolkey=true) + + # # check if there are more than 1 key per categories + # for i ∈ Symbol.(dictkey) + # matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i) + # if length(matchkeys) > 1 + # error("generatechat has more than one key per categories") + # end + # end # check if Context: is in chat if occursin("Context:", responsedict[:chat]) @@ -1385,9 +1394,10 @@ function generatequestion(a, text2textInstructLLM::Function; recent=nothing)::St error("no answer found in the response ", Dates.now(), " ", @__FILE__, " ", @__LINE__) end - responsedict = GeneralUtils.textToDict(response, - ["Understanding", "Q1"], - rightmarker=":", symbolkey=true, lowercasekey=true) + header = ["Understanding:", "Q1:"] + dictkey = ["understanding", "q1"] + responsedict = GeneralUtils.textToDict(response, header; + dictKey=dictkey, symbolkey=true) response = "Q1: " * responsedict[:q1] println("\n~~~ generatequestion ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(response) @@ -1469,9 +1479,10 @@ function generateSituationReport(a, text2textInstructLLM::Function; skiprecent:: """ response = text2textInstructLLM(prompt) - eventheader = ["Event_$i" for i in eachindex(a.memory[:events])] - responsedict = GeneralUtils.textToDict(response, eventheader, - rightmarker=":", symbolkey=true) + header = ["Event_$i:" for i in eachindex(a.memory[:events])] + dictkey = lowercase.(["Event_$i" for i in eachindex(a.memory[:events])]) + responsedict = GeneralUtils.textToDict(response, header; + dictKey=dictkey, symbolkey=true) println("\n~~~ generateSituationReport() ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(response) @@ -1530,8 +1541,10 @@ function detectWineryName(a, text) println("\n~~~ detectWineryName() ", Dates.now(), " ", @__FILE__, " ", @__LINE__) pprintln(response) - responsedict = GeneralUtils.textToDict(response, ["winery_names"], - rightmarker=":", symbolkey=true, lowercasekey=true) + header = ["Winery_names:"] + dictkey = ["winery_names"] + responsedict = GeneralUtils.textToDict(response, header; + dictKey=dictkey, symbolkey=true) result = responsedict[:winery_names] diff --git a/src/llmfunction.jl b/src/llmfunction.jl index cffc122..565fd13 100644 --- a/src/llmfunction.jl +++ b/src/llmfunction.jl @@ -326,7 +326,7 @@ julia> # TODO - [] update docstring - - [x] implement the function + - [WORKING] implement the function # Signature """ @@ -336,31 +336,41 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2< """ As a helpful sommelier, your task is to extract the user information from the user's query as much as possible to fill out user's preference form. - At each round of conversation, the user will give you the current situation: + At each round of conversation, the user will give you the following: User's query: ... You must follow the following guidelines: - 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. + - 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) Do not generate other comments. + - Do not generate other comments. - You should then respond to the user with the following points: - - reasoning: state your understanding of the current situation - - wine_name: name of the wine - - winery: name of the winery - - vintage: the year of the wine - - region: a region (NOT a country) where the wine is produced, such as Burgundy, Napa Valley, etc - - country: a country where the wine is produced. Can be "Austria", "Australia", "France", "Germany", "Italy", "Portugal", "Spain", "United States" - - wine_type: can be one of: "red", "white", "sparkling", "rose", "dessert" or "fortified" - - grape_varietal: the name of the primary grape used to make the wine - - tasting_notes: a brief description of the wine's taste, such as "butter", "oak", "fruity", etc - - wine_price: price range of wine. - - occasion: the occasion the user is having the wine for - - food_to_be_paired_with_wine: food that the user will be served with the wine such as poultry, fish, steak, etc - + You should then respond to the user with: + Comprehension: state your understanding of the current situation + Wine_name: name of the wine + Winery: name of the winery + Vintage: the year of the wine + Region: a region (NOT a country) where the wine is produced, such as Burgundy, Napa Valley, etc + Country: a country where the wine is produced. Can be "Austria", "Australia", "France", "Germany", "Italy", "Portugal", "Spain", "United States" + Wine_type: can be one of: "red", "white", "sparkling", "rose", "dessert" or "fortified" + Grape_varietal: the name of the primary grape used to make the wine + Tasting_notes: a brief description of the wine's taste, such as "butter", "oak", "fruity", etc + Wine_price: price range of wine. + Occasion: the occasion the user is having the wine for + Food_to_be_paired_with_wine: food that the user will be served with the wine such as poultry, fish, steak, etc - You should only respond in the user's preference form (JSON) as described below: - {"reasoning": ..., "winery": ..., "wine_name": ..., "vintage": ..., "region": ..., "country": ..., "wine_type": ..., "grape_varietal": ..., "tasting_notes": ..., "wine_price": ..., "occasion": ..., "food_to_be_paired_with_wine": ...} + You should only respond in format as described below: + Comprehension: ... + Wine_name: ... + Winery: ... + Vintage: ... + Region: ... + Country: ... + Wine_type: + Grape_varietal: ... + Tasting_notes: ... + Wine_price: ... + Occasion: ... + Food_to_be_paired_with_wine: ... Here are some example: User's query: red, Chenin Blanc, Riesling, 20 USD @@ -372,7 +382,9 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2< Let's begin! """ - attributes = ["reasoning", "winery", "wine_name", "vintage", "region", "country", "wine_type", "grape_varietal", "tasting_notes", "wine_price", "occasion", "food_to_be_paired_with_wine"] + attributes = + header = ["Comprehension:", "Wine_name:", "Winery:", "Vintage:", "Region:", "Country:", "Wine_type:", "Grape_varietal:", "Tasting_notes:", "Wine_price:", "Occasion:", "Food_to_be_paired_with_wine:"] + dictkey = ["comprehension", "wine_name", "winery", "vintage", "region", "country", "wine_type", "grape_varietal", "tasting_notes", "wine_price", "occasion", "food_to_be_paired_with_wine"] errornote = "" for attempt in 1:5 @@ -389,12 +401,7 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2< ] # put in model format - prompt = GeneralUtils.formatLLMtext(_prompt; formatname="llama3instruct") - prompt *= - """ - <|start_header_id|>assistant<|end_header_id|> - """ - + prompt = GeneralUtils.formatLLMtext(_prompt; formatname="qwen") response = a.func[:text2textInstructLLM](prompt) response = GeneralUtils.remove_french_accents(response) @@ -753,8 +760,11 @@ function paraphrase(text2textInstructLLM::Function, text::String) response = replace(response, '$' => "USD") response = replace(response, '`' => "") response = GeneralUtils.remove_french_accents(response) - responsedict = GeneralUtils.textToDict(response, ["Paraphrase"], - rightmarker=":", symbolkey=true, lowercasekey=true) + + header = ["Paraphrase:"] + dictkey = ["paraphrase"] + responsedict = GeneralUtils.textToDict(response, header; + dictKey=dictkey, symbolkey=true) for i ∈ [:paraphrase] if length(JSON3.write(responsedict[i])) == 0 diff --git a/test/config.json b/test/config.json index 7bf19e8..74c7a75 100644 --- a/test/config.json +++ b/test/config.json @@ -31,26 +31,46 @@ "description": "organization name" }, "externalservice": { - "text2textinstruct": { - "mqtttopic": "/loadbalancer/requestingservice", - "description": "text to text service with instruct LLM", - "llminfo": { - "name": "llama3instruct" - } - }, - "virtualWineCustomer_1": { - "mqtttopic": "/virtualenvironment/winecustomer", - "description": "text to text service with instruct LLM that act as wine customer", - "llminfo": { - "name": "llama3instruct" - } - }, - "text2textchat": { - "mqtttopic": "/loadbalancer/requestingservice", - "description": "text to text service with instruct LLM", - "llminfo": { - "name": "llama3instruct" - } - } + "loadbalancer": { + "mqtttopic": "/loadbalancer/requestingservice", + "description": "text to text service with instruct LLM" + }, + "text2textinstruct": { + "mqtttopic": "/loadbalancer/requestingservice", + "description": "text to text service with instruct LLM", + "llminfo": { + "name": "llama3instruct" + } + }, + "virtualWineCustomer_1": { + "mqtttopic": "/virtualenvironment/winecustomer", + "description": "text to text service with instruct LLM that act as wine customer", + "llminfo": { + "name": "llama3instruct" + } + }, + "text2textchat": { + "mqtttopic": "/loadbalancer/requestingservice", + "description": "text to text service with instruct LLM", + "llminfo": { + "name": "llama3instruct" + } + }, + "wineDB" : { + "description": "A wine database connection info for LibPQ client", + "host": "192.168.88.12", + "port": 10201, + "dbname": "wineDB", + "user": "yiemtechnologies", + "password": "yiemtechnologies@Postgres_0.0" + }, + "SQLVectorDB" : { + "description": "A wine database connection info for LibPQ client", + "host": "192.168.88.12", + "port": 10203, + "dbname": "SQLVectorDB", + "user": "yiemtechnologies", + "password": "yiemtechnologies@Postgres_0.0" + } } } \ No newline at end of file diff --git a/test/runtest.jl b/test/runtests.jl similarity index 98% rename from test/runtest.jl rename to test/runtests.jl index 524bfe6..4180407 100644 --- a/test/runtest.jl +++ b/test/runtests.jl @@ -8,7 +8,7 @@ using Base.Threads # load config -config = JSON3.read("./test/config.json") +config = JSON3.read("/appfolder/app/dev/YiemAgent/test/config.json") # config = copy(JSON3.read("../mountvolume/config.json")) @@ -32,7 +32,7 @@ function text2textInstructLLM(prompt::String) msgPurpose="inference", senderName="yiemagent", senderId=string(uuid4()), - receiverName="text2textinstruct", + receiverName="text2textinstruct_small", mqttBrokerAddress=config[:mqttServerInfo][:broker], mqttBrokerPort=config[:mqttServerInfo][:port], ) @@ -61,7 +61,7 @@ function getEmbedding(text::T) where {T<:AbstractString} msgPurpose="embedding", senderName="yiemagent", senderId=string(uuid4()), - receiverName="text2textinstruct", + receiverName="text2textinstruct_small", mqttBrokerAddress=config[:mqttServerInfo][:broker], mqttBrokerPort=config[:mqttServerInfo][:port], )