update
This commit is contained in:
@@ -318,14 +318,14 @@ function decisionMaker(a::T; recent::Integer=5)::Dict{Symbol,Any} where {T<:agen
|
|||||||
|
|
||||||
delete!(responsedict, :mentioned_winery)
|
delete!(responsedict, :mentioned_winery)
|
||||||
|
|
||||||
# cache decision dict into vectorDB, this should be after new message is added to a.memory[:events]
|
# #CHANGE cache decision dict into vectorDB, this should be after new message is added to a.memory[:events]
|
||||||
println("\n~~~ Do you want to cache decision dict? (y/n)")
|
# println("\n~~~ Do you want to cache decision dict? (y/n)")
|
||||||
user_answer = readline()
|
# user_answer = readline()
|
||||||
if user_answer == "y"
|
# if user_answer == "y"
|
||||||
timeline = timeline
|
# timeline = timeline
|
||||||
decisiondict = responsedict
|
# decisiondict = responsedict
|
||||||
a.func[:insertSommelierDecision](timeline, decisiondict)
|
# a.func[:insertSommelierDecision](timeline, decisiondict)
|
||||||
end
|
# end
|
||||||
|
|
||||||
return responsedict
|
return responsedict
|
||||||
catch e
|
catch e
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module llmfunction
|
module llmfunction
|
||||||
|
|
||||||
export virtualWineUserChatbox, jsoncorrection, checkinventory, # recommendbox,
|
export virtualWineUserChatbox, jsoncorrection, checkinventory, # recommendbox,
|
||||||
virtualWineUserRecommendbox, userChatbox, userRecommendbox
|
virtualWineUserRecommendbox, userChatbox, userRecommendbox, extractWineAttributes_1
|
||||||
|
|
||||||
using HTTP, JSON3, URIs, Random, PrettyPrinting, UUIDs, Dates
|
using HTTP, JSON3, URIs, Random, PrettyPrinting, UUIDs, Dates
|
||||||
using GeneralUtils, SQLLLM
|
using GeneralUtils, SQLLLM
|
||||||
@@ -300,7 +300,7 @@ function checkinventory(a::T1, input::T2
|
|||||||
# add suppport for similarSQLVectorDB
|
# add suppport for similarSQLVectorDB
|
||||||
textresult, rawresponse = SQLLLM.query(inventoryquery, a.func[:executeSQL],
|
textresult, rawresponse = SQLLLM.query(inventoryquery, a.func[:executeSQL],
|
||||||
a.func[:text2textInstructLLM],
|
a.func[:text2textInstructLLM],
|
||||||
addSQLVectorDB=a.func[:insertSQLVectorDB],
|
insertSQLVectorDB=a.func[:insertSQLVectorDB],
|
||||||
similarSQLVectorDB=a.func[:similarSQLVectorDB])
|
similarSQLVectorDB=a.func[:similarSQLVectorDB])
|
||||||
|
|
||||||
println("\n~~~ checkinventory result ", @__FILE__, " ", @__LINE__)
|
println("\n~~~ checkinventory result ", @__FILE__, " ", @__LINE__)
|
||||||
@@ -329,30 +329,203 @@ julia>
|
|||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
|
# function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<:AbstractString}
|
||||||
|
|
||||||
|
# systemmsg =
|
||||||
|
# """
|
||||||
|
# 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:
|
||||||
|
# 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.
|
||||||
|
# Additionally, words like 'any' or 'unlimited' mean no information is available.
|
||||||
|
# 2) 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 in 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_variety: 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 of wine. For example, up to 100, less than 100, 20 to 100, 30-79.95
|
||||||
|
# - 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 as described below:
|
||||||
|
# reasoning: ...
|
||||||
|
# winery: ...
|
||||||
|
# wine_name: ...
|
||||||
|
# vintage: ...
|
||||||
|
# region: ...
|
||||||
|
# country: ...
|
||||||
|
# wine_type: ...
|
||||||
|
# grape_variety: ...
|
||||||
|
# tasting_notes: ...
|
||||||
|
# wine_price: ...
|
||||||
|
# occasion: ...
|
||||||
|
# food_to_be_paired_with_wine: ...
|
||||||
|
|
||||||
|
# Here are some example:
|
||||||
|
# User's query: red, Chenin Blanc, Riesling, under 20
|
||||||
|
# reasoning: ...
|
||||||
|
# winery: NA
|
||||||
|
# wine_name: NA
|
||||||
|
# vintage: NA
|
||||||
|
# region: NA
|
||||||
|
# country: NA
|
||||||
|
# wine_type: red
|
||||||
|
# grape_variety: Chenin Blanc, Riesling
|
||||||
|
# tasting_notes: NA
|
||||||
|
# wine_price: under 20
|
||||||
|
# occasion: NA
|
||||||
|
# food_to_be_paired_with_wine: NA
|
||||||
|
|
||||||
|
# User's query: Domaine du Collier Saumur Blanc 2019, France, white, Chenin Blanc
|
||||||
|
# reasoning: ...
|
||||||
|
# winery: Domaine du Collier
|
||||||
|
# wine_name: Saumur Blanc
|
||||||
|
# vintage: 2019
|
||||||
|
# region: Saumur
|
||||||
|
# country: France
|
||||||
|
# wine_type: white
|
||||||
|
# grape_variety: Chenin Blanc
|
||||||
|
# tasting_notes: NA
|
||||||
|
# wine_price: 109
|
||||||
|
# occasion: NA
|
||||||
|
# food_to_be_paired_with_wine: NA
|
||||||
|
|
||||||
|
# Let's begin!
|
||||||
|
# """
|
||||||
|
|
||||||
|
# attributes = ["reasoning", "winery", "wine_name", "vintage", "region", "country", "wine_type", "grape_variety", "tasting_notes", "wine_price", "occasion", "food_to_be_paired_with_wine"]
|
||||||
|
# errornote = ""
|
||||||
|
# maxattempt = 5
|
||||||
|
# for attempt in 1:maxattempt
|
||||||
|
|
||||||
|
# usermsg =
|
||||||
|
# """
|
||||||
|
# User's query: $input
|
||||||
|
# $errornote
|
||||||
|
# """
|
||||||
|
|
||||||
|
# _prompt =
|
||||||
|
# [
|
||||||
|
# Dict(:name=> "system", :text=> systemmsg),
|
||||||
|
# Dict(:name=> "user", :text=> usermsg)
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# # put in model format
|
||||||
|
# prompt = GeneralUtils.formatLLMtext(_prompt; formatname="llama3instruct")
|
||||||
|
# prompt *=
|
||||||
|
# """
|
||||||
|
# <|start_header_id|>assistant<|end_header_id|>
|
||||||
|
# """
|
||||||
|
|
||||||
|
# try
|
||||||
|
# response = a.func[:text2textInstructLLM](prompt)
|
||||||
|
# response = GeneralUtils.remove_french_accents(response)
|
||||||
|
|
||||||
|
# # check wheter all attributes are in the response
|
||||||
|
# for word in attributes
|
||||||
|
# if !occursin(word, response)
|
||||||
|
# error("$word attribute is missing")
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# responsedict = GeneralUtils.textToDict(response, attributes, rightmarker=":", symbolkey=true)
|
||||||
|
|
||||||
|
# for i ∈ attributes
|
||||||
|
# if length(JSON3.write(responsedict[Symbol(i)])) == 0
|
||||||
|
# error("$i is empty ", @__LINE__)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# #check if the following attributes has more than 1 name
|
||||||
|
# # responsedict[:grape_variety] = split(responsedict[:grape_variety], ',')[1]
|
||||||
|
# # responsedict[:grape_variety] = split(responsedict[:grape_variety], '/')[1]
|
||||||
|
|
||||||
|
# responsedict[:country] = split(responsedict[:country], ',')[1]
|
||||||
|
# responsedict[:country] = split(responsedict[:country], '/')[1]
|
||||||
|
|
||||||
|
# responsedict[:region] = split(responsedict[:region], ',')[1]
|
||||||
|
# responsedict[:region] = split(responsedict[:region], '/')[1]
|
||||||
|
|
||||||
|
# delete!(responsedict, :reasoning)
|
||||||
|
# delete!(responsedict, :tasting_notes)
|
||||||
|
# delete!(responsedict, :occasion)
|
||||||
|
# delete!(responsedict, :food_to_be_paired_with_wine)
|
||||||
|
|
||||||
|
# # check if winery, wine_name, region, country, wine_type, grape_variety are in the query because sometime AI halucinates
|
||||||
|
# for i in [:grape_variety, :winery, :wine_name, :region]
|
||||||
|
# result = check_key_in_input(input, responsedict, attempt, maxattempt, i)
|
||||||
|
# if result === nothing
|
||||||
|
# # nothing wrong
|
||||||
|
# elseif result == "NA"
|
||||||
|
# responsedict[i] = "NA"
|
||||||
|
# else
|
||||||
|
# errornote = result
|
||||||
|
# error(errornote)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # remove (some text)
|
||||||
|
# for (k, v) in responsedict
|
||||||
|
# _v = replace(v, r"\(.*?\)" => "")
|
||||||
|
# responsedict[k] = _v
|
||||||
|
# end
|
||||||
|
|
||||||
|
# result = ""
|
||||||
|
# for (k, v) in responsedict
|
||||||
|
# # some time LLM generate text with "(some comment)". this line removes it
|
||||||
|
# if !occursin("NA", v) && v != "" && !occursin("none", v) && !occursin("None", v)
|
||||||
|
# result *= "$k: $v, "
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# #[PENDING] remove halucination. "highend dry white wine" --> "wine_type: white, occasion: special occasion, food_to_be_paired_with_wine: seafood, fish, country: France, Italy, USA, grape_variety: Chardonnay, Sauvignon Blanc, Pinot Grigio\nwine_notes: citrus, green apple, floral"
|
||||||
|
|
||||||
|
# result = result[1:end-2] # remove the ending ", "
|
||||||
|
|
||||||
|
# return result
|
||||||
|
# catch e
|
||||||
|
# io = IOBuffer()
|
||||||
|
# showerror(io, e)
|
||||||
|
# errorMsg = String(take!(io))
|
||||||
|
# st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
|
||||||
|
# println("")
|
||||||
|
# println("Attempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__)
|
||||||
|
# println("")
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# error("wineattributes_wordToNumber() failed to get a response")
|
||||||
|
# end
|
||||||
function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<:AbstractString}
|
function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<:AbstractString}
|
||||||
|
|
||||||
systemmsg =
|
systemmsg =
|
||||||
"""
|
"""
|
||||||
As an helpful sommelier, your task is to fill out the user's preference form based on the corresponding words from the user's query.
|
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 current situation:
|
||||||
User's query: ...
|
User's query: ...
|
||||||
|
|
||||||
The preference form requires the following information:
|
|
||||||
wine_type, price, occasion, food_to_be_paired_with_wine, region, country, grape_variety, flavors, aromas.
|
|
||||||
|
|
||||||
You must follow the following guidelines:
|
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.
|
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.
|
||||||
Additionally, words like 'any' or 'unlimited' mean no information is available.
|
Additionally, words like 'any' or 'unlimited' mean no information is available.
|
||||||
2) Use the conversion table to convert the descriptive word level of sweetness, intensity, tannin, and acidity into a corresponding integer.
|
2) Do not generate other comments.
|
||||||
3) Do not generate other comments.
|
|
||||||
|
|
||||||
You should then respond to the user with the following points:
|
You should then respond to the user with the following points:
|
||||||
- reasoning: state your understanding of the current situation
|
- reasoning: state your understanding of the current situation
|
||||||
- wine_name: name of the wine
|
- wine_name: name of the wine
|
||||||
- winery: name of the winery
|
- winery: name of the winery
|
||||||
- vintage: the year of the wine
|
- vintage: the year of the wine
|
||||||
- region: a region in a country where the wine is produced, such as Burgundy, Napa Valley, etc
|
- 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"
|
- 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"
|
- wine_type: can be one of: "red", "white", "sparkling", "rose", "dessert" or "fortified"
|
||||||
- grape_variety: the name of the primary grape used to make the wine
|
- grape_variety: the name of the primary grape used to make the wine
|
||||||
@@ -362,33 +535,15 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<
|
|||||||
- food_to_be_paired_with_wine: food that the user will be served with the wine such as poultry, fish, steak, etc
|
- 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 form as described below:
|
You should only respond in the user's preference form (JSON) as described below:
|
||||||
reasoning: ...
|
{"reasoning": ..., "winery": ..., "wine_name": ..., "vintage": ..., "region": ..., "country": ..., "wine_type": ..., "grape_variety": ..., "tasting_notes": ..., "wine_price": ..., "occasion": ..., "food_to_be_paired_with_wine": ...}
|
||||||
winery: ...
|
|
||||||
wine_name: ...
|
|
||||||
vintage: ...
|
|
||||||
region: ...
|
|
||||||
country: ...
|
|
||||||
wine_type: ...
|
|
||||||
grape_variety: ...
|
|
||||||
tasting_notes: ...
|
|
||||||
wine_price: ...
|
|
||||||
occasion: ...
|
|
||||||
food_to_be_paired_with_wine: ...
|
|
||||||
|
|
||||||
Here are some example:
|
Here are some example:
|
||||||
reasoning: ...
|
User's query: red, Chenin Blanc, Riesling, under 20
|
||||||
winery: Domaine du Collier
|
{"reasoning": ..., "winery": "NA", "wine_name": "NA", "vintage": "NA", "region": "NA", "country": "NA", "wine_type": "red", "grape_variety": "Chenin Blanc, Riesling", "tasting_notes": "NA", "wine_price": "under 20", "occasion": "NA", "food_to_be_paired_with_wine": "NA"}
|
||||||
wine_name: Saumur Blanc
|
|
||||||
vintage: 2019
|
User's query: Domaine du Collier Saumur Blanc 2019, France, white, Chenin Blanc
|
||||||
region: Saumur
|
{"reasoning": ..., "winery": "Domaine du Collier", "wine_name": "Saumur Blanc", "vintage": "2019", "region": "Saumur", "country": "France", "wine_type": "white", "grape_variety": "Chenin Blanc", "tasting_notes": "NA", "wine_price": "109", "occasion": "NA", "food_to_be_paired_with_wine": "NA"}
|
||||||
country: France
|
|
||||||
wine_type: white
|
|
||||||
grape_variety: Chenin Blanc
|
|
||||||
tasting_notes: NA
|
|
||||||
wine_price: 109
|
|
||||||
occasion: NA
|
|
||||||
food_to_be_paired_with_wine: NA
|
|
||||||
|
|
||||||
Let's begin!
|
Let's begin!
|
||||||
"""
|
"""
|
||||||
@@ -428,23 +583,7 @@ function extractWineAttributes_1(a::T1, input::T2)::String where {T1<:agent, T2<
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
responsedict = GeneralUtils.textToDict(response, attributes, rightmarker=":", symbolkey=true)
|
responsedict = copy(JSON3.read(response))
|
||||||
|
|
||||||
for i ∈ attributes
|
|
||||||
if length(JSON3.write(responsedict[Symbol(i)])) == 0
|
|
||||||
error("$i is empty ", @__LINE__)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#check if the following attributes has more than 1 name
|
|
||||||
responsedict[:grape_variety] = split(responsedict[:grape_variety], ',')[1]
|
|
||||||
responsedict[:grape_variety] = split(responsedict[:grape_variety], '/')[1]
|
|
||||||
|
|
||||||
responsedict[:country] = split(responsedict[:country], ',')[1]
|
|
||||||
responsedict[:country] = split(responsedict[:country], '/')[1]
|
|
||||||
|
|
||||||
responsedict[:region] = split(responsedict[:region], ',')[1]
|
|
||||||
responsedict[:region] = split(responsedict[:region], '/')[1]
|
|
||||||
|
|
||||||
delete!(responsedict, :reasoning)
|
delete!(responsedict, :reasoning)
|
||||||
delete!(responsedict, :tasting_notes)
|
delete!(responsedict, :tasting_notes)
|
||||||
|
|||||||
Reference in New Issue
Block a user