This commit is contained in:
narawat lamaiin
2025-05-17 12:18:25 +07:00
parent 3e79c0bfed
commit 68c2c2f12b
3 changed files with 133 additions and 91 deletions

View File

@@ -500,16 +500,24 @@ function extractWineAttributes_1(a::T1, input::T2; maxattempt=10
# responsedict = GeneralUtils.textToDict(response, header;
# dictKey=dictkey, symbolkey=true)
removekeys = [:thought, :tasting_notes, :occasion, :food_to_be_paired_with_wine, :vintage]
for i in removekeys
delete!(responsedict, i)
end
delete!(responsedict, :thought)
delete!(responsedict, :tasting_notes)
delete!(responsedict, :occasion)
delete!(responsedict, :food_to_be_paired_with_wine)
delete!(responsedict, :vintage)
# check if winery, wine_name, region, country, wine_type, grape_varietal's value are in the query because sometime AI halucinates
checkFlag = false
for i in requiredKeys
j = Symbol(i)
if j [:thought, :tasting_notes, :occasion, :food_to_be_paired_with_wine]
if j removekeys
# in case j is wine_price it needs to be checked differently because its value is ranged
if j == :wine_price
if responsedict[:wine_price] != "N/A"
@@ -592,7 +600,7 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2<
conversiontable =
"""
<Conversion Table>
<conversion_table>
Intensity level:
1 to 2: May correspond to "light-bodied" or a similar description.
2 to 3: May correspond to "med light bodied", "medium light" or a similar description.
@@ -617,16 +625,16 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2<
3 to 4: May correspond to "medium acidity" or a similar description.
4 to 5: May correspond to "semi high acidity" or a similar description.
4 to 5: May correspond to "high acidity" or a similar description.
</Conversion Table>
</conversion_table>
"""
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:
Conversion Table: ...
User's query: ...
At each round of conversation, you will be given the following information:
conversion_table: a conversion table that maps descriptive words to their corresponding integer levels
query: the words from the user's query that describe their preferences
The preference form requires the following information:
sweetness, acidity, tannin, intensity
@@ -637,86 +645,109 @@ function extractWineAttributes_2(a::T1, input::T2)::String where {T1<:agent, T2<
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:
Sweetness_keyword: The exact keywords in the user's query describing the sweetness level of the wine.
Sweetness: ( S ), where ( S ) represents integers indicating the range of sweetness levels. Example: 1-2
Acidity_keyword: The exact keywords in the user's query describing the acidity level of the wine.
Acidity: ( A ), where ( A ) represents integers indicating the range of acidity level. Example: 3-5
Tannin_keyword: The exact keywords in the user's query describing the tannin level of the wine.
Tannin: ( T ), where ( T ) represents integers indicating the range of tannin level. Example: 1-3
Intensity_keyword: The exact keywords in the user's query describing the intensity level of the wine.
Intensity: ( I ), where ( I ) represents integers indicating the range of intensity level. Example: 2-4
You should only respond in format as described below:
Sweetness_keyword: ...
Sweetness: ...
Acidity_keyword: ...
Acidity: ...
Tannin_keyword: ...
Tannin: ...
Intensity_keyword: ...
Intensity: ...
sweetness_keyword: The exact keywords in the user's query describing the sweetness level of the wine.
sweetness: ( S ), where ( S ) represents integers indicating the range of sweetness levels. Example: 1-2
acidity_keyword: The exact keywords in the user's query describing the acidity level of the wine.
acidity: ( A ), where ( A ) represents integers indicating the range of acidity level. Example: 3-5
tannin_keyword: The exact keywords in the user's query describing the tannin level of the wine.
tannin: ( T ), where ( T ) represents integers indicating the range of tannin level. Example: 1-3
intensity_keyword: The exact keywords in the user's query describing the intensity level of the wine.
intensity: ( I ), where ( I ) represents integers indicating the range of intensity level. Example: 2-4
You should only respond in JSON format as described below:
{
"sweetness_keyword": "...",
"sweetness": "...",
"acidity_keyword": "...",
"acidity": "...",
"tannin_keyword": "...",
"tannin": "...",
"intensity_keyword": "...",
"intensity": "..."
}
Here are some examples:
User's query: I want a wine with a medium-bodied, low acidity, medium tannin.
Sweetness_keyword: N/A
Sweetness: N/A
Acidity_keyword: low acidity
Acidity: 1-2
Tannin_keyword: medium tannin
Tannin: 3-4
Intensity_keyword: medium-bodied
Intensity: 3-4
{
"sweetness_keyword": "N/A",
"sweetness": "N/A",
"acidity_keyword": "low acidity",
"acidity": 1-2,
"tannin_keyword": "medium tannin",
"tannin": 3-4,
"intensity_keyword": "medium-bodied",
"intensity": 3-4
}
User's query: German red wine, under 100, pairs with spicy food
Sweetness_keyword: N/A
Sweetness: N/A
Acidity_keyword: N/A
Acidity: N/A
Tannin_keyword: N/A
Tannin: N/A
Intensity_keyword: N/A
Intensity: N/A
{
"sweetness_keyword": "N/A",
"sweetness": "N/A",
"acidity_keyword": "N/A",
"acidity": "N/A",
"tannin_keyword": "N/A",
"tannin": "N/A",
"intensity_keyword": "N/A",
"intensity": "N/A"
}
Let's begin!
"""
header = ["Sweetness_keyword:", "Sweetness:", "Acidity_keyword:", "Acidity:", "Tannin_keyword:", "Tannin:", "Intensity_keyword:", "Intensity:"]
dictkey = ["sweetness_keyword", "sweetness", "acidity_keyword", "acidity", "tannin_keyword", "tannin", "intensity_keyword", "intensity"]
requiredKeys = [:sweetness_keyword, :sweetness, :acidity_keyword, :acidity, :tannin_keyword, :tannin, :intensity_keyword, :intensity]
# header = ["Sweetness_keyword:", "Sweetness:", "Acidity_keyword:", "Acidity:", "Tannin_keyword:", "Tannin:", "Intensity_keyword:", "Intensity:"]
# dictkey = ["sweetness_keyword", "sweetness", "acidity_keyword", "acidity", "tannin_keyword", "tannin", "intensity_keyword", "intensity"]
errornote = "N/A"
for attempt in 1:10
usermsg =
context =
"""
$conversiontable
User's query: $input
<query>
$input
</query>
P.S. $errornote
/no_think
"""
_prompt =
unformatPrompt =
[
Dict(:name=> "system", :text=> systemmsg),
Dict(:name=> "user", :text=> usermsg)
]
# put in model format
prompt = GeneralUtils.formatLLMtext(_prompt, a.llmFormatName)
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
# add info
prompt = prompt * context
response = a.func[:text2textInstructLLM](prompt)
response = a.func[:text2textInstructLLM](prompt; modelsize="medium", senderId=a.id)
response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
response = GeneralUtils.remove_french_accents(response)
think, response = GeneralUtils.extractthink(response)
# check whether response has all answer's key points
detected_kw = GeneralUtils.detect_keyword(header, response)
if 0 values(detected_kw)
errornote = "In your previous attempt does not have all answer's key points"
println("\nERROR YiemAgent extractWineAttributes_2() Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
elseif sum(values(detected_kw)) > length(header)
errornote = "In your previous attempt has duplicated answer's key points"
println("\nERROR YiemAgent extractWineAttributes_2() Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
responsedict = nothing
try
responsedict = copy(JSON3.read(response))
catch
println("\nERROR YiemAgent extractWineAttributes_2() failed to parse response: $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
responsedict = GeneralUtils.textToDict(response, header;
dictKey=dictkey, symbolkey=true)
# 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 extractWineAttributes_2() $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 extractWineAttributes_2() $errornote --> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# check whether each describing keyword is in the input to prevent halucination
for i in ["sweetness", "acidity", "tannin", "intensity"]