diff --git a/assets/css/app.scss b/assets/css/app.scss index c6e5ce2..38c7869 100644 --- a/assets/css/app.scss +++ b/assets/css/app.scss @@ -78,3 +78,35 @@ ); @use '~bitstyles/scss/bitstyles/utilities/z-index'; + +.loader { + width: 1rem; + height: 1rem; + border: 5px solid #9485ff; + border-bottom-color: transparent; + border-radius: 50%; + display: inline-block; + box-sizing: border-box; + animation: rotation 1s linear infinite; + } + + @keyframes rotation { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.a-card ol { + padding-inline-start: var(--bs-size-l2); +} + +.a-card ul { + padding-inline-start: var(--bs-size-l2); +} + +.a-card code { + text-wrap: wrap; +} diff --git a/config/config.exs b/config/config.exs index d88837a..03a84ef 100644 --- a/config/config.exs +++ b/config/config.exs @@ -6,6 +6,9 @@ import Config +config :chatbot, Chatbot.Repo, types: Chatbot.PostgrexTypes +config :chatbot, openai_key: "your openai API key" +config :nx, default_backend: EXLA.Backend import_config "config/endpoint.exs" import_config "config/logger.exs" import_config "config/phoenix.exs" diff --git a/config/dev.exs b/config/dev.exs new file mode 100644 index 0000000..becde76 --- /dev/null +++ b/config/dev.exs @@ -0,0 +1 @@ +import Config diff --git a/config/prod.exs b/config/prod.exs new file mode 100644 index 0000000..becde76 --- /dev/null +++ b/config/prod.exs @@ -0,0 +1 @@ +import Config diff --git a/config/test.exs b/config/test.exs new file mode 100644 index 0000000..becde76 --- /dev/null +++ b/config/test.exs @@ -0,0 +1 @@ +import Config diff --git a/eval/rag_triad_eval.exs b/eval/rag_triad_eval.exs new file mode 100644 index 0000000..73d8f2e --- /dev/null +++ b/eval/rag_triad_eval.exs @@ -0,0 +1,63 @@ +openai_key = Application.compile_env(:chatbot, :openai_key) + +dataset = + "https://huggingface.co/datasets/explodinggradients/amnesty_qa/resolve/main/english.json" + +IO.puts("downloading dataset") + +data = + Req.get!(dataset).body + |> Jason.decode!() + +IO.puts("indexing") + +data["contexts"] +|> Enum.map(&Enum.join(&1, " ")) +|> Enum.with_index(fn context, index -> %{document: context, source: "#{index}"} end) +|> Chatbot.Rag.index() + +IO.puts("generating responses") + +generations = + for question <- data["question"] do + Chatbot.Rag.query(question) + end + +provider = Rag.Ai.OpenAI.new(%{text_model: "gpt-4o-mini", api_key: openai_key}) + +IO.puts("evaluating") + +generations = + for generation <- generations do + Rag.Evaluation.evaluate_rag_triad(generation, provider) + end + +json = + generations + |> Enum.map(fn generation -> + Map.from_struct(generation) + |> Map.take([:query, :context, :context_sources, :response, :evaluations]) + end) + |> Jason.encode!() + +File.write!(Path.join(__DIR__, "triad_eval.json"), json) + +average_rag_triad_scores = + Enum.map( + generations, + fn gen -> + %{ + evaluations: %{ + "context_relevance_score" => context_relevance_score, + "groundedness_score" => groundedness_score, + "answer_relevance_score" => answer_relevance_score + } + } = gen + + (context_relevance_score + groundedness_score + answer_relevance_score) / 3 + end + ) + +total_average_score = Enum.sum(average_rag_triad_scores) / Enum.count(average_rag_triad_scores) + +IO.puts("Score: ,#{total_average_score}") diff --git a/lib/chatbot/application.ex b/lib/chatbot/application.ex index 93625a7..22a30cd 100644 --- a/lib/chatbot/application.ex +++ b/lib/chatbot/application.ex @@ -5,9 +5,18 @@ defmodule Chatbot.Application do use Application + alias Chatbot.Rag.Serving + alias Chatbot.Rag.TelemetryHandler + @impl true def start(_type, _args) do children = [ + {Nx.Serving, + [ + serving: Serving.build_embedding_serving(), + name: Rag.EmbeddingServing, + batch_timeout: 100 + ]}, {Task.Supervisor, name: Chatbot.TaskSupervisor}, ChatbotWeb.Telemetry, Chatbot.Repo, @@ -19,6 +28,14 @@ defmodule Chatbot.Application do ChatbotWeb.Endpoint ] + :ok = + :telemetry.attach_many( + "rag-handler", + Rag.Telemetry.events(), + &TelemetryHandler.handle_event/4, + nil + ) + # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options opts = [strategy: :one_for_one, name: Chatbot.Supervisor] diff --git a/lib/chatbot/chat.ex b/lib/chatbot/chat.ex index d172f50..a115137 100644 --- a/lib/chatbot/chat.ex +++ b/lib/chatbot/chat.ex @@ -3,13 +3,12 @@ defmodule Chatbot.Chat do Context for chat related functions. """ import Ecto.Query, only: [from: 2] - alias Chatbot.{Chat.Message, LLMMock, Repo} + alias Chatbot.{Chat.Message, Repo} alias LangChain.Chains.LLMChain # There is currently a bug in the LangChain type specs: # `add_callback/2` expects a map with all possible handler functions. # See: # https://hexdocs.pm/langchain/0.3.0-rc.0/LangChain.Chains.ChainCallbacks.html#t:chain_callback_handler/0 - @dialyzer {:nowarn_function, stream_assistant_message: 1} @doc """ Creates a message. @@ -42,16 +41,14 @@ defmodule Chatbot.Chat do @spec request_assistant_message([Message.t()]) :: {:ok, Message.t()} | {:error, String.t() | Ecto.Changeset.t()} def request_assistant_message(messages) do - maybe_mock_llm() - messages = Enum.map(messages, &to_langchain_message/1) @chain |> LLMChain.add_messages(messages) |> LLMChain.run() |> case do - {:ok, _chain, response} -> - create_message(%{role: :assistant, content: response.content}) + {:ok, chain} -> + create_message(%{role: :assistant, content: chain.last_message.content}) _error -> {:error, "I failed, I'm sorry"} @@ -64,15 +61,13 @@ defmodule Chatbot.Chat do Once the full message was processed, it is saved as an assistant message. """ - @spec stream_assistant_message(pid()) :: Message.t() - def stream_assistant_message(receiver) do - messages = all_messages() |> Enum.map(&to_langchain_message/1) - - {:ok, assistant_message} = create_message(%{role: :assistant, content: ""}) + @spec stream_assistant_message(pid(), [Message.t()], Message.t()) :: Message.t() + def stream_assistant_message(receiver, messages, assistant_message) do + messages = Enum.map(messages, &to_langchain_message/1) handler = %{ on_llm_new_delta: fn _model, %LangChain.MessageDelta{} = data -> - send(receiver, {:next_message_delta, assistant_message.id, data}) + send(receiver, {:next_message_delta, assistant_message, data}) end, on_message_processed: fn _chain, %LangChain.Message{} = data -> completed_message = update_message!(assistant_message, %{content: data.content}) @@ -81,29 +76,21 @@ defmodule Chatbot.Chat do end } - Task.Supervisor.start_child(Chatbot.TaskSupervisor, fn -> - maybe_mock_llm(stream: true) - + {:ok, _chain} = @chain |> LLMChain.add_callback(handler) - |> LLMChain.add_llm_callback(handler) |> LLMChain.add_messages(messages) |> LLMChain.run() - end) assistant_message end - defp to_langchain_message(%{role: :user, content: content}), + def to_langchain_message(%{role: :user, content: content}), do: LangChain.Message.new_user!(content) - defp to_langchain_message(%{role: :assistant, content: content}), + def to_langchain_message(%{role: :assistant, content: content}), do: LangChain.Message.new_assistant!(content) - defp maybe_mock_llm(opts \\ []) do - if Application.fetch_env!(:chatbot, :mock_llm_api), do: LLMMock.mock(opts) - end - @doc """ Lists all messages ordered by insertion date. """ diff --git a/lib/chatbot/chat/message.ex b/lib/chatbot/chat/message.ex index 2e69242..fa10d89 100644 --- a/lib/chatbot/chat/message.ex +++ b/lib/chatbot/chat/message.ex @@ -13,6 +13,7 @@ defmodule Chatbot.Chat.Message do schema "messages" do field :role, Ecto.Enum, values: @message_types field :content, :string + field :sources, {:array, :string} timestamps() end @@ -24,7 +25,7 @@ defmodule Chatbot.Chat.Message do @spec changeset(t(), map()) :: Ecto.Changeset.t() def changeset(message \\ %__MODULE__{}, attrs) do message - |> cast(attrs, [:role]) + |> cast(attrs, [:role, :sources]) |> cast(attrs, [:content], empty_values: [nil]) # we cannot require the content, as # validate_required still considers "" as empty diff --git a/lib/chatbot/llm_mock.ex b/lib/chatbot/llm_mock.ex deleted file mode 100644 index 68f108a..0000000 --- a/lib/chatbot/llm_mock.ex +++ /dev/null @@ -1,51 +0,0 @@ -defmodule Chatbot.LLMMock do - @moduledoc """ - This module provides functions to mock the messages from the - LLM. - - Note: - We are using `set_api_override/1` from LangChain.Utils.ApiOverride - for this, which uses the process dictionary. So make sure to call - the functions of this module from within the process that calls - `LangChain.Chains.LLMChain.run/0`. - """ - import LangChain.Utils.ApiOverride - alias LangChain.{Message, MessageDelta} - - def mock(opts) do - if Keyword.get(opts, :stream, false) do - do_mock() - else - do_mock_stream() - end - end - - def do_mock do - content = """ - Thanks for your question. - I don't have an answer right now. - Please try another question. - Maybe I can help with that. - """ - - set_api_override({:ok, Message.new_assistant!(%{content: content}), :on_llm_new_message}) - end - - def do_mock_stream do - fake_messages = [ - [MessageDelta.new!(%{role: :assistant, content: nil, status: :incomplete})], - [MessageDelta.new!(%{content: "Thanks for your question. ", status: :incomplete})], - [MessageDelta.new!(%{content: "Let me think about that. ", status: :incomplete})], - [MessageDelta.new!(%{content: "... ", status: :incomplete})], - [MessageDelta.new!(%{content: "I don't have an answer right now. ", status: :incomplete})], - [ - MessageDelta.new!(%{ - content: "Please try another question. Maybe I can help with that.", - status: :complete - }) - ] - ] - - set_api_override({:ok, fake_messages, :on_llm_new_delta}) - end -end diff --git a/lib/chatbot/rag.ex b/lib/chatbot/rag.ex new file mode 100644 index 0000000..980b069 --- /dev/null +++ b/lib/chatbot/rag.ex @@ -0,0 +1,136 @@ +defmodule Chatbot.Rag do + @moduledoc false + alias Chatbot.Repo + alias Rag.{Ai, Embedding, Generation, Retrieval} + + import Ecto.Query + import Pgvector.Ecto.Query + + @provider Ai.Nx.new(%{embeddings_serving: Rag.EmbeddingServing}) + + def ingest_ecto do + docs_url = "https://repo.hex.pm/docs/ecto-3.12.5.tar.gz" + + code_url = "https://repo.hex.pm/tarballs/ecto-3.12.5.tar" + + req = Req.new(url: docs_url) |> ReqHex.attach() + docs_tarball = Req.get!(req).body + + docs = + for {file, content} <- docs_tarball, text_file?(file) do + file = to_string(file) + %{source: file, document: content} + end + + req = Req.new(url: code_url) |> ReqHex.attach() + code_tarball = Req.get!(req).body + + code = + for {file, content} <- code_tarball["contents.tar.gz"] do + %{source: file, document: content} + end + + index(docs ++ code) + end + + defp text_file?(file) when is_list(file) do + file + |> to_string() + |> String.ends_with?([".html", ".md", ".txt"]) + end + + defp text_file?(file) when is_binary(file) do + file + |> String.ends_with?([".html", ".md", ".txt"]) + end + + def index(ingestions) do + chunks = + ingestions + |> Enum.flat_map(&chunk_text(&1, :document)) + |> Embedding.generate_embeddings_batch(@provider, + text_key: :chunk, + embedding_key: :embedding + ) + |> Enum.map(&to_chunk(&1)) + + Repo.insert_all(Chatbot.Rag.Chunk, chunks) + end + + defp chunk_text(ingestion, text_key, opts \\ []) do + text = Map.fetch!(ingestion, text_key) + chunks = TextChunker.split(text, opts) + + Enum.map(chunks, &Map.put(ingestion, :chunk, &1.text)) + end + + def build_generation(query) do + generation = + Generation.new(query) + |> Embedding.generate_embedding(@provider) + |> Retrieval.retrieve(:fulltext_results, fn generation -> query_fulltext(generation) end) + |> Retrieval.retrieve(:semantic_results, fn generation -> + query_with_pgvector(generation) + end) + |> Retrieval.reciprocal_rank_fusion( + %{fulltext_results: 1, semantic_results: 1}, + :rrf_result + ) + |> Retrieval.deduplicate(:rrf_result, [:source]) + + context = + Generation.get_retrieval_result(generation, :rrf_result) + |> Enum.map_join("\n\n", & &1.document) + + context_sources = + Generation.get_retrieval_result(generation, :rrf_result) + |> Enum.map(& &1.source) + + prompt = prompt(query, context) + + generation + |> Generation.put_context(context) + |> Generation.put_context_sources(context_sources) + |> Generation.put_prompt(prompt) + end + + defp to_chunk(ingestion) do + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + + ingestion + |> Map.put_new(:inserted_at, now) + |> Map.put_new(:updated_at, now) + end + + defp query_with_pgvector(%{query_embedding: query_embedding}, limit \\ 3) do + {:ok, + Repo.all( + from(c in Chatbot.Rag.Chunk, + order_by: l2_distance(c.embedding, ^Pgvector.new(query_embedding)), + limit: ^limit + ) + )} + end + + defp query_fulltext(%{query: query}, limit \\ 3) do + {:ok, + Repo.all( + from(c in Chatbot.Rag.Chunk, + where: fragment("to_tsvector(?) @@ websearch_to_tsquery(?)", c.chunk, ^query), + limit: ^limit + ) + )} + end + + defp prompt(query, context) do + """ + Context information is below. + --------------------- + #{context} + --------------------- + Given the context information and no prior knowledge, answer the query. + Query: #{query} + Answer: + """ + end +end diff --git a/lib/chatbot/rag/chunk.ex b/lib/chatbot/rag/chunk.ex new file mode 100644 index 0000000..32ae106 --- /dev/null +++ b/lib/chatbot/rag/chunk.ex @@ -0,0 +1,18 @@ +defmodule Chatbot.Rag.Chunk do + @moduledoc false + + use Ecto.Schema + + schema "chunks" do + field(:document, :string) + field(:source, :string) + field(:chunk, :string) + field(:embedding, Pgvector.Ecto.Vector) + + timestamps() + end + + def changeset(chunk \\ %__MODULE__{}, attrs) do + Ecto.Changeset.cast(chunk, attrs, [:document, :source, :chunk, :embedding]) + end +end diff --git a/lib/chatbot/rag/serving.ex b/lib/chatbot/rag/serving.ex new file mode 100644 index 0000000..6ceb292 --- /dev/null +++ b/lib/chatbot/rag/serving.ex @@ -0,0 +1,40 @@ +defmodule Chatbot.Rag.Serving do + @moduledoc false + + alias Bumblebee.Text + + def build_embedding_serving do + repo = {:hf, "jinaai/jina-embeddings-v2-base-code"} + + {:ok, model_info} = + Bumblebee.load_model(repo, + params_filename: "model.safetensors", + spec_overrides: [architecture: :base] + ) + + {:ok, tokenizer} = Bumblebee.load_tokenizer(repo) + + Text.TextEmbedding.text_embedding(model_info, tokenizer, + compile: [batch_size: 64, sequence_length: 512], + defn_options: [compiler: EXLA], + output_attribute: :hidden_state, + output_pool: :mean_pooling + ) + end + + def build_llm_serving do + repo = {:hf, "HuggingFaceTB/SmolLM2-135M-Instruct"} + + {:ok, model_info} = Bumblebee.load_model(repo) + {:ok, tokenizer} = Bumblebee.load_tokenizer(repo) + {:ok, generation_config} = Bumblebee.load_generation_config(repo) + + generation_config = Bumblebee.configure(generation_config, max_new_tokens: 100) + + Bumblebee.Text.generation(model_info, tokenizer, generation_config, + compile: [batch_size: 1, sequence_length: 6000], + defn_options: [compiler: EXLA], + stream: false + ) + end +end diff --git a/lib/chatbot/rag/telemetry_handler.ex b/lib/chatbot/rag/telemetry_handler.ex new file mode 100644 index 0000000..6337532 --- /dev/null +++ b/lib/chatbot/rag/telemetry_handler.ex @@ -0,0 +1,9 @@ +defmodule Chatbot.Rag.TelemetryHandler do + @moduledoc false + alias Phoenix.PubSub + + def handle_event(prefix, _measurement, _metadata, _config) do + [:rag, key, event] = prefix + PubSub.broadcast(Chatbot.PubSub, "rag", {key, event}) + end +end diff --git a/lib/chatbot_web/live/chat_live.ex b/lib/chatbot_web/live/chat_live.ex index 1167d4e..09db903 100644 --- a/lib/chatbot_web/live/chat_live.ex +++ b/lib/chatbot_web/live/chat_live.ex @@ -3,13 +3,17 @@ defmodule ChatbotWeb.ChatLive do import ChatbotWeb.CoreComponents import BitcrowdEcto.Random, only: [uuid: 0] alias Chatbot.Chat + alias Phoenix.PubSub @impl Phoenix.LiveView def mount(_params, _session, socket) do + if connected?(socket), do: PubSub.subscribe(Chatbot.PubSub, "rag") + socket = socket |> stream(:messages, Chat.all_messages()) |> assign(:currently_streamed_response, nil) + |> assign(:current_activity, nil) |> assign(:form, build_form()) {:ok, socket} @@ -36,10 +40,15 @@ defmodule ChatbotWeb.ChatLive do id={dom_id} role={message.role} content={message.content} + sources={message.sources} />
+ <.ui_card :if={@current_activity}> + + <%= @current_activity %> + <.simple_form for={@form} phx-submit="send" class="u-justify-self-end u-width-75"> <.ui_input type="textarea" @@ -76,18 +85,43 @@ defmodule ChatbotWeb.ChatLive do ~H""" <.ui_card id={@id} class={@class}> <%= @markdown %> + +
+ Sources +
    +
  1. + <%= source %> +
  2. +
+
""" end @impl Phoenix.LiveView def handle_event("send", %{"message" => %{"content" => content}}, socket) do + messages = Chat.all_messages() + + pid = self() + with {:ok, user_message} <- Chat.create_message(%{role: :user, content: content}), - assistant_message <- Chat.stream_assistant_message(self()) do + {:ok, assistant_message} <- Chat.create_message(%{role: :assistant, content: ""}) do {:noreply, socket |> assign(:form, build_form()) - |> stream(:messages, [user_message, assistant_message])} + |> stream(:messages, [user_message, assistant_message]) + |> start_async(:rag, fn -> + {:ok, augmented_user_message, augmentation} = augment_user_message(user_message) + + assistant_message = + Chat.update_message!(assistant_message, %{sources: augmentation.context_sources}) + + Chat.stream_assistant_message( + pid, + messages ++ [augmented_user_message], + assistant_message + ) + end)} end end @@ -108,7 +142,7 @@ defmodule ChatbotWeb.ChatLive do {:noreply, assign(socket, :currently_streamed_response, nil)} end - def handle_info({:next_message_delta, id, %{status: :incomplete} = message_delta}, socket) do + def handle_info({:next_message_delta, message, %{status: :incomplete} = message_delta}, socket) do currently_streamed_response = socket.assigns.currently_streamed_response merged_message_deltas = @@ -116,11 +150,7 @@ defmodule ChatbotWeb.ChatLive do {:noreply, socket - |> stream_insert(:messages, %{ - id: id, - role: :assistant, - content: merged_message_deltas.content - }) + |> stream_insert(:messages, %{message | content: merged_message_deltas.content}) |> assign(:currently_streamed_response, merged_message_deltas)} end @@ -128,6 +158,27 @@ defmodule ChatbotWeb.ChatLive do {:noreply, stream_insert(socket, :messages, completed_message)} end + def handle_info({:generate_embedding, :start}, socket) do + {:noreply, assign(socket, current_activity: "looking up information")} + end + + def handle_info({:retrieve, :stop}, socket) do + {:noreply, assign(socket, current_activity: "generating response")} + end + + def handle_info({_key, :exception}, socket) do + {:noreply, assign(socket, current_activity: "an error occurred :(")} + end + + def handle_info({_key, _event}, socket) do + {:noreply, socket} + end + + @impl true + def handle_async(:rag, _no, socket) do + {:noreply, assign(socket, current_activity: nil)} + end + defp build_form do %{role: :user, content: ""} |> Chat.Message.changeset() @@ -136,4 +187,12 @@ defmodule ChatbotWeb.ChatLive do # for a new message and clears the input |> to_form(id: uuid()) end + + defp augment_user_message(user_message) do + %{role: :user, content: query} = user_message + + rag_generation = Chatbot.Rag.build_generation(query) + + {:ok, %{user_message | content: rag_generation.prompt}, rag_generation} + end end diff --git a/lib/postgrex_types.ex b/lib/postgrex_types.ex new file mode 100644 index 0000000..0850089 --- /dev/null +++ b/lib/postgrex_types.ex @@ -0,0 +1,5 @@ +Postgrex.Types.define( + Chatbot.PostgrexTypes, + [Pgvector.Extensions.Vector] ++ Ecto.Adapters.Postgres.extensions(), + [] +) diff --git a/mix.exs b/mix.exs index 26baa8b..308a812 100644 --- a/mix.exs +++ b/mix.exs @@ -33,11 +33,17 @@ defmodule Chatbot.MixProject do # Type `mix help deps` for examples and options. defp deps do [ + {:req_hex, "~> 0.2.1"}, + {:pgvector, "~> 0.3.0"}, + {:ecto, "~> 3.0"}, + {:exla, "~> 0.9.1"}, + {:bumblebee, github: "joelpaulkoch/bumblebee", branch: "jina-embeddings-v2-base-code"}, + {:text_chunker, "~> 0.3.1"}, {:ex_machina, "~> 2.8"}, {:bitcrowd_ecto, "~> 1.0"}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, - {:langchain, "~> 0.3.0-rc.0"}, + {:langchain, "~> 0.3.1"}, {:phoenix, "~> 1.7.14"}, {:earmark, "~> 1.0"}, {:phoenix_ecto, "~> 4.5"}, @@ -47,6 +53,7 @@ defmodule Chatbot.MixProject do {:phoenix_live_reload, "~> 1.2", only: :dev}, # TODO bump on release to {:phoenix_live_view, "~> 1.0.0"}, {:phoenix_live_view, "~> 1.0.0-rc.1", override: true}, + {:rag, "~> 0.2.1"}, {:floki, ">= 0.30.0", only: :test}, {:phoenix_live_dashboard, "~> 0.8.3"}, {:telemetry_metrics, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index a71cc19..6af8e76 100644 --- a/mix.lock +++ b/mix.lock @@ -1,33 +1,47 @@ %{ "abacus": {:hex, :abacus, "2.1.0", "b6db5c989ba3d9dd8c36d1cb269e2f0058f34768d47c67eb8ce06697ecb36dd4", [:mix], [], "hexpm", "255de08b02884e8383f1eed8aa31df884ce0fb5eb394db81ff888089f2a1bbff"}, + "axon": {:hex, :axon, "0.7.0", "2e2c6d93b4afcfa812566b8922204fa022b60081e86ebd411df4db7ea30f5457", [:mix], [{:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}, {:kino_vega_lite, "~> 0.1.7", [hex: :kino_vega_lite, repo: "hexpm", optional: true]}, {:nx, "~> 0.9", [hex: :nx, repo: "hexpm", optional: false]}, {:polaris, "~> 0.1", [hex: :polaris, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: true]}], "hexpm", "ee9857a143c9486597ceff434e6ca833dc1241be6158b01025b8217757ed1036"}, "bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"}, "bitcrowd_ecto": {:hex, :bitcrowd_ecto, "1.0.0", "b255cf7b8e22bc17adeb8bbc9907ef02dcdc751fd68ab3e444b0a098dac99b65", [:mix], [{:ecto, "~> 3.6", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ex_money, "~> 5.12", [hex: :ex_money, repo: "hexpm", optional: true]}, {:jason, "> 0.0.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "862effc5eba425176472c2f01dd50b9994622089fa4bc2a11d75732b47dcdab9"}, "bitstyles_phoenix": {:hex, :bitstyles_phoenix, "2.5.0", "c02aae26fcf6ff752738b35aa97f3991c67533412eda381abaad3e22aa2e2215", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.12 or ~> 0.19.0 or ~> 0.20.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "fe018f0eeec6c84afedc1785495efe0a651ecf34656c4b52f6da09d5149a9f28"}, + "bumblebee": {:git, "https://github.com/joelpaulkoch/bumblebee.git", "1c27550b1cbfcfff3b0fb99e84bf2b3d5ccb4369", [branch: "jina-embeddings-v2-base-code"]}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, - "castore": {:hex, :castore, "1.0.9", "5cc77474afadf02c7c017823f460a17daa7908e991b0cc917febc90e466a375c", [:mix], [], "hexpm", "5ea956504f1ba6f2b4eb707061d8e17870de2bee95fb59d512872c2ef06925e7"}, + "castore": {:hex, :castore, "1.0.12", "053f0e32700cbec356280c0e835df425a3be4bc1e0627b714330ad9d0f05497f", [:mix], [], "hexpm", "3dca286b2186055ba0c9449b4e95b97bf1b57b47c1f2644555879e659960c224"}, + "complex": {:hex, :complex, "0.6.0", "b0130086a7a8c33574d293b2e0e250f4685580418eac52a5658a4bd148f3ccf1", [:mix], [], "hexpm", "0a5fa95580dcaf30fcd60fe1aaf24327c0fe401e98c24d892e172e79498269f9"}, "credo": {:hex, :credo, "1.7.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, - "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, + "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"}, "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, "earmark": {:hex, :earmark, "1.4.47", "7e7596b84fe4ebeb8751e14cbaeaf4d7a0237708f2ce43630cfd9065551f94ca", [:mix], [], "hexpm", "3e96bebea2c2d95f3b346a7ff22285bc68a99fbabdad9b655aa9c6be06c698f8"}, - "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"}, + "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, + "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"}, "ex_machina": {:hex, :ex_machina, "2.8.0", "a0e847b5712065055ec3255840e2c78ef9366634d62390839d4880483be38abe", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "79fe1a9c64c0c1c1fab6c4fa5d871682cb90de5885320c187d117004627a7729"}, + "exla": {:hex, :exla, "0.9.2", "2b5cb7334f79fedc301502a793ffd10bc1ec8de2c61eebabcabf213fc98ae7e6", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:nx, "~> 0.9.0", [hex: :nx, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:xla, "~> 0.8.0", [hex: :xla, repo: "hexpm", optional: false]}], "hexpm", "e51085e196b466d235e93d9f5ea2cbf7d90315d216aa02e996f99bcaaa19c593"}, "expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"}, "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, - "gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"}, - "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, + "gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"}, + "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, + "hex_core": {:hex, :hex_core, "0.10.3", "7dc866ca8f5830566aacef141bdde4f1d61f687407c7070611c349e983f185d2", [:rebar3], [], "hexpm", "bc7c2b6ceb99e29550f74234952ad3b8153e6f2dbc38892bd0ff46043be073f5"}, + "hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"}, + "igniter": {:hex, :igniter, "0.5.33", "799a49a8eb7e2fbebd6af2b770a856fa8ede9acad73a74269a04b8e775ead199", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "ac962445d426dd3815e6b5568daa86586487293d126a946a67d9cf17d0665005"}, + "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, - "langchain": {:hex, :langchain, "0.3.0-rc.0", "930d22170fff2c599e8a63a664e437f896555b3cebe3055276bca37e7ae17d1b", [:mix], [{:abacus, "~> 2.1.0", [hex: :abacus, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10", [hex: :ecto, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:nx, ">= 0.7.0", [hex: :nx, repo: "hexpm", optional: true]}, {:req, ">= 0.5.0", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "c1f4f563cfddc502d3cfa5180fef154b8e194ef0f6f7bf0fe540761d2439b7ab"}, + "langchain": {:hex, :langchain, "0.3.1", "df63af8f928438bd98253e569099109041ce985092227cbe8e1216612b0d4f23", [:mix], [{:abacus, "~> 2.1.0", [hex: :abacus, repo: "hexpm", optional: true]}, {:ecto, "~> 3.10", [hex: :ecto, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:nx, ">= 0.7.0", [hex: :nx, repo: "hexpm", optional: true]}, {:req, ">= 0.5.2", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "0cc40659e9a76e4e6599727d71fc841122f0aefc036a09a145caeaca8e45558b"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, - "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, + "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, + "nx": {:hex, :nx, "0.9.2", "17563029c01bf749aad3c31234326d7665abd0acc33ee2acbe531a4759f29a8a", [:mix], [{:complex, "~> 0.5", [hex: :complex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "914d74741617d8103de8ab1f8c880353e555263e1c397b8a1109f79a3716557f"}, + "nx_image": {:hex, :nx_image, "0.1.2", "0c6e3453c1dc30fc80c723a54861204304cebc8a89ed3b806b972c73ee5d119d", [:mix], [{:nx, "~> 0.4", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "9161863c42405ddccb6dbbbeae078ad23e30201509cc804b3b3a7c9e98764b81"}, + "nx_signal": {:hex, :nx_signal, "0.2.0", "e1ca0318877b17c81ce8906329f5125f1e2361e4c4235a5baac8a95ee88ea98e", [:mix], [{:nx, "~> 0.6", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "7247e5e18a177a59c4cb5355952900c62fdeadeb2bad02a9a34237b68744e2bb"}, + "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, + "pgvector": {:hex, :pgvector, "0.3.0", "c55c7c0f6224b06105fc3214965c6217e4cfe907d7524cd8c27ba7612b7f8582", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "aeb7c36c5851881fd1d8a39e213472fa0b07bd72cdb0acabc693055aa14693ab"}, "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"}, "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, @@ -38,12 +52,27 @@ "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "polaris": {:hex, :polaris, "0.1.0", "dca61b18e3e801ecdae6ac9f0eca5f19792b44a5cb4b8d63db50fc40fc038d22", [:mix], [{:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "13ef2b166650e533cb24b10e2f3b8ab4f2f449ba4d63156e8c569527f206e2c2"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, - "req": {:hex, :req, "0.5.6", "8fe1eead4a085510fe3d51ad854ca8f20a622aae46e97b302f499dfb84f726ac", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cfaa8e720945d46654853de39d368f40362c2641c4b2153c886418914b372185"}, + "progress_bar": {:hex, :progress_bar, "3.0.0", "f54ff038c2ac540cfbb4c2bfe97c75e7116ead044f3c2b10c9f212452194b5cd", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "6981c2b25ab24aecc91a2dc46623658e1399c21a2ae24db986b90d678530f2b7"}, + "rag": {:hex, :rag, "0.2.1", "5c507b065c52ea3a48c82b8c45fb864f635acc2109917aa6068a7f403d65c6b1", [:mix], [{:igniter, "~> 0.5.7", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nx, "~> 0.9.0", [hex: :nx, repo: "hexpm", optional: false]}, {:req, "~> 0.5.0", [hex: :req, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2e9870bd3f12b8234128048aeb5ced2b8c48975e33d3ef16b1ed679b53ab2468"}, + "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, + "req_hex": {:hex, :req_hex, "0.2.1", "f7566a61afde1f3f31977fdb230c2b9e801742da5de0b66a7b1e14febb304be7", [:mix], [{:hex_core, "~> 0.10.0", [hex: :hex_core, repo: "hexpm", optional: false]}, {:req, "~> 0.4.0 or ~> 0.5.0", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "f132012071714cfc277ff52ea5a80b793a4bebd79675d75820e02b425d897461"}, + "rewrite": {:hex, :rewrite, "1.1.2", "f5a5d10f5fed1491a6ff48e078d4585882695962ccc9e6c779bae025d1f92eda", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "7f8b94b1e3528d0a47b3e8b7bfeca559d2948a65fa7418a9ad7d7712703d39d4"}, + "rustler_precompiled": {:hex, :rustler_precompiled, "0.8.2", "5f25cbe220a8fac3e7ad62e6f950fcdca5a5a5f8501835d2823e8c74bf4268d5", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "63d1bd5f8e23096d1ff851839923162096364bac8656a4a3c00d1fff8e83ee0a"}, + "safetensors": {:hex, :safetensors, "0.1.3", "7ff3c22391e213289c713898481d492c9c28a49ab1d0705b72630fb8360426b2", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "fe50b53ea59fde4e723dd1a2e31cfdc6013e69343afac84c6be86d6d7c562c14"}, + "sourceror": {:hex, :sourceror, "1.7.1", "599d78f4cc2be7d55c9c4fd0a8d772fd0478e3a50e726697c20d13d02aa056d4", [:mix], [], "hexpm", "cd6f268fe29fa00afbc535e215158680a0662b357dc784646d7dff28ac65a0fc"}, + "spitfire": {:hex, :spitfire, "0.2.0", "0de1f519a23f65bde40d316adad53c07a9563f25cc68915d639d8a509a0aad8a", [:mix], [], "hexpm", "743daaee2d81a0d8095431729f478ce49b47ea8943c7d770de86704975cb7775"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"}, "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, + "text_chunker": {:hex, :text_chunker, "0.3.2", "bf587de84dcd405215095201ac9e2cff0d0a2c49d0fe1d8f16461944fdb124ae", [:mix], [{:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "84061ef0a861065ca3be66c5e3a8e0725cb0b31210f614b8b7eb135c9e6cb6b2"}, + "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, + "tokenizers": {:hex, :tokenizers, "0.5.1", "b0975d92b4ee5b18e8f47b5d65b9d5f1e583d9130189b1a2620401af4e7d4b35", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "5f08d97cc7f2ed3d71d370d68120da6d3de010948ccf676c9c0eb591ba4bacc9"}, + "unpickler": {:hex, :unpickler, "0.1.0", "c2262c0819e6985b761e7107546cef96a485f401816be5304a65fdd200d5bd6a", [:mix], [], "hexpm", "e2b3f61e62406187ac52afead8a63bfb4e49394028993f3c4c42712743cab79e"}, + "unzip": {:hex, :unzip, "0.12.0", "beed92238724732418b41eba77dcb7f51e235b707406c05b1732a3052d1c0f36", [:mix], [], "hexpm", "95655b72db368e5a84951f0bed586ac053b55ee3815fd96062fce10ce4fc998d"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.7", "65fa74042530064ef0570b75b43f5c49bb8b235d6515671b3d250022cb8a1f9e", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d0f478ee64deddfec64b800673fd6e0c8888b079d9f3444dd96d2a98383bdbd1"}, + "xla": {:hex, :xla, "0.8.0", "fef314d085dd3ee16a0816c095239938f80769150e15db16dfaa435553d7cb16", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "739c61c8d93b97e12ba0369d10e76130224c208f1a76ad293e3581f056833e57"}, } diff --git a/priv/repo/migrations/20250106193459_add_sources_to_messages.exs b/priv/repo/migrations/20250106193459_add_sources_to_messages.exs new file mode 100644 index 0000000..d7fddc4 --- /dev/null +++ b/priv/repo/migrations/20250106193459_add_sources_to_messages.exs @@ -0,0 +1,9 @@ +defmodule Chatbot.Repo.Migrations.AddSourcesToMessages do + use Ecto.Migration + + def change do + alter table(:messages) do + add(:sources, {:array, :string}) + end + end +end diff --git a/priv/repo/migrations/20250311215959_create_chunks_table.exs b/priv/repo/migrations/20250311215959_create_chunks_table.exs new file mode 100644 index 0000000..3c48071 --- /dev/null +++ b/priv/repo/migrations/20250311215959_create_chunks_table.exs @@ -0,0 +1,23 @@ +defmodule Chatbot.Repo.Migrations.CreateChunksTable do + use Ecto.Migration + + def up() do + execute("CREATE EXTENSION IF NOT EXISTS vector") + + flush() + + create table(:chunks) do + add(:document, :text) + add(:source, :text) + add(:chunk, :text) + add(:embedding, :vector, size: 768) + + timestamps() + end + end + + def down() do + drop(table(:chunks)) + execute("DROP EXTENSION vector") + end +end