@@ -2,9 +2,107 @@ defmodule MusicLibrary.ArtistChatTest do
|
|||||||
use ExUnit.Case
|
use ExUnit.Case
|
||||||
|
|
||||||
alias MusicLibrary.ArtistChat
|
alias MusicLibrary.ArtistChat
|
||||||
|
alias MusicLibrary.Artists.{Artist, ArtistInfo}
|
||||||
|
|
||||||
test "implements the Chat behaviour" do
|
defp build_artist(attrs \\ %{}) do
|
||||||
Code.ensure_loaded!(ArtistChat)
|
defaults = %{
|
||||||
assert function_exported?(ArtistChat, :stream_response, 3)
|
musicbrainz_id: Ecto.UUID.generate(),
|
||||||
|
name: "Radiohead",
|
||||||
|
sort_name: "Radiohead"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct!(Artist, Map.merge(defaults, attrs))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp build_artist_info(attrs \\ %{}) do
|
||||||
|
defaults = %{
|
||||||
|
musicbrainz_data: %{
|
||||||
|
"area" => %{
|
||||||
|
"name" => "United Kingdom",
|
||||||
|
"iso-3166-1-codes" => ["GB"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
wikipedia_data: %{
|
||||||
|
"description" => "English rock band",
|
||||||
|
"extract" =>
|
||||||
|
"Radiohead are an English rock band formed in Abingdon, Oxfordshire, in 1985."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct!(ArtistInfo, Map.merge(defaults, attrs))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sse_event(type, data) do
|
||||||
|
json = JSON.encode!(%{type: type, delta: data})
|
||||||
|
"event: #{type}\ndata: #{json}\n\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp completed_response do
|
||||||
|
sse_event("response.output_text.delta", "Hello") <>
|
||||||
|
"event: response.completed\ndata: {\"type\":\"response.completed\"}\n\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp stub_and_capture_instructions(test_pid) do
|
||||||
|
Req.Test.stub(OpenAI.API, fn conn ->
|
||||||
|
{:ok, body, conn} = Plug.Conn.read_body(conn)
|
||||||
|
request = JSON.decode!(body)
|
||||||
|
send(test_pid, {:captured_instructions, request["instructions"]})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_resp_content_type("text/event-stream")
|
||||||
|
|> Plug.Conn.send_resp(200, completed_response())
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "stream_response includes artist context with full info" do
|
||||||
|
stub_and_capture_instructions(self())
|
||||||
|
|
||||||
|
artist = build_artist()
|
||||||
|
artist_info = build_artist_info()
|
||||||
|
|
||||||
|
assert :ok = ArtistChat.stream_response([], {artist, artist_info}, fn _chunk -> :ok end)
|
||||||
|
|
||||||
|
assert_receive {:captured_instructions, instructions}
|
||||||
|
assert instructions =~ "Name: Radiohead"
|
||||||
|
assert instructions =~ "Country: United Kingdom"
|
||||||
|
assert instructions =~ "Description: English rock band"
|
||||||
|
assert instructions =~ "Biography: Radiohead are an English rock band formed in Abingdon"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "stream_response excludes nil wikipedia fields" do
|
||||||
|
stub_and_capture_instructions(self())
|
||||||
|
|
||||||
|
artist = build_artist()
|
||||||
|
artist_info = build_artist_info(%{wikipedia_data: %{}})
|
||||||
|
|
||||||
|
assert :ok = ArtistChat.stream_response([], {artist, artist_info}, fn _chunk -> :ok end)
|
||||||
|
|
||||||
|
assert_receive {:captured_instructions, instructions}
|
||||||
|
assert instructions =~ "Name: Radiohead"
|
||||||
|
assert instructions =~ "Country: United Kingdom"
|
||||||
|
refute instructions =~ "Description:"
|
||||||
|
refute instructions =~ "Biography:"
|
||||||
|
refute instructions =~ "nil"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "stream_response handles missing country gracefully" do
|
||||||
|
stub_and_capture_instructions(self())
|
||||||
|
|
||||||
|
artist = build_artist()
|
||||||
|
|
||||||
|
artist_info =
|
||||||
|
build_artist_info(%{
|
||||||
|
musicbrainz_data: %{
|
||||||
|
"area" => %{"name" => nil}
|
||||||
|
},
|
||||||
|
wikipedia_data: %{}
|
||||||
|
})
|
||||||
|
|
||||||
|
assert :ok = ArtistChat.stream_response([], {artist, artist_info}, fn _chunk -> :ok end)
|
||||||
|
|
||||||
|
assert_receive {:captured_instructions, instructions}
|
||||||
|
assert instructions =~ "Name: Radiohead"
|
||||||
|
# Falls back to "World" when area name is nil
|
||||||
|
refute instructions =~ "Country: \n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,10 +1,101 @@
|
|||||||
defmodule MusicLibrary.RecordChatTest do
|
defmodule MusicLibrary.RecordChatTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case
|
||||||
|
|
||||||
|
alias MusicLibrary.Artists.Artist
|
||||||
alias MusicLibrary.RecordChat
|
alias MusicLibrary.RecordChat
|
||||||
|
alias MusicLibrary.Records.Record
|
||||||
|
|
||||||
test "implements the Chat behaviour" do
|
defp build_record(attrs \\ %{}) do
|
||||||
Code.ensure_loaded!(RecordChat)
|
defaults = %{
|
||||||
assert function_exported?(RecordChat, :stream_response, 3)
|
title: "OK Computer",
|
||||||
|
type: :album,
|
||||||
|
format: :cd,
|
||||||
|
genres: ["alternative rock", "art rock"],
|
||||||
|
release_date: "1997-06-16",
|
||||||
|
artists: [
|
||||||
|
%Artist{
|
||||||
|
musicbrainz_id: Ecto.UUID.generate(),
|
||||||
|
name: "Radiohead",
|
||||||
|
sort_name: "Radiohead"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct!(Record, Map.merge(defaults, attrs))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sse_event(type, data) do
|
||||||
|
json = JSON.encode!(%{type: type, delta: data})
|
||||||
|
"event: #{type}\ndata: #{json}\n\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp completed_response do
|
||||||
|
sse_event("response.output_text.delta", "Hello") <>
|
||||||
|
"event: response.completed\ndata: {\"type\":\"response.completed\"}\n\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp stub_and_capture_instructions(test_pid) do
|
||||||
|
Req.Test.stub(OpenAI.API, fn conn ->
|
||||||
|
{:ok, body, conn} = Plug.Conn.read_body(conn)
|
||||||
|
request = JSON.decode!(body)
|
||||||
|
send(test_pid, {:captured_instructions, request["instructions"]})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_resp_content_type("text/event-stream")
|
||||||
|
|> Plug.Conn.send_resp(200, completed_response())
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "stream_response uses embedding text when present" do
|
||||||
|
stub_and_capture_instructions(self())
|
||||||
|
|
||||||
|
record = build_record()
|
||||||
|
embedding_text = "Radiohead - OK Computer (1997). Alternative rock masterpiece."
|
||||||
|
|
||||||
|
assert :ok = RecordChat.stream_response([], {record, embedding_text}, fn _chunk -> :ok end)
|
||||||
|
|
||||||
|
assert_receive {:captured_instructions, instructions}
|
||||||
|
assert instructions =~ embedding_text
|
||||||
|
refute instructions =~ "Album: OK Computer"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "stream_response falls back to basic context when embedding text is nil" do
|
||||||
|
stub_and_capture_instructions(self())
|
||||||
|
|
||||||
|
record = build_record()
|
||||||
|
|
||||||
|
assert :ok = RecordChat.stream_response([], {record, nil}, fn _chunk -> :ok end)
|
||||||
|
|
||||||
|
assert_receive {:captured_instructions, instructions}
|
||||||
|
assert instructions =~ "Album: OK Computer"
|
||||||
|
assert instructions =~ "Artists: Radiohead"
|
||||||
|
assert instructions =~ "Genres: alternative rock, art rock"
|
||||||
|
assert instructions =~ "Released: 1997-06-16"
|
||||||
|
assert instructions =~ "Type: album"
|
||||||
|
assert instructions =~ "Format: cd"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "stream_response falls back to basic context when embedding text is empty" do
|
||||||
|
stub_and_capture_instructions(self())
|
||||||
|
|
||||||
|
record = build_record()
|
||||||
|
|
||||||
|
assert :ok = RecordChat.stream_response([], {record, ""}, fn _chunk -> :ok end)
|
||||||
|
|
||||||
|
assert_receive {:captured_instructions, instructions}
|
||||||
|
assert instructions =~ "Album: OK Computer"
|
||||||
|
assert instructions =~ "Artists: Radiohead"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "stream_response handles missing optional fields gracefully" do
|
||||||
|
stub_and_capture_instructions(self())
|
||||||
|
|
||||||
|
record = build_record(%{genres: nil, release_date: nil})
|
||||||
|
|
||||||
|
assert :ok = RecordChat.stream_response([], {record, nil}, fn _chunk -> :ok end)
|
||||||
|
|
||||||
|
assert_receive {:captured_instructions, instructions}
|
||||||
|
assert instructions =~ "Genres: \n"
|
||||||
|
assert instructions =~ "Released: Unknown"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user