Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ on:

jobs:
test:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
env:
MIX_ENV: test
strategy:
fail-fast: false
matrix:
include:
- pair:
elixir: "1.16"
elixir: "1.17"
otp: "26.2"
lint: lint
steps:
Expand Down
4 changes: 3 additions & 1 deletion lib/instructor/adapters/anthropic.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ defmodule Instructor.Adapters.Anthropic do
reask_messages_for_mode(params[:mode], raw_response)
end

defp reask_messages_for_mode(:tools, %{"content" => [%{"input" => args, "type" => "tool_use", "id" => id, "name" => name}]}) do
defp reask_messages_for_mode(:tools, %{
"content" => [%{"input" => args, "type" => "tool_use", "id" => id, "name" => name}]
}) do
[
%{
role: "assistant",
Expand Down
24 changes: 17 additions & 7 deletions lib/instructor/json_schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,11 @@ defmodule Instructor.JSONSchema do
defp for_type(:decimal), do: %{type: "number", format: "float"}

defp for_type(:date),
do: %{type: "string", description: "ISO8601 Date, [yyyy]-[mm]-[dd], e.g. \"2024-07-20\"", format: "date"}
do: %{
type: "string",
description: "ISO8601 Date, [yyyy]-[mm]-[dd], e.g. \"2024-07-20\"",
format: "date"
}

defp for_type(:time),
do: %{
Expand All @@ -302,35 +306,40 @@ defmodule Instructor.JSONSchema do
defp for_type(:time_usec),
do: %{
type: "string",
description: "ISO8601 Time with microseconds, [hh]:[mm]:[ss].[microseconds], e.g. \"12:00:00.000000\"",
description:
"ISO8601 Time with microseconds, [hh]:[mm]:[ss].[microseconds], e.g. \"12:00:00.000000\"",
pattern: "^[0-9]{2}:?[0-9]{2}:?[0-9]{2}.[0-9]{6}$"
}

defp for_type(:naive_datetime),
do: %{
type: "string",
description: "ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss], e.g. \"2024-07-20T12:00:00\"",
description:
"ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss], e.g. \"2024-07-20T12:00:00\"",
format: "date-time"
}

defp for_type(:naive_datetime_usec),
do: %{
type: "string",
description: "ISO8601 DateTime with microseconds, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss].[microseconds], e.g. \"2024-07-20T12:00:00.000000\"",
description:
"ISO8601 DateTime with microseconds, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss].[microseconds], e.g. \"2024-07-20T12:00:00.000000\"",
format: "date-time"
}

defp for_type(:utc_datetime),
do: %{
type: "string",
description: "ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss]Z, e.g. \"2024-07-20T12:00:00Z\"",
description:
"ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss]Z, e.g. \"2024-07-20T12:00:00Z\"",
format: "date-time"
}

defp for_type(:utc_datetime_usec),
do: %{
type: "string",
description: "ISO8601 DateTime with microseconds, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss].[microseconds]Z, e.g. \"2024-07-20T12:00:00.000000Z\"",
description:
"ISO8601 DateTime with microseconds, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss].[microseconds]Z, e.g. \"2024-07-20T12:00:00.000000Z\"",
format: "date-time"
}

Expand Down Expand Up @@ -451,7 +460,8 @@ defmodule Instructor.JSONSchema do
|> maybe_call_with_path(fun, path, opts)
end

defp do_traverse_and_update(tree, fun, path, opts), do: maybe_call_with_path(tree, fun, path, opts)
defp do_traverse_and_update(tree, fun, path, opts),
do: maybe_call_with_path(tree, fun, path, opts)

defp maybe_call_with_path(value, fun, path, opts) do
if Keyword.get(opts, :include_path, false) do
Expand Down
3 changes: 2 additions & 1 deletion lib/instructor/types/duration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ defmodule Instructor.Types.Duration do
type: "string",
description: "A valid ISO8601 duration, e.g. PT3M14S",
format: "duration",
pattern: "^P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+(?:\\.\\d+)?)S)?)?$"
pattern:
"^P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+(?:\\.\\d+)?)S)?)?$"
}
end

Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule Instructor.MixProject do
[
app: :instructor,
version: @version,
elixir: "~> 1.15",
elixir: "~> 1.17",
start_permanent: Mix.env() == :prod,
deps: deps(),
elixirc_paths: elixirc_paths(Mix.env()),
Expand Down
5 changes: 4 additions & 1 deletion pages/cookbook/o1_cot_ui.exs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ defmodule DemoLive do
pid = self()

selected_model = socket.assigns.selected_model

response_model =
socket.assigns.output_schema
|> Enum.map(fn {key, type} -> {String.to_atom(key), type} end)
Expand Down Expand Up @@ -161,7 +162,9 @@ defmodule DemoLive do
<div class="flex justify-start items-center bg-gradient-to-r from-red-400/30 via-purple-400/20 via-20% to-white rounded-lg p-2 pl-4 pr-16 border border-gray-300 animate-gradient">
<span class="text-3xl font-bold text-white">🍓</span>
<img src="https://hexdocs.pm/elixir/assets/logo.png" alt="Elixir" class="h-8 ml-1" />
<span class="ml-6 text-lg font-medium text-gray-700">Structured Outputs <span class="text-gray-400">w/</span> Reasoning</span>
<span class="ml-6 text-lg font-medium text-gray-700">
Structured Outputs <span class="text-gray-400">w/</span> Reasoning
</span>
</div>
</div>
<style>
Expand Down
33 changes: 25 additions & 8 deletions pages/cookbook/streaming_ui.exs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,12 @@ defmodule StreamingUILive do

def render(assigns) do
~H"""
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" />
<script src="https://cdn.tailwindcss.com">
</script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
/>
<div class="flex h-screen">
<div class="w-1/3 pr-8 flex flex-col justify-center items-center px-8 py-16 border-r border-zinc-200">
<h1 class="text-3xl font-bold mb-6">✨ AI Recipe Generator</h1>
Expand All @@ -161,19 +165,28 @@ defmodule StreamingUILive do
</div>

<div class="w-2/3 pl-8 flex flex-col justify-center overflow-y-auto bg-zinc-100 px-8 py-16">
<.recipe {assigns}/>
<.recipe {assigns} />
</div>
</div>
"""
end

defp recipe(assigns) do
~H"""
<div :if={@recipe.result != nil} class="bg-white shadow-lg rounded-lg overflow-hidden max-w-3xl mx-auto">
<div
:if={@recipe.result != nil}
class="bg-white shadow-lg rounded-lg overflow-hidden max-w-3xl mx-auto"
>
<div class="relative">
<div class="absolute inset-0 bg-gradient-to-b from-transparent to-black opacity-70"></div>
<img src={image_for_recipe(@recipe.result)} alt={@recipe.result.name} class="w-full h-64 object-cover" />
<h2 class="absolute bottom-4 left-4 text-3xl font-bold text-white"><%= @recipe.result.name %></h2>
<img
src={image_for_recipe(@recipe.result)}
alt={@recipe.result.name}
class="w-full h-64 object-cover"
/>
<h2 class="absolute bottom-4 left-4 text-3xl font-bold text-white">
<%= @recipe.result.name %>
</h2>
</div>

<div class="p-6">
Expand All @@ -196,7 +209,9 @@ defmodule StreamingUILive do
<%= to_string(ingredient.quantity) %>
<% end %>
</span>
<span class="text-gray-700 flex-grow"><%= ingredient.unit %> <%= ingredient.name %></span>
<span class="text-gray-700 flex-grow">
<%= ingredient.unit %> <%= ingredient.name %>
</span>
</div>
<% end %>
</div>
Expand All @@ -207,7 +222,9 @@ defmodule StreamingUILive do
<ol class="space-y-4">
<%= for {step, index} <- Enum.with_index(@recipe.result.instructions) do %>
<li class="flex">
<span class="bg-gray-300 text-gray-700 rounded-full w-8 h-8 flex items-center justify-center mr-4 flex-shrink-0"><%= index + 1 %></span>
<span class="bg-gray-300 text-gray-700 rounded-full w-8 h-8 flex items-center justify-center mr-4 flex-shrink-0">
<%= index + 1 %>
</span>
<p class="text-gray-700"><%= step.step %></p>
</li>
<% end %>
Expand Down
3 changes: 0 additions & 3 deletions test/instructor_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@ defmodule InstructorTest do
field(:number, :integer)
end


def validate_changeset(changeset) do
changeset
|> Ecto.Changeset.validate_change(:number, fn :number, number ->
Expand All @@ -386,7 +385,6 @@ defmodule InstructorTest do
test "reask" do
mock_response(unquote(adapter), :tools, %{number: 11})


result =
Instructor.chat_completion(
Keyword.merge(unquote(params),
Expand All @@ -400,7 +398,6 @@ defmodule InstructorTest do

assert {:ok, %{number: number}} = result
assert number >= 10

end
end
end
Expand Down
9 changes: 6 additions & 3 deletions test/json_schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ defmodule JSONSchemaTest do
"format" => "date-time",
"title" => "naive_datetime",
"type" => "string",
"description" => "ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss], e.g. \"2024-07-20T12:00:00\""
"description" =>
"ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss], e.g. \"2024-07-20T12:00:00\""
},
"naive_datetime_usec" => %{
"format" => "date-time",
Expand All @@ -251,13 +252,15 @@ defmodule JSONSchemaTest do
"pattern" => "^[0-9]{2}:?[0-9]{2}:?[0-9]{2}.[0-9]{6}$",
"title" => "time_usec",
"type" => "string",
"description" => "ISO8601 Time with microseconds, [hh]:[mm]:[ss].[microseconds], e.g. \"12:00:00.000000\""
"description" =>
"ISO8601 Time with microseconds, [hh]:[mm]:[ss].[microseconds], e.g. \"12:00:00.000000\""
},
"utc_datetime" => %{
"format" => "date-time",
"title" => "utc_datetime",
"type" => "string",
"description" => "ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss]Z, e.g. \"2024-07-20T12:00:00Z\""
"description" =>
"ISO8601 DateTime, [yyyy]-[mm]-[dd]T[hh]:[mm]:[ss]Z, e.g. \"2024-07-20T12:00:00Z\""
},
"utc_datetime_usec" => %{
"format" => "date-time",
Expand Down