Spaces:
Sleeping
Sleeping
Adapt fixture and runner
Browse files- agents/claude.py +14 -5
- langsmith_evals/evaluators.py +51 -7
- langsmith_evals/runner.py +9 -5
- langsmith_evals/similarity_fixture.json +30 -28
agents/claude.py
CHANGED
|
@@ -8,6 +8,12 @@ from .base import Agent, AgentResult, ToolCall
|
|
| 8 |
|
| 9 |
_DEFAULT_MODEL = "claude-sonnet-4-6"
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
class ClaudeAgent(Agent):
|
| 13 |
"""Agent using the Anthropic SDK, connecting to tools via an MCP SSE server."""
|
|
@@ -32,6 +38,7 @@ class ClaudeAgent(Agent):
|
|
| 32 |
response = self._client.messages.create(
|
| 33 |
model=self.model,
|
| 34 |
max_tokens=4096,
|
|
|
|
| 35 |
tools=tools,
|
| 36 |
messages=messages,
|
| 37 |
)
|
|
@@ -45,21 +52,23 @@ class ClaudeAgent(Agent):
|
|
| 45 |
tool_results = []
|
| 46 |
for block in response.content:
|
| 47 |
if block.type == "tool_use":
|
| 48 |
-
|
| 49 |
-
result_text = "\n".join(
|
| 50 |
-
item.text for item in mcp_result.content if hasattr(item, "text")
|
| 51 |
-
)
|
| 52 |
tool_calls.append(ToolCall(name=block.name, args=dict(block.input), result=result_text))
|
| 53 |
tool_results.append({
|
| 54 |
"type": "tool_result",
|
| 55 |
"tool_use_id": block.id,
|
| 56 |
-
"content":
|
| 57 |
})
|
| 58 |
|
| 59 |
messages.append({"role": "assistant", "content": response.content})
|
| 60 |
messages.append({"role": "user", "content": tool_results})
|
| 61 |
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
def _to_anthropic(tool) -> dict:
|
| 64 |
return {
|
| 65 |
"name": tool.name,
|
|
|
|
| 8 |
|
| 9 |
_DEFAULT_MODEL = "claude-sonnet-4-6"
|
| 10 |
|
| 11 |
+
_SYSTEM = (
|
| 12 |
+
"You are a harmonic analysis assistant. After analysing a chord sequence, present only "
|
| 13 |
+
"well-known results — songs that are recognisable hits or by widely-known artists. "
|
| 14 |
+
"Use your knowledge to filter out obscure tracks. If no well-known matches exist, say so."
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
|
| 18 |
class ClaudeAgent(Agent):
|
| 19 |
"""Agent using the Anthropic SDK, connecting to tools via an MCP SSE server."""
|
|
|
|
| 38 |
response = self._client.messages.create(
|
| 39 |
model=self.model,
|
| 40 |
max_tokens=4096,
|
| 41 |
+
system=_SYSTEM,
|
| 42 |
tools=tools,
|
| 43 |
messages=messages,
|
| 44 |
)
|
|
|
|
| 52 |
tool_results = []
|
| 53 |
for block in response.content:
|
| 54 |
if block.type == "tool_use":
|
| 55 |
+
result_text = await self._invoke_tool(session, block.name, dict(block.input))
|
|
|
|
|
|
|
|
|
|
| 56 |
tool_calls.append(ToolCall(name=block.name, args=dict(block.input), result=result_text))
|
| 57 |
tool_results.append({
|
| 58 |
"type": "tool_result",
|
| 59 |
"tool_use_id": block.id,
|
| 60 |
+
"content": result_text,
|
| 61 |
})
|
| 62 |
|
| 63 |
messages.append({"role": "assistant", "content": response.content})
|
| 64 |
messages.append({"role": "user", "content": tool_results})
|
| 65 |
|
| 66 |
|
| 67 |
+
async def _invoke_tool(self, session: ClientSession, name: str, args: dict) -> str:
|
| 68 |
+
mcp_result = await session.call_tool(name, args)
|
| 69 |
+
return "\n".join(item.text for item in mcp_result.content if hasattr(item, "text"))
|
| 70 |
+
|
| 71 |
+
|
| 72 |
def _to_anthropic(tool) -> dict:
|
| 73 |
return {
|
| 74 |
"name": tool.name,
|
langsmith_evals/evaluators.py
CHANGED
|
@@ -22,11 +22,8 @@ def _count_tool_use_in_llm_runs(llm_runs: list[Run], tool_name: str) -> int:
|
|
| 22 |
return count
|
| 23 |
|
| 24 |
|
| 25 |
-
def
|
| 26 |
-
"""
|
| 27 |
-
|
| 28 |
-
Ideally the agent calls it exactly once before analysing chords.
|
| 29 |
-
A score of 0 means it was never called; higher values indicate redundant calls.
|
| 30 |
|
| 31 |
:param run: LangSmith run — LLM child runs are fetched via the client.
|
| 32 |
:param example: Dataset example (unused).
|
|
@@ -35,12 +32,59 @@ def evaluate_formats_tool_call_count(run: Run, example: Example) -> EvaluationRe
|
|
| 35 |
llm_runs = list(client.list_runs(trace_id=run.id, run_type="llm"))
|
| 36 |
count = _count_tool_use_in_llm_runs(llm_runs, _FORMATS_TOOL)
|
| 37 |
return EvaluationResult(
|
| 38 |
-
key="
|
| 39 |
-
score=count,
|
| 40 |
comment=f"{_FORMATS_TOOL} called {count} time(s)",
|
| 41 |
)
|
| 42 |
|
| 43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
def evaluate_result_count(run: Run, example: Example) -> EvaluationResult:
|
| 45 |
"""Check the number of returned songs does not exceed the requested limit.
|
| 46 |
|
|
|
|
| 22 |
return count
|
| 23 |
|
| 24 |
|
| 25 |
+
def evaluate_formats_tool_called_once(run: Run, example: Example) -> EvaluationResult:
|
| 26 |
+
"""Check that the supported-formats tool was called exactly once.
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
:param run: LangSmith run — LLM child runs are fetched via the client.
|
| 29 |
:param example: Dataset example (unused).
|
|
|
|
| 32 |
llm_runs = list(client.list_runs(trace_id=run.id, run_type="llm"))
|
| 33 |
count = _count_tool_use_in_llm_runs(llm_runs, _FORMATS_TOOL)
|
| 34 |
return EvaluationResult(
|
| 35 |
+
key="formats_tool_called_once",
|
| 36 |
+
score=int(count == 1),
|
| 37 |
comment=f"{_FORMATS_TOOL} called {count} time(s)",
|
| 38 |
)
|
| 39 |
|
| 40 |
|
| 41 |
+
def _title_in_text(title: str, text: str) -> bool:
|
| 42 |
+
return title.lower() in text.lower()
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def evaluate_notable_songs_recalled(run: Run, example: Example) -> EvaluationResult:
|
| 46 |
+
"""Fraction of expected notable songs that appear in the agent's response.
|
| 47 |
+
|
| 48 |
+
1.0 = all present (green), 0.0 = none present (red).
|
| 49 |
+
|
| 50 |
+
:param run: LangSmith run — expects ``outputs["response"]`` as a string.
|
| 51 |
+
:param example: Dataset example — expects ``outputs["expected_in_response"]`` as a list of titles.
|
| 52 |
+
"""
|
| 53 |
+
response = (run.outputs or {}).get("response", "")
|
| 54 |
+
expected = (example.outputs or {}).get("expected_in_response", [])
|
| 55 |
+
if not expected:
|
| 56 |
+
return EvaluationResult(key="notable_songs_recalled", score=None,
|
| 57 |
+
comment="no expected_in_response in example outputs")
|
| 58 |
+
found = [t for t in expected if _title_in_text(t, response)]
|
| 59 |
+
return EvaluationResult(
|
| 60 |
+
key="notable_songs_recalled",
|
| 61 |
+
score=len(found) / len(expected),
|
| 62 |
+
comment=f"{len(found)}/{len(expected)} notable songs present in response",
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def evaluate_non_notable_songs_excluded(run: Run, example: Example) -> EvaluationResult:
|
| 67 |
+
"""Fraction of expected-excluded songs that do NOT appear in the agent's response.
|
| 68 |
+
|
| 69 |
+
1.0 = none leaked (green), 0.0 = all leaked (red).
|
| 70 |
+
|
| 71 |
+
:param run: LangSmith run — expects ``outputs["response"]`` as a string.
|
| 72 |
+
:param example: Dataset example — expects ``outputs["expected_not_in_response"]`` as a list of titles.
|
| 73 |
+
"""
|
| 74 |
+
response = (run.outputs or {}).get("response", "")
|
| 75 |
+
excluded = (example.outputs or {}).get("expected_not_in_response", [])
|
| 76 |
+
if not excluded:
|
| 77 |
+
return EvaluationResult(key="non_notable_songs_excluded", score=None,
|
| 78 |
+
comment="no expected_not_in_response in example outputs")
|
| 79 |
+
leaked = [t for t in excluded if _title_in_text(t, response)]
|
| 80 |
+
return EvaluationResult(
|
| 81 |
+
key="non_notable_songs_excluded",
|
| 82 |
+
score=1 - len(leaked) / len(excluded),
|
| 83 |
+
comment=(f"{len(leaked)} excluded song(s) found: {leaked}" if leaked
|
| 84 |
+
else "no excluded songs in response"),
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
def evaluate_result_count(run: Run, example: Example) -> EvaluationResult:
|
| 89 |
"""Check the number of returned songs does not exceed the requested limit.
|
| 90 |
|
langsmith_evals/runner.py
CHANGED
|
@@ -4,19 +4,23 @@ from langsmith import Client
|
|
| 4 |
from langsmith import evaluate as ls_evaluate
|
| 5 |
|
| 6 |
from langsmith_evals.dataset import DATASET_NAME
|
| 7 |
-
from langsmith_evals.evaluators import
|
| 8 |
|
|
|
|
| 9 |
|
| 10 |
-
|
| 11 |
-
|
|
|
|
| 12 |
|
| 13 |
:param target: Callable ``(inputs: dict) -> dict`` to evaluate.
|
| 14 |
:param prefix: Experiment name prefix shown in the LangSmith UI.
|
|
|
|
|
|
|
| 15 |
"""
|
| 16 |
ls_evaluate(
|
| 17 |
target,
|
| 18 |
-
data=DATASET_NAME,
|
| 19 |
-
evaluators=
|
| 20 |
experiment_prefix=prefix,
|
| 21 |
client=Client(),
|
| 22 |
)
|
|
|
|
| 4 |
from langsmith import evaluate as ls_evaluate
|
| 5 |
|
| 6 |
from langsmith_evals.dataset import DATASET_NAME
|
| 7 |
+
from langsmith_evals.evaluators import evaluate_formats_tool_called_once, evaluate_result_count
|
| 8 |
|
| 9 |
+
_DEFAULT_EVALUATORS = [evaluate_result_count, evaluate_formats_tool_called_once]
|
| 10 |
|
| 11 |
+
|
| 12 |
+
def run(target, prefix: str, evaluators: list | None = None, dataset: str | None = None) -> None:
|
| 13 |
+
"""Run a LangSmith experiment against a dataset.
|
| 14 |
|
| 15 |
:param target: Callable ``(inputs: dict) -> dict`` to evaluate.
|
| 16 |
:param prefix: Experiment name prefix shown in the LangSmith UI.
|
| 17 |
+
:param evaluators: Evaluator functions. Defaults to result-count + formats-tool-called-once.
|
| 18 |
+
:param dataset: Dataset name. Defaults to the main chord-sequences dataset.
|
| 19 |
"""
|
| 20 |
ls_evaluate(
|
| 21 |
target,
|
| 22 |
+
data=dataset or DATASET_NAME,
|
| 23 |
+
evaluators=evaluators or _DEFAULT_EVALUATORS,
|
| 24 |
experiment_prefix=prefix,
|
| 25 |
client=Client(),
|
| 26 |
)
|
langsmith_evals/similarity_fixture.json
CHANGED
|
@@ -1,57 +1,59 @@
|
|
| 1 |
[
|
| 2 |
{"title": "Let It Be", "artist": "The Beatles", "similarity": 0.97},
|
| 3 |
-
{"title": "
|
| 4 |
-
{"title": "
|
| 5 |
{"title": "With or Without You", "artist": "U2", "similarity": 0.943},
|
|
|
|
| 6 |
{"title": "Stand By Me", "artist": "Ben E. King", "similarity": 0.934},
|
| 7 |
-
{"title": "
|
| 8 |
-
{"title": "
|
| 9 |
-
{"title": "Wonderful Tonight", "artist": "Eric Clapton", "similarity": 0.907},
|
| 10 |
-
{"title": "Brown Eyed Girl", "artist": "Van Morrison", "similarity": 0.898},
|
| 11 |
-
{"title": "Take Me Home Country Roads", "artist": "John Denver", "similarity": 0.889},
|
| 12 |
{"title": "Someone Like You", "artist": "Adele", "similarity": 0.880},
|
| 13 |
-
{"title": "
|
|
|
|
| 14 |
{"title": "Wagon Wheel", "artist": "Old Crow Medicine Show", "similarity": 0.862},
|
| 15 |
-
{"title": "I'm Yours", "artist": "Jason Mraz", "similarity": 0.853},
|
| 16 |
-
{"title": "Hey Soul Sister", "artist": "Train", "similarity": 0.844},
|
| 17 |
-
{"title": "Photograph", "artist": "Ed Sheeran", "similarity": 0.835},
|
| 18 |
-
{"title": "Perfect", "artist": "Ed Sheeran", "similarity": 0.826},
|
| 19 |
{"title": "Can't Help Falling in Love", "artist": "Elvis Presley", "similarity": 0.817},
|
|
|
|
| 20 |
{"title": "Hallelujah", "artist": "Leonard Cohen", "similarity": 0.808},
|
| 21 |
-
{"title": "Horse With No Name", "artist": "America", "similarity": 0.799},
|
| 22 |
-
{"title": "Wonderwall", "artist": "Oasis", "similarity": 0.790},
|
| 23 |
-
{"title": "Don't Look Back in Anger", "artist": "Oasis", "similarity": 0.781},
|
| 24 |
-
{"title": "21 Guns", "artist": "Green Day", "similarity": 0.772},
|
| 25 |
{"title": "Save Tonight", "artist": "Eagle-Eye Cherry", "similarity": 0.763},
|
|
|
|
| 26 |
{"title": "Mr Jones", "artist": "Counting Crows", "similarity": 0.754},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
{"title": "Good Riddance", "artist": "Green Day", "similarity": 0.745},
|
| 28 |
-
{"title": "
|
| 29 |
-
{"title": "Riptide", "artist": "Vance Joy", "similarity": 0.727},
|
| 30 |
-
{"title": "Ho Hey", "artist": "The Lumineers", "similarity": 0.718},
|
| 31 |
-
{"title": "Home", "artist": "Phillip Phillips", "similarity": 0.709},
|
| 32 |
-
{"title": "Little Talks", "artist": "Of Monsters and Men", "similarity": 0.700},
|
| 33 |
{"title": "Iris", "artist": "Goo Goo Dolls", "similarity": 0.691},
|
| 34 |
-
{"title": "
|
| 35 |
{"title": "Tears in Heaven", "artist": "Eric Clapton", "similarity": 0.673},
|
|
|
|
| 36 |
{"title": "The Scientist", "artist": "Coldplay", "similarity": 0.664},
|
|
|
|
| 37 |
{"title": "Yellow", "artist": "Coldplay", "similarity": 0.655},
|
|
|
|
| 38 |
{"title": "Fix You", "artist": "Coldplay", "similarity": 0.646},
|
|
|
|
| 39 |
{"title": "Thinking Out Loud", "artist": "Ed Sheeran", "similarity": 0.637},
|
|
|
|
| 40 |
{"title": "Love Yourself", "artist": "Justin Bieber", "similarity": 0.628},
|
| 41 |
-
{"title": "Despacito", "artist": "Luis Fonsi", "similarity": 0.619},
|
| 42 |
{"title": "Shape of You", "artist": "Ed Sheeran", "similarity": 0.610},
|
|
|
|
| 43 |
{"title": "Just the Way You Are", "artist": "Bruno Mars", "similarity": 0.601},
|
| 44 |
-
{"title": "The Lazy Song", "artist": "Bruno Mars", "similarity": 0.592},
|
| 45 |
{"title": "Grenade", "artist": "Bruno Mars", "similarity": 0.583},
|
| 46 |
{"title": "Viva la Vida", "artist": "Coldplay", "similarity": 0.574},
|
| 47 |
{"title": "Under the Bridge", "artist": "Red Hot Chili Peppers", "similarity": 0.565},
|
| 48 |
-
{"title": "What's Up", "artist": "4 Non Blondes", "similarity": 0.556},
|
| 49 |
{"title": "La Bamba", "artist": "Ritchie Valens", "similarity": 0.547},
|
| 50 |
{"title": "Shallow", "artist": "Lady Gaga and Bradley Cooper", "similarity": 0.538},
|
| 51 |
-
{"title": "Let Her Go", "artist": "Passenger", "similarity": 0.529},
|
| 52 |
{"title": "Fast Car", "artist": "Tracy Chapman", "similarity": 0.520},
|
| 53 |
{"title": "Blowin in the Wind", "artist": "Bob Dylan", "similarity": 0.511},
|
| 54 |
-
{"title": "Piano Man", "artist": "Billy Joel", "similarity": 0.502},
|
| 55 |
-
{"title": "Hotel California", "artist": "Eagles", "similarity": 0.493},
|
| 56 |
{"title": "Losing My Religion", "artist": "R.E.M.", "similarity": 0.484}
|
| 57 |
]
|
|
|
|
| 1 |
[
|
| 2 |
{"title": "Let It Be", "artist": "The Beatles", "similarity": 0.97},
|
| 3 |
+
{"title": "Machine Hit", "artist": "John Harald", "similarity": 0.718},
|
| 4 |
+
{"title": "Ho Hey", "artist": "The Lumineers", "similarity": 0.718},
|
| 5 |
{"title": "With or Without You", "artist": "U2", "similarity": 0.943},
|
| 6 |
+
{"title": "Spring Song", "artist": "Gryphon", "similarity": 0.709},
|
| 7 |
{"title": "Stand By Me", "artist": "Ben E. King", "similarity": 0.934},
|
| 8 |
+
{"title": "Walter Murphy and the Big Apple Band", "artist": "A Fifth of Beethoven", "similarity": 0.934},
|
| 9 |
+
{"title": "My Life", "artist": "Oliver Holloway", "similarity": 0.736},
|
|
|
|
|
|
|
|
|
|
| 10 |
{"title": "Someone Like You", "artist": "Adele", "similarity": 0.880},
|
| 11 |
+
{"title": "Little Talks", "artist": "Of Monsters and Men", "similarity": 0.700},
|
| 12 |
+
{"title": "Wonderwall", "artist": "Oasis", "similarity": 0.790},
|
| 13 |
{"title": "Wagon Wheel", "artist": "Old Crow Medicine Show", "similarity": 0.862},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
{"title": "Can't Help Falling in Love", "artist": "Elvis Presley", "similarity": 0.817},
|
| 15 |
+
{"title": "Riptide", "artist": "Vance Joy", "similarity": 0.727},
|
| 16 |
{"title": "Hallelujah", "artist": "Leonard Cohen", "similarity": 0.808},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
{"title": "Save Tonight", "artist": "Eagle-Eye Cherry", "similarity": 0.763},
|
| 18 |
+
{"title": "No Woman No Cry", "artist": "Bob Marley", "similarity": 0.961},
|
| 19 |
{"title": "Mr Jones", "artist": "Counting Crows", "similarity": 0.754},
|
| 20 |
+
{"title": "Piano Man", "artist": "Billy Joel", "similarity": 0.502},
|
| 21 |
+
{"title": "Hey Soul Sister", "artist": "Train", "similarity": 0.844},
|
| 22 |
+
{"title": "Hotel California", "artist": "Eagles", "similarity": 0.493},
|
| 23 |
+
{"title": "Horse With No Name", "artist": "America", "similarity": 0.799},
|
| 24 |
+
{"title": "Africa", "artist": "Toto", "similarity": 0.952},
|
| 25 |
+
{"title": "More Than Words", "artist": "Extreme", "similarity": 0.682},
|
| 26 |
+
{"title": "Zombie", "artist": "The Cranberries", "similarity": 0.925},
|
| 27 |
+
{"title": "Let Her Go", "artist": "Passenger", "similarity": 0.529},
|
| 28 |
+
{"title": "Knockin on Heavens Door", "artist": "Bob Dylan", "similarity": 0.916},
|
| 29 |
+
{"title": "What's Up", "artist": "4 Non Blondes", "similarity": 0.556},
|
| 30 |
+
{"title": "Wonderful Tonight", "artist": "Eric Clapton", "similarity": 0.907},
|
| 31 |
+
{"title": "The Lazy Song", "artist": "Bruno Mars", "similarity": 0.592},
|
| 32 |
+
{"title": "Brown Eyed Girl", "artist": "Van Morrison", "similarity": 0.898},
|
| 33 |
{"title": "Good Riddance", "artist": "Green Day", "similarity": 0.745},
|
| 34 |
+
{"title": "Take Me Home Country Roads", "artist": "John Denver", "similarity": 0.889},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
{"title": "Iris", "artist": "Goo Goo Dolls", "similarity": 0.691},
|
| 36 |
+
{"title": "Counting Stars", "artist": "OneRepublic", "similarity": 0.871},
|
| 37 |
{"title": "Tears in Heaven", "artist": "Eric Clapton", "similarity": 0.673},
|
| 38 |
+
{"title": "I'm Yours", "artist": "Jason Mraz", "similarity": 0.853},
|
| 39 |
{"title": "The Scientist", "artist": "Coldplay", "similarity": 0.664},
|
| 40 |
+
{"title": "Photograph", "artist": "Ed Sheeran", "similarity": 0.835},
|
| 41 |
{"title": "Yellow", "artist": "Coldplay", "similarity": 0.655},
|
| 42 |
+
{"title": "Perfect", "artist": "Ed Sheeran", "similarity": 0.826},
|
| 43 |
{"title": "Fix You", "artist": "Coldplay", "similarity": 0.646},
|
| 44 |
+
{"title": "Don't Look Back in Anger", "artist": "Oasis", "similarity": 0.781},
|
| 45 |
{"title": "Thinking Out Loud", "artist": "Ed Sheeran", "similarity": 0.637},
|
| 46 |
+
{"title": "21 Guns", "artist": "Green Day", "similarity": 0.772},
|
| 47 |
{"title": "Love Yourself", "artist": "Justin Bieber", "similarity": 0.628},
|
|
|
|
| 48 |
{"title": "Shape of You", "artist": "Ed Sheeran", "similarity": 0.610},
|
| 49 |
+
{"title": "Despacito", "artist": "Luis Fonsi", "similarity": 0.619},
|
| 50 |
{"title": "Just the Way You Are", "artist": "Bruno Mars", "similarity": 0.601},
|
|
|
|
| 51 |
{"title": "Grenade", "artist": "Bruno Mars", "similarity": 0.583},
|
| 52 |
{"title": "Viva la Vida", "artist": "Coldplay", "similarity": 0.574},
|
| 53 |
{"title": "Under the Bridge", "artist": "Red Hot Chili Peppers", "similarity": 0.565},
|
|
|
|
| 54 |
{"title": "La Bamba", "artist": "Ritchie Valens", "similarity": 0.547},
|
| 55 |
{"title": "Shallow", "artist": "Lady Gaga and Bradley Cooper", "similarity": 0.538},
|
|
|
|
| 56 |
{"title": "Fast Car", "artist": "Tracy Chapman", "similarity": 0.520},
|
| 57 |
{"title": "Blowin in the Wind", "artist": "Bob Dylan", "similarity": 0.511},
|
|
|
|
|
|
|
| 58 |
{"title": "Losing My Religion", "artist": "R.E.M.", "similarity": 0.484}
|
| 59 |
]
|