update
This commit is contained in:
412
test/runtest.jl
412
test/runtest.jl
@@ -1,227 +1,255 @@
|
||||
using Revise # remove when this package is completed
|
||||
using YiemAgent, GeneralUtils, JSON3, MQTTClient, Dates, UUIDs, LibPQ, Base64, DataFrames
|
||||
using Revise
|
||||
using JSON, JSON3, MQTTClient, Dates, UUIDs, PrettyPrinting, LibPQ, Base64, DataFrames
|
||||
using YiemAgent, GeneralUtils
|
||||
using Base.Threads
|
||||
|
||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||
|
||||
config = copy(JSON3.read("config.json"))
|
||||
|
||||
# instanceInternalTopic = config[:serviceInternalTopic][:mqtttopic] * "/1"
|
||||
|
||||
# client, connection = MakeConnection(config[:mqttServerInfo][:broker],
|
||||
# config[:mqttServerInfo][:port])
|
||||
|
||||
receiveUserMsgChannel = Channel{Dict}(4)
|
||||
# receiveInternalMsgChannel = Channel{Dict}(4)
|
||||
# println(typeof(connection))
|
||||
# msgMeta = GeneralUtils.generate_msgMeta(
|
||||
# "N/A",
|
||||
# replyTopic = config[:servicetopic][:mqtttopic] # ask frontend reply to this instance_chat_topic
|
||||
# )
|
||||
# load config
|
||||
config = copy(JSON3.read("../mountvolume/config.json"))
|
||||
|
||||
function executeSQL(sql::T) where {T<:AbstractString}
|
||||
DBconnection = LibPQ.Connection("host=192.168.88.12 port=5432 dbname=yiem_wine_assistant user=yiem password=yiem@Postgres_0.0")
|
||||
DBconnection = LibPQ.Connection("host=192.168.88.12 port=10201 dbname=wineDB user=yiemtechnologies password=yiemtechnologies@Postgres_0.0")
|
||||
result = LibPQ.execute(DBconnection, sql)
|
||||
close(DBconnection)
|
||||
return result
|
||||
end
|
||||
|
||||
function executeSQLVectorDB(sql)
|
||||
DBconnection = LibPQ.Connection("host=192.168.88.12 port=10203 dbname=SQLVectorDB user=yiemtechnologies password=yiemtechnologies@Postgres_0.0")
|
||||
result = LibPQ.execute(DBconnection, sql)
|
||||
close(DBconnection)
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
function text2textInstructLLM(prompt::String)
|
||||
msgMeta = GeneralUtils.generate_msgMeta(
|
||||
config[:externalservice][:text2textinstruct][:mqtttopic];
|
||||
msgPurpose= "inference",
|
||||
senderName= "yiemagent",
|
||||
senderId= string(uuid4()),
|
||||
receiverName= "text2textinstruct",
|
||||
mqttBrokerAddress= config[:mqttServerInfo][:broker],
|
||||
mqttBrokerPort= config[:mqttServerInfo][:port],
|
||||
msgPurpose="inference",
|
||||
senderName="yiemagent",
|
||||
senderId=string(uuid4()),
|
||||
receiverName="text2textinstruct",
|
||||
mqttBrokerAddress=config[:mqttServerInfo][:broker],
|
||||
mqttBrokerPort=config[:mqttServerInfo][:port],
|
||||
)
|
||||
|
||||
outgoingMsg = Dict(
|
||||
:msgMeta=> msgMeta,
|
||||
:payload=> Dict(
|
||||
:text=> prompt,
|
||||
:kwargs=> Dict(
|
||||
:max_tokens=> 2048,
|
||||
:stop=> ["<|eot_id|>"],
|
||||
:temperature=> 0.2,
|
||||
)
|
||||
:msgMeta => msgMeta,
|
||||
:payload => Dict(
|
||||
:text => prompt,
|
||||
:kwargs => Dict(
|
||||
:num_ctx => 16384,
|
||||
:temperature => 0.2,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
_response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
|
||||
_response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=6000)
|
||||
response = _response[:response][:text]
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
function executeSQLVectorDB(sql)
|
||||
DBconnection = LibPQ.Connection("host=192.168.88.12 port=5433 dbname=SQLVectorDB user=yiemtechnologies@gmail.com password=yiem@Postgres_0.0")
|
||||
result = LibPQ.execute(DBconnection, sql)
|
||||
close(DBconnection)
|
||||
return result
|
||||
end
|
||||
|
||||
function addSQLVectorDB(state)
|
||||
# get embedding of the query
|
||||
query = [state[:thoughtHistory][:question]]
|
||||
# get text embedding from a LLM service
|
||||
function getEmbedding(text::T) where {T<:AbstractString}
|
||||
msgMeta = GeneralUtils.generate_msgMeta(
|
||||
config[:externalservice][:text2textinstruct][:mqtttopic];
|
||||
msgPurpose= "embedding",
|
||||
senderName= "yiemagent",
|
||||
senderId= string(uuid4()),
|
||||
receiverName= "text2textinstruct",
|
||||
mqttBrokerAddress= config[:mqttServerInfo][:broker],
|
||||
mqttBrokerPort= config[:mqttServerInfo][:port],
|
||||
msgPurpose="embedding",
|
||||
senderName="yiemagent",
|
||||
senderId=string(uuid4()),
|
||||
receiverName="text2textinstruct",
|
||||
mqttBrokerAddress=config[:mqttServerInfo][:broker],
|
||||
mqttBrokerPort=config[:mqttServerInfo][:port],
|
||||
)
|
||||
|
||||
outgoingMsg = Dict(
|
||||
:msgMeta=> msgMeta,
|
||||
:payload=> Dict(
|
||||
:text=> query
|
||||
)
|
||||
:msgMeta => msgMeta,
|
||||
:payload => Dict(
|
||||
:text => [text] # must be a vector of string
|
||||
)
|
||||
)
|
||||
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
|
||||
embedding = response[:response][:embeddings][1]
|
||||
embedding = response[:response][:embeddings]
|
||||
return embedding
|
||||
end
|
||||
|
||||
function findSimilarTextFromVectorDB(text::T1, tablename::T2, embeddingColumnName::T3,
|
||||
vectorDB::Function; limit::Integer=1
|
||||
)::DataFrame where {T1<:AbstractString, T2<:AbstractString, T3<:AbstractString}
|
||||
|
||||
# get embedding from LLM service
|
||||
embedding = getEmbedding(text)[1]
|
||||
|
||||
# check whether there is close enough vector already store in vectorDB. if no, add, else skip
|
||||
sql =
|
||||
"""
|
||||
SELECT *, embedding <-> '$embedding' as distance
|
||||
FROM sql_statement_repository
|
||||
ORDER BY distance LIMIT 1;
|
||||
"""
|
||||
response = executeSQLVectorDB(sql)
|
||||
sql = """
|
||||
SELECT *, $embeddingColumnName <-> '$embedding' as distance
|
||||
FROM $tablename
|
||||
ORDER BY distance LIMIT $limit;
|
||||
"""
|
||||
response = vectorDB(sql)
|
||||
df = DataFrame(response)
|
||||
return df
|
||||
end
|
||||
|
||||
|
||||
function similarSQLVectorDB(query; maxdistance::Integer=100)
|
||||
tablename = "sqlllm_decision_repository"
|
||||
# get embedding of the query
|
||||
df = findSimilarTextFromVectorDB(query, tablename,
|
||||
"function_input_embedding", executeSQLVectorDB)
|
||||
row, col = size(df)
|
||||
distance = row == 0 ? Inf : df[1, :distance]
|
||||
if row != 0 && distance < maxdistance
|
||||
# if there is usable SQL, return it.
|
||||
output_b64 = df[1, :function_output_base64] # pick the closest match
|
||||
output_str = String(base64decode(output_b64))
|
||||
rowid = df[1, :id]
|
||||
println("\n~~~ found similar sql. row id $rowid, distance $distance ", @__FILE__, " ", @__LINE__)
|
||||
return (dict=output_str, distance=distance)
|
||||
else
|
||||
println("\n~~~ similar sql not found, max distance $maxdistance ", @__FILE__, " ", @__LINE__)
|
||||
return (dict=nothing, distance=nothing)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function insertSQLVectorDB(query::T1, SQL::T2; maxdistance::Integer=1) where {T1<:AbstractString, T2<:AbstractString}
|
||||
tablename = "sqlllm_decision_repository"
|
||||
# get embedding of the query
|
||||
# query = state[:thoughtHistory][:question]
|
||||
df = findSimilarTextFromVectorDB(query, tablename,
|
||||
"function_input_embedding", executeSQLVectorDB)
|
||||
row, col = size(df)
|
||||
distance = row == 0 ? Inf : df[1, :distance]
|
||||
if row == 0 || distance > 10 # no close enough SQL stored in the database
|
||||
latestKey, _ = GeneralUtils.findHighestIndexKey(state[:thoughtHistory], :action_input)
|
||||
_sqlStatement = state[:thoughtHistory][latestKey]
|
||||
if occursin("SELECT", _sqlStatement) # make sure it is an SQL statement before adding into DB
|
||||
sqlStatementBase64 = base64encode(_sqlStatement)
|
||||
sqlStatement = replace(_sqlStatement, "'"=>"")
|
||||
sql =
|
||||
"""
|
||||
INSERT INTO sql_statement_repository (question, sql_statement, sql_statement_base64, embedding) VALUES ('$query', '$sqlStatement', '$sqlStatementBase64', '$embedding');
|
||||
"""
|
||||
_ = executeSQLVectorDB(sql)
|
||||
println("--> added new SQL statement to vectorDB ", @__FILE__, " ", @__LINE__)
|
||||
println(sqlStatement)
|
||||
end
|
||||
if row == 0 || distance > maxdistance # no close enough SQL stored in the database
|
||||
query_embedding = getEmbedding(query)[1]
|
||||
query = replace(query, "'" => "")
|
||||
sql_base64 = base64encode(SQL)
|
||||
sql_ = replace(SQL, "'" => "")
|
||||
|
||||
sql = """
|
||||
INSERT INTO $tablename (function_input, function_output, function_output_base64, function_input_embedding) VALUES ('$query', '$sql_', '$sql_base64', '$query_embedding');
|
||||
"""
|
||||
println("\n~~~ added new decision to vectorDB ", @__FILE__, " ", @__LINE__)
|
||||
println(sql)
|
||||
_ = executeSQLVectorDB(sql)
|
||||
end
|
||||
end
|
||||
|
||||
function querySQLVectorDB(state)
|
||||
|
||||
# provide similarSQL at the first time thinking only
|
||||
latestKey, _ = GeneralUtils.findHighestIndexKey(state[:thoughtHistory], :action_input)
|
||||
if latestKey === nothing
|
||||
# get embedding of the query
|
||||
query = [state[:thoughtHistory][:question]]
|
||||
msgMeta = GeneralUtils.generate_msgMeta(
|
||||
config[:externalservice][:text2textinstruct][:mqtttopic];
|
||||
msgPurpose= "embedding",
|
||||
senderName= "yiemagent",
|
||||
senderId= string(uuid4()),
|
||||
receiverName= "text2textinstruct",
|
||||
mqttBrokerAddress= config[:mqttServerInfo][:broker],
|
||||
mqttBrokerPort= config[:mqttServerInfo][:port],
|
||||
)
|
||||
|
||||
outgoingMsg = Dict(
|
||||
:msgMeta=> msgMeta,
|
||||
:payload=> Dict(
|
||||
:text=> query
|
||||
)
|
||||
)
|
||||
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
|
||||
embedding = response[:response][:embeddings][1]
|
||||
|
||||
# check whether there is close enough vector already store in vectorDB. if no, add, else skip
|
||||
sql =
|
||||
"""
|
||||
SELECT *, embedding <-> '$embedding' as distance
|
||||
FROM sql_statement_repository
|
||||
ORDER BY distance LIMIT 1;
|
||||
"""
|
||||
response = executeSQLVectorDB(sql)
|
||||
df = DataFrame(response)
|
||||
row, col = size(df)
|
||||
distance = row == 0 ? Inf : df[1, :distance]
|
||||
if row != 0 && distance < 100
|
||||
# if there is usable SQL, return it.
|
||||
sqlStatementBase64 = df[1, :sql_statement_base64]
|
||||
sqlStatement = String(base64decode(sqlStatementBase64))
|
||||
println("--> getting SQL statement from vectorDB ", @__FILE__, " ", @__LINE__)
|
||||
println(sqlStatement)
|
||||
return sqlStatement
|
||||
else
|
||||
return nothing
|
||||
end
|
||||
function similarSommelierDecision(recentevents::T1; maxdistance::Integer=5
|
||||
)::Union{AbstractDict, Nothing} where {T1<:AbstractString}
|
||||
tablename = "sommelier_decision_repository"
|
||||
# find similar
|
||||
println("\n~~~ search vectorDB for this: $recentevents ", @__FILE__, " ", @__LINE__)
|
||||
df = findSimilarTextFromVectorDB(recentevents, tablename,
|
||||
"function_input_embedding", executeSQLVectorDB)
|
||||
row, col = size(df)
|
||||
distance = row == 0 ? Inf : df[1, :distance]
|
||||
if row != 0 && distance < maxdistance
|
||||
# if there is usable decision, return it.
|
||||
rowid = df[1, :id]
|
||||
println("\n~~~ found similar decision. row id $rowid, distance $distance ", @__FILE__, " ", @__LINE__)
|
||||
output_b64 = df[1, :function_output_base64] # pick the closest match
|
||||
_output_str = String(base64decode(output_b64))
|
||||
output = copy(JSON3.read(_output_str))
|
||||
return output
|
||||
else
|
||||
println("\n~~~ similar decision not found, max distance $maxdistance ", @__FILE__, " ", @__LINE__)
|
||||
return nothing
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
|
||||
|
||||
# Instantiate an agent
|
||||
function insertSommelierDecision(recentevents::T1, decision::T2; maxdistance::Integer=5
|
||||
) where {T1<:AbstractString, T2<:AbstractDict}
|
||||
tablename = "sommelier_decision_repository"
|
||||
# find similar
|
||||
df = findSimilarTextFromVectorDB(recentevents, tablename,
|
||||
"function_input_embedding", executeSQLVectorDB)
|
||||
row, col = size(df)
|
||||
distance = row == 0 ? Inf : df[1, :distance]
|
||||
if row == 0 || distance > maxdistance # no close enough SQL stored in the database
|
||||
recentevents_embedding = a.func[:getEmbedding](recentevents)[1]
|
||||
recentevents = replace(recentevents, "'" => "")
|
||||
decision_json = JSON3.write(decision)
|
||||
decision_base64 = base64encode(decision_json)
|
||||
decision = replace(decision_json, "'" => "")
|
||||
|
||||
sql = """
|
||||
INSERT INTO $tablename (function_input, function_output, function_output_base64, function_input_embedding) VALUES ('$recentevents', '$decision', '$decision_base64', '$recentevents_embedding');
|
||||
"""
|
||||
println("\n~~~ added new decision to vectorDB ", @__FILE__, " ", @__LINE__)
|
||||
println(sql)
|
||||
_ = executeSQLVectorDB(sql)
|
||||
else
|
||||
println("~~~ similar decision previously cached, distance $distance ", @__FILE__, " ", @__LINE__)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
sessionId = "12345"
|
||||
|
||||
externalFunction = (
|
||||
getEmbedding=getEmbedding,
|
||||
text2textInstructLLM=text2textInstructLLM,
|
||||
executeSQL=executeSQL,
|
||||
similarSQLVectorDB=similarSQLVectorDB,
|
||||
insertSQLVectorDB=insertSQLVectorDB,
|
||||
similarSommelierDecision=similarSommelierDecision,
|
||||
insertSommelierDecision=insertSommelierDecision,
|
||||
)
|
||||
|
||||
|
||||
|
||||
a = YiemAgent.sommelier(
|
||||
text2textInstructLLM,
|
||||
executeSQL,
|
||||
querySQLVectorDB,
|
||||
addSQLVectorDB;
|
||||
name= "Jene",
|
||||
id= "tempId", # agent instance id
|
||||
externalFunction;
|
||||
name="Ton",
|
||||
id=sessionId, # agent instance id
|
||||
retailername="Yiem",
|
||||
)
|
||||
|
||||
function main()
|
||||
for i in 1:10
|
||||
userinput = ""
|
||||
for i in 1:3
|
||||
if userinput == ""
|
||||
println("")
|
||||
println("--> user input:")
|
||||
userinput = readline()
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
response = YiemAgent.conversation(a, Dict(:text=> userinput))
|
||||
println("")
|
||||
println("--> assistant response: \n", response)
|
||||
end
|
||||
while true
|
||||
println("your respond: ")
|
||||
user_answer = readline()
|
||||
response = YiemAgent.conversation(a, Dict(:text=> user_answer))
|
||||
println("\n$response")
|
||||
end
|
||||
|
||||
main()
|
||||
|
||||
"""
|
||||
I'm joining a graduation party this evening. I want to get a bottle of white wine from the US to celebrate. I'm ok with any price range.
|
||||
Well, the party is small casual with close friends and no food serving.
|
||||
I'm open to suggestion since I have no specific idea.
|
||||
I'm ok with any region.
|
||||
|
||||
|
||||
|
||||
|
||||
The input is instructions on how you want the presentation to be conducted.
|
||||
"""
|
||||
|
||||
|
||||
wines =
|
||||
"""
|
||||
Summary: This table contains two wine records, both from the United States, with white wine types, moderate sweetness (2), and high intensity (5).
|
||||
More details: 1) wine_id: add9824f-81b0-47da-a08a-ee20498bc6c8, wine_name: Belle Cote Chardonnay, brand: Peter Michael, manufacturer: Peter Michael, region: Californian, country: United States, wine_type: white, grape_variety: Chardonnay, serving_temperature: 11 to 13 Celsius, intensity: 5, sweetness: 2, tannin: missing, acidity: 3, fizziness: missing, tasting_notes: oak, butter, vanilla, cream, oil, lemon curd, pear, peach, apple
|
||||
2) wine_id: ff9a494c-e916-44c4-9385-1c18b23aa825, wine_name: Ma Belle-Fille Chardonnay, brand: Peter Michael, manufacturer: Peter Michael, region: Californian, country: United States, wine_type: white, grape_variety: Chardonnay, serving_temperature: 11 to 13 Celsius, intensity: 5, sweetness: 2, tannin: missing, acidity: 3, fizziness: missing, tasting_notes: oak, butter, vanilla, cream, banana, cheese, apricot, peach, apple
|
||||
"""
|
||||
|
||||
|
||||
|
||||
# response = YiemAgent.conversation(a, Dict(:text=> "newtopic",) )
|
||||
|
||||
# response = YiemAgent.conversation(a, Dict(:text=> "Hello, I would like a get a bottle of wine."))
|
||||
# println("---> YiemAgent: ", response)
|
||||
|
||||
# response = YiemAgent.conversation(a, Dict(:text=> "I'm having a graduation party this evening. I'll pay at most 30 bucks."))
|
||||
# response = YiemAgent.conversation(a, Dict(:text=> "I want to get a French red wine under 100."))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -229,60 +257,16 @@ More details: 1) wine_id: add9824f-81b0-47da-a08a-ee20498bc6c8, wine_name: Belle
|
||||
|
||||
|
||||
|
||||
# # input = "query=\"off dry, medium tannin, French Rosé\""
|
||||
# input = "Search the database for wine type: white, country: France, sweetness level: 1"
|
||||
# YiemAgent.winestock(a, input)
|
||||
|
||||
|
||||
|
||||
|
||||
# input = "French dry white wines with medium body"
|
||||
# input = "query=\"medium-bodied dry white wine\""
|
||||
# # input = "the customer is looking for a medium-bodied, dry white wine."
|
||||
# result = YiemAgent.checkinventory(a, input)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
error("test done")
|
||||
|
||||
|
||||
|
||||
|
||||
function run_with_timeout(f, args...; timeout=5)
|
||||
result = Ref{Any}()
|
||||
task = Threads.@spawn try
|
||||
result[] = f(args...)
|
||||
catch e
|
||||
println("Task interrupted: ", e)
|
||||
end
|
||||
|
||||
Timer(timeout) do _
|
||||
if !istaskdone(task)
|
||||
schedule(task, InterruptException())
|
||||
println("Task did not complete in time. Aborting.")
|
||||
else
|
||||
println("Task completed within the timeout.")
|
||||
end
|
||||
end
|
||||
|
||||
return result[]
|
||||
end
|
||||
|
||||
# Example function that takes arguments and returns a value
|
||||
function example_function(x, y)
|
||||
sleep(10) # Simulate a long-running task
|
||||
return x + y
|
||||
end
|
||||
|
||||
# Example usage
|
||||
result = run_with_timeout(example_function, 3, 4; timeout=5)
|
||||
println("Result: ", result)
|
||||
|
||||
|
||||
a = `$"hello\nworld"`
|
||||
a = $"hello\nworld"
|
||||
|
||||
a = """$("hello\nworld")"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user