This commit is contained in:
narawat lamaiin
2024-08-09 14:18:52 +07:00
parent 5228e2cfe1
commit debb7004d6
3 changed files with 269 additions and 117 deletions

View File

@@ -1,6 +1,6 @@
module llmfunction
export virtualWineUserChatbox, jsoncorrection, checkinventory,
export virtualWineUserChatbox, jsoncorrection, checkinventory, # recommendbox,
virtualWineUserRecommendbox, userChatbox, userRecommendbox
using HTTP, JSON3, URIs, Random, PrettyPrinting, UUIDs
@@ -319,8 +319,7 @@ julia>
# Signature
"""
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 =
"""
@@ -398,23 +397,28 @@ function extractWineAttributes_1(a::T1, input::T2
end
end
#[PENDING] check if grape_variety has more than 1 name
#[PENDING] check if the following attributes has more than 1 name
x = length(split(responsedict[:grape_variety], ",")) * length(split(responsedict[:grape_variety], "/"))
if x > 1
errornote = "only a single name in grape_variety is allowed"
errornote = "Note: You can put only one name in grape_variety."
error("only a single grape_variety name is allowed")
end
x = length(split(responsedict[:country], ",")) * length(split(responsedict[:country], "/"))
if x > 1
errornote = "only a single name in country is allowed"
errornote = "Note: You can put only one name in country."
error("only a single country name is allowed")
end
x = length(split(responsedict[:region], ",")) * length(split(responsedict[:region], "/"))
if x > 1
errornote = "only a single name in region is allowed"
errornote = "Note: You can put only one name in region."
error("only a single region name is allowed")
end
# check if grape_variety is mentioned in the input
if !occursin("NA", responsedict[:grape_variety]) && !occursin(responsedict[:grape_variety], input)
error("$(responsedict[:grape_variety]) is not mentioned in the input")
end
responsedict[:flavors] = replace(responsedict[:flavors], "notes"=>"")
delete!(responsedict, :reasoning)
delete!(responsedict, :tasting_notes)
@@ -457,8 +461,7 @@ end
# TODO
- [PENDING] "French dry white wines with medium bod" the LLM does not recognize sweetness. use LLM self questioning to solve.
"""
function extractWineAttributes_2(a::T1, input::T2
)::String where {T1<:agent, T2<:AbstractString}
function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2<:AbstractString}
conversiontable =
"""
@@ -622,6 +625,144 @@ function extractWineAttributes_2(a::T1, input::T2
end
# function recommendbox(a::T1, input::T2)::String where {T1<:agent, T2<:AbstractString}
# error("recommendbox")
# 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.
# At each round of conversation, the user will give you the current situation:
# User's query: ...
# The preference form requires the following information:
# wine_type, price, occasion, food_to_be_paired_with_wine, country, grape_variety, flavors, aromas.
# 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) Use the conversion table to convert the descriptive word level of sweetness, intensity, tannin, and acidity into a corresponding integer.
# 3) 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_type: Can be one of: "red", "white", "sparkling", "rose", "dessert" or "fortified"
# - price: Must be an integer representing the cost of the wine.
# - occasion: ...
# - food_to_be_paired_with_wine: food that the user will be served with wine
# - country: wine's country of origin
# - region: wine's region of origin such as Burgundy, Napa Valley
# - grape variety: a single name of grape used to make wine.
# - flavors: Names of items that the wine tastes like.
# - aromas: wine's aroma
# You should only respond in the form as described below:
# reasoning: ...
# wine_type: ...
# price: ...
# occasion: ...
# food_to_be_paired_with_wine: ...
# country: ...
# region: ...
# grape_variety: ...
# flavors: ...
# aromas: ...
# Let's begin!
# """
# attributes = ["reasoning", "wine_type", "price", "occasion", "food_to_be_paired_with_wine", "country", "region", "grape_variety", "flavors", "aromas"]
# errornote = ""
# for attempt in 1:5
# 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, "llama3instruct")
# prompt *=
# """
# <|start_header_id|>assistant<|end_header_id|>
# """
# try
# response = a.text2textInstructLLM(prompt)
# 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
# #[PENDING] check if the following attributes has more than 1 name
# x = length(split(responsedict[:grape_variety], ",")) * length(split(responsedict[:grape_variety], "/"))
# if x > 1
# errornote = "only a single name in grape_variety is allowed"
# error("only a single grape_variety name is allowed")
# end
# x = length(split(responsedict[:country], ",")) * length(split(responsedict[:country], "/"))
# if x > 1
# errornote = "only a single name in country is allowed"
# error("only a single country name is allowed")
# end
# x = length(split(responsedict[:region], ",")) * length(split(responsedict[:region], "/"))
# if x > 1
# errornote = "only a single name in region is allowed"
# error("only a single region name is allowed")
# end
# # check if grape_variety is mentioned in the input
# if responsedict[:grape_variety] != "NA" && !occursin(responsedict[:grape_variety], input)
# error("$(responsedict[:grape_variety]) is not mentioned in the input")
# end
# responsedict[:flavors] = replace(responsedict[:flavors], "notes"=>"")
# delete!(responsedict, :reasoning)
# delete!(responsedict, :tasting_notes)
# delete!(responsedict, :flavors)
# delete!(responsedict, :aromas)
# # 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")
# println("")
# end
# end
# error("wineattributes_wordToNumber() failed to get a response")
# end
""" Attemp to correct LLM response's incorrect JSON response.
@@ -711,7 +852,8 @@ function jsoncorrection(config::T1, input::T2, correctJsonExample::T3;
end
end
# [WORKING] check whether
# function isrecommend(state::T1, text2textInstructLLM::Function
# ) where {T1<:AbstractDict}