module interface
export agent, addNewMessage, clearMessage, removeLatestMsg, generatePrompt_tokenPrefix,
generatePrompt_tokenSuffix
using JSON3, DataStructures, Dates
# ---------------------------------------------------------------------------- #
# pythoncall setting #
# ---------------------------------------------------------------------------- #
# Ref: https://github.com/JuliaPy/PythonCall.jl/issues/252
# by setting the following variables, PythonCall will use system python or conda python and
# packages installed by system or conda
# if these setting are not set (comment out), PythonCall will use its own python and package that
# installed by CondaPkg
ENV["JULIA_CONDAPKG_BACKEND"] = "Null"
systemPython = split(read(`which python`, String), "\n")[1]
ENV["JULIA_PYTHONCALL_EXE"] = systemPython # find python location with $> which python ex. raw"/root/conda/bin/python"
using PythonCall
const py_agents = PythonCall.pynew()
const py_llms = PythonCall.pynew()
function __init__()
# PythonCall.pycopy!(py_cv2, pyimport("cv2"))
# equivalent to from urllib.request import urlopen in python
PythonCall.pycopy!(py_agents, pyimport("langchain.agents"))
PythonCall.pycopy!(py_llms, pyimport("langchain.llms"))
end
#------------------------------------------------------------------------------------------------100
@kwdef mutable struct agent
availableRole=["system", "user", "assistant"]
maxUserMsg::Int= 10
llmAIRequestTopic_openblas = "llm/openblas/request"
llmAIRequestTopic_gpu = "llm/api/v0.0.1/gpu/request"
self_llmReceiveTopic = "chatbothub/llm/respond"
""" 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"),
]
"""
# Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
messages=[Dict(:role=>"system", :content=> "You are a helpful assistant.", :timestamp=> Dates.now()),]
end
@kwdef mutable struct agentLangchain
availableRole=["system", "user", "assistant"]
maxUserMsg::Int= 10
llmAIRequestTopic_openblas = "llm/openblas/request"
llmAIRequestTopic_gpu = "llm/api/v0.0.1/gpu/request"
self_llmReceiveTopic = "chatbothub/llm/respond"
""" 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"),
]
"""
# Ref: https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
#
messages=[Dict(:role=>"system", :content=> "You are a helpful assistant.", :timestamp=> Dates.now()),]
end
"""
add new message to agent
# Example
```jldoctest
julia> addNewMessage(agent1, "user", "Where should I go to buy snacks")
````
"""
function addNewMessage(a::agent, role::String, content::String)
if role ∉ a.availableRole # guard against typo
error("role is not in agent.availableRole")
end
# check whether user messages exceed limit
userMsg = 0
for i in a.messages
if i[:role] == "user"
userMsg += 1
end
end
messageleft = 0
if userMsg > a.maxUserMsg # delete all conversation
clearMessage(a)
messageleft = a.maxUserMsg
else
userMsg += 1
d = Dict(:role=> role, :content=> content, :timestamp=> Dates.now())
push!(a.messages, d)
messageleft = a.maxUserMsg - userMsg
end
return messageleft
end
function clearMessage(a::agent)
for i in eachindex(a.messages)
if length(a.messages) > 1 # system instruction will NOT be deleted
pop!(a.messages)
else
break
end
end
end
function removeLatestMsg(a::agent)
if length(a.messages) > 1
pop!(a.messages)
end
end
function generatePrompt_tokenSuffix(a::agent;
userToken::String="[/INST]", assistantToken="[INST]",
systemToken="[INST]<> content <>")
prompt = nothing
for msg in a.messages
role = msg[:role]
content = msg[:content]
if role == "system"
prompt = replace(systemToken, "content" => content) * " "
elseif role == "user"
prompt *= " " * content * " " * userToken
elseif role == "assistant"
prompt *= " " * content * " " * assistantToken
else
error("undefied condition role = $role")
end
end
return prompt
end
function generatePrompt_tokenPrefix(a::agent;
userToken::String="Q:", assistantToken="A:",
systemToken="[INST]<> content <>")
prompt = nothing
for msg in a.messages
role = msg[:role]
content = msg[:content]
if role == "system"
prompt = replace(systemToken, "content" => content) * " "
elseif role == "user"
prompt *= userToken * " " * content * " "
elseif role == "assistant"
prompt *= assistantToken * " " * content * " "
else
error("undefied condition role = $role")
end
end
return prompt
end
end # module