Packages
langchain
0.6.0
0.9.2
0.9.1
0.9.0
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.4.0-rc.3
0.4.0-rc.2
0.4.0-rc.1
0.4.0-rc.0
0.3.3
0.3.2
0.3.1
0.3.0
0.3.0-rc.2
0.3.0-rc.1
0.3.0-rc.0
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Elixir implementation of a LangChain style framework that lets Elixir projects integrate with and leverage LLMs.
Current section
Files
Jump to
Current section
Files
lib/utils/bedrock_stream_decoder.ex
defmodule LangChain.Utils.BedrockStreamDecoder do
alias LangChain.Utils.AwsEventstreamDecoder
require Logger
def decode_stream({chunk, buffer}, chunks \\ []) do
combined_data = buffer <> chunk
case decode_chunk(combined_data) do
{:ok, chunk, remaining} ->
chunks = [chunk | chunks]
finish_or_decode_remaining(chunks, remaining)
{:incomplete_message, _} ->
finish(chunks, combined_data)
{:exception_response, response, remaining} ->
chunks = [response | chunks]
finish_or_decode_remaining(chunks, remaining)
{:error, error} ->
Logger.error("Failed to decode Bedrock chunk: #{inspect(error)}")
finish(chunks, combined_data)
end
end
defp finish_or_decode_remaining(chunks, remaining) when byte_size(remaining) > 0 do
decode_stream({"", remaining}, chunks)
end
defp finish_or_decode_remaining(chunks, remaining) do
finish(chunks, remaining)
end
defp finish(chunks, remaining) do
{Enum.reverse(chunks), remaining}
end
defp decode_chunk(chunk) do
with {:ok, decoded_message, remaining} <- AwsEventstreamDecoder.decode(chunk),
{:ok, response_json} <- decode_json(decoded_message),
{:ok, bytes} <- get_bytes(response_json, remaining),
{:ok, json} <- decode_base64(bytes),
{:ok, payload} <- decode_json(json) do
{:ok, payload, remaining}
end
end
defp decode_json(data) do
case Jason.decode(data) do
{:ok, json} ->
{:ok, json}
{:error, error} ->
{:error, "Unable to decode JSON: #{inspect(error)}"}
end
end
defp decode_base64(bytes) do
case Base.decode64(bytes) do
{:ok, bytes} ->
{:ok, bytes}
:error ->
{:error, "Unable to decode base64 \"bytes\" from Bedrock response"}
end
end
defp get_bytes(%{"bytes" => bytes}, _remaining) do
{:ok, bytes}
end
# bytes is likely missing from the response in exception cases
# https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModelWithResponseStream.html
defp get_bytes(response, remaining) do
Logger.debug("Bedrock response is an exception: #{inspect(response)}")
exception_message = Map.keys(response) |> Enum.join(", ")
# Make it easier to match on this pattern in process_data fns
response = Map.put(response, :bedrock_exception, exception_message)
{:exception_response, response, remaining}
end
end