This commit is contained in:
narawat lamaiin
2024-12-09 20:29:28 +07:00
parent 159d1717a4
commit d4895a728d
27 changed files with 7742 additions and 4002 deletions

BIN
core

Binary file not shown.

View File

@@ -0,0 +1,879 @@
# This file is machine-generated - editing it directly is not advised
julia_version = "1.11.0"
manifest_format = "2.0"
project_hash = "dbd62da0dcca1a1b2302848e770ef42c10a9d0d8"
[[deps.AliasTables]]
deps = ["PtrArrays", "Random"]
git-tree-sha1 = "9876e1e164b144ca45e9e3198d0b689cadfed9ff"
uuid = "66dad0bd-aa9a-41b7-9441-69ab47430ed8"
version = "1.1.3"
[[deps.ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
version = "1.1.2"
[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
version = "1.11.0"
[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
version = "1.11.0"
[[deps.BitFlags]]
git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d"
uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
version = "0.1.9"
[[deps.CEnum]]
git-tree-sha1 = "389ad5c84de1ae7cf0e28e381131c98ea87d54fc"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.5.0"
[[deps.CSV]]
deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"]
git-tree-sha1 = "6c834533dc1fabd820c1db03c839bf97e45a3fab"
uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
version = "0.10.14"
[[deps.CodeTracking]]
deps = ["InteractiveUtils", "UUIDs"]
git-tree-sha1 = "7eee164f122511d3e4e1ebadb7956939ea7e1c77"
uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
version = "1.3.6"
[[deps.CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.6"
[[deps.Compat]]
deps = ["TOML", "UUIDs"]
git-tree-sha1 = "8ae8d32e09f0dcf42a36b90d4e17f5dd2e4c4215"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "4.16.0"
weakdeps = ["Dates", "LinearAlgebra"]
[deps.Compat.extensions]
CompatLinearAlgebraExt = "LinearAlgebra"
[[deps.CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
version = "1.1.1+0"
[[deps.ConcurrentUtilities]]
deps = ["Serialization", "Sockets"]
git-tree-sha1 = "ea32b83ca4fefa1768dc84e504cc0a94fb1ab8d1"
uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb"
version = "2.4.2"
[[deps.CondaPkg]]
deps = ["JSON3", "Markdown", "MicroMamba", "Pidfile", "Pkg", "Preferences", "TOML"]
git-tree-sha1 = "8f7faef2ca039ee068cd971a80ccd710d23fb2eb"
uuid = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
version = "0.2.23"
[[deps.Crayons]]
git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.1.1"
[[deps.DBInterface]]
git-tree-sha1 = "a444404b3f94deaa43ca2a58e18153a82695282b"
uuid = "a10d1c49-ce27-4219-8d33-6db1a4562965"
version = "2.6.1"
[[deps.DataAPI]]
git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.16.0"
[[deps.DataFrames]]
deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"]
git-tree-sha1 = "fb61b4812c49343d7ef0b533ba982c46021938a6"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.7.0"
[[deps.DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.20"
[[deps.DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"
[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
version = "1.11.0"
[[deps.Decimals]]
git-tree-sha1 = "e98abef36d02a0ec385d68cd7dadbce9b28cbd88"
uuid = "abce61dc-4473-55a0-ba07-351d65e31d42"
version = "0.4.1"
[[deps.Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"
version = "1.11.0"
[[deps.Distributions]]
deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"]
git-tree-sha1 = "d7477ecdafb813ddee2ae727afa94e9dcb5f3fb0"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.112"
[deps.Distributions.extensions]
DistributionsChainRulesCoreExt = "ChainRulesCore"
DistributionsDensityInterfaceExt = "DensityInterface"
DistributionsTestExt = "Test"
[deps.Distributions.weakdeps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[[deps.DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.9.3"
[[deps.Downloads]]
deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
version = "1.6.0"
[[deps.ExceptionUnwrapping]]
deps = ["Test"]
git-tree-sha1 = "dcb08a0d93ec0b1cdc4af184b26b591e9695423a"
uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4"
version = "0.1.10"
[[deps.ExprTools]]
git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec"
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
version = "0.1.10"
[[deps.FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "62ca0547a14c57e98154423419d8a342dca75ca9"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.16.4"
[[deps.FilePathsBase]]
deps = ["Compat", "Dates"]
git-tree-sha1 = "7878ff7172a8e6beedd1dea14bd27c3c6340d361"
uuid = "48062228-2e41-5def-b9a4-89aafe57970f"
version = "0.9.22"
weakdeps = ["Mmap", "Test"]
[deps.FilePathsBase.extensions]
FilePathsBaseMmapExt = "Mmap"
FilePathsBaseTestExt = "Test"
[[deps.FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
version = "1.11.0"
[[deps.FillArrays]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "6a70198746448456524cb442b8af316927ff3e1a"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "1.13.0"
weakdeps = ["PDMats", "SparseArrays", "Statistics"]
[deps.FillArrays.extensions]
FillArraysPDMatsExt = "PDMats"
FillArraysSparseArraysExt = "SparseArrays"
FillArraysStatisticsExt = "Statistics"
[[deps.Future]]
deps = ["Random"]
uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820"
version = "1.11.0"
[[deps.GeneralUtils]]
deps = ["CSV", "DataFrames", "DataStructures", "Dates", "Distributions", "JSON3", "MQTTClient", "PrettyPrinting", "Random", "SHA", "UUIDs"]
path = "/appfolder/app/privatejuliapkg/GeneralUtils"
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
version = "0.1.0"
[[deps.HTTP]]
deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"]
git-tree-sha1 = "d1d712be3164d61d1fb98e7ce9bcbc6cc06b45ed"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "1.10.8"
[[deps.HypergeometricFunctions]]
deps = ["LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"]
git-tree-sha1 = "7c4195be1649ae622304031ed46a2f4df989f1eb"
uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a"
version = "0.3.24"
[[deps.ICU_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "20b6765a3016e1fca0c9c93c80d50061b94218b7"
uuid = "a51ab1cf-af8e-5615-a023-bc2c838bba6b"
version = "69.1.0+0"
[[deps.Infinity]]
deps = ["Dates", "Random", "Requires"]
git-tree-sha1 = "cf8234411cbeb98676c173f930951ea29dca3b23"
uuid = "a303e19e-6eb4-11e9-3b09-cd9505f79100"
version = "0.2.4"
[[deps.InlineStrings]]
git-tree-sha1 = "45521d31238e87ee9f9732561bfee12d4eebd52d"
uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48"
version = "1.4.2"
[deps.InlineStrings.extensions]
ArrowTypesExt = "ArrowTypes"
ParsersExt = "Parsers"
[deps.InlineStrings.weakdeps]
ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
Parsers = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
[[deps.InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
version = "1.11.0"
[[deps.Intervals]]
deps = ["Dates", "Printf", "RecipesBase", "Serialization", "TimeZones"]
git-tree-sha1 = "ac0aaa807ed5eaf13f67afe188ebc07e828ff640"
uuid = "d8418881-c3e1-53bb-8760-2df7ec849ed5"
version = "1.10.0"
[[deps.InvertedIndices]]
git-tree-sha1 = "0dc7b50b8d436461be01300fd8cd45aa0274b038"
uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f"
version = "1.3.0"
[[deps.IrrationalConstants]]
git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.2.2"
[[deps.IterTools]]
git-tree-sha1 = "42d5f897009e7ff2cf88db414a389e5ed1bdd023"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.10.0"
[[deps.IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"
[[deps.JLLWrappers]]
deps = ["Artifacts", "Preferences"]
git-tree-sha1 = "be3dc50a92e5a386872a493a10050136d4703f9b"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.6.1"
[[deps.JSON3]]
deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"]
git-tree-sha1 = "eb3edce0ed4fa32f75a0a11217433c31d56bd48b"
uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
version = "1.14.0"
[deps.JSON3.extensions]
JSON3ArrowExt = ["ArrowTypes"]
[deps.JSON3.weakdeps]
ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
[[deps.JuliaInterpreter]]
deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"]
git-tree-sha1 = "2984284a8abcfcc4784d95a9e2ea4e352dd8ede7"
uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a"
version = "0.9.36"
[[deps.Kerberos_krb5_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "60274b4ab38e8d1248216fe6b6ace75ae09b0502"
uuid = "b39eb1a6-c29a-53d7-8c32-632cd16f18da"
version = "1.19.3+0"
[[deps.LLMMCTS]]
deps = ["GeneralUtils", "JSON3"]
path = "/appfolder/app/privatejuliapkg/LLMMCTS"
uuid = "d76c5a4d-449e-4835-8cc4-dd86ec44f241"
version = "0.1.0"
[[deps.LaTeXStrings]]
git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.3.1"
[[deps.LayerDicts]]
git-tree-sha1 = "6087ad3521d6278ebe5c27ae55e7bbb15ca312cb"
uuid = "6f188dcb-512c-564b-bc01-e0f76e72f166"
version = "1.0.0"
[[deps.LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"
version = "1.11.0"
[[deps.LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
version = "0.6.4"
[[deps.LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
version = "8.6.0+0"
[[deps.LibGit2]]
deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
version = "1.11.0"
[[deps.LibGit2_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"]
uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5"
version = "1.7.2+0"
[[deps.LibPQ]]
deps = ["CEnum", "DBInterface", "Dates", "Decimals", "DocStringExtensions", "FileWatching", "Infinity", "Intervals", "IterTools", "LayerDicts", "LibPQ_jll", "Libdl", "Memento", "OffsetArrays", "SQLStrings", "Tables", "TimeZones", "UTCDateTimes"]
git-tree-sha1 = "3d227cd13cbf1e9a54d7748dab33e078da6f9168"
uuid = "194296ae-ab2e-5f79-8cd4-7183a0a5a0d1"
version = "1.18.0"
[[deps.LibPQ_jll]]
deps = ["Artifacts", "ICU_jll", "JLLWrappers", "Kerberos_krb5_jll", "Libdl", "OpenSSL_jll", "Zstd_jll"]
git-tree-sha1 = "09163f837936c8cc44f4691cb41d805eb1769642"
uuid = "08be9ffa-1c94-5ee5-a977-46a84ec9b350"
version = "16.0.0+0"
[[deps.LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
version = "1.11.0+1"
[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
version = "1.11.0"
[[deps.LinearAlgebra]]
deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
version = "1.11.0"
[[deps.LogExpFunctions]]
deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "a2d09619db4e765091ee5c6ffe8872849de0feea"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.28"
[deps.LogExpFunctions.extensions]
LogExpFunctionsChainRulesCoreExt = "ChainRulesCore"
LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables"
LogExpFunctionsInverseFunctionsExt = "InverseFunctions"
[deps.LogExpFunctions.weakdeps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
[[deps.Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
version = "1.11.0"
[[deps.LoggingExtras]]
deps = ["Dates", "Logging"]
git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075"
uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36"
version = "1.0.3"
[[deps.LoweredCodeUtils]]
deps = ["JuliaInterpreter"]
git-tree-sha1 = "96d2a4a668f5c098fb8a26ce7da53cde3e462a80"
uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b"
version = "3.0.3"
[[deps.MQTTClient]]
deps = ["Distributed", "Random", "Sockets"]
git-tree-sha1 = "f2597b290d4bf17b577346153cd2ddf9accb5c26"
uuid = "985f35cc-2c3d-4943-b8c1-f0931d5f0959"
version = "0.3.1"
weakdeps = ["PrecompileTools"]
[deps.MQTTClient.extensions]
PrecompileMQTT = "PrecompileTools"
[[deps.MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.13"
[[deps.Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
version = "1.11.0"
[[deps.MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"]
git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.1.9"
[[deps.MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
version = "2.28.6+0"
[[deps.Memento]]
deps = ["Dates", "Distributed", "Requires", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "bb2e8f4d9f400f6e90d57b34860f6abdc51398e5"
uuid = "f28f55f0-a522-5efc-85c2-fe41dfb9b2d9"
version = "1.4.1"
[[deps.MicroMamba]]
deps = ["Pkg", "Scratch", "micromamba_jll"]
git-tree-sha1 = "011cab361eae7bcd7d278f0a7a00ff9c69000c51"
uuid = "0b3b1443-0f03-428d-bdfb-f27f9c1191ea"
version = "0.1.14"
[[deps.Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.2.0"
[[deps.Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"
version = "1.11.0"
[[deps.Mocking]]
deps = ["Compat", "ExprTools"]
git-tree-sha1 = "2c140d60d7cb82badf06d8783800d0bcd1a7daa2"
uuid = "78c3b35d-d492-501b-9361-3d52fe80e533"
version = "0.8.1"
[[deps.MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
version = "2023.12.12"
[[deps.NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
version = "1.2.0"
[[deps.OffsetArrays]]
git-tree-sha1 = "1a27764e945a152f7ca7efa04de513d473e9542e"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.14.1"
[deps.OffsetArrays.extensions]
OffsetArraysAdaptExt = "Adapt"
[deps.OffsetArrays.weakdeps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
[[deps.OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
version = "0.3.27+1"
[[deps.OpenLibm_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112"
version = "0.8.1+2"
[[deps.OpenSSL]]
deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"]
git-tree-sha1 = "38cb508d080d21dc1128f7fb04f20387ed4c0af4"
uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c"
version = "1.4.3"
[[deps.OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
git-tree-sha1 = "7493f61f55a6cce7325f197443aa80d32554ba10"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "3.0.15+1"
[[deps.OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"
[[deps.OrderedCollections]]
git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.6.3"
[[deps.PDMats]]
deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
git-tree-sha1 = "949347156c25054de2db3b166c52ac4728cbad65"
uuid = "90014a1f-27ba-587c-ab20-58faa44d9150"
version = "0.11.31"
[[deps.Parsers]]
deps = ["Dates", "PrecompileTools", "UUIDs"]
git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.8.1"
[[deps.Pidfile]]
deps = ["FileWatching", "Test"]
git-tree-sha1 = "2d8aaf8ee10df53d0dfb9b8ee44ae7c04ced2b03"
uuid = "fa939f87-e72e-5be4-a000-7fc836dbe307"
version = "1.3.0"
[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
version = "1.11.0"
weakdeps = ["REPL"]
[deps.Pkg.extensions]
REPLExt = "REPL"
[[deps.PooledArrays]]
deps = ["DataAPI", "Future"]
git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3"
uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720"
version = "1.4.3"
[[deps.PrecompileTools]]
deps = ["Preferences"]
git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f"
uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
version = "1.2.1"
[[deps.Preferences]]
deps = ["TOML"]
git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.4.3"
[[deps.PrettyPrinting]]
git-tree-sha1 = "142ee93724a9c5d04d78df7006670a93ed1b244e"
uuid = "54e16d92-306c-5ea0-a30b-337be88ac337"
version = "0.4.2"
[[deps.PrettyTables]]
deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"]
git-tree-sha1 = "1101cd475833706e4d0e7b122218257178f48f34"
uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
version = "2.4.0"
[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
version = "1.11.0"
[[deps.PtrArrays]]
git-tree-sha1 = "77a42d78b6a92df47ab37e177b2deac405e1c88f"
uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d"
version = "1.2.1"
[[deps.PythonCall]]
deps = ["CondaPkg", "Dates", "Libdl", "MacroTools", "Markdown", "Pkg", "REPL", "Requires", "Serialization", "Tables", "UnsafePointers"]
git-tree-sha1 = "06a778ec6d6e76b0c2fb661436a18bce853ec45f"
uuid = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
version = "0.9.23"
[[deps.QuadGK]]
deps = ["DataStructures", "LinearAlgebra"]
git-tree-sha1 = "cda3b045cf9ef07a08ad46731f5a3165e56cf3da"
uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
version = "2.11.1"
[deps.QuadGK.extensions]
QuadGKEnzymeExt = "Enzyme"
[deps.QuadGK.weakdeps]
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
[[deps.REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "StyledStrings", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
version = "1.11.0"
[[deps.Random]]
deps = ["SHA"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
version = "1.11.0"
[[deps.RecipesBase]]
deps = ["PrecompileTools"]
git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.3.4"
[[deps.Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"
[[deps.Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.3.0"
[[deps.Revise]]
deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "REPL", "Requires", "UUIDs", "Unicode"]
git-tree-sha1 = "2d4e5de3ac1c348fd39ddf8adbef82aa56b65576"
uuid = "295af30f-e4ad-537b-8983-00126c2a3abe"
version = "3.6.1"
[[deps.Rmath]]
deps = ["Random", "Rmath_jll"]
git-tree-sha1 = "852bd0f55565a9e973fcfee83a84413270224dc4"
uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa"
version = "0.8.0"
[[deps.Rmath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
git-tree-sha1 = "58cdd8fb2201a6267e1db87ff148dd6c1dbd8ad8"
uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f"
version = "0.5.1+0"
[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
version = "0.7.0"
[[deps.SQLStrings]]
git-tree-sha1 = "55de0530689832b1d3d43491ee6b67bd54d3323c"
uuid = "af517c2e-c243-48fa-aab8-efac3db270f5"
version = "0.1.0"
[[deps.Scratch]]
deps = ["Dates"]
git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.2.1"
[[deps.SentinelArrays]]
deps = ["Dates", "Random"]
git-tree-sha1 = "ff11acffdb082493657550959d4feb4b6149e73a"
uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
version = "1.4.5"
[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
version = "1.11.0"
[[deps.SimpleBufferStream]]
git-tree-sha1 = "f305871d2f381d21527c770d4788c06c097c9bc1"
uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7"
version = "1.2.0"
[[deps.Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
version = "1.11.0"
[[deps.SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.2.1"
[[deps.SparseArrays]]
deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
version = "1.11.0"
[[deps.SpecialFunctions]]
deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "2f5d4697f21388cbe1ff299430dd169ef97d7e14"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "2.4.0"
[deps.SpecialFunctions.extensions]
SpecialFunctionsChainRulesCoreExt = "ChainRulesCore"
[deps.SpecialFunctions.weakdeps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
[[deps.Statistics]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "ae3bb1eb3bba077cd276bc5cfc337cc65c3075c0"
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
version = "1.11.1"
weakdeps = ["SparseArrays"]
[deps.Statistics.extensions]
SparseArraysExt = ["SparseArrays"]
[[deps.StatsAPI]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.7.0"
[[deps.StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "5cf7606d6cef84b543b483848d4ae08ad9832b21"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.34.3"
[[deps.StatsFuns]]
deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
git-tree-sha1 = "b423576adc27097764a90e163157bcfc9acf0f46"
uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
version = "1.3.2"
[deps.StatsFuns.extensions]
StatsFunsChainRulesCoreExt = "ChainRulesCore"
StatsFunsInverseFunctionsExt = "InverseFunctions"
[deps.StatsFuns.weakdeps]
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
[[deps.StringManipulation]]
deps = ["PrecompileTools"]
git-tree-sha1 = "a6b1675a536c5ad1a60e5a5153e1fee12eb146e3"
uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e"
version = "0.4.0"
[[deps.StructTypes]]
deps = ["Dates", "UUIDs"]
git-tree-sha1 = "159331b30e94d7b11379037feeb9b690950cace8"
uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
version = "1.11.0"
[[deps.StyledStrings]]
uuid = "f489334b-da3d-4c2e-b8f0-e476e12c162b"
version = "1.11.0"
[[deps.SuiteSparse]]
deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
[[deps.SuiteSparse_jll]]
deps = ["Artifacts", "Libdl", "libblastrampoline_jll"]
uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
version = "7.7.0+0"
[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
version = "1.0.3"
[[deps.TZJData]]
deps = ["Artifacts"]
git-tree-sha1 = "36b40607bf2bf856828690e097e1c799623b0602"
uuid = "dc5dba14-91b3-4cab-a142-028a31da12f7"
version = "1.3.0+2024b"
[[deps.TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"
[[deps.Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "OrderedCollections", "TableTraits"]
git-tree-sha1 = "598cd7c1f68d1e205689b1c2fe65a9f85846f297"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.12.0"
[[deps.Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
version = "1.10.0"
[[deps.Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
version = "1.11.0"
[[deps.TimeZones]]
deps = ["Dates", "Downloads", "InlineStrings", "Mocking", "Printf", "Scratch", "TZJData", "Unicode", "p7zip_jll"]
git-tree-sha1 = "8323074bc977aa85cf5ad71099a83ac75b0ac107"
uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53"
version = "1.18.1"
weakdeps = ["RecipesBase"]
[deps.TimeZones.extensions]
TimeZonesRecipesBaseExt = "RecipesBase"
[[deps.TranscodingStreams]]
git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.11.3"
[[deps.URIs]]
git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.5.1"
[[deps.UTCDateTimes]]
deps = ["Dates", "TimeZones"]
git-tree-sha1 = "4af3552bf0cf4a071bf3d14bd20023ea70f31b62"
uuid = "0f7cfa37-7abf-4834-b969-a8aa512401c2"
version = "1.6.1"
[[deps.UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
version = "1.11.0"
[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
version = "1.11.0"
[[deps.UnsafePointers]]
git-tree-sha1 = "c81331b3b2e60a982be57c046ec91f599ede674a"
uuid = "e17b2a0c-0bdf-430a-bd0c-3a23cae4ff39"
version = "1.0.0"
[[deps.WeakRefStrings]]
deps = ["DataAPI", "InlineStrings", "Parsers"]
git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23"
uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5"
version = "1.4.2"
[[deps.WorkerUtilities]]
git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7"
uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60"
version = "1.6.1"
[[deps.Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
version = "1.2.13+1"
[[deps.Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
git-tree-sha1 = "555d1076590a6cc2fdee2ef1469451f872d8b41b"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.6+1"
[[deps.libblastrampoline_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
version = "5.11.0+0"
[[deps.micromamba_jll]]
deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"]
git-tree-sha1 = "b4a5a3943078f9fd11ae0b5ab1bdbf7718617945"
uuid = "f8abcde7-e9b7-5caa-b8af-a437887ae8e4"
version = "1.5.8+0"
[[deps.nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
version = "1.59.0+0"
[[deps.p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
version = "17.4.0+2"

View File

@@ -0,0 +1,26 @@
name = "SQLLLM"
uuid = "2ebc79c7-cc10-4a3a-9665-d2e1d61e63d3"
authors = ["narawat lamaiin <narawat@outlook.com>"]
version = "0.1.0"
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
GeneralUtils = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
LLMMCTS = "d76c5a4d-449e-4835-8cc4-dd86ec44f241"
LibPQ = "194296ae-ab2e-5f79-8cd4-7183a0a5a0d1"
MQTTClient = "985f35cc-2c3d-4943-b8c1-f0931d5f0959"
PrettyPrinting = "54e16d92-306c-5ea0-a30b-337be88ac337"
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

View File

@@ -0,0 +1,56 @@
{
"mqttServerInfo": {
"description": "mqtt server info",
"port": 1883,
"broker": "mqtt.yiem.cc"
},
"testingOrProduction": {
"value": "testing",
"description": "agent status, couldbe testing or production"
},
"agentid": {
"value": "2b74b87a-5413-4fe2-a4d3-405891051680",
"description": "a unique id for this agent"
},
"agentCentralConfigTopic": {
"mqtttopic": "/yiem_branch_1/agent/sommelier/backend/config/api/v1.1",
"description": "a central agent server's topic to get this agent config"
},
"servicetopic": {
"mqtttopic": [
"/yiem/branch_1/agent/wine/backend/prompt/api_v1/testing"
],
"description": "a topic this agent are waiting for service request"
},
"role": {
"value": "sommelier",
"description": "agent role"
},
"organization": {
"value": "yiem_branch_1",
"description": "organization name"
},
"externalservice": {
"text2textinstruct": {
"mqtttopic": "/loadbalancer/requestingservice",
"description": "text to text service with instruct LLM",
"llminfo": {
"name": "llama3instruct"
}
},
"virtualWineCustomer_1": {
"mqtttopic": "/virtualenvironment/winecustomer",
"description": "text to text service with instruct LLM that act as wine customer",
"llminfo": {
"name": "llama3instruct"
}
},
"text2textchat": {
"mqtttopic": "/loadbalancer/requestingservice",
"description": "text to text service with instruct LLM",
"llminfo": {
"name": "llama3instruct"
}
}
}
}

View File

@@ -0,0 +1,103 @@
module SQLLLM
# export
""" 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("util.jl")
using .util
include("llmfunction.jl")
using .llmfunction
include("interface.jl")
using .interface
# ---------------------------------------------- 100 --------------------------------------------- #
end # module SQLLLM

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,955 @@
module llmfunction
export listAllTable_json, listAllTable_str, tableinfo, getdata, finalAnswerBox,
getTableNameFromSQL, extractContent_dataframe, SQLexecution
using HTTP, JSON3, URIs, Random, PrettyPrinting, UUIDs, LibPQ, Tables, DataFrames, CSV,
DataStructures, StatsBase
using GeneralUtils, LLMMCTS
using ..util
# ---------------------------------------------- 100 --------------------------------------------- #
""" List all tables in the database and return in JSON format.
# Arguments
- `executeSQL::Function`
A connection object to Postgres database
# Return
- `NamedTuple{(:result, :success), Tuple{DataFrame, Bool}}`
# Example
```jldoctest
julia> using LibPQ, SQLLLM
julia> function executeSQL(sql)
DBconnection = LibPQ.Connection("host=192.168.88.122 port=5432 dbname=xyz user=zyx password=1234")
result = LibPQ.execute(DBconnection, sql)
close(DBconnection)
return result
end
julia> response = SQLLLM.listAllTable_json(executeSQL)
julia> result = response[:result]
```
# Signature
"""
function listAllTable_json(executeSQL::Function
)::NamedTuple{(:result, :success),Tuple{DataFrame,Bool}}
sql = """
SELECT
table_name,
obj_description(relfilenode, 'pg_class') AS table_comment,
string_agg(column_name || ' (' || data_type || ')', ', ') AS columns
FROM
information_schema.columns
JOIN
pg_class ON table_name = relname
WHERE
table_schema = 'public'
GROUP BY
table_name, relfilenode
ORDER BY
table_name;
"""
result = executeSQL(sql)
df = DataFrame(result)
tablesinfo_df = df
return (result=tablesinfo_df, success=true)
end
function listAllTable_str(executeSQL::Function
)::NamedTuple{(:result, :success),Tuple{String,Bool}}
sql = """
SELECT
table_name,
obj_description(relfilenode, 'pg_class') AS table_comment,
string_agg(column_name || ' (' || data_type || ')', ', ') AS columns
FROM
information_schema.columns
JOIN
pg_class ON table_name = relname
WHERE
table_schema = 'public'
GROUP BY
table_name, relfilenode
ORDER BY
table_name;
"""
result = executeSQL(sql)
df = DataFrame(result)
tableinfo = "Here are a list of available tables in the database (each row is in this format: table name; table comment; table columns): \n"
for i in 1:size(df)[1]
table_name = df[i, 1]
table_comment = df[i, 2]
columns = df[i, 3]
tableinfo *= "$i. $table_name; $table_comment; $columns\n"
end
return (result=tableinfo, success=true)
end
""" Get table description, column comments and the first 3-rows of the table data
# Arguments
- `executeSQL::Function`
A connection object to Postgres database
# Return
- `tableinfo::String`
# Signature
"""
function tableinfo_str(executeSQL::Function, tablename::String)::NamedTuple{(:result, :success),Tuple{String,Bool}}
sql = """
SELECT
column_name,
data_type,
col_description(format('%s.%s', table_schema, table_name)::regclass::oid, ordinal_position) AS column_comment
FROM
information_schema.columns
WHERE
table_name = '$tablename'
AND table_schema = 'public';
"""
result = executeSQL(sql)
df = DataFrame(result)
tableinfo = "Here are info of table $tablename (each row is in this format: column name; data type; column comment):\n"
for i in 1:size(df)[1]
column_name = df[i, 1]
column_datatype = df[i, 2]
column_comment = df[i, 3]
tableinfo *= "$i. $column_name; $column_datatype; $column_comment \n"
end
return (result=tableinfo, success=true)
end
""" Get table description, column comments.
# Arguments
- `executeSQL::Function`
A connection object to Postgres database
- `tablenames<:AbstractVector`
A list of table name to get description
# Return
- `NamedTuple{(:result), Tuple{String}}`
Text contain multiple table info
# Example
```jldoctest
julia> using SQLLLM, LibPQ
julia> function executeSQL(sql)
DBconnection = LibPQ.Connection("host=192.168.88.122 port=5432 dbname=xyz user=zyx password=1234")
result = LibPQ.execute(DBconnection, sql)
close(DBconnection)
return result
end
julia> response = SQLLLM.tableinfo(executeSQL, ["wine", "food"])
julia> result = response[:result]
```
# Signature
"""
function tableinfo(executeSQL::Function, tablenames::T
)::NamedTuple{(:result,),Tuple{String}} where {T<:AbstractVector}
# list all tables in a database
sql = """
SELECT pg_namespace.nspname AS schema_name,
relname AS table_name,
pg_catalog.obj_description(pg_class.oid) AS comment
FROM pg_class
INNER JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE pg_namespace.nspname = 'public' -- Replace 'public' with your desired schema
AND pg_class.relkind IN ('r', 't');
"""
_result = executeSQL(sql)
df = DataFrame(_result)
alltable_df = df[:, [:table_name, :comment]]
tableNameList = alltable_df.table_name |> collect
# check if the requested table name exist in the database
notExistingTable = []
for i in tablenames
if i tableNameList
push!(notExistingTable, i)
end
end
if !isempty(notExistingTable)
result = "Error, the following tables does not exist in the database: $(JSON3.write(notExistingTable))"
return (result=result,)
end
tableInfoStr = ""
for i in tablenames
x, _ = tableinfo_str(executeSQL, i)
tableInfoStr *= x
end
return (result=tableInfoStr,)
end
""" Convert a query process in English into SQL, execute and get the result from the database.
# Arguments
- `query<:AbstractString`
A query to a database in SQL.
- `context::Union{Dict, Nothing}`
A context to be available at transition()
- `executeSQL::Function`
A connection object connected to the database
- `text2textInstructLLM::Function`
A function that handles communication to LLM service.
# Return
- `NamedTuple{(:result, :errormsg, success), Tuple{String, String, Bool}}`
# TODO
- [x] getdata directly using sql execute
# Signature
"""
function getdata(query::T, context::Union{Dict,Nothing}, executeSQL::Function,
text2textInstructLLM::Function;
) where {T<:AbstractString}
response = SQLexecution(executeSQL, query)
if response[:success]
extracted = extractContent_dataframe(response[:result], context, text2textInstructLLM)
response_ = (result=extracted, errormsg=nothing, success=true)
return response_
else
response_ = (result=nothing, errormsg=response[:errormsg], success=false)
return response_
end
end
# function getdata(query::T, context::Union{Dict, Nothing}, executeSQL::Function,
# text2textInstructLLM::Function;
# )::NamedTuple{(:result, :errormsg, :success), Tuple{String, Union{String, Nothing}, Bool}} where {T<:AbstractString}
# # get table info here because it'll be called only 1-time. If this function is in
# # getdata_decisionMaker(), it'll be called everytime
# mentionedtable = getTableNameFromSQL(query, text2textInstructLLM)
# mentionedTableInfo = tableinfo(executeSQL, mentionedtable)[:result]
# context[:mentionedTableInfo] = mentionedTableInfo
# initialstate = Dict{Symbol, Any}(
# :reward=> 0,
# :isterminal=> false,
# :evaluation=> nothing,
# :errormsg=> nothing,
# :errorexplain=> nothing,
# :question=> query,
# :code=> nothing,
# :response=> nothing,
# )
# transitionargs = (
# # decisionMaker=getdata_decisionMaker,
# # evaluator=getdata_evaluator,
# # reflector=getdata_reflector,
# context=context,
# executeSQL=executeSQL,
# text2textInstructLLM=text2textInstructLLM
# )
# result_1, result_2 = LLMMCTS.runMCTS(initialstate, getdata_transition, transitionargs;
# totalsample=1, maxdepth=3, maxiterations=1, explorationweight=1.0)
# if result_2[:isterminal] == true
# return (result=result_2[:response], errormsg=nothing, success=true) # succues=true to finish getdata()
# else
# # return (response="Failed to act with the following error message: $(result_2[:errorexplain])", select=nothing, reward=0, success=false)
# return (result="Failed to get the data. $(result_1[:errormsg])",
# errormsg=result_1[:errormsg], success=false)
# end
# end
"""
# Arguments
`v::Integer`
dummy variable
# Return
# Example
```jldoctest
julia>
```
# TODO
- [] update docstring
- [PENDING] implement the function
# Signature
"""
function getdata_evaluator(newstate, config)
return (evaluation="None", score=0)
end
""" State transition
# Arguments
- `state<:AbstractDict`
A game state
- `args::NamedTuple`
Arguments for various function within transition()
# Return
- `NamedTuple{(:newNodeKey, :newstate, :progressvalue), Tuple{String, T, Integer}}`
# Signature
"""
function getdata_transition(state::T, args::NamedTuple
)::NamedTuple{(:newNodeKey, :newstate, :progressvalue),Tuple{String,T,Integer}} where {T<:AbstractDict}
# decisionMaker::Function = args[:decisionMaker]
# evaluator::Function = args[:evaluator]
# reflector::Function = args[:reflector]
context = args[:context]
executeSQL::Function = args[:executeSQL]
text2textInstructLLM::Function = args[:text2textInstructLLM]
thought, sql =
if state[:code] !== nothing
result = getdata_decisionMaker(state, context, text2textInstructLLM)
result[:thought], result[:code]
else
nothing, state[:question]
end
# make new state
newNodeKey = GeneralUtils.uuid4snakecase()
newstate = deepcopy(state)
response, success, errormsg, reward, isterminal =
if sql !== nothing
response, success, errormsg, reward, isterminal = SQLexecution(executeSQL, sql)
else
(result=nothing,
success=false,
errormsg="SQL execution failed. An unexpected error occurred. Please try again.",
reward=0,
isterminal=false)
end
println("getdata_transition() 1 ", @__FILE__, " ", @__LINE__)
newstate[:code] = sql
newstate[:response] = response
newstate[:errorexplain] = thought
newstate[:errormsg] = errormsg
newstate[:reward] = reward
newstate[:isterminal] = isterminal
if response !== nothing
extracted = extractContent_dataframe(response, context, text2textInstructLLM)
newstate[:response] = extracted
end
println("getdata_transition() 2 ", @__FILE__, " ", @__LINE__)
stateevaluation = "None"
progressvalue = 0
return (newNodeKey=newNodeKey, newstate=newstate, progressvalue=progressvalue)
end
""" Make a decision using LLM
# Arguments
- `state::Dict`
A game state
- `context::Dict`
Additional context for LLM to use
- `text2textInstructLLM::Function`
A function to handles communication to LLM
# Return
- `NamedTuple{(:thought, :code, :success, :errormsg), Tuple{String, String, Bool, Union{String, Nothing}}}`
# Signature
"""
function getdata_decisionMaker(state::Dict, context::Dict, text2textInstructLLM::Function
)::NamedTuple{(:thought, :code, :success, :errormsg),Tuple{Union{String,Nothing},Union{String,Nothing},Bool,Union{String,Nothing}}}
Hints = "None"
# """
# Here are some useful SQL programs:
# $usefulSQL
# """
# systemmsg =
# """
# You are an assistant helping the user to execute SQL code from the user's query.
# At each round of conversation, the user will give you:
# Context: ...
# User intention: ...
# Code executed from the last round: ...
# Execution error: execution error of the last round code.
# You should consider the following guidelines:
# - Text information in the database is sometimes stored in lower case. If your search returns empty, try using lower case to search.
# You should then respond to the user with:
# - thought: Why the code does not complete the task. What does the execution error imply exactly?
# - plan: Step-by-step instructions of how to complete the task.
# 1) Focus on improving the code from the last round.
# 2) Do not create any table in the database.
# - code:
# 1) Write new improved code.
# 2) Do not wrap the code and no comment as it will be executed directly without any modification against the database.
# You should only respond in format as described below and nothing more:
# thought: ...
# plan:
# 1) ...
# 2) ...
# ...
# code: ...
# Let's begin!
# """
systemmsg = """
You are an assistant helping the user to execute SQL code from the user's query.
At each round of conversation, the user will give you:
Context: ...
User intention: ...
Code executed from the last round: ...
Execution error: execution error of the last round code.
You should consider the following guidelines:
- Text information in the database is sometimes stored in lower case. If your search returns empty, try using lower case to search.
You should then respond to the user with:
1) Understanding:
- State your understanding about the current situation.
2) Reasoning:
- State your step by step reasoning about the current situation.
3) Plan: Step-by-step instructions of how to complete the task.
- Focus on improving the code from the last round.
- Do not create any table in the database.
4) Code:
- Write new improved code.
- Do not wrap the code and no comment as it will be executed directly without any modification against the database.
You should only respond in format as described below and nothing more:
Understanding: ...
Reasoning: ...
Plan:
1) ...
2) ...
...
Code: ...
Let's begin!
"""
noise = ""
note_flag = ""
for attempt in 1:10
usermsg = """
Context:
$(context[:mentionedTableInfo])
User intention: $(context[:userintention])
Code executed from the last round: $(state[:code])
Execution error: $(state[:errormsg])
$noise
$note_flag
"""
_prompt =
[
Dict(:name => "system", :text => systemmsg),
Dict(:name => "user", :text => usermsg)
]
# put in model format
prompt = GeneralUtils.formatLLMtext(_prompt; formatname="llama3instruct")
prompt *= """
<|start_header_id|>assistant<|end_header_id|>
"""
try
response = text2textInstructLLM(prompt)
responsedict = GeneralUtils.textToDict(response,
["Understanding", "Reasoning", "Plan", "Code"];
rightmarker=":", symbolkey=true, lowercasekey=true)
_code = responsedict[:code]
code = strip(_code)
if length(code) < 2
error("No code available.")
elseif code == state[:code]
error("generated code is the same as earlier.")
else
end
# check code
if occursin("CREATE TABLE", code)
note_flag = "Note: Create new table is not allowed."
error("create table is not allowed")
elseif occursin("```", code)
error("Note: code contains backtick ` which is not allowed")
elseif code[end] != ';'
error("SQL does not ending with ';'")
elseif count(';', code) > 1
error("Multiple SQL statement are not allowed")
else
end
println("\n~~~ getdata_decisionMaker() ", @__FILE__, " ", @__LINE__)
pprintln(Dict(responsedict))
return (thought=responsedict[:reasoning], code=code, success=true, errormsg=nothing)
catch e
io = IOBuffer()
showerror(io, e)
errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
print("Attempt $attempt. Error occurred: $errorMsg\n$st")
println("")
noise = GeneralUtils.randstrings(3, 5)
end
end
return (thought=nothing, code=nothing, success=false,
errormsg="Failed to generate SQL after numerous attempts.")
end
""" Execute a given SQL.
# Arguments
- `sql::T<:AbstractString`
A SQL command
- `executeSQL::Function`
A connection object to a database
# Return
- `NamedTuple{(:result, :errormsg, :reward, :isterminal), Tuple{Union{Nothing, DataFrame}, String, Integer, Bool}}`
# Example
```jldoctest
julia> using LibPQ, SQLLLM
julia> function executeSQL(sql)
DBconnection = LibPQ.Connection("host=192.168.88.122 port=5432 dbname=xyz user=zyx password=1234")
result = LibPQ.execute(DBconnection, sql)
close(DBconnection)
return result
end
julia> response = SQLLLM.SQLexecution(executeSQL, sql)
```
# Signature
"""
# function SQLexecution(executeSQL::Function, sql::T
# )::NamedTuple{(:result, :success, :errormsg, :reward, :isterminal), Tuple{Union{DataFrame, Nothing}, Bool, Union{String, Nothing}, Integer, Bool}} where {T<:AbstractString}
# println("\n~~~ 1-01 ", @__FILE__, " ", @__LINE__)
# #XXX dummy SQL. use for testing
# # sql = "SELECT w.wine_name FROM wine w JOIN wine_food wf ON w.wine_id = wf.wine_id JOIN food f ON wf.food_id = f.food_id WHERE f.\"food_name\" = 'lamb';"
# # sql = " SELECT w.wine_name FROM wine w JOIN food f ON f.food_name = 'lamb' JOIN wine_food wf ON w.wine_id = wf.wine_id AND f.food_id = wf.food_id GROUP BY w.wine_name ORDER BY COUNT(DISTINCT w.wine_id) DESC;"
# # sql = " SELECT COUNT(DISTINCT wf.wine_id) FROM wine w JOIN wine_food wf ON w.wine_id = wf.wine_id JOIN food f ON wf.food_id = f.food_id WHERE f.food_name ILIKE '%lamb%'"
# #XXX use for package testing, remove when done
# # ans = "1.schilfwein zweigelt 2.cabernet sauvignon reserve limited edition"
# # ans = "There are 1500 wines that can be paired with lamb."
# # ans = "1500"
# # return (response=ans, errormsg=nothing, reward=1, isterminal=true)
# # add LIMIT to the SQL to prevent loading large data
# sql = strip(sql)
# println("\n~~~ SQL 1", @__FILE__, " ", @__LINE__)
# println(sql)
# println("\n~~~ 1-02 ", @__FILE__, " ", @__LINE__)
# if sql[end] != ';'
# errorMsg = "Error, SQL execution failed because it does not ended with ';'"
# return (result=nothing, success=false, errormsg=errorMsg, reward=0, isterminal=false)
# end
# println("\n~~~ 1-03 ", @__FILE__, " ", @__LINE__)
# if !occursin("LIMIT", sql)
# # sql = sql[1:end-1] * " LIMIT 100;"
# sql = sql[1:end-1] * " ORDER BY RANDOM() LIMIT 2;"
# end
# println("\n~~~ SQL 2", @__FILE__, " ", @__LINE__)
# println(sql)
# println("\n~~~ 1-1 ", @__FILE__, " ", @__LINE__)
# result = executeSQL(sql)
# println("\n~~~ 1-2 ", @__FILE__, " ", @__LINE__)
# df = DataFrame(result)
# println("\n~~~ raw df ", df)
# tablesize = size(df)
# println("\n~~~ df size ", tablesize)
# println("\n~~~ 6 ", @__FILE__, " ", @__LINE__)
# row = tablesize[1]
# println("\n~~~ 7 ", @__FILE__, " ", @__LINE__)
# if row == 0 # if 0 row
# errorMsg = "The resulting table has 0 row. Possible causes: 1) SQL is incorrect 2) There is no data that match your search criteria."
# return (result=nothing, success=false, errormsg=errorMsg, reward=0, isterminal=false)
# end
# println("\n~~~ 8 ", @__FILE__, " ", @__LINE__)
# df1 =
# if row > 2
# # ramdom row to pick
# df[sample(1:nrow(df), 2, replace=false), :] # random select 2 rows from df
# else
# df
# end
# println("\n~~~ SQLexecution result ", @__FILE__, " ", @__LINE__)
# println(df1)
# return (result=df1, success=true, errormsg=nothing, reward=1, isterminal=true)
# end
function SQLexecution(executeSQL::Function, sql::T
) where {T<:AbstractString}
try
#XXX dummy SQL. use for testing
# sql = "SELECT w.wine_name FROM wine w JOIN wine_food wf ON w.wine_id = wf.wine_id JOIN food f ON wf.food_id = f.food_id WHERE f.\"food_name\" = 'lamb';"
# sql = " SELECT w.wine_name FROM wine w JOIN food f ON f.food_name = 'lamb' JOIN wine_food wf ON w.wine_id = wf.wine_id AND f.food_id = wf.food_id GROUP BY w.wine_name ORDER BY COUNT(DISTINCT w.wine_id) DESC;"
# sql = " SELECT COUNT(DISTINCT wf.wine_id) FROM wine w JOIN wine_food wf ON w.wine_id = wf.wine_id JOIN food f ON wf.food_id = f.food_id WHERE f.food_name ILIKE '%lamb%'"
#XXX use for package testing, remove when done
# ans = "1.schilfwein zweigelt 2.cabernet sauvignon reserve limited edition"
# ans = "There are 1500 wines that can be paired with lamb."
# ans = "1500"
# return (response=ans, errormsg=nothing, reward=1, isterminal=true)
# add LIMIT to the SQL to prevent loading large data
sql = strip(sql)
if sql[end] == ';'
if !occursin("LIMIT", sql)
# sql = sql[1:end-1] * " LIMIT 100;"
sql = sql[1:end-1] * " ORDER BY RANDOM() LIMIT 2;"
end
else
sql = sql * ";"
end
println("\n~~~ SQLexecution() SQL: ", @__FILE__, " ", @__LINE__)
println(sql)
result = executeSQL(sql)
df = DataFrame(result)
tablesize = size(df)
row, column = tablesize
if row == 0 # if 0 row
error("The resulting table has 0 row. Possible causes: 1) You might be searching in the wrong place 2) There could be a typo in your search query.")
elseif column > 30
error("SQL execution failed. An unexpected error occurred. Please try again.")
end
df1 =
if row > 2
# ramdom row to pick
df[sample(1:nrow(df), 2, replace=false), :] # random select 2 rows from df
else
df
end
println("\n~~~ SQLexecution() result: ", @__FILE__, " ", @__LINE__)
println(df1)
return (result=df1, success=true, errormsg=nothing)
catch e
io = IOBuffer()
showerror(io, e)
errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
println(errorMsg)
response = (result=nothing, success=false, errormsg=errorMsg)
return response
end
end
""" Extract content from a dataframe with LLM.
# Arguments
- `df::DataFrame`
A dataframe to be read.
- `context::Dict`
A dictionary to give LLM more context
- `text2textInstructLLM::Function`
A function that handles communication to LLM service
# Return
- `result::String`
# Signature
"""
function extractContent_dataframe(df::DataFrame, context::Dict, text2textInstructLLM::Function
)::String
tablesize = size(df)
row = tablesize[1]
column = tablesize[2]
#[PENDING] Since selected column depend on the question, there should be a better way to select column on the fly, not hard coded like this.
# df1 =
# if column > 10 # assuming if columns > 10, agent is getting wine info but the info is too much
# selectedcolumn = ["wine_id",
# "wine_name",
# "winery",
# "region",
# "country",
# "wine_type",
# "grape",
# "serving_temperature",
# "intensity",
# "sweetness",
# "tannin",
# "acidity",
# "fizziness",
# "tasting_notes"]
# df1 = df[:, selectedcolumn]
# else
# df
# end
df1 = df
dfstr = dfToString(df1)
systemmsg = """
You are an assistant that readouts the resulting table after the user executing SQL command.
At each round of conversation, the user will give you:
- User intention: ...
- Resulting table dimension: ...
- Resulting table: The resulting table after executing the user's intention.
You should then respond to the user with:
- About_resulting_table:
1) What is the resulting table represent?
- Search_summary:
1) Summarize the table's content based on the user intension in verbal English.
Here are some example:
Bad example (you are not Summarize the table content): there are 2 columns in the table i.e. "cash" and "number".
2) Do not generate additional text.
You should only respond in format as described below:
About_resulting_table: ...
Search_summary: ...
Let's begin!
"""
usermsg = """
User intention: $(context[:userintention])
Resulting table: $dfstr
"""
_prompt =
[
Dict(:name => "system", :text => systemmsg),
Dict(:name => "user", :text => usermsg)
]
# put in model format
prompt = GeneralUtils.formatLLMtext(_prompt; formatname="llama3instruct")
prompt *= """
<|start_header_id|>assistant<|end_header_id|>
"""
for i in 1:5
response = text2textInstructLLM(prompt)
responsedict = GeneralUtils.textToDict(response, ["About_resulting_table", "Search_summary"],
rightmarker=":", symbolkey=true)
# result = dfstr
result = """
Summary: $(responsedict[:Search_summary])
More details: $dfstr
"""
if row > 2
result *= "There are many more rows, but they are truncated because there are too many of them."
end
println("\n~~~ extractContent_dataframe() ", @__FILE__, " ", @__LINE__)
println(result)
return result
end
error("Failed to get Code part.")
end
""" Extract a database's table name that mentioned in SQL
# Arguments
- `sql<:AbstractString`
SQL command
- `text2textInstructLLM::Function`
A function that handles communication to LLM service
# Return
- `tablename::Vector{String}`
A list of table name
# Example
```jldoctest
julia> using SQLLLM, UUIDs, GeneralUtils
julia> sql = "Get all rows from the \"food\" table where the description contains the word \"lamb\". Then, join this result with the \"wine_food\" table on the \"food_id\" column to get a list of wines that can be paired with lamb. Finally, group the result by the \"wine_id\" column and count the number of unique wines."
julia> function text2textInstructLLM(prompt::String)
config = Dict(
:mqttServerInfo => Dict(
:description => "mqtt server info",
:port => 1883,
:broker => "mqtt.yiem.cc"
),
:externalservice => Dict(
:text2textinstruct => Dict(
:mqtttopic => "/loadbalancer/requestingservice",
:description => "text to text service with instruct LLM",
:llminfo => Dict(:name => "llama3instruct")
),
)
)
# apply LLM specific instruct format
externalService = config[:externalservice][:text2textinstruct]
msgMeta = GeneralUtils.generate_msgMeta(
externalService[:mqtttopic],
senderName= "SQLLLM",
senderId= string(uuid4()),
receiverName= "text2textinstruct",
mqttBroker= config[:mqttServerInfo][:broker],
mqttBrokerPort= config[:mqttServerInfo][:port],
)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> prompt,
:kwargs=> Dict(
:max_tokens=> 512,
:stop=> ["<|eot_id|>"],
:temperature=> 0.2,
)
)
)
_response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
response = _response[:response][:text]
return response
end
julia> result = SQLLLM.getTableNameFromSQL(sql, text2textInstructLLM)
```
# Signature
"""
function getTableNameFromSQL(sql::T, text2textInstructLLM::Function)::Vector{String} where {T<:AbstractString}
systemmsg = """
Extract table name out of the user query.
At each round of conversation, the user will give you:
Query: ...
You should then respond to the user with:
- table_name: a list of table name that the user mentioned in the query.
For example, ["color", "type"]
You must only respond in format as described below:
table_name: ["...", "...", ...]
Let's begin!
"""
usermsg = """
Query: $sql
"""
_prompt =
[
Dict(:name => "system", :text => systemmsg),
Dict(:name => "user", :text => usermsg)
]
# put in model format
prompt = GeneralUtils.formatLLMtext(_prompt; formatname="llama3instruct")
prompt *= """
<|start_header_id|>assistant<|end_header_id|>
"""
for attempt in 1:5
try
response = text2textInstructLLM(prompt)
responsedict = GeneralUtils.textToDict(response,
["table_name"],
rightmarker=":", symbolkey=true)
response = copy(JSON3.read(responsedict[:table_name]))
return response
catch e
io = IOBuffer()
showerror(io, e)
errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
println("")
println("Attempt $attempt. Error occurred: $errorMsg\n$st")
println("")
end
end
error("getTableNameFromSQL failed to generate a thought")
end
end # module llmfunction

View File

@@ -0,0 +1,81 @@
module type
end # module type

View File

@@ -0,0 +1,116 @@
module util
export getDataFrameValue, dfRowtoString, dfToString
using DataFrames
""" get a value from a dataframe row by a given key
"""
getDataFrameValue(row::DataFrameRow, key::Symbol) = row.:($key)
""" convert df row into key:value string
"""
function dfRowtoString(row::DataFrameRow)::String
str = ""
for key in keys(row)
value = getDataFrameValue(row, key)
str *= "$key: $value, "
end
result = str[1:end-2] # remove ", " at the end of row
return result
end
""" convert df table into string
"""
function dfToString(df::DataFrame)
dfstr = ""
for (i, row) in enumerate(eachrow(df))
rowstr = dfRowtoString(row)
dfstr *= "$i) $rowstr\n"
end
return dfstr
end
end # module util

View File

@@ -0,0 +1,305 @@
using Revise
using LibPQ, JSON3, PrettyPrinting, UUIDs, DataFrames, DataStructures, Base64
using GeneralUtils, SQLLLM
config = copy(JSON3.read("config.json"))
function executeSQL(sql::T) where {T<:AbstractString}
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 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],
)
outgoingMsg = Dict(
:msgMeta => msgMeta,
:payload => Dict(
:text => prompt,
:kwargs => Dict(
:num_ctx => 20480,
:temperature => 0.2,
)
)
)
_response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
response = _response[:response][:text]
return response
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 addSQLVectorDB(state)
# 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 > 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
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))
return sqlStatement
else
return nothing
end
end
return nothing
end
# query = Dict(:text=> "How many wines from France do you have that can be paired with lamb?")
# query = "How many wines are from United States?"
query = "retailer: Yiem, wine_type: red, sweetness: 1-2, intensity: 4-5, wine price: 20-40"
# query = "wine_type: white, country: United States, sweetness: 1-2, tannin: 3, food to be served with wine: pizza"
# query = "wine_type: white, country: Austria, food to be served with wine: pork"
# query = "wine price: less than 25, wine_type: rose, country: France, sweetness: 2, tannin: 3, food to be served with wine: pizza"
# query = Dict(:text=> "wine_type: white, country: France, sweetness: 1")
result = SQLLLM.query(query, executeSQL, text2textInstructLLM;
addSQLVectorDB=addSQLVectorDB,
querySQLVectorDB=querySQLVectorDB)
println(result)
error(555)
"""
CREATE TABLE sql_statement_repository (id bigserial PRIMARY KEY, question text, sql_statement text, sql_statement_base64 text, embedding vector(768));
SELECT * FROM wine WHERE wine_type = 'red' AND country = 'France' AND sweetness >= 1 AND sweetness <= 2 AND intensity >= 4 AND intensity <= 5 ORDER BY RANDOM() LIMIT 2;
"""
# sql =
# """
# SELECT COUNT(*) FROM wine_food JOIN wine ON wine_food.wine_id = wine.wine_id JOIN food ON wine_food.food_id = food.food_id WHERE food.description LIKE '%lamb%';
# """
# response = SQLLLM.SQLexecution(executeSQL, sql);
# result = response[:result]
# userintention =
# """
# Since this is the first round, there's no execution error to analyze. However, we can think about how to improve the query to achieve the desired result.
# 1) We need to join the wine_food table with the food table on the food_id column.\n 2) We want to filter the results to include only wines that can be paired with lamb by checking if the food_name or additional_search_term matches 'lamb'.\n 3) We'll use a COUNT(DISTINCT) function to count the number of unique wine_id values that meet the condition.
# """
# userintention_dict = Dict(:userintention=>userintention)
# sql =
# """
# SELECT DISTINCT wf.wine_id, COUNT(wf.wine_id) AS wine_count FROM wine_food wf JOIN food f ON wf.food_id = f.food_id WHERE f.description LIKE '%lamb%' GROUP BY wf.wine_id ORDER BY wine_count DESC;
# """
# response = SQLLLM.SQLexecution(executeSQL, sql);
# result = response[:result]
# userintention =
# """
# 1. Use TABLEINFO function to get information about the columns in the wine_food table.\n2. Use GETDATA function to retrieve data from the wine_food table that contains information about wines paired with lamb.\n3. Join the retrieved data with the wine table on the wine_id column to get information about the wines that can be paired with lamb.\n4. Count the number of unique wines associated with lamb through the wine_food junction table. 1. Use TABLEINFO function to get information about the columns in the wine_food table.\n2. Use GETDATA function to retrieve data from the wine_food table that contains information about wines paired with lamb.\n3. Join the retrieved data with the wine table on the wine_id column to get information about the wines that can be paired with lamb.\n4. Count the number of unique wines associated with lamb through the wine_food junction table.
# """
# userintention_dict = Dict(:userintention=>userintention)
# sql =
# """
# SELECT COUNT(DISTINCT w.wine_name) FROM (SELECT * FROM wine_food wf JOIN food f ON wf.food_id = f.food_id WHERE f.food_name = 'lamb') AS temp_table JOIN wine w ON temp_table.wine_id = w.wine_id;
# """
# response = SQLLLM.SQLexecution(executeSQL, sql);
# result = response[:result]
# userintention =
# """
# 1. Join the wine_food table with the food table using the food_id column in both tables.\n2. Filter the results to only include rows where the associated food is 'lamb'.\n3. Join the resulting table with the wine table using the wine_id column in both tables.\n4. Count the number of unique wines that can be paired with lamb. 1. Join the wine_food table with the food table using the food_id column in both tables.\n2. Filter the results to only include rows where the associated food is 'lamb'.\n3. Join the resulting table with the wine table using the wine_id column in both tables.\n4. Count the number of unique wines that can be paired with lamb.
# """
# userintention_dict = Dict(:userintention=>userintention)
# sql =
# """
# SELECT * FROM wine WHERE country = 'France' AND sweetness = 1 AND wine_type = 'white' LIMIT 2;
# """
# response = SQLLLM.SQLexecution(executeSQL, sql);
# result = response[:result]
# userintention =
# """
# "- Identify the primary key in the wine table.\n- Filter the results to only include wines with type white, from France and level of sweetness 1.\n- Retrieve the information about wines that match the specified criteria. - Identify the primary key in the wine table.\n- Filter the results to only include wines with type white, from France and level of sweetness 1.\n- Retrieve the information about wines that match the specified criteria.
# """
# userintention_dict = Dict(:userintention=>userintention)
# readout = SQLLLM.extractContent_dataframe(result, userintention_dict, text2textInstructLLM)
# println("runtest.jl is done")
# sql =
# """
# SELECT * FROM wine WHERE country = 'France' AND sweetness = 1 AND wine_type = 'white' LIMIT 2;
# """
# _result = executeSQL(sql)
# df2 = DataFrame(_result)
# state = Dict(
# :isterminal => true,
# :lesson => nothing,
# :reward => 1,
# :evaluation =>
# "The user's question is to search the database for wines that have a type of \"white\", are from \"France\", and have a sweetness level of 1. The thought is correct in identifying the conditions needed to filter the wine table. The action taken is to execute a SQL query to retrieve the desired data, which is also correct. The observation provides a search summary and two search results that match the user's question. Each result includes details about the wine such as ID, name, brand, manufacturer, region, country, type, grape variety, serving temperature, intensity, sweetness, tannin, and acidity.",
# :accepted_as_answer => "Yes",
# :thoughtHistory =>
# OrderedDict{Symbol, Any}(:question => "Search the database for wine_type: white, country: France, sweetness: 1", :thought_1 => "The user wants to search the database for wines that have a type of \"white\", are from \"France\", and have a sweetness level of 1. To achieve this, we need to filter the wine table based on these conditions.", :action_name_1 => "GETDATA", :action_input_1 => "SELECT * FROM wine WHERE wine.wine_type = 'white' AND wine.country = 'France' AND wine.sweetness = 1;", :observation_1 => "\"Search summary: The resulting table represents wines.\\nSearch result: 1) wine_id: 5b6b6df9-d87c-4f33-8995-7249c2ecc917, wine_name: corton-charlemagne grand cru, brand: domaine des croix, manufacturer: domaine des croix, region: bourgogne, country: France, wine_type: white, grape_variety: cote de beaune blanc, serving_temperature: 11 to 13 Celsius, intensity: 4, sweetness: 1, tannin: missing, acidity: 3, fizziness: missing\\n2) wine_id: 1ad27d16-ef64-4907-acf1-40631630c143, wine_name: puligny-montrachet 1er cru 'les demoiselles', brand: amiot guy, manufacturer: amiot guy, region: bourgogne, country: France, wine_type: white, grape_variety: cote de beaune blanc, serving_temperature: 11 to 13 Celsius, intensity: 4, sweetness: 1, tannin: missing, acidity: 3, fizziness: missing\\n\\n\""),
# :evaluationscore => 9,
# :select => nothing,
# :suggestion => "None")
# result = SQLLLM.evaluator(state, text2textInstructLLM)
println("runtest.jl done")

View File

@@ -0,0 +1,88 @@
using Revise
using LibPQ, JSON3, PrettyPrinting, UUIDs, DataFrames, DataStructures, Dates, MQTTClient, Random
using SQLLLM, GeneralUtils
function executeSQL(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
sql =
"""
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
"""
result = executeSQL(sql)
sql =
"""
INSERT INTO items (embedding) VALUES ('[[1,2,3], [1,2,3], [1,2,3]]'), ('[4,5,6]');
"""
result = executeSQL(sql)
sql =
"""
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 1;
"""
result = executeSQL(sql)
df = DataFrame(result)
config = copy(JSON3.read("config.json"))
msgMeta = GeneralUtils.generate_msgMeta(
config[:externalservice][:text2textinstruct][:mqtttopic];
msgPurpose= "embedding",
senderName= "yiemagent",
senderId= string(uuid4()),
receiverName= "text2textinstruct",
mqttBrokerAddress= "mqtt.yiem.cc",
mqttBrokerPort= 1883,
)
text = ["hello world"]
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> text,
:kwargs=> Dict(
:max_tokens=> 2048,
:stop=> ["<|eot_id|>"],
:temperature=> 0.2,
)
)
)
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)

View File

@@ -0,0 +1,23 @@
using Revise
function testf(a)::NamedTuple{(:a, :b), Tuple{Union{Nothing, Int}, Int}}
if a == 1
return (a=nothing, b=5)
else
return (a=5, b=5)
end
end
q = testf(1)
w = testf(2)

View File

@@ -0,0 +1,8 @@
table_name,comment
customer,"The customer table stores information about customers. It includes details such as first name, last name, display name, username, password, gender, country, telephone number, email, birthdate, additional_search_term, other attributes (in JSON format) and a description."
wine,"The wine table stores information about different wines. It includes details namely id, name, brand, manufacturer, region, country, wine_type, grape_variety, serving_temperature, intensity, sweetness, tannin, acidity, fizziness, additional_search_term, other attributes (in JSON format) and a description."
wine_food,"The wine_food table represents the association between wines and food items. It establishes a many-to-many relationship, allowing us to link specific wines with various food items."
food,"The food table represents various food items. It stores information related to food names, country of origin, taste attributes (spiciness, sweetness, sourness, savoriness, and bitterness), serving temperature, additional_search_term, other attributes (in JSON format) and a description."
retailer,"The retailer table stores information about different retailers. It includes details related to retailer names, usernames, passwords, addresses, contact persons, telephone numbers, email addresses, additional_search_term, other attributes (in JSON format) and a description."
retailer_wine,"The retailer_wine table represents the relationship between retailers and wines. It stores information about the wines available from which retailers, including vintage, their price, and the currency."
retailer_food,"The retailer_food table represents the relationship between retailers and food items. It stores information about the food items available from which retailers, including their price and the currency."
1 table_name comment
2 customer The customer table stores information about customers. It includes details such as first name, last name, display name, username, password, gender, country, telephone number, email, birthdate, additional_search_term, other attributes (in JSON format) and a description.
3 wine The wine table stores information about different wines. It includes details namely id, name, brand, manufacturer, region, country, wine_type, grape_variety, serving_temperature, intensity, sweetness, tannin, acidity, fizziness, additional_search_term, other attributes (in JSON format) and a description.
4 wine_food The wine_food table represents the association between wines and food items. It establishes a many-to-many relationship, allowing us to link specific wines with various food items.
5 food The food table represents various food items. It stores information related to food names, country of origin, taste attributes (spiciness, sweetness, sourness, savoriness, and bitterness), serving temperature, additional_search_term, other attributes (in JSON format) and a description.
6 retailer The retailer table stores information about different retailers. It includes details related to retailer names, usernames, passwords, addresses, contact persons, telephone numbers, email addresses, additional_search_term, other attributes (in JSON format) and a description.
7 retailer_wine The retailer_wine table represents the relationship between retailers and wines. It stores information about the wines available from which retailers, including vintage, their price, and the currency.
8 retailer_food The retailer_food table represents the relationship between retailers and food items. It stores information about the food items available from which retailers, including their price and the currency.

View File

@@ -101,15 +101,8 @@ Dict(
# Signature
"""
function decisionMaker(state::T1, context, text2textInstructLLM::Function,
QandA::T2; similarSQL::Union{T3, Nothing}=nothing
)::Dict{Symbol, Any} where {T1<:AbstractDict, T2<:AbstractString, T3<:AbstractString}
similarSQL =
if similarSQL === nothing
"None"
else
"This is the closest matching SQL statement for a similar query: $similarSQL"
end
; querySQLVectorDBF::Union{T2, Nothing}=nothing
)::Dict{Symbol, Any} where {T1<:AbstractDict, T2<:Function}
# lessonDict =
# if isfile("lesson.json")
@@ -184,30 +177,38 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
Let's begin!
"""
# [WORKING] add no backtick
workprogress = ""
for (k, v) in state[:thoughtHistory]
if k [:query]
if k [:question]
workprogress *= "$k: $v\n"
end
end
response = nothing # store for show when error msg show up
errornote = ""
noise = ""
# provide similar sql only for the first attempt
similarSQL_ = "None"
if length(state[:thoughtHistory]) == 1
sql, distance = querySQLVectorDBF(state[:thoughtHistory][:question])
similarSQL_ = sql !== nothing ? sql : "None"
end
for attempt in 1:10
QandA = generatequestion(state, context, text2textInstructLLM; similarSQL=similarSQL_)
usermsg =
"""
$(context[:tablelist])
User query: $(state[:thoughtHistory][:question])
Hints: $similarSQL
Hints: $similarSQL_
Your Q&A: $QandA
Your work progress: $workprogress
Evaluation: $(state[:evaluation])
Suggestion: $(state[:suggestion])
$errornote
$noise
"""
_prompt =
@@ -233,8 +234,10 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
delete!(responsedict, :observation)
if occursin('`', response)
response = replace(response, '`'=>"")
# remove backticks
if occursin("```", responsedict[:action_input])
responsedict[:action_input] =
GeneralUtils.extract_triple_backtick_text(responsedict[:action_input])
end
toollist = ["TABLEINFO", "GETDATA"]
@@ -262,6 +265,8 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
end
end
state[:decisionMaker] = responsedict
return responsedict
catch e
io = IOBuffer()
@@ -271,175 +276,10 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
println("")
println("\n~~~ SQLLLM decisionMaker() Attempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__)
println("")
noise = GeneralUtils.randstrings(3, 5)
end
end
error("DecisionMaker failed to generate a thought ", response)
end
# function decisionMaker(state::T1, context, text2textInstructLLM::Function,
# QandA::T2; similarSQL::Union{T3, Nothing}=nothing
# )::Dict{Symbol, Any} where {T1<:AbstractDict, T2<:AbstractString, T3<:AbstractString}
# similarSQL =
# if similarSQL === nothing
# "None"
# else
# "This is the closest matching SQL statement for a similar query: $similarSQL"
# end
# # lessonDict =
# # if isfile("lesson.json")
# # lessonDict = copy(JSON3.read("lesson.json"))
# # else
# # lessonDict = nothing
# # end
# # lessonDict = nothing
# # lesson =
# # if lessonDict === nothing
# # ""
# # else
# # """
# # You have attempted to help the user before and failed, either because your reasoning for the
# # recommendation was incorrect or your response did not exactly match the user expectation.
# # The following lesson(s) give a plan to avoid failing to help the user in the same way you
# # did previously. Use them to improve your strategy to help the user.
# # Here are some lessons in JSON format:
# # $(JSON3.write(lessonDict))
# # When providing the thought and action for the current trial, that into account these failed
# # trajectories and make sure not to repeat the same mistakes and incorrect answers.
# # """
# # end
# systemmsg =
# """
# You are a helpful assistant that get the data from a database to satisfy the user's query.
# You are also eager to improve your helpfulness.
# At each round of conversation, the user will give you the current situation:
# User Query: ...
# Hints: ...
# Your Q&A: ...
# Your work progress: ...
# Evaluation: Evaluation of the latest action and observation
# Suggestion: ...
# You should consider the following guidelines:
# - Do not create any table in the database
# - Column name can be the same in different tables. Refer to column comments to get more details by using TABLEINFO function
# - A junction table can be used to link tables together. Another use case is for filtering data.
# - If you can't find a single table that can be used to answer the user's query, try joining multiple tables to see if you can obtain the answer.
# - If you are unable to find the requested information, kindly inform the user, "The current data in our database does not provide the specific answer to your query".
# - Text information in the database usually stored in lower case. If your search returns empty, try using lower case to search.
# You should then respond to the user with interleaving Understanding, Reasoning, Plan, Action:
# 1) Understanding:
# - State your understanding about the current situation.
# 2) Reasoning:
# - State your step by step reasoning about the current situation.
# 3) Plan: Given the current circumstances, outline a detailed, step-by-step plan to accomplish the task. Be specific.
# 4) Action_name (Must be aligned with your plan): Can be one of the following functions:
# - TABLEINFO[list_of_table_name], which you can use to get the data type of a table column. "list_of_table_name" is a list of table name you want to get info. e.g. TABLEINFO["table name 1", "table name 2"]
# - GETDATA[SQL], which you can use to get the data from the database. "SQL" is the single SQL command to be executed against the database.
# For more effective text search, it's necessary to use case-insensitivity and the ILIKE operator.
# Do not wrap the SQL as it will be executed against the database directly and SQL must be ended with ';'.
# 5) Action_input: Input to the action
# 6) Observation: Result of the immediately preceding action
# You should only respond in format as described below:
# Understanding: ...
# Reasoning: ...
# Plan: ...
# Action_name: ...
# Action_input: ...
# Observation: ...
# Let's begin!
# """
# workprogress = ""
# for (k, v) in state[:thoughtHistory]
# if k ∉ [:query]
# workprogress *= "$k: $v\n"
# end
# end
# usermsg =
# """
# $(context[:tablelist])
# User query: $(state[:thoughtHistory][:question])
# Hints: $similarSQL
# Your Q&A: $QandA
# Your work progress: $workprogress
# Evaluation: $(state[:evaluation])
# Suggestion: $(state[:suggestion])
# """
# _prompt =
# [
# Dict(:name=> "system", :text=> systemmsg),
# Dict(:name=> "user", :text=> usermsg)
# ]
# # put in model format
# prompt = GeneralUtils.formatLLMtext(_prompt; formatname="llama3instruct")
# prompt *=
# """
# <|start_header_id|>assistant<|end_header_id|>
# """
# response = nothing # store for show when error msg show up
# for attempt in 1:10
# try
# response = text2textInstructLLM(prompt)
# # textToDict() search for action_input
# responsedict = GeneralUtils.textToDict(response,
# ["Understanding", "Reasoning", "Plan", "Action_name", "Action_input", "Observation"],
# rightmarker=":", symbolkey=true, lowercasekey=true)
# delete!(responsedict, :observation)
# toollist = ["TABLEINFO", "GETDATA"]
# if responsedict[:action_name] ∉ toollist
# error("SQL decisionMaker() didn't use the given functions ", @__FILE__, " ", @__LINE__)
# end
# for i in toollist
# if occursin(i, responsedict[:action_input])
# error("Action_name is in action_input which is not allowed.")
# end
# end
# for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input]
# if length(JSON3.write(responsedict[i])) == 0
# error("$i is empty ", @__FILE__, " ", @__LINE__)
# end
# end
# # check if there are more than 1 key per categories
# for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input]
# matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i)
# if length(matchkeys) > 1
# error("DecisionMaker has more than one key per categories")
# end
# end
# return responsedict
# catch e
# io = IOBuffer()
# showerror(io, e)
# errorMsg = String(take!(io))
# st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
# println("")
# println("Attempt $attempt. Error occurred: $errorMsg\n$st")
# println("")
# end
# end
# error("DecisionMaker failed to generate a thought ", response)
# end
""" Assigns a scalar value to each new child node to be used for selec-
tion and backpropagation. This value effectively quantifies the agent's progress in task completion,
@@ -654,12 +494,10 @@ function evaluator(state::T1, text2textInstructLLM::Function;
thoughthistory *= "$k: $v\n"
end
noise = ""
for attempt in 1:5
usermsg =
"""
Trajectory: $thoughthistory
$noise
"""
_prompt =
@@ -691,7 +529,7 @@ function evaluator(state::T1, text2textInstructLLM::Function;
accepted_as_answer::AbstractString = responsedict[:accepted_as_answer]
suggestion::AbstractString = responsedict[:suggestion]
if accepted_as_answer ["Yes", "No"] # [WORKING] add errornote into the prompt
if accepted_as_answer ["Yes", "No"] # [PENDING] add errornote into the prompt
error("generated accepted_as_answer has wrong format")
end
@@ -704,12 +542,6 @@ function evaluator(state::T1, text2textInstructLLM::Function;
# mark as terminal state when the answer is achieved
if accepted_as_answer == "Yes"
# add to vectorDB only if the answer is achieved and the state is terminal
# (found some row in the database)
if addSQLVectorDB !== nothing && state[:isterminal] == true
addSQLVectorDB(state)
end
# mark the state as terminal state because the evaluation say so.
state[:isterminal] = true
@@ -728,7 +560,6 @@ function evaluator(state::T1, text2textInstructLLM::Function;
println("")
println("Attempt $attempt. Error occurred: $errorMsg\n$st")
println("")
noise = GeneralUtils.randstrings(3, 5)
end
end
error("evaluator failed to generate an evaluation")
@@ -925,7 +756,7 @@ julia> state = Dict(
# TODO
- [] add embedding of newstate and store in newstate[:embedding]
- [WORKING] should getdata() return isterminal?
- [PENDING] should getdata() return isterminal?
# Signature
"""
function transition(state::T, args::NamedTuple
@@ -935,42 +766,43 @@ function transition(state::T, args::NamedTuple
evaluatorF::Function = args[:evaluator]
reflector::Function = args[:reflector]
context = args[:context]
executeSQLF::Function = args[:executeSQL]
executeSQL::Function = args[:executeSQL]
text2textInstructLLM::Function = args[:text2textInstructLLM]
addSQLVectorDBF::Function = args[:addSQLVectorDB]
querySQLVectorDBF::Function = args[:querySQLVectorDB]
# find similar SQL statement
similarSQL = querySQLVectorDBF(state)
QandA = generatequestion(state, context, text2textInstructLLM; similarSQL=similarSQL)
# getting SQL from vectorDB
thoughtDict = decisionMakerF(state, context, text2textInstructLLM, QandA; similarSQL=similarSQL)
actionname = thoughtDict[:action_name]
actioninput = thoughtDict[:action_input]
thoughtDict = decisionMakerF(state, context, text2textInstructLLM; querySQLVectorDBF)
# map action and input() to llm function
response =
if actionname == "listalltables"
if thoughtDict[:action_name] == "listalltables"
# deepcopy(state[:virtualCustomerChatHistory]) because I want to keep it clean
# so that other simulation start from this same node is not contaminated with actioninput
listAllTable_json(executeSQLF)
elseif actionname == "TABLEINFO"
input = copy(JSON3.read(actioninput))
tableinfo(executeSQLF, input)
elseif actionname == "GETDATA"
userintention = Dict(:userintention=> "$(thoughtDict[:plan]) $(thoughtDict[:plan])")
getdata(actioninput, userintention, executeSQLF, text2textInstructLLM)
listAllTable_json(executeSQL)
elseif thoughtDict[:action_name] == "TABLEINFO"
input = copy(JSON3.read(thoughtDict[:action_input]))
tableinfo(executeSQL, input)
elseif thoughtDict[:action_name] == "GETDATA"
response = SQLexecution(executeSQL, thoughtDict[:action_input])
if response[:success]
# intention = Dict(:intention=> "$(thoughtDict[:plan])")
extracted = extractContent_dataframe(response[:result], text2textInstructLLM)
(rawresponse=response[:result], result=extracted, errormsg=nothing, success=true)
else
error("undefined LLM function. Requesting $actionname")
(result=nothing, errormsg=response[:errormsg], success=false)
end
else
error("undefined LLM function. Requesting $(thoughtDict[:action_name])")
end
# this section allow LLM functions above to have different return values.
success::Bool = haskey(response, :success) ? response[:success] : false
result = success ? response[:result] : response[:errormsg]
rawresponse = haskey(response, :rawresponse) ? response[:rawresponse] : nothing
select = haskey(response, :select) ? response[:select] : nothing
reward::Integer = haskey(response, :reward) ? response[:reward] : 0
isterminal::Bool = haskey(response, :isterminal) ? response[:isterminal] : false
newNodeKey, newstate = makeNewState(state, thoughtDict, JSON3.write(result), select, reward, isterminal)
newNodeKey, newstate = makeNewState(state, thoughtDict, rawresponse, JSON3.write(result), select, reward, isterminal)
progressvalue::Integer = evaluatorF(newstate, text2textInstructLLM;
addSQLVectorDB=addSQLVectorDBF)
@@ -1056,10 +888,23 @@ julia> println(result)
"""
function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
addSQLVectorDB::Union{Function, Nothing}=nothing,
querySQLVectorDB::Union{Function, Nothing}=nothing
)::String where {T<:AbstractString}
similarSQLVectorDB::Union{Function, Nothing}=nothing,
) where {T<:AbstractString}
# use similarSQLVectorDB to find similar SQL for the query
sql, distance = similarSQLVectorDB(query)
if sql !== nothing && distance <= 1
# query vector db to get wine
response = SQLexecution(executeSQL, sql)
if response[:success]
# intention = Dict(:intention=> "$(thoughtDict[:plan])")
extracted = extractContent_dataframe(response[:result], text2textInstructLLM)
return (text=extracted, rawresponse=response[:result])
end
end
# do MCTS if no data in the database
# add extra context for Evaluator so that it knows the observation is from seaching a database
query = "Search the database for {$query}"
initialstate = Dict{Symbol, Any}(
:reward=> 0,
:isterminal=> false,
@@ -1085,7 +930,7 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
context=context,
executeSQL=executeSQL,
text2textInstructLLM=text2textInstructLLM,
querySQLVectorDB=querySQLVectorDB,
querySQLVectorDB=similarSQLVectorDB,
addSQLVectorDB=addSQLVectorDB,
)
@@ -1094,10 +939,17 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
_, resultState = LLMMCTS.runMCTS(initialstate, transition, transitionargs;
totalsample=1, maxdepth=3, maxiterations=3, explorationweight=1.0,
earlystop=earlystop)
latestKey, _ = GeneralUtils.findHighestIndexKey(resultState[:thoughtHistory], "observation")
resulttext = resultState[:thoughtHistory][latestKey]
latestKey, latestInd = GeneralUtils.findHighestIndexKey(resultState[:thoughtHistory], "observation")
action_input = Symbol("action_input_$latestInd") # latest sql
sql = resultState[:thoughtHistory][action_input]
extracted = resultState[:thoughtHistory][latestKey]
return resulttext
# add to vectorDB only if the answer is achieved and the state is terminal
if addSQLVectorDB !== nothing && resultState[:isterminal] == true
addSQLVectorDB(resultState[:thoughtHistory][:question], sql)
end
return (text=extracted, rawresponse=resultState[:rawresponse])
end
@@ -1114,7 +966,7 @@ julia>
# Signature
"""
function makeNewState(currentstate::T1, thoughtDict::T4, response::T2, select::Union{T3, Nothing},
function makeNewState(currentstate::T1, thoughtDict::T4, rawresponse, response::T2, select::Union{T3, Nothing},
reward::T3, isterminal::Bool
)::NamedTuple{(:newNodeKey, :newstate), Tuple{String, Dict{Symbol, <:Any}}} where {T1<:AbstractDict, T2<:AbstractString, T3<:Number, T4<:AbstractDict}
@@ -1141,6 +993,7 @@ function makeNewState(currentstate::T1, thoughtDict::T4, response::T2, select::U
newstate[:reward] = reward
newstate[:select] = select
newstate[:isterminal] = isterminal
newstate[:rawresponse] = rawresponse # whatever return from action
newNodeKey = GeneralUtils.uuid4snakecase()

View File

@@ -205,83 +205,43 @@ end
""" Convert a query process in English into SQL, execute and get the result from the database.
# """ Convert a query process in English into SQL, execute and get the result from the database.
# Arguments
- `query<:AbstractString`
A query to a database in SQL.
- `context::Union{Dict, Nothing}`
A context to be available at transition()
- `executeSQL::Function`
A connection object connected to the database
- `text2textInstructLLM::Function`
A function that handles communication to LLM service.
# # Arguments
# - `query<:AbstractString`
# A query to a database in SQL.
# - `context::Union{Dict, Nothing}`
# A context to be available at transition()
# - `executeSQL::Function`
# A connection object connected to the database
# - `text2textInstructLLM::Function`
# A function that handles communication to LLM service.
# Return
- `NamedTuple{(:result, :errormsg, success), Tuple{String, String, Bool}}`
# # Return
# - `NamedTuple{(:result, :errormsg, success), Tuple{String, String, Bool}}`
# TODO
- [x] getdata directly using sql execute
# # TODO
# - [x] getdata directly using sql execute
# Signature
"""
function getdata(query::T, context::Union{Dict,Nothing}, executeSQL::Function,
text2textInstructLLM::Function;
) where {T<:AbstractString}
response = SQLexecution(executeSQL, query)
if response[:success]
extracted = extractContent_dataframe(response[:result], context, text2textInstructLLM)
response_ = (result=extracted, errormsg=nothing, success=true)
return response_
else
response_ = (result=nothing, errormsg=response[:errormsg], success=false)
return response_
end
end
# # Signature
# """
# function getdata(query::T, context::Union{Dict,Nothing}, executeSQL::Function,
# text2textInstructLLM::Function;
# )::NamedTuple{(:result, :errormsg, :success), Tuple{String, Union{String, Nothing}, Bool}} where {T<:AbstractString}
# ) where {T<:AbstractString}
# # get table info here because it'll be called only 1-time. If this function is in
# # getdata_decisionMaker(), it'll be called everytime
# mentionedtable = getTableNameFromSQL(query, text2textInstructLLM)
# mentionedTableInfo = tableinfo(executeSQL, mentionedtable)[:result]
# context[:mentionedTableInfo] = mentionedTableInfo
# initialstate = Dict{Symbol, Any}(
# :reward=> 0,
# :isterminal=> false,
# :evaluation=> nothing,
# :errormsg=> nothing,
# :errorexplain=> nothing,
# :question=> query,
# :code=> nothing,
# :response=> nothing,
# )
# transitionargs = (
# # decisionMaker=getdata_decisionMaker,
# # evaluator=getdata_evaluator,
# # reflector=getdata_reflector,
# context=context,
# executeSQL=executeSQL,
# text2textInstructLLM=text2textInstructLLM
# )
# result_1, result_2 = LLMMCTS.runMCTS(initialstate, getdata_transition, transitionargs;
# totalsample=1, maxdepth=3, maxiterations=1, explorationweight=1.0)
# if result_2[:isterminal] == true
# return (result=result_2[:response], errormsg=nothing, success=true) # succues=true to finish getdata()
# response = SQLexecution(executeSQL, query)
# if response[:success]
# extracted = extractContent_dataframe(response[:result], context, text2textInstructLLM)
# response_ = (result=extracted, errormsg=nothing, success=true)
# return response_
# else
# # return (response="Failed to act with the following error message: $(result_2[:errorexplain])", select=nothing, reward=0, success=false)
# return (result="Failed to get the data. $(result_1[:errormsg])",
# errormsg=result_1[:errormsg], success=false)
# response_ = (result=nothing, errormsg=response[:errormsg], success=false)
# return response_
# end
# end
"""
# Arguments
@@ -696,7 +656,7 @@ end
# Signature
"""
function extractContent_dataframe(df::DataFrame, context::Dict, text2textInstructLLM::Function
function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function
)::String
tablesize = size(df)
row = tablesize[1]
@@ -725,7 +685,7 @@ function extractContent_dataframe(df::DataFrame, context::Dict, text2textInstruc
df1 = df
dfstr = dfToString(df1)
dfstr = GeneralUtils.dfToString(df1)
systemmsg = """
You are an assistant that readouts the resulting table after the user executing SQL command.
@@ -751,7 +711,6 @@ function extractContent_dataframe(df::DataFrame, context::Dict, text2textInstruc
Let's begin!
"""
usermsg = """
User intention: $(context[:userintention])
Resulting table: $dfstr
"""
_prompt =

View File

@@ -1,41 +1,5 @@
module util
export getDataFrameValue, dfRowtoString, dfToString
using DataFrames
""" get a value from a dataframe row by a given key
"""
getDataFrameValue(row::DataFrameRow, key::Symbol) = row.:($key)
""" convert df row into key:value string
"""
function dfRowtoString(row::DataFrameRow)::String
str = ""
for key in keys(row)
value = getDataFrameValue(row, key)
str *= "$key: $value, "
end
result = str[1:end-2] # remove ", " at the end of row
return result
end
""" convert df table into string
"""
function dfToString(df::DataFrame)
dfstr = ""
for (i, row) in enumerate(eachrow(df))
rowstr = dfRowtoString(row)
dfstr *= "$i) $rowstr\n"
end
return dfstr
end