new version
This commit is contained in:
7
previousVersion/0.0.7/CondaPkg.toml
Executable file
7
previousVersion/0.0.7/CondaPkg.toml
Executable file
@@ -0,0 +1,7 @@
|
||||
channels = ["anaconda", "conda-forge", "pytorch"]
|
||||
|
||||
[deps]
|
||||
python = ">=3.8,<3.11"
|
||||
|
||||
[pip.deps]
|
||||
langchain = ""
|
||||
1171
previousVersion/0.0.7/Manifest.toml
Executable file
1171
previousVersion/0.0.7/Manifest.toml
Executable file
File diff suppressed because it is too large
Load Diff
17
previousVersion/0.0.7/Project.toml
Executable file
17
previousVersion/0.0.7/Project.toml
Executable file
@@ -0,0 +1,17 @@
|
||||
name = "ChatAgent"
|
||||
uuid = "cff63402-b71f-455f-804d-24489fc61e5e"
|
||||
authors = ["narawat <narawat@gmail.com>"]
|
||||
version = "0.1.0"
|
||||
|
||||
[deps]
|
||||
CommUtils = "646cbe82-3d4a-47b2-9440-2e80a472ca20"
|
||||
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
|
||||
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
|
||||
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||
GeneralUtils = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
|
||||
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
|
||||
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
|
||||
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
|
||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||
URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
|
||||
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
|
||||
101
previousVersion/0.0.7/src/ChatAgent.jl
Executable file
101
previousVersion/0.0.7/src/ChatAgent.jl
Executable file
@@ -0,0 +1,101 @@
|
||||
module ChatAgent
|
||||
|
||||
# export agent, addNewMessage, clearMessage
|
||||
|
||||
|
||||
""" Order by dependencies of each file. The 1st included file must not depend on any other
|
||||
files and each file can only depend on the file included before it.
|
||||
"""
|
||||
|
||||
include("type.jl")
|
||||
using .type
|
||||
|
||||
include("utils.jl")
|
||||
using .utils
|
||||
|
||||
include("llmfunction.jl")
|
||||
using .llmfunction
|
||||
|
||||
include("interface.jl")
|
||||
using .interface
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------------------------100
|
||||
|
||||
""" version 0.0.5
|
||||
Todo:
|
||||
[WORKING] add formulateUserRespond to AI tools
|
||||
|
||||
Change from version: 0.0.4
|
||||
-
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end # module ChatAgent
|
||||
2162
previousVersion/0.0.7/src/interface.jl
Executable file
2162
previousVersion/0.0.7/src/interface.jl
Executable file
File diff suppressed because it is too large
Load Diff
368
previousVersion/0.0.7/src/llmfunction.jl
Normal file
368
previousVersion/0.0.7/src/llmfunction.jl
Normal file
@@ -0,0 +1,368 @@
|
||||
module llmfunction
|
||||
|
||||
export wikisearch, winestock, askbox
|
||||
|
||||
using HTTP, JSON3, URIs, Random
|
||||
using GeneralUtils
|
||||
using ..type, ..utils
|
||||
#------------------------------------------------------------------------------------------------100
|
||||
|
||||
""" Search wikipedia.
|
||||
|
||||
Arguments\n
|
||||
query {string} : The query to search for
|
||||
|
||||
Returns\n
|
||||
result {string} : The search result text from wikipedia
|
||||
```jldoctest
|
||||
julia> using HTTP, JSON3
|
||||
julia> result = wikisearch("AMD")
|
||||
"Advanced Micro Devices, Inc., commonly abbreviated as AMD, is an ..."
|
||||
```
|
||||
"""
|
||||
function wikisearch(a::agentReflex, phrase::T) where {T<:AbstractString}
|
||||
phrase = phrase[1] == " " ? phrase[2:end] : phrase
|
||||
# prepare input phrase
|
||||
if occursin("\"", phrase)
|
||||
phrase = GeneralUtils.getStringBetweenCharacters(phrase, "\"", "\"")
|
||||
end
|
||||
phrase = replace(phrase, "\n"=>"")
|
||||
|
||||
url = "https://en.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&titles=$(replace(phrase, " " => "%20"))&exintro=1&explaintext=1"
|
||||
@show url
|
||||
response = HTTP.get(url)
|
||||
json_data = JSON3.read(String(response.body))
|
||||
page_id = first(keys(json_data["query"]["pages"]))
|
||||
if page_id == "-1"
|
||||
return "Sorry, I couldn't find any Wikipedia page for the given phrase."
|
||||
end
|
||||
|
||||
result = nothing
|
||||
try
|
||||
result = json_data["query"]["pages"][page_id]["extract"]
|
||||
wiki = result
|
||||
@show wiki
|
||||
catch
|
||||
result = "No info available for your search query."
|
||||
end
|
||||
|
||||
# if result == ""
|
||||
# result = "No info available for your search query."
|
||||
# else
|
||||
# result = makeSummary(a, result)
|
||||
# end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
""" Search wine in stock.
|
||||
|
||||
Arguments\n
|
||||
a : one of ChatAgent's agent.
|
||||
Return\n
|
||||
A JSON string of available wine
|
||||
|
||||
Example\n
|
||||
```jldoctest
|
||||
julia> using ChatAgent, CommUtils
|
||||
julia> agent = ChatAgent.agentReflex("Jene")
|
||||
julia> input = "{\"food\": \"pizza\", \"occasion\": \"anniversary\"}"
|
||||
julia> result = winestock(agent, input)
|
||||
"{"wine 1": {\"Winery\": \"Pichon Baron\", \"wine name\": \"Pauillac (Grand Cru Classé)\", \"grape variety\": \"Cabernet Sauvignon\", \"year\": 2010, \"price\": \"125 USD\", \"stock ID\": \"ar-17\"}, }"
|
||||
```
|
||||
"""
|
||||
function winestock(a::agentReflex, input::NamedTuple)
|
||||
println("")
|
||||
@show input
|
||||
|
||||
wineSearchCriteria = GeneralUtils.JSON3read_stringKey(input[:toolinput])
|
||||
newDict = Dict{String,Any}()
|
||||
for (k,v) in wineSearchCriteria
|
||||
println("k $k v $v")
|
||||
newDict[string(k)] = v
|
||||
end
|
||||
|
||||
#TODO temporary delete key "food pairing from a dict
|
||||
newDict = deepcopy(a.memory[:keyword])
|
||||
delete!(newDict, "food pairing")
|
||||
|
||||
query = JSON3.write(newDict)
|
||||
|
||||
println("")
|
||||
@show query
|
||||
|
||||
# prompt =
|
||||
# """
|
||||
# <|system|>
|
||||
# <About yourself>
|
||||
# Your are a helpful assistant.
|
||||
# </About yourself>
|
||||
# <You have the following conversion table>
|
||||
# Database table name by wine type:
|
||||
# Red = table for wine type "red"
|
||||
# White = table for wine type "white"
|
||||
# Sparkling = table for wine type "sparkling"
|
||||
# Rose = table for wine type "rose"
|
||||
# Dessert = table for wine type "dessert"
|
||||
# Fortified = table for wine type "fortified"
|
||||
# Intensity level:
|
||||
# intensity = 1, light bodied
|
||||
# intensity = 2, semi-light bodied
|
||||
# intensity = 3, medium bodied
|
||||
# intensity = 4, semi-full bodied
|
||||
# intensity = 5, full bodied
|
||||
# Sweetness level:
|
||||
# sweetness = 1, dry
|
||||
# sweetness = 2, off-dry
|
||||
# sweetness = 3, semi-sweet
|
||||
# sweetness = 4, sweet
|
||||
# sweetness = 5, very sweet
|
||||
# Tannin level:
|
||||
# tannin = 1, low tannin
|
||||
# tannin = 2, semi-low tannin
|
||||
# tannin = 3, medium tannin
|
||||
# tannin = 4, semi-high tannin
|
||||
# tannin = 5, high tannin
|
||||
# Acidity level:
|
||||
# acidity = 1, low acidity
|
||||
# acidity = 2, semi-low acidity
|
||||
# acidity = 3, medium acidity
|
||||
# acidity = 4, semi-high acidity
|
||||
# acidity = 5, high acidity
|
||||
# </You have the following conversion table>
|
||||
# <Your job>
|
||||
# Consult the conversion table then write a specific SQL command using only available info from a JSON-format query.
|
||||
# List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"]
|
||||
|
||||
# Use the following format:
|
||||
# Info map: based on conversion table, map the info in query to appropriate variables
|
||||
# SQL: write a specific SQL command
|
||||
# </Your job>
|
||||
# <Example 1>
|
||||
# query: {\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | low to medium tannin\", \"price\": {\"max\": \"50\"}}
|
||||
# Think: 1) low to medium tannin is not explicitly stated, but assuming it falls within the range of low-medium tannin.
|
||||
# Info map: {\"wine type\": \"white\", \"intensity\": 5, \"sweetness\": 2, \"tannin\": 2, \"acidity\": 1, \"price\": 50}
|
||||
# SQL: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 2 AND price <= 50;
|
||||
# </Example 1>
|
||||
# <Example 2>
|
||||
# query: {\"wine characteristics\":\"low-bodied | a little sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
|
||||
# Think: 1) medium sweet is not explicitly stated, but assuming it falls within the range of dry and off-dry.
|
||||
# Info map: {\"wine type\": \"Rose\", \"intensity\": 1, \"sweetness\": 3, \"tannin\": 2, \"acidity\": 3, \"price\": 22, \"food\":\"American dishes\"}
|
||||
# SQL: SELECT * FROM Rose WHERE intensity = 1 AND tannin = 2 AND (sweetness = 1 OR sweetness = 2) AND price <= 22 AND food = American;
|
||||
# </Example 2>
|
||||
# </s>
|
||||
# <|query|>
|
||||
# $query
|
||||
# </s>
|
||||
# <|assistant|>
|
||||
# """
|
||||
|
||||
prompt =
|
||||
"""
|
||||
<s>
|
||||
<|system|>
|
||||
<About yourself>
|
||||
Your are a helpful assistant.
|
||||
</About yourself>
|
||||
<You have the following conversion table>
|
||||
Database table name by wine type:
|
||||
Red = table for wine type "red"
|
||||
White = table for wine type "white"
|
||||
Sparkling = table for wine type "sparkling"
|
||||
Rose = table for wine type "rose"
|
||||
Dessert = table for wine type "dessert"
|
||||
Fortified = table for wine type "fortified"
|
||||
Intensity level:
|
||||
light bodied = 1
|
||||
semi-light bodied = 2
|
||||
medium bodied = 3
|
||||
semi-full bodied = 4
|
||||
full bodied = 5
|
||||
Sweetness level:
|
||||
dry = 1
|
||||
off-dry = 2
|
||||
semi-sweet = 3
|
||||
sweet = 4
|
||||
very sweet = 5
|
||||
Tannin level:
|
||||
low tannin = 1
|
||||
semi-low tannin = 2
|
||||
medium tannin = 3
|
||||
semi-high tannin = 4
|
||||
high tannin = 4
|
||||
Acidity level:
|
||||
low acidity = 1
|
||||
semi-low acidity = 2
|
||||
medium acidity = 3
|
||||
semi-high acidity = 4
|
||||
high acidity = 5
|
||||
</You have the following conversion table>
|
||||
<Your job>
|
||||
Write a specific SQL command from a query using a conversion table
|
||||
List of keywords not allowed the command: ["BETWEEN", "--", "WHEN", "IN"]
|
||||
|
||||
Use the following format:
|
||||
Info map: based on conversion table, map the info in query to appropriate variables
|
||||
SQL: write a specific SQL command
|
||||
</Your job>
|
||||
</|system|>
|
||||
<Example 1>
|
||||
<query>
|
||||
{\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | low to medium tannin\", \"price\": {\"max\": \"50\"}}
|
||||
</query>
|
||||
<|assistant|>
|
||||
Think: 1) low to medium tannin is not explicitly stated, but assuming it falls within the range of low-medium tannin.
|
||||
Info map: {\"wine type\": \"white\", \"intensity\": 5, \"sweetness\": 2, \"tannin\": 2, \"acidity\": 1, \"price\": 50}
|
||||
SQL: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 2 AND price <= 50;
|
||||
</|assistant|>
|
||||
</Example 1>
|
||||
<Example 2>
|
||||
<query>
|
||||
{\"wine characteristics\":\"low-bodied | a little sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
|
||||
</query>
|
||||
<|assistant|>
|
||||
Think: 1) medium sweet is not explicitly stated, but assuming it falls within the range of dry and off-dry.
|
||||
Info map: {\"wine type\": \"Rose\", \"intensity\": 1, \"sweetness\": 3, \"tannin\": 2, \"acidity\": 3, \"price\": 22, \"food\":\"American dishes\"}
|
||||
SQL: SELECT * FROM Rose WHERE intensity = 1 AND tannin = 2 AND (sweetness = 1 OR sweetness = 2) AND price <= 22 AND food = American;
|
||||
</|assistant|>
|
||||
</Example 2>
|
||||
</s>
|
||||
<query>
|
||||
$query
|
||||
</query>
|
||||
<|assistant|>
|
||||
"""
|
||||
|
||||
println("")
|
||||
@show db_prompt = prompt
|
||||
_sql = nothing
|
||||
while true
|
||||
_sql = sendReceivePrompt(a, prompt, max_tokens=256, temperature=0.4,
|
||||
stopword=["/n/n", "END", "End", "Obs", "<|", "</"])
|
||||
_sql = split(_sql, ";")[1] * ";"
|
||||
@show _sql
|
||||
# check for valid SQL command
|
||||
check_1 = occursin("BETWEEN", _sql)
|
||||
check_2 = occursin("--", _sql)
|
||||
check_3 = occursin("IN", _sql)
|
||||
|
||||
if check_1 == false && check_2 == false && check_3 == false
|
||||
break
|
||||
end
|
||||
println("invalid SQL command")
|
||||
end
|
||||
|
||||
_sql = split(_sql, "SQL:")[end]
|
||||
println("")
|
||||
@show db_sql = replace(_sql, '\n'=>"")
|
||||
|
||||
# remove any blank character in front of a string
|
||||
newsql = nothing
|
||||
for i in eachindex(_sql)
|
||||
if _sql[i] != ' '
|
||||
newsql = _sql[i:end]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
body = newsql
|
||||
uri = URI(scheme="http", host="192.168.88.12", port="9010", path="/sql", userinfo="root:root")
|
||||
r = HTTP.request("POST", uri, ["Accept" => "application/json", "NS"=>"yiem", "DB"=>"Blossom_wines"], body)
|
||||
|
||||
a.memory[:r] = r
|
||||
result = copy(JSON3.read(r.body))
|
||||
|
||||
|
||||
wines = shuffle(result[1][:result]) # shuffle in case there are more than 1 result
|
||||
|
||||
|
||||
# choose only 2 wines
|
||||
if length(wines) > 2
|
||||
println("$(length(wines)) wines found")
|
||||
wines = wines[1:2]
|
||||
end
|
||||
|
||||
println("")
|
||||
@show wines
|
||||
|
||||
result = nothing
|
||||
if length(wines) == 0
|
||||
result =
|
||||
"""
|
||||
No wine match my search query.
|
||||
"""
|
||||
else
|
||||
# write wines dictionary in to string
|
||||
wines_str = ""
|
||||
for (i, wine) in enumerate(wines)
|
||||
winename = wine[:wine_name]
|
||||
wines_str *= "$i: $(JSON3.write(wines[i])),"
|
||||
end
|
||||
|
||||
result =
|
||||
"""
|
||||
I found the following wines in our stock:
|
||||
{
|
||||
$wines_str
|
||||
}
|
||||
"""
|
||||
end
|
||||
|
||||
@show result
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
""" Get the first JSON string questions.
|
||||
|
||||
Arguments\n
|
||||
a : one of ChatAgent's agent.
|
||||
input {JSON string} : message to the user
|
||||
|
||||
Return\n
|
||||
a single message to the user
|
||||
|
||||
Example\n
|
||||
```jldoctest
|
||||
julia> input = "{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}"
|
||||
julia> askbox(input)
|
||||
"How are you doing?"
|
||||
```
|
||||
"""
|
||||
function askbox(input::String)
|
||||
dict = GeneralUtils.JSON3read_stringKey(input)
|
||||
_keylist = keys(dict)
|
||||
keylist = [key for key in _keylist]
|
||||
return dict[keylist[1]]
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end # end module
|
||||
342
previousVersion/0.0.7/src/type.jl
Normal file
342
previousVersion/0.0.7/src/type.jl
Normal file
@@ -0,0 +1,342 @@
|
||||
module type
|
||||
|
||||
export agent, agentReflex, newAgentMemory
|
||||
|
||||
using Dates, UUIDs, DataStructures
|
||||
using CommUtils
|
||||
|
||||
#------------------------------------------------------------------------------------------------100
|
||||
|
||||
function newAgentMemory()
|
||||
memory::Dict{Any, Any} = Dict(
|
||||
:shortterm=> OrderedDict{String, Any}(),
|
||||
:longterm=> OrderedDict{String, Any}(),
|
||||
:log=> OrderedDict{String, Any}(), # span from user stimulus -> multiples attempts -> final respond
|
||||
:keyword=> Dict{String, Any}(),
|
||||
)
|
||||
return memory
|
||||
end
|
||||
|
||||
|
||||
abstract type agent end
|
||||
|
||||
""" A LLM agent with self reflect capabilities.
|
||||
|
||||
Example:
|
||||
```jldoctest
|
||||
julia> using ChatAgent
|
||||
julia> mqttClientSpec = (
|
||||
clientName= "someclient", # name of this client
|
||||
clientID= "$(uuid4())",
|
||||
broker= "mqtt.yiem.ai",
|
||||
pubtopic= (imgAI="img/api/v0.0.1/gpu/request",
|
||||
txtAI="txt/api/v0.1.0/gpu/request"), # this is where LLM server located
|
||||
subtopic= (imgAI="agent/api/v0.1.0/img/respond",
|
||||
txtAI="agent/api/v0.1.0/txt/respond"), # this is where this agent located
|
||||
keepalive= 30,
|
||||
)
|
||||
julia> msgMeta = Dict(
|
||||
:msgPurpose=> "updateStatus",
|
||||
:from=> "agent",
|
||||
:to=> "llmAI",
|
||||
:requestrespond=> "request",
|
||||
:sendto=> "", # destination topic
|
||||
:replyTo=> "agent/api/v0.1.0/txt/respond", # requester ask responder to send reply to this topic
|
||||
:repondToMsgId=> "", # responder is responding to this msg id
|
||||
:taskstatus=> "", # "complete", "fail", "waiting" or other status
|
||||
:timestamp=> Dates.now(),
|
||||
:msgId=> "$(uuid4())",
|
||||
)
|
||||
julia> tools=Dict(
|
||||
:chatbox=>Dict(
|
||||
:name => "chatbox",
|
||||
:description => "Useful only for when you need to ask the user for more info or context. Do not ask the user their own question.",
|
||||
:input => "Input should be a text.",
|
||||
:output => "" ,
|
||||
:func => nothing,
|
||||
),
|
||||
:wikisearch=>Dict(
|
||||
:name => "wikisearch",
|
||||
:description => "Useful for when you need to search an encyclopedia.",
|
||||
:input => "Input is keywords and not a question.",
|
||||
:output => "",
|
||||
:func => ChatAgent.wikisearch, # put function here
|
||||
),
|
||||
:winestock=>Dict(
|
||||
:name => "wineStock",
|
||||
:description => "useful for when you need to search your wine stock by wine description, price, name or ID.",
|
||||
:input => "Input is a search query.",
|
||||
:output => "Output are Wine name, description, price and ID" ,
|
||||
:func => ChatAgent.winestock,
|
||||
),
|
||||
)
|
||||
julia> agent = ChatAgent.agentReflex(
|
||||
"Jene",
|
||||
role=:assistant,
|
||||
mqttClientSpec=mqttClientSpec,
|
||||
msgMeta=msgMeta,
|
||||
tools=tools
|
||||
)
|
||||
```
|
||||
"""
|
||||
@kwdef mutable struct agentReflex <: agent
|
||||
availableRole::AbstractVector = ["system", "user", "assistant"]
|
||||
agentName::String = "Jene" # ex. Jene
|
||||
maxUserMsg::Int = 30
|
||||
earlierConversation::String = "N/A" # summary of earlier conversation
|
||||
mqttClient::Union{mqttClient, Nothing} = nothing
|
||||
msgMeta::Union{Dict, Nothing} = nothing
|
||||
|
||||
""" Dict(Role=> Content) ; Role can be system, user, assistant
|
||||
Example:
|
||||
messages=[
|
||||
Dict(:role=>"system", :content=> "You are a helpful assistant."),
|
||||
Dict(:role=>"assistant", :content=> "How may I help you"),
|
||||
Dict(:role=>"user", :content=> "Hello, how are you"),
|
||||
]
|
||||
"""
|
||||
role::Symbol = :assistant
|
||||
roles::Dict = Dict(:assistant => "You are a helpful assistant.",)
|
||||
|
||||
# Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
|
||||
# messages= [Dict(:role=>"system", :content=> "", :timestamp=> Dates.now()),]
|
||||
messages = Vector{Dict{Symbol, Any}}()
|
||||
tools::Union{Dict, Nothing} = nothing
|
||||
newplan::Bool = false # if true, new plan will be generated
|
||||
attemptlimit::Int = 5 # thinking round limit
|
||||
attempt::Int = 1 # attempted number
|
||||
task::Int = 1 # task number
|
||||
env::AbstractString = "N/A"
|
||||
thinkingFormat::Union{Dict, Nothing} = nothing
|
||||
roleSpecificInstruction::Union{Dict, Nothing} = nothing
|
||||
memory = newAgentMemory()
|
||||
|
||||
# LLM function related
|
||||
winestockResult = ""
|
||||
end
|
||||
|
||||
function agentReflex(
|
||||
agentName::String;
|
||||
mqttClientSpec::NamedTuple=(
|
||||
clientName= "someclient", # name of this client
|
||||
clientID= "$(uuid4())",
|
||||
broker= "mqtt.yiem.ai",
|
||||
pubtopic= (imgAI="img/api/v0.0.1/gpu/request",
|
||||
txtAI="txt/api/v0.1.0/gpu/request"),
|
||||
subtopic= (imgAI="agent/api/v0.1.0/img/respond",
|
||||
txtAI="agent/api/v0.1.0/txt/respond"),
|
||||
keepalive= 30,),
|
||||
role::Symbol=:assistant,
|
||||
roles::Dict=Dict(
|
||||
:assistant =>
|
||||
"""
|
||||
You are a helpful assistant.
|
||||
""",
|
||||
:sommelier =>
|
||||
"""
|
||||
You are a helpful sommelier at a wine retailer.
|
||||
You helps users by searching wine that match the user preferences from your stock.
|
||||
""",
|
||||
),
|
||||
roleSpecificInstruction::Dict=Dict(
|
||||
:assistant => "",
|
||||
# :sommelier =>
|
||||
# """
|
||||
# Required info you need for wine recommendation:
|
||||
# - occasion: ask the user
|
||||
# - type of food that will be served with wine: ask the user
|
||||
# - type of wine (we have Rose, White, Red, Rose and Sparkling): ask the user
|
||||
# - wine sweetness level (dry to very sweet)
|
||||
# - wine intensity level (light to full bodied)
|
||||
# - wine tannin level (low to high)
|
||||
# - wine acidity level (low to high)
|
||||
# - wine price range: ask the user
|
||||
# - wines we have in stock: use winestock tool
|
||||
# """
|
||||
:sommelier =>
|
||||
"""
|
||||
<Required wine info>
|
||||
You need to gather all of the following info sequentially before you can recommend wine:
|
||||
1. "wine budget"
|
||||
2. "wine type" (rose, white, red, sparkling, dessert)
|
||||
3. "food pairing" that will be served with wine
|
||||
4. "wine sweetness level" (dry to very sweet)
|
||||
5. "wine intensity level" (light to full bodied)
|
||||
6. "wine tannin level" (low to high)
|
||||
7. "wine acidity level" (low to high)
|
||||
8. wine you have in stock that match the user preferences
|
||||
</Required wine info>
|
||||
"""
|
||||
),
|
||||
|
||||
thinkingFormat::Dict=Dict(
|
||||
:react=>
|
||||
"""
|
||||
Use the following format:
|
||||
Question: the input question your user is asking and you must answer
|
||||
Plan: first you should always think about the question and the info you have thoroughly then extract and devise a complete plan to find the answer (pay attention to variables and their corresponding numerals).
|
||||
Thought: ask yourself do you have all the info you need? And what to do according to the plan (pay attention to correct numeral calculation and commonsense).
|
||||
Act: the tool that match your thought, should be one of {toolnames}
|
||||
Actinput: the input to the action (pay attention to the tool's input)
|
||||
Obs: the result of the action
|
||||
... (this Plan/Thought/Act/Actinput/Obs can repeat N times until you know the answer.)
|
||||
Thought: I think I know the answer
|
||||
Answer: Answer of the original question
|
||||
|
||||
Begin!""",
|
||||
:planner=>
|
||||
"""
|
||||
Use the following format:
|
||||
Stimulus: the input user gives to you and you must respond
|
||||
Plan: first you should always think about the stimulus, the info you need and the info you have thoroughly then extract and devise a step by step plan (pay attention to correct numeral calculation and commonsense).
|
||||
P.S.1 each step should be a single action.
|
||||
""",
|
||||
:actor=>
|
||||
"""
|
||||
<Your job>
|
||||
Use the following format:
|
||||
Thought: based on the plan and the recap of the plan, what to do? (pay attention to correct numeral calculation and commonsense).
|
||||
Act: an action to take based on your thought, must be one of [{toolnames}]
|
||||
Actinput: your input to the action based on your thought (pay attention to the tool's input)
|
||||
Obs: observed result of the action
|
||||
|
||||
P.S.1 ask the user one by one question.
|
||||
P.S.2 ask the user what you want to know if you didn't ask yet.
|
||||
</Your job>
|
||||
""",
|
||||
:actorOriginal=>
|
||||
"""
|
||||
Use the following format:
|
||||
Thought: you should always think about do you have all the required info and what to do according to step {step} of the plan and the info you have (pay attention to correct numeral calculation and commonsense).
|
||||
Act: the action to take that match your thought, should be one of [{toolnames}]
|
||||
Actinput: the input to the action (pay attention to the tool's input)
|
||||
Obs: the result of the action
|
||||
""",
|
||||
),
|
||||
tools::Dict=Dict(
|
||||
:chatbox=>Dict(
|
||||
:name => "chatbox",
|
||||
:description => "Useful for when you need to communicate with the user.",
|
||||
:input => "Input should be a conversation to the user.",
|
||||
:output => "" ,
|
||||
:func => nothing,
|
||||
),
|
||||
# :wikisearch=>Dict(
|
||||
# :name => "wikisearch",
|
||||
# :description => "Useful for when you need to search an encyclopedia",
|
||||
# :input => "Input is keywords and not a question.",
|
||||
# :output => "",
|
||||
# :func => wikisearch, # put function here
|
||||
# ),
|
||||
# :wineStock=>Dict(
|
||||
# :name => "wineStock",
|
||||
# :description => "useful for when you need to search for wine by your description, price, name or ID.",
|
||||
# :input => "Input should be a search query with as much details as possible.",
|
||||
# :output => "" ,
|
||||
# :func => nothing,
|
||||
# ),
|
||||
# :NTHING=>Dict(
|
||||
# :name => "NTHING",
|
||||
# :description => "useful for when you don't need to use tools or actions",
|
||||
# :input => "No input is needed",
|
||||
# :output => "" ,
|
||||
# :func => nothing,
|
||||
# ),
|
||||
),
|
||||
msgMeta::Dict=Dict(
|
||||
:msgPurpose=> "updateStatus",
|
||||
:from=> "chatbothub",
|
||||
:to=> "llmAI",
|
||||
:requestrespond=> "request",
|
||||
:sendto=> "", # destination topic
|
||||
:replyTo=> "agent/api/v0.1.0/txt/respond", # requester ask responder to send reply to this topic
|
||||
:repondToMsgId=> "", # responder is responding to this msg id
|
||||
:taskstatus=> "", # "complete", "fail", "waiting" or other status
|
||||
:timestamp=> Dates.now(),
|
||||
:msgId=> "$(uuid4())",
|
||||
),
|
||||
availableRole::AbstractArray=["system", "user", "assistant"],
|
||||
maxUserMsg::Int=10,)
|
||||
|
||||
newAgent = agentReflex()
|
||||
newAgent.availableRole = availableRole
|
||||
newAgent.maxUserMsg = maxUserMsg
|
||||
newAgent.mqttClient = CommUtils.mqttClient(mqttClientSpec)
|
||||
newAgent.msgMeta = msgMeta
|
||||
newAgent.tools = tools
|
||||
newAgent.role = role
|
||||
newAgent.roles = roles
|
||||
newAgent.thinkingFormat = thinkingFormat
|
||||
newAgent.roleSpecificInstruction = roleSpecificInstruction
|
||||
newAgent.agentName = agentName
|
||||
|
||||
return newAgent
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end # end module
|
||||
|
||||
|
||||
|
||||
1049
previousVersion/0.0.7/src/utils.jl
Normal file
1049
previousVersion/0.0.7/src/utils.jl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -201,7 +201,8 @@ function planner_mistral_openorca(a::agentReflex)
|
||||
|
||||
assistant_plan_prompt =
|
||||
"""
|
||||
<|system|>
|
||||
<s>
|
||||
<|system|>
|
||||
<About yourself>
|
||||
$aboutYourself
|
||||
</About yourself>
|
||||
|
||||
Reference in New Issue
Block a user