Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a3ab288cfe | |||
| 17b0974d82 | |||
| 8fed0b5e8f | |||
| 567d6b79d7 | |||
| 74be3e5717 | |||
| 402b6fcadd | |||
| ef523aaa48 | |||
| ddbb135b6b | |||
| afda364484 | |||
| af73d955eb | |||
| 39cf9a72a1 | |||
| 1c829ad854 | |||
| da98baddb6 | |||
| c5fbaabf42 | |||
| 8080905bad | |||
| b349c3a8b6 | |||
| 0148e03d6a | |||
| e718cc4a5c | |||
| 87bc6a46a1 | |||
| 44bb8baf7c | |||
| 18b2d54ba7 | |||
| b3c3bb9b75 | |||
| d004193b19 | |||
| 8898226825 | |||
| 686b9b2e92 | |||
| 3acf46964b | |||
| 5c7caf0b49 | |||
| ad917ea8d0 | |||
| edeef4ed2a | |||
| 31daa805f3 | |||
| c9937ab5d7 | |||
| 4610137f04 | |||
| 9d7eed7cde | |||
| aedc53bf86 | |||
| 286da3cf2c | |||
| 7fa988313d | |||
| e5b19dd268 | |||
| 0df4159261 | |||
| 45e8ded111 | |||
| 9167ece0c0 | |||
| f45a036971 |
+57
-15
@@ -2,7 +2,7 @@
|
||||
|
||||
julia_version = "1.12.6"
|
||||
manifest_format = "2.0"
|
||||
project_hash = "76bd6c852fad3452022f32202b19c4689be8e912"
|
||||
project_hash = "dc7878808bbc4637a12e709dd495979a784824a5"
|
||||
|
||||
[[deps.Accessors]]
|
||||
deps = ["CompositionsBase", "ConstructionBase", "Dates", "InverseFunctions", "MacroTools"]
|
||||
@@ -97,9 +97,9 @@ uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
|
||||
version = "0.7.8"
|
||||
|
||||
[[deps.CommonSolve]]
|
||||
git-tree-sha1 = "99ee296f88c12485402e37c2fd025f95ae097637"
|
||||
git-tree-sha1 = "eeaad7cef88554c2fa56b5a3f71cfd5cb708c662"
|
||||
uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2"
|
||||
version = "0.2.9"
|
||||
version = "0.2.11"
|
||||
|
||||
[[deps.Compat]]
|
||||
deps = ["TOML", "UUIDs"]
|
||||
@@ -244,11 +244,21 @@ git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec"
|
||||
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
|
||||
version = "0.1.10"
|
||||
|
||||
[[deps.EzXML]]
|
||||
deps = ["Printf", "XML2_jll"]
|
||||
git-tree-sha1 = "7ea1aa5869e2626ccae84480e4f37185bc6f41d3"
|
||||
uuid = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615"
|
||||
version = "1.2.3"
|
||||
|
||||
[[deps.FileIO]]
|
||||
deps = ["Pkg", "Requires", "UUIDs"]
|
||||
git-tree-sha1 = "91e0e5c68d02bcdaae76d3c8ceb4361e8f28d2e9"
|
||||
git-tree-sha1 = "6621fef488e496356c9c9625d0562c12a6070819"
|
||||
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
|
||||
version = "1.16.5"
|
||||
version = "1.20.0"
|
||||
weakdeps = ["HTTP"]
|
||||
|
||||
[deps.FileIO.extensions]
|
||||
HTTPExt = "HTTP"
|
||||
|
||||
[[deps.FilePathsBase]]
|
||||
deps = ["Compat", "Dates"]
|
||||
@@ -290,11 +300,11 @@ version = "1.1.0"
|
||||
|
||||
[[deps.GeneralUtils]]
|
||||
deps = ["CSV", "DataFrames", "DataStructures", "Dates", "Distributions", "Graphs", "HTTP", "JSON", "LibPQ", "NATS", "PrettyPrinting", "Random", "Revise", "SHA", "StringDistances", "UUIDs"]
|
||||
git-tree-sha1 = "aa695d21f155567524e7329fb7b96d8a9d0eba86"
|
||||
git-tree-sha1 = "a75a088ee8e5faf10f554ca00748e0e6ca58d1ca"
|
||||
repo-rev = "main"
|
||||
repo-url = "https://git.yiem.cc/ton/GeneralUtils"
|
||||
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
|
||||
[[deps.Graphs]]
|
||||
deps = ["ArnoldiMethod", "DataStructures", "Inflate", "LinearAlgebra", "Random", "SimpleTraits", "SparseArrays", "Statistics"]
|
||||
@@ -311,9 +321,9 @@ version = "1.14.0"
|
||||
|
||||
[[deps.HTTP]]
|
||||
deps = ["Base64", "CodecZlib", "Dates", "EnumX", "PrecompileTools", "Random", "Reseau", "SHA", "URIs", "UUIDs", "Zlib_jll"]
|
||||
git-tree-sha1 = "eda1d37cb55d90a17d0957c75841138c88b361a1"
|
||||
git-tree-sha1 = "c2c808326222b6dc4bec295a83b55f79aeec98e0"
|
||||
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
|
||||
version = "2.5.4"
|
||||
version = "2.5.5"
|
||||
|
||||
[[deps.HashArrayMappedTries]]
|
||||
git-tree-sha1 = "2eaa69a7cab70a52b9687c8bf950a5a93ec895ae"
|
||||
@@ -496,6 +506,12 @@ version = "1.11.3+1"
|
||||
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
|
||||
version = "1.11.0"
|
||||
|
||||
[[deps.Libiconv_jll]]
|
||||
deps = ["Artifacts", "JLLWrappers", "Libdl"]
|
||||
git-tree-sha1 = "be484f5c92fad0bd8acfef35fe017900b0b73809"
|
||||
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
|
||||
version = "1.18.0+0"
|
||||
|
||||
[[deps.LinearAlgebra]]
|
||||
deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
|
||||
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||
@@ -678,15 +694,17 @@ version = "0.4.2"
|
||||
|
||||
[[deps.PrettyTables]]
|
||||
deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "REPL", "Reexport", "StringManipulation", "Tables"]
|
||||
git-tree-sha1 = "624de6279ab7d94fc9f672f0068107eb6619732c"
|
||||
git-tree-sha1 = "ebf455bb866ee6737030e3d3816bb6a0683c4325"
|
||||
uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
|
||||
version = "3.3.2"
|
||||
version = "3.4.0"
|
||||
|
||||
[deps.PrettyTables.extensions]
|
||||
PrettyTablesExcelExt = "XLSX"
|
||||
PrettyTablesTypstryExt = "Typstry"
|
||||
|
||||
[deps.PrettyTables.weakdeps]
|
||||
Typstry = "f0ed7684-a786-439e-b1e3-3b82803b501e"
|
||||
XLSX = "fdbf4ff8-1666-58a4-91e7-1b58723a45e0"
|
||||
|
||||
[[deps.Printf]]
|
||||
deps = ["Unicode"]
|
||||
@@ -767,9 +785,9 @@ version = "0.5.1+0"
|
||||
|
||||
[[deps.Roots]]
|
||||
deps = ["Accessors", "CommonSolve", "Printf"]
|
||||
git-tree-sha1 = "ed45bcc7cf3c8887595b973f2b1efbe91dcc50ec"
|
||||
git-tree-sha1 = "a7caaf7ba8cf307112ca443784d1b56b4a591455"
|
||||
uuid = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
|
||||
version = "3.0.1"
|
||||
version = "3.0.5"
|
||||
|
||||
[deps.Roots.extensions]
|
||||
RootsChainRulesCoreExt = "ChainRulesCore"
|
||||
@@ -822,6 +840,12 @@ git-tree-sha1 = "084c47c7c5ce5cfecefa0a98dff69eb3646b5a80"
|
||||
uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
|
||||
version = "1.4.10"
|
||||
|
||||
[[deps.Serde]]
|
||||
deps = ["CSV", "Dates", "EzXML", "JSON", "TOML", "UUIDs", "YAML"]
|
||||
git-tree-sha1 = "f397fc8779cc53e4677c2708f3802c6996f28d00"
|
||||
uuid = "db9b398d-9517-45f8-9a95-92af99003e0e"
|
||||
version = "3.7.2"
|
||||
|
||||
[[deps.Serialization]]
|
||||
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||
version = "1.11.0"
|
||||
@@ -926,6 +950,12 @@ git-tree-sha1 = "cd83a04baf746e3b43b83c61b7de77ab0409b80a"
|
||||
uuid = "88034a9c-02f8-509d-84a9-84ec65e18404"
|
||||
version = "1.0.0"
|
||||
|
||||
[[deps.StringEncodings]]
|
||||
deps = ["Libiconv_jll"]
|
||||
git-tree-sha1 = "b765e46ba27ecf6b44faf70df40c57aa3a547dcb"
|
||||
uuid = "69024149-9ee7-55f6-a4c4-859efe599b68"
|
||||
version = "0.3.7"
|
||||
|
||||
[[deps.StringManipulation]]
|
||||
deps = ["PrecompileTools"]
|
||||
git-tree-sha1 = "d05693d339e37d6ab134c5ab53c29fce5ee5d7d5"
|
||||
@@ -1046,11 +1076,23 @@ git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7"
|
||||
uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60"
|
||||
version = "1.6.1"
|
||||
|
||||
[[deps.XML2_jll]]
|
||||
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"]
|
||||
git-tree-sha1 = "3f3315d89fc954a28f5b471bce698ed6e27481be"
|
||||
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
|
||||
version = "2.15.3+0"
|
||||
|
||||
[[deps.YAML]]
|
||||
deps = ["Base64", "Dates", "Printf", "StringEncodings"]
|
||||
git-tree-sha1 = "a1c0c7585346251353cddede21f180b96388c403"
|
||||
uuid = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
|
||||
version = "0.4.16"
|
||||
|
||||
[[deps.YiemAgent]]
|
||||
deps = ["CSV", "DataFrames", "DataStructures", "Dates", "GeneralUtils", "HTTP", "JSON", "LLMMCTS", "LibPQ", "NATS", "PrettyPrinting", "Random", "Revise", "Serialization", "URIs", "UUIDs"]
|
||||
deps = ["Base64", "CSV", "DataFrames", "DataStructures", "Dates", "GeneralUtils", "HTTP", "JSON", "LLMMCTS", "LibPQ", "NATS", "PrettyPrinting", "Random", "Revise", "SQLLLM", "Serialization", "URIs", "UUIDs"]
|
||||
path = "."
|
||||
uuid = "e012c34b-7f78-48e0-971c-7abb83b6f0a2"
|
||||
version = "0.5.0"
|
||||
version = "0.7.2"
|
||||
|
||||
[[deps.Zlib_jll]]
|
||||
deps = ["Libdl"]
|
||||
|
||||
+6
-2
@@ -1,9 +1,10 @@
|
||||
name = "YiemAgent"
|
||||
uuid = "e012c34b-7f78-48e0-971c-7abb83b6f0a2"
|
||||
version = "0.6.0"
|
||||
version = "0.7.4"
|
||||
authors = ["narawat lamaiin <narawat@outlook.com>"]
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
|
||||
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
|
||||
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
|
||||
@@ -18,16 +19,19 @@ PrettyPrinting = "54e16d92-306c-5ea0-a30b-337be88ac337"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
|
||||
SQLLLM = "2ebc79c7-cc10-4a3a-9665-d2e1d61e63d3"
|
||||
Serde = "db9b398d-9517-45f8-9a95-92af99003e0e"
|
||||
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||
URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
|
||||
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||
|
||||
[compat]
|
||||
Base64 = "1.11.0"
|
||||
CSV = "0.10.15"
|
||||
DataFrames = "1.7.0"
|
||||
GeneralUtils = "0.5.0"
|
||||
GeneralUtils = "0.5.1"
|
||||
HTTP = "2.4.0"
|
||||
JSON = "1.6.1"
|
||||
LLMMCTS = "0.1.5"
|
||||
NATS = "0.1.0"
|
||||
SQLLLM = "0.2.8"
|
||||
Serde = "3.7.2"
|
||||
|
||||
@@ -1,13 +1,200 @@
|
||||
using HTTP, JSON, URIs, Random, PrettyPrinting, UUIDs, Dates, DataFrames, DataStructures
|
||||
using GeneralUtils, SQLLLM, YiemAgent
|
||||
|
||||
config = JSON.parsefile("./appconfig.json")
|
||||
host_url, _port = split(config["externalservice"]["sommpanion_db"]["url"], ':')
|
||||
port = parse(Int, _port)
|
||||
dbname = "winedb"
|
||||
user = config["externalservice"]["sommpanion_db"]["user"]
|
||||
password = config["externalservice"]["sommpanion_db"]["password"]
|
||||
pg_conn_str = "host=$host_url port=$port dbname=$dbname user=$user password=$password"
|
||||
|
||||
function execute_sql_winedb(sql::T) where {T<:AbstractString}
|
||||
host_url, _port = split(config["externalservice"]["sommpanion_db"]["url"], ':')
|
||||
port = parse(Int, _port)
|
||||
dbname = "winedb"
|
||||
user = config["externalservice"]["sommpanion_db"]["user"]
|
||||
password = config["externalservice"]["sommpanion_db"]["password"]
|
||||
db_connection = LibPQ.Connection("host=$host_url port=$port dbname=$dbname user=$user password=$password")
|
||||
result = nothing
|
||||
try
|
||||
result = LibPQ.execute(db_connection, sql)
|
||||
catch e
|
||||
LibPQ.close(db_connection)
|
||||
end
|
||||
|
||||
LibPQ.close(db_connection)
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
d = Dict(
|
||||
"hello"=> 555,
|
||||
"world"=> Dict(
|
||||
"name"=> "ton"
|
||||
)
|
||||
)
|
||||
sql =
|
||||
"""
|
||||
SELECT T1.winery, T1.wine_name, T1.wine_id, T1.vintage, T1.region, T1.country, T1.wine_type, T1.grape, T1.serving_temperature, T1.sweetness, T1.intensity, T1.tannin, T1.acidity, T1.tasting_notes, T2.price, T2.currency, T1.image_url, T3.retailer_name, T3.retailer_id FROM "wine" AS T1 JOIN "retailer_wine" AS T2 ON T1.wine_id = T2.wine_id JOIN "retailer" AS T3 ON T2.retailer_id = T3.retailer_id WHERE T1.wine_name = 'Montrachet Grand Cru' AND T1.winery = 'Domaine Jacques Prieur' AND T3.retailer_name = 'Yiem Wines Ltd' AND T3.retailer_id = 'f54eab6b-7650-4448-b009-c53f3efbcc3b';
|
||||
"""
|
||||
|
||||
textresult, sql_result_raw, _, _ = YiemAgent.SQLexecution(execute_sql_winedb, sql)
|
||||
result_vec = GeneralUtils.dfToVectorDict(sql_result_raw)
|
||||
|
||||
for d in result_vec
|
||||
wine_name = d["wine_name"]
|
||||
image_url_json_str = d["image_url"]
|
||||
image_url_json_obj = JSON.parse(image_url_json)
|
||||
base_url = "http://192.168.88.106:8080/"
|
||||
image_base64 =
|
||||
if haskey(image_url_json_obj, "bottle")
|
||||
url = base_url * image_url_json_obj["bottle"]
|
||||
image_data = HTTP.get(url) # vector{int} data
|
||||
image_base64_string = base64encode(image_data)
|
||||
else
|
||||
nothing
|
||||
end
|
||||
d["image"] = image_base64
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using LibPQ
|
||||
using Tables
|
||||
|
||||
"""
|
||||
update_car_regions_one_by_one(conn::LibPQ.Connection, target_word::String)
|
||||
|
||||
Iterates through all rows in the 'car' table where the region is "German",
|
||||
and updates them one-by-one to the `target_word`.
|
||||
"""
|
||||
function update_car_regions_one_by_one(pg_conn_str::String, replace_word::String , target_word::String)
|
||||
conn = LibPQ.Connection(pg_conn_str)
|
||||
# 1. Fetch the target rows. Assumes 'id' is the primary key.
|
||||
# We select the ID to target rows individually during the update step.
|
||||
select_query = "SELECT id FROM car WHERE region = '$replace_word';"
|
||||
|
||||
result = execute(conn, select_query)
|
||||
rows = Tables.rows(result)
|
||||
|
||||
# 2. Prepare the update statement for execution reuse
|
||||
# Using explicit types for parameter placeholders ($1, $2)
|
||||
update_query = "UPDATE car SET region = \$1 WHERE id = \$2;"
|
||||
|
||||
println("Starting one-by-one update...")
|
||||
updated_count = 0
|
||||
|
||||
# 3. Iterate through rows one-by-one
|
||||
for row in rows
|
||||
# LibPQ row values are accessed via properties or column names
|
||||
row_id = row.id
|
||||
|
||||
# Execute the parameterized statement safely
|
||||
execute(conn, update_query, [target_word, row_id])
|
||||
updated_count += 1
|
||||
end
|
||||
|
||||
println("Successfully updated \$updated_count rows.")
|
||||
return updated_count
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function generate_wine_retail_sql(conditions::Dict{String, Any})::String
|
||||
# 1. Base SQL structure
|
||||
base_query = """
|
||||
SELECT
|
||||
w.winery,
|
||||
w.wine_name,
|
||||
w.wine_id,
|
||||
w.vintage,
|
||||
w.region,
|
||||
w.country,
|
||||
w.wine_type,
|
||||
w.grape,
|
||||
w.serving_temperature,
|
||||
w.sweetness,
|
||||
w.intensity,
|
||||
w.tannin,
|
||||
w.acidity,
|
||||
w.tasting_notes,
|
||||
rw.price,
|
||||
rw.currency,
|
||||
w.image_url,
|
||||
NULL AS retailer_name,
|
||||
rw.retailer_id
|
||||
FROM wine AS w
|
||||
JOIN retailer_wine AS rw
|
||||
ON w.wine_id = rw.wine_id
|
||||
"""
|
||||
|
||||
# 2. Dynamic WHERE Clause Builder
|
||||
where_clauses = String[]
|
||||
|
||||
# Iterate over each table condition provided
|
||||
for (table_name, table_conditions) in conditions
|
||||
|
||||
# Determine table alias
|
||||
alias = if table_name == "wine"
|
||||
"w"
|
||||
elseif table_name == "retailer_wine"
|
||||
"rw"
|
||||
else
|
||||
continue # Skip unsupported tables
|
||||
end
|
||||
|
||||
# Process condition dictionaries
|
||||
if isa(table_conditions, Dict) && !isempty(table_conditions)
|
||||
|
||||
for (column_name, filter_details) in table_conditions
|
||||
|
||||
if isa(filter_details, Dict) && haskey(filter_details, "operator")
|
||||
op = filter_details["operator"]
|
||||
raw_val = filter_details["value"]
|
||||
|
||||
# --- Value Type Handling ---
|
||||
# Use tryparse instead of try/catch for cleaner, faster parsing
|
||||
final_val = raw_val
|
||||
|
||||
if op in ("=", "<", ">", "<=", ">=")
|
||||
str_val = string(raw_val)
|
||||
num_val = tryparse(Float64, str_val)
|
||||
|
||||
if !isnothing(num_val)
|
||||
final_val = isinteger(num_val) ? round(Int, num_val) : num_val
|
||||
end
|
||||
end
|
||||
|
||||
# --- SQL Formatting ---
|
||||
if isa(final_val, Number)
|
||||
clause = "$(alias).$(column_name) $(op) $(final_val)"
|
||||
else
|
||||
# Escape single quotes within string values
|
||||
escaped_val = replace(string(final_val), "'" => "''")
|
||||
clause = "$(alias).$(column_name) $(op) '$(escaped_val)'"
|
||||
end
|
||||
|
||||
push!(where_clauses, clause)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# 3. Assemble Final Query
|
||||
where_sql = isempty(where_clauses) ? "" : "WHERE " * join(where_clauses, " AND ")
|
||||
|
||||
return string(base_query, where_sql, ";")
|
||||
end
|
||||
|
||||
x = 55
|
||||
|
||||
@info "YiemAgent think() 1 " d x @__LINE__
|
||||
+166
-91
@@ -4,7 +4,7 @@ export addNewMessage, conversation, decisionMaker, reflector, generatechat,
|
||||
generalconversation, detectWineryName, generateSituationReport
|
||||
|
||||
using JSON, DataStructures, Dates, UUIDs, HTTP, Random, PrettyPrinting, Serialization,
|
||||
DataFrames, CSV
|
||||
DataFrames, Serde
|
||||
using GeneralUtils
|
||||
using ..type, ..util, ..llmfunction
|
||||
|
||||
@@ -73,9 +73,9 @@ OrderedDict{String, Any} with 4 entries:
|
||||
"action_result" => "1) winery: Terrazze dell Etna, wine_name: Rose Brut.
|
||||
```
|
||||
"""
|
||||
function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
|
||||
function decisionMaker(a::T; recentevents::Integer=20, maxattempt=3
|
||||
) where {T<:agent}
|
||||
|
||||
@info "YiemAgent decisionMaker() start " @__LINE__
|
||||
# lessonDict = copy(JSON.parsefile("lesson.json"))
|
||||
|
||||
# lesson =
|
||||
@@ -122,23 +122,16 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
|
||||
errornote = "N/A"
|
||||
response = nothing # placeholder for show when error msg show up
|
||||
|
||||
for attempt in 1:maxattempt
|
||||
if attempt > 1
|
||||
println("\nYiemAgent decisionMaker() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
end
|
||||
|
||||
msg = Dict(
|
||||
"model" => "gemma-4-E4B-it-UD-Q4_K_XL",
|
||||
"messages" => a.chathistory,
|
||||
"temperature" => 0.7
|
||||
)
|
||||
|
||||
for attempt in 1:maxattempt
|
||||
response = a.context.text2textInstructLLM(a.id, msg)
|
||||
response = GeneralUtils.clean_json_response(response)
|
||||
response = GeneralUtils.remove_french_accents(response)
|
||||
think, response = GeneralUtils.extractthink(response)
|
||||
response = String(split(response, ", observation")[1]) # in case LLM generate observation key which it isn't supposed to
|
||||
response = strip(response)
|
||||
# think, response = GeneralUtils.extractthink(response)
|
||||
|
||||
# dollar sign in Julia means string interpolation
|
||||
while occursin('$', response)
|
||||
@@ -146,34 +139,28 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
|
||||
end
|
||||
|
||||
responsedict = nothing
|
||||
if occursin(requiredKeys[2], response)
|
||||
try
|
||||
_responsedict = JSON.parse(response)
|
||||
responsedict = GeneralUtils.dictify(_responsedict; keytype=String, sort_order=requiredKeys)
|
||||
catch
|
||||
println("\nERROR YiemAgent decisionMaker() failed to parse response: $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
end
|
||||
|
||||
# fall back to normal text because LLM default to natural chat when it didn't use action_call
|
||||
else
|
||||
try
|
||||
responsedict = OrderedDict(
|
||||
"plan"=> "I will talk to the user",
|
||||
"action_name"=> "CHAT_BOX",
|
||||
"action_input"=> response[2:end-1] # remove { } at the front and back that added by clean_json_response
|
||||
)
|
||||
responsedict = Serde.parse_yaml(response)
|
||||
catch e
|
||||
println("\nERROR YiemAgent decisionMaker(). $e --(not qualify response)-> $response", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
println("\nERROR YiemAgent decisionMaker() Error: $e --(not qualify response)-> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
# check whether all answer's key points are in responsedict
|
||||
println("\n---")
|
||||
println(responsedict)
|
||||
println("---\n")
|
||||
ispass, errormsg = GeneralUtils.checkAgentResponse_JSON(responsedict, requiredKeys)
|
||||
|
||||
if !ispass
|
||||
errornote = errormsg
|
||||
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)-> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)-> $responsedict ", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
continue
|
||||
end
|
||||
|
||||
if responsedict["action_input"] == "CHAT_BOX" &&
|
||||
occursin("similar", responsedict["action_input"])
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
@@ -185,10 +172,17 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
|
||||
|
||||
# println("\nYiem decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
# pprintln(responsedict)
|
||||
|
||||
@info "YiemAgent decisionMaker() end " @__LINE__
|
||||
return responsedict
|
||||
end
|
||||
error("DecisionMaker failed to generate a thought ", response)
|
||||
|
||||
# in case decisionMaker failed, force to use generatechat!()
|
||||
responsedict = OrderedDict(
|
||||
"plan"=> "N/A",
|
||||
"action_name"=> "CHAT_BOX",
|
||||
"action_input"=> "N/A"
|
||||
)
|
||||
return responsedict
|
||||
end
|
||||
|
||||
|
||||
@@ -317,7 +311,7 @@ function evaluator(a::T1, timeline, decisiondict, evaluateecontext
|
||||
ispass, errormsg = checkAgentResponse_JSON(responsedict, requiredKeys)
|
||||
if !ispass
|
||||
errornote = errormsg
|
||||
println("\nERROR YiemAgent evaluator() $errornote --(not qualify response)> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
println("\nERROR YiemAgent evaluator() $errornote --(not qualify response)> $responsedict ", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
continue
|
||||
end
|
||||
|
||||
@@ -360,7 +354,7 @@ message => Dict(
|
||||
function conversation(a::sommelier; userinput::Union{Dict{String, Any}, JSON.Object{String, Any}},
|
||||
maximumMsg=50, max_think_loop::Integer=3)
|
||||
|
||||
@info "YiemAgent conversation() 1 " @__LINE__
|
||||
@info "YiemAgent conversation() start " @__LINE__
|
||||
userinput = GeneralUtils.dictify(userinput; keytype=String, sort_order=["text"])
|
||||
|
||||
# find text in usermsg
|
||||
@@ -376,7 +370,7 @@ function conversation(a::sommelier; userinput::Union{Dict{String, Any}, JSON.Obj
|
||||
clearhistory(a)
|
||||
return "Okay. What shall we talk about?"
|
||||
else
|
||||
@info "YiemAgent conversation() 2 " @__LINE__
|
||||
|
||||
# add usermsg to a.chathistory but how do I handle images?
|
||||
addNewMessage(a, "user", userinput; maximumMsg=maximumMsg)
|
||||
|
||||
@@ -385,49 +379,119 @@ function conversation(a::sommelier; userinput::Union{Dict{String, Any}, JSON.Obj
|
||||
while true
|
||||
loopcount += 1
|
||||
if loopcount > max_think_loop
|
||||
@info "YiemAgent conversation() 2-1 think count $loopcount " @__LINE__
|
||||
r = generatechat!(a)
|
||||
@info "YiemAgent conversation() 2-2 think count $loopcount " @__LINE__
|
||||
return r
|
||||
end
|
||||
|
||||
@info "YiemAgent conversation() 2-3 think count $loopcount " @__LINE__
|
||||
thoughtdict, result_raw = think(a)
|
||||
if thoughtdict["action_name"] ∈ ["CHAT_BOX"]
|
||||
@info "YiemAgent conversation() 2-4 think count $loopcount " @__LINE__
|
||||
thoughtdict, result_raw = generatechat!(a)
|
||||
assistant_response = Dict{String, Any}(
|
||||
"role" => "assistant",
|
||||
"content" => [Dict("type" => "text", "text" => thoughtdict["action_input"]),]
|
||||
)
|
||||
addNewMessage(a, "assistant", assistant_response; maximumMsg=maximumMsg)
|
||||
@info "YiemAgent conversation() 2-5 think count $loopcount " @__LINE__
|
||||
return thoughtdict["action_input"]
|
||||
# elseif thoughtdict["action_name"] ∈ ["CHAT_BOX"]
|
||||
# @info "YiemAgent conversation() 2-4 think count $loopcount " @__LINE__
|
||||
# assistant_response = Dict{String, Any}(
|
||||
# "role" => "assistant",
|
||||
# "content" => [
|
||||
# Dict("type" => "text", "text" => thoughtdict["action_input"]),
|
||||
# Dict( #WORKING put 1st image here
|
||||
# "type" => "image_url",
|
||||
# "image_url" => Dict("url" => image1_data_uri)
|
||||
# ),
|
||||
# Dict( #WORKING put 2nd image here
|
||||
# "type" => "image_url",
|
||||
# "image_url" => Dict("url" => image2_data_uri)
|
||||
# ),
|
||||
# ]
|
||||
# )
|
||||
# addNewMessage(a, "assistant", assistant_response; maximumMsg=maximumMsg)
|
||||
|
||||
# return thoughtdict["action_input"] #XXX change output from string to dict
|
||||
else
|
||||
items_info = []
|
||||
send_item_ind = [] # index of the item being send to frontend
|
||||
if haskey(a.memory["shortmem"], "items_info")
|
||||
for (i, item) in enumerate(a.memory["shortmem"]["items_info"])
|
||||
@info "YiemAgent conversation() shortmem: $(length(a.memory["shortmem"]["items_info"])), items_info: $(length(items_info)), item name: $(item["wine_name"]) " @__LINE__
|
||||
if haskey(item, "wine_name") && occursin(item["wine_name"], thoughtdict["action_input"])
|
||||
push!(items_info, deepcopy(item))
|
||||
push!(send_item_ind, i)
|
||||
@info "YiemAgent conversation() shortmem: $(length(a.memory["shortmem"]["items_info"])), items_info: $(length(items_info)) " @__LINE__
|
||||
end
|
||||
end
|
||||
# remove sent items
|
||||
deleteat!(a.memory["shortmem"]["items_info"], send_item_ind)
|
||||
@info "YiemAgent conversation() shortmem: $(length(a.memory["shortmem"]["items_info"])), items_info: $(length(items_info)) " @__LINE__
|
||||
end
|
||||
|
||||
response_to_frontend = Dict{String, Any}(
|
||||
"role" => "assistant",
|
||||
"content" => [
|
||||
Dict("type" => "text", "text" => thoughtdict["action_input"]),
|
||||
Dict(
|
||||
"type" => "items_info",
|
||||
"items_info" => items_info
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
return response_to_frontend
|
||||
end
|
||||
|
||||
|
||||
thoughtdict, result_raw = think(a)
|
||||
|
||||
if thoughtdict["action_name"] ∈ ["CHAT_BOX"]
|
||||
assistant_response = Dict{String, Any}(
|
||||
"role" => "assistant",
|
||||
"content" => [Dict("type" => "text", "text" => thoughtdict["action_input"]),]
|
||||
)
|
||||
addNewMessage(a, "assistant", assistant_response; maximumMsg=maximumMsg)
|
||||
|
||||
items_info = []
|
||||
send_item_ind = [] # index of the item being send to frontend
|
||||
if haskey(a.memory["shortmem"], "items_info")
|
||||
for (i, item) in enumerate(a.memory["shortmem"]["items_info"])
|
||||
@info "YiemAgent conversation() shortmem: $(length(a.memory["shortmem"]["items_info"])), items_info: $(length(items_info)), item name: $(item["wine_name"]) " @__LINE__
|
||||
if haskey(item, "wine_name") && occursin(item["wine_name"], thoughtdict["action_input"])
|
||||
push!(items_info, deepcopy(item))
|
||||
push!(send_item_ind, i)
|
||||
@info "YiemAgent conversation() shortmem: $(length(a.memory["shortmem"]["items_info"])), items_info: $(length(items_info)) " @__LINE__
|
||||
end
|
||||
end
|
||||
# remove sent items
|
||||
deleteat!(a.memory["shortmem"]["items_info"], send_item_ind)
|
||||
@info "YiemAgent conversation() shortmem: $(length(a.memory["shortmem"]["items_info"])), items_info: $(length(items_info)) " @__LINE__
|
||||
end
|
||||
|
||||
response_to_frontend = Dict{String, Any}(
|
||||
"role" => "assistant",
|
||||
"content" => [
|
||||
Dict("type" => "text", "text" => thoughtdict["action_input"]),
|
||||
Dict(
|
||||
"type" => "items_info",
|
||||
"items_info" => items_info
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
""" intended message to send to frontend should have the following format.
|
||||
response_to_frontend = Dict{String, Any}(
|
||||
"role" => "assistant",
|
||||
"content" => [
|
||||
Dict("type" => "text", "text" => "assistant_text_response"),
|
||||
Dict(
|
||||
"type" => "items_info",
|
||||
"items_info" => [
|
||||
Dict(
|
||||
"wine_name"=> "wine name 1",
|
||||
"wine_id"=> "...",
|
||||
"image"=> base64 encoded image,
|
||||
...
|
||||
),
|
||||
Dict(
|
||||
"wine_name"=> "wine name 2",
|
||||
"wine_id"=> "...",
|
||||
"image"=> base64 encoded image,
|
||||
...
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
return response_to_frontend
|
||||
else # still in action
|
||||
|
||||
action_name = thoughtdict["action_name"]
|
||||
action_input = thoughtdict["action_input"]
|
||||
|
||||
action_call = Dict{String, Any}(
|
||||
"role" => "action_call",
|
||||
"content" => [Dict("type" => "text", "text" => "{action_name: $action_name, action_input: $action_input}"),]
|
||||
)
|
||||
|
||||
addNewMessage(a, "action_call", action_call; maximumMsg=maximumMsg)
|
||||
|
||||
action_result = thoughtdict["action_result"]
|
||||
@@ -435,7 +499,9 @@ function conversation(a::sommelier; userinput::Union{Dict{String, Any}, JSON.Obj
|
||||
"role" => "action_result",
|
||||
"content" => [Dict("type" => "text", "text" => "$action_result"),]
|
||||
)
|
||||
|
||||
addNewMessage(a, "actionresult", actionresult; maximumMsg=maximumMsg)
|
||||
@info "YiemAgent conversation() end think count $loopcount " @__LINE__
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -455,34 +521,51 @@ julia>
|
||||
"""
|
||||
function think(a::T)::NamedTuple{(:thoughtdict, :result_raw), Tuple{OrderedDict, Any}} where {T<:agent}
|
||||
# a.memory[:recap] = generateSituationReport(a, a.context["text"2textInstructLLM]; skiprecent=0)
|
||||
@info "YiemAgent think() start " @__LINE__
|
||||
thoughtdict = decisionMaker(a)
|
||||
@info "YiemAgent think() 1 " @__LINE__
|
||||
# pprintln(thoughtdict)
|
||||
@show thoughtdict
|
||||
println("---\n")
|
||||
|
||||
result_raw = nothing
|
||||
if thoughtdict["action_name"] ∈ ["CHAT_BOX"]
|
||||
@info "YiemAgent think() 2 " @__LINE__
|
||||
|
||||
# sometime CHAT_BOX input is too short.
|
||||
# if thoughtdict["action_input] < 20 character, use generatechat!()
|
||||
if length(thoughtdict["action_input"]) < 20
|
||||
thoughtdict, result_raw = generatechat!(a)
|
||||
else
|
||||
thoughtdict["action_result"] = "Action result is the next user dialogue."
|
||||
result_raw = thoughtdict["action_input"]
|
||||
end
|
||||
|
||||
elseif thoughtdict["action_name"] == "END_CONVER_GUIDELINE"
|
||||
@info "YiemAgent think() 3 " @__LINE__
|
||||
|
||||
thoughtdict, result_raw = end_conversation_guideline!(a, thoughtdict)
|
||||
|
||||
elseif thoughtdict["action_name"] ∈ ["WINE_PRESENTATION_GUIDELINE"]
|
||||
@info "YiemAgent think() 4 " @__LINE__
|
||||
|
||||
thoughtdict, result_raw = wine_presentation_guideline!(a, thoughtdict)
|
||||
|
||||
elseif thoughtdict["action_name"] == "SEARCH_WINE_DATABASE"
|
||||
@info "YiemAgent think() 5 " @__LINE__
|
||||
thoughtdict, result_raw = search_wine_database!(a, thoughtdict; useSQLLLM=true)
|
||||
#WORKING result_raw will be a df. i need to get images so i can send to frontend
|
||||
|
||||
thoughtdict, result_raw = search_wine_database!(a, thoughtdict; useSQLLLM=false)
|
||||
if result_raw !== nothing && result_raw isa Vector
|
||||
if haskey(a.memory["shortmem"], "items_info")
|
||||
append!(a.memory["shortmem"]["items_info"], result_raw)
|
||||
else
|
||||
@info "YiemAgent think() 6 " @__LINE__
|
||||
a.memory["shortmem"]["items_info"] = result_raw
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
error("condition is not defined ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
end
|
||||
println("\n")
|
||||
|
||||
@info "YiemAgent think() end " @__LINE__
|
||||
@show thoughtdict
|
||||
@info "YiemAgent think() 7 " @__LINE__
|
||||
println("---\n")
|
||||
return (thoughtdict=thoughtdict, result_raw=result_raw)
|
||||
end
|
||||
|
||||
@@ -559,7 +642,7 @@ end
|
||||
#PENDING
|
||||
function generatechat!(a::T; maxattempt::Integer=10
|
||||
)::NamedTuple{(:thoughtdict, :result_raw), Tuple{OrderedDict, Any}} where {T<:agent}
|
||||
|
||||
@info "YiemAgent generatechat!() start " @__LINE__
|
||||
# lessonDict = copy(JSON.parsefile("lesson.json"))
|
||||
|
||||
# lesson =
|
||||
@@ -673,7 +756,6 @@ function generatechat!(a::T; maxattempt::Integer=10
|
||||
response = GeneralUtils.clean_json_response(response)
|
||||
response = GeneralUtils.remove_french_accents(response)
|
||||
think, response = GeneralUtils.extractthink(response)
|
||||
response = String(split(response, ", observation")[1]) # in case LLM generate observation key which it isn't supposed to
|
||||
|
||||
response = strip(response)
|
||||
|
||||
@@ -686,26 +768,17 @@ function generatechat!(a::T; maxattempt::Integer=10
|
||||
println("\nERROR YiemAgent generatechat() failed to parse response: $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
continue
|
||||
end
|
||||
|
||||
# fall back to normal text because LLM default to natural chat when it didn't use action_call
|
||||
else
|
||||
try
|
||||
responsedict = OrderedDict(
|
||||
"plan"=> "I will talk to the user",
|
||||
"action_name"=> "CHAT_BOX",
|
||||
"action_input"=> response[2:end-1] # remove { } at the front and back that added by clean_json_response
|
||||
)
|
||||
catch e
|
||||
println("\nERROR YiemAgent decisionMaker(). $e --(not qualify response)-> $response", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
println("\nERROR YiemAgent generatechat() $errornote --(not qualify response)> $responsedict ", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# check whether all answer's key points are in responsedict
|
||||
ispass, errormsg = GeneralUtils.checkAgentResponse_JSON(responsedict, requiredKeys)
|
||||
if !ispass
|
||||
errornote = errormsg
|
||||
println("\nERROR YiemAgent generatechat() $errornote --(not qualify response)> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
println("\nERROR YiemAgent generatechat() $errornote --(not qualify response)> $responsedict ", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
|
||||
continue
|
||||
end
|
||||
|
||||
@@ -717,9 +790,11 @@ function generatechat!(a::T; maxattempt::Integer=10
|
||||
|
||||
# println("\nYiem decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
# pprintln(responsedict)
|
||||
|
||||
responsedict["action_result"] = "Action result is the next user dialogue."
|
||||
@info "YiemAgent generatechat!() end " @__LINE__
|
||||
return (thoughtdict=responsedict, result_raw=responsedict["action_input"])
|
||||
end
|
||||
@info "YiemAgent generatechat() failed to generate a thought " @__LINE__
|
||||
error("YiemAgent generatechat() failed to generate a thought ", response)
|
||||
end
|
||||
|
||||
|
||||
+616
-299
File diff suppressed because it is too large
Load Diff
+8
-80
@@ -23,75 +23,6 @@ end
|
||||
|
||||
abstract type agent end
|
||||
|
||||
mutable struct companion <: agent
|
||||
name::String # agent name
|
||||
id::String # agent id
|
||||
systemmsg::String # system message
|
||||
tools::Dict # tools
|
||||
maxHistoryMsg::Integer # e.g. 21th and earlier messages will get summarized
|
||||
chathistory::Vector{Dict{String, Any}}
|
||||
memory::Dict{String, Any}
|
||||
context::NamedTuple # NamedTuple of functions
|
||||
llmFormatName::String
|
||||
end
|
||||
|
||||
function companion(
|
||||
context::agentcontext # NamedTuple of functions
|
||||
;
|
||||
name::String= "Assistant",
|
||||
id::String= GeneralUtils.uuid4snakecase(),
|
||||
maxHistoryMsg::Integer= 20,
|
||||
chathistory::Vector{Dict{String, String}} = Vector{Dict{String, String}}(),
|
||||
llmFormatName::String= "granite3",
|
||||
systemmsg::String=
|
||||
"""
|
||||
Your name: $name
|
||||
Your sex: Female
|
||||
Your role: You are a helpful assistant.
|
||||
You should follow the following guidelines:
|
||||
- Focus on the latest conversation.
|
||||
- Your like to be short and concise.
|
||||
|
||||
Let's begin!
|
||||
""",
|
||||
)
|
||||
|
||||
tools = Dict( # update input format
|
||||
"CHAT_BOX"=> Dict(
|
||||
"description" => "- CHAT_BOX which you can use to talk with the user. The input is your intentions for the dialogue. Be specific.",
|
||||
),
|
||||
)
|
||||
|
||||
""" Memory
|
||||
Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
|
||||
NO "system" message in chathistory because I want to add it at the inference time
|
||||
chathistory= [
|
||||
Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()),
|
||||
Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()),
|
||||
]
|
||||
"""
|
||||
memory = Dict{String, Any}(
|
||||
"events"=> Vector{Dict{String, Any}}(),
|
||||
"state"=> Dict{String, Any}(), # state of the agent
|
||||
"recap"=> OrderedDict{String, Any}(), # recap summary of the conversation
|
||||
)
|
||||
|
||||
newAgent = companion(
|
||||
name,
|
||||
id,
|
||||
systemmsg,
|
||||
tools,
|
||||
maxHistoryMsg,
|
||||
chathistory,
|
||||
memory,
|
||||
context,
|
||||
llmFormatName
|
||||
)
|
||||
|
||||
return newAgent
|
||||
end
|
||||
|
||||
|
||||
mutable struct sommelier <: agent
|
||||
name::String # agent name
|
||||
id::String # agent id
|
||||
@@ -210,11 +141,7 @@ function sommelier(
|
||||
memory = Dict{String, Any}(
|
||||
"shortmem"=> OrderedDict{String, Any}(),
|
||||
"scratchpad"=> "",
|
||||
"events"=> Vector{Dict{String, Any}}(),
|
||||
"state"=> Dict{String, Any}(
|
||||
),
|
||||
"recap"=> OrderedDict{String, Any}(),
|
||||
|
||||
)
|
||||
|
||||
newAgent = sommelier(
|
||||
@@ -252,6 +179,7 @@ function sommelier(
|
||||
- Your store carries only wine.
|
||||
- Vintage 0 means non-vintage.
|
||||
- Start searching the database as broadly as possible within the given information boundary to maximize the chances of finding. Avoid unnecessary parameters unless specified by the user. Refine the search subsequently.
|
||||
- User usually ask for something similar. This means you should use the search term based on the profile they like.
|
||||
|
||||
# situation
|
||||
You are having conversation with a customer.
|
||||
@@ -278,17 +206,17 @@ function sommelier(
|
||||
3) "action_input", The input to the action you are about to perform according to your plan.
|
||||
After the action is executed you gets "action_result". It is the output from the action you selected.
|
||||
|
||||
# you should only respond in JSON format as described below (not Markdown format)
|
||||
"plan": "...",
|
||||
"action_name": "...",
|
||||
"action_input": "..."
|
||||
# you should only respond in YAML format as described below
|
||||
plan: "..."
|
||||
action_name: "..."
|
||||
action_input: "..."
|
||||
|
||||
# available actions
|
||||
"CHAT_BOX", which you can use to talk with the user. The input is dialogue you want to chat with the user according to your plan.
|
||||
"SEARCH_WINE_DATABASE", allows you to search information about wines you want in your inventory's database. The input is supported search criteria including: retailer_name, wine price, winery, name, vintage, region, country, type, grape varietal, tasting notes, occasion, food pairing, intensity, tannin, sweetness, and acidity.
|
||||
Example query 1: "Dry, full-bodied red wine from 1) region: Burgundy, country: France or 2) region: Tuscany, country: Italy. Grape varietal: Merlot or Syrah. price 100 to 1000 USD."
|
||||
"SEARCH_WINE_DATABASE", allows you to search information about wines you want in your inventory's database. The input is strictly supported search term including: retailer_name, wine price, winery, name, vintage, region, country, type of wine, grape varietal, tasting notes, occasion, food pairing, intensity, tannin, sweetness, and acidity.
|
||||
Example query 1: "Dry, full-bodied red wine from Burgundy, France. Grape varietal could be Merlot or Syrah. price 100 to 1000 USD."
|
||||
Example query 2: "Red or white wine, medium tannin, price under 700 USD"
|
||||
Example query 3: "white wine, region: Tuscany or Bordeaux, country: Italy or France
|
||||
Example query 3: "white wine from Tuscany, Italy or Bordeaux, France
|
||||
"WINE_PRESENTATION_GUIDELINE", which you can use to check the store guidelines about how to present wines you have found to the user. The input is "nothing" keyword. The output is the guidelines that you can follow.
|
||||
"END_CONVER_GUIDELINE", which you can use to check the store guidelines about how to end the conversation with the user. The input is "nothing" keyword. The output is the guidelines that you can follow.
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user