Packages
langchain
0.3.0-rc.2
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, _} ->
{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)}")
{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
{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