✨(langfuse) allow user to score messages from LLM (#61)
* ✨(langfuse) allow user to score messages from LLM We store the trace ID in the message ID... this is not very clean but it is the easiest way to consistently save the trace ID. This adds the endpoint for the "thumb up"/"thumb down" calls. * 💄(frontend) add the thumb up/down to score LLM messages This enables the score button when a trace exists (ie the user allows analytics and Langfuse is setup). * ✨(langfuse) allow user to score messages from LLM allow user to score messages from LLM --------- Co-authored-by: Eléonore Voisin <[email protected]> Co-authored-by: elvoisin <[email protected]>
This commit is contained in:
co-authored by
Eléonore Voisin
elvoisin
parent
5ed92c286e
commit
ba62bd82d5
@@ -51,6 +51,7 @@ and this project adheres to
|
||||
- ✨(web-search) add Brave search tool #47
|
||||
- ✨(models) add mistral support & customization #51
|
||||
- 🐛(web-search) add summarization to Brave results #58
|
||||
- ✨(langfuse) allow user to score messages from LLM #6
|
||||
|
||||
|
||||
[unreleased]: https://github.com/numerique-gouv/conversations/compare/HEAD...main
|
||||
|
||||
@@ -386,6 +386,7 @@ class AIAgentService: # pylint: disable=too-many-instance-attributes
|
||||
)
|
||||
|
||||
_tool_is_streaming = False
|
||||
_model_response_message_id = None
|
||||
async with AsyncExitStack() as stack:
|
||||
# MCP servers (if any) can be initialized here
|
||||
mcp_servers = [await stack.enter_async_context(mcp) for mcp in get_mcp_servers()]
|
||||
@@ -553,6 +554,23 @@ class AIAgentService: # pylint: disable=too-many-instance-attributes
|
||||
elif Agent.is_end_node(node):
|
||||
# Once an End node is reached, the agent run is complete
|
||||
logger.debug("v: %s", dataclasses.asdict(node))
|
||||
|
||||
# Enforce the message ID to store the trace ID and allow scoring later
|
||||
# We use the start step part (to set the message ID) even if it's
|
||||
# not the purpose of this event, but Vercel AI SDK does not
|
||||
# have a better place to set the message ID and we only want to enforce
|
||||
# The last message to store the trace ID...
|
||||
if _model_response_message_id:
|
||||
logger.error("_model_response_message_id already set")
|
||||
_model_response_message_id = (
|
||||
str(uuid.uuid4())
|
||||
if not self._store_analytics
|
||||
else f"trace-{langfuse.get_current_trace_id()}"
|
||||
)
|
||||
yield events_v4.StartStepPart(
|
||||
message_id=_model_response_message_id,
|
||||
)
|
||||
|
||||
if (
|
||||
isinstance(node.data, FinalResult)
|
||||
and node.data.tool_name == "summarize"
|
||||
@@ -610,6 +628,7 @@ class AIAgentService: # pylint: disable=too-many-instance-attributes
|
||||
usage=usage,
|
||||
final_output_from_tool=_final_output_from_tool,
|
||||
ui_sources=_ui_sources,
|
||||
model_response_message_id=_model_response_message_id,
|
||||
)
|
||||
|
||||
if self._store_analytics:
|
||||
@@ -624,7 +643,7 @@ class AIAgentService: # pylint: disable=too-many-instance-attributes
|
||||
),
|
||||
)
|
||||
|
||||
def _update_conversation(
|
||||
def _update_conversation( # noqa: PLR0913
|
||||
self,
|
||||
*,
|
||||
final_output: List[ModelRequest | ModelMessage],
|
||||
@@ -632,6 +651,7 @@ class AIAgentService: # pylint: disable=too-many-instance-attributes
|
||||
usage: Dict[str, int],
|
||||
final_output_from_tool: str | None,
|
||||
ui_sources: List[SourceUIPart] = None,
|
||||
model_response_message_id: str | None = None,
|
||||
): # pylint: disable=too-many-arguments
|
||||
"""
|
||||
Save everything related to the conversation.
|
||||
@@ -663,6 +683,10 @@ class AIAgentService: # pylint: disable=too-many-instance-attributes
|
||||
_output_ui_message = model_message_to_ui_message(_merged_final_output_message)
|
||||
if ui_sources:
|
||||
_output_ui_message.parts += ui_sources
|
||||
if model_response_message_id:
|
||||
_output_ui_message.id = model_response_message_id
|
||||
else:
|
||||
logger.warning("model_response_message_id is None")
|
||||
|
||||
self.conversation.messages += [
|
||||
model_message_to_ui_message(_merged_final_output_request),
|
||||
|
||||
@@ -127,6 +127,17 @@ class LLModelSerializer(serializers.Serializer): # pylint: disable=abstract-met
|
||||
return obj.hrid == settings.LLM_DEFAULT_MODEL_HRID
|
||||
|
||||
|
||||
class ChatMessageCategoricalScoreSerializer(serializers.Serializer): # pylint: disable=abstract-method
|
||||
"""Serializer for chat message scores."""
|
||||
|
||||
message_id = serializers.CharField(help_text="ID of the message to score.")
|
||||
name = serializers.HiddenField(default="sentiment")
|
||||
value = serializers.ChoiceField(
|
||||
choices=["positive", "negative"],
|
||||
help_text="Sentiment of the score.",
|
||||
)
|
||||
|
||||
|
||||
class LLMConfigurationSerializer(serializers.Serializer): # pylint: disable=abstract-method
|
||||
"""Serializer for LLM configuration."""
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ def test_post_conversation_data_protocol(api_client, mock_openai_stream, mock_uu
|
||||
assert response_content == (
|
||||
'0:"Hello"\n'
|
||||
'0:" there"\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -383,6 +384,7 @@ def test_post_conversation_with_image(api_client, mock_openai_stream_image, mock
|
||||
assert response_content == (
|
||||
'0:"I see a cat"\n'
|
||||
'0:" in the picture."\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -586,6 +588,7 @@ def test_post_conversation_tool_call(api_client, mock_openai_stream_tool, mock_u
|
||||
'a:{"toolCallId":"xLDcIljdsDrz0idal7tATWSMm2jhMj47","result":{"location":'
|
||||
'"Paris","temperature":22,"unit":"celsius"}}\n'
|
||||
'0:"The current weather in Paris is nice"\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -793,6 +796,7 @@ def test_post_conversation_tool_call_fails(
|
||||
'a:{"toolCallId":"xLDcIljdsDrz0idal7tATWSMm2jhMj47","result":"Unknown tool '
|
||||
"name: 'get_current_weather'. No tools available.\"}\n"
|
||||
'0:"I cannot give you an answer to that."\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -984,7 +988,12 @@ def test_post_conversation_model_selection_invalid(api_client):
|
||||
|
||||
@freeze_time("2025-07-25T10:36:35.297675Z")
|
||||
@respx.mock
|
||||
def test_post_conversation_model_selection_new(api_client, mock_openai_stream, settings):
|
||||
def test_post_conversation_model_selection_new(
|
||||
api_client,
|
||||
mock_openai_stream,
|
||||
mock_uuid4,
|
||||
settings,
|
||||
):
|
||||
"""Test the user can select a different model."""
|
||||
settings.LLM_CONFIGURATIONS = {
|
||||
"plop": LLModel(
|
||||
@@ -1030,6 +1039,7 @@ def test_post_conversation_model_selection_new(api_client, mock_openai_stream, s
|
||||
assert response_content == (
|
||||
'0:"Hello"\n'
|
||||
'0:" there"\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -1114,11 +1124,13 @@ def test_post_conversation_data_protocol_no_stream(
|
||||
'0:" sca"\n'
|
||||
'0:"tter"\n'
|
||||
'0:"ing."\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":135}}\n'
|
||||
)
|
||||
else:
|
||||
assert response_content == (
|
||||
'0:"The sky appears blue due to a phenomenon called Rayleigh scattering."\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":135}}\n'
|
||||
)
|
||||
|
||||
|
||||
+5
-1
@@ -285,6 +285,7 @@ def test_post_conversation_with_document_upload( # pylint: disable=too-many-arg
|
||||
'a:{"toolCallId":"pyd_ai_YYY","result":[{"url":"sample.pdf","content":"This '
|
||||
'is the content of the PDF.","score":0.9}]}\n'
|
||||
"0:\"From the document, I can see that it says 'Hello PDF'.\"\n"
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":100,"completionTokens":20}}\n'
|
||||
).replace("XXX", str_mock_uuid4).replace("pyd_ai_YYY", toolcall_id)
|
||||
|
||||
@@ -467,12 +468,13 @@ def test_post_conversation_with_document_upload( # pylint: disable=too-many-arg
|
||||
@responses.activate
|
||||
@respx.mock
|
||||
@freeze_time("2025-07-25T10:36:35.297675Z")
|
||||
def test_post_conversation_with_document_upload_feature_disabled( # pylint: disable=too-many-arguments,too-many-positional-arguments
|
||||
def test_post_conversation_with_document_upload_feature_disabled( # noqa: PLR0913 # pylint: disable=too-many-arguments,too-many-positional-arguments
|
||||
api_client,
|
||||
caplog,
|
||||
mock_openai_stream, # pylint: disable=unused-argument
|
||||
sample_pdf_content,
|
||||
feature_flags,
|
||||
mock_uuid4,
|
||||
):
|
||||
"""
|
||||
Test POST to /api/v1/chats/{pk}/conversation/ with a PDF document while feature is disabled.
|
||||
@@ -520,6 +522,7 @@ def test_post_conversation_with_document_upload_feature_disabled( # pylint: dis
|
||||
assert response_content == (
|
||||
'0:"From the document, I can see that "\n'
|
||||
"0:\"it says 'Hello PDF'.\"\n"
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":150,"completionTokens":25}}\n'
|
||||
)
|
||||
|
||||
@@ -597,6 +600,7 @@ def test_post_conversation_with_document_upload_summarize( # pylint: disable=to
|
||||
'"args":{"documents":[{"identifier":"sample.pdf"}]}}\n'
|
||||
'a:{"toolCallId":"XXX","result":{"state":"done"}}\n'
|
||||
'b:{"toolCallId":"pyd_ai_YYY","toolName":"summarize"}\n'
|
||||
'f:{"messageId":"XXX"}\n'
|
||||
'a:{"toolCallId":"pyd_ai_YYY","result":{"state":"done"}}\n'
|
||||
'0:"The document discusses various topics."\n'
|
||||
'h:{"sourceType":"url","id":"XXX","url":"sample.pdf","title":null,"providerMetadata":{}}\n'
|
||||
|
||||
@@ -234,6 +234,7 @@ def test_post_conversation_data_protocol_with_history(
|
||||
assert response_content == (
|
||||
'0:"Hello"\n'
|
||||
'0:" there"\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -410,6 +411,7 @@ def test_post_conversation_with_image_with_history(
|
||||
assert response_content == (
|
||||
'0:"I see a cat"\n'
|
||||
'0:" in the picture."\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -532,6 +534,7 @@ def test_post_conversation_tool_call_with_history(
|
||||
'a:{"toolCallId":"xLDcIljdsDrz0idal7tATWSMm2jhMj47","result":{"location":'
|
||||
'"Paris","temperature":22,"unit":"celsius"}}\n'
|
||||
'0:"The current weather in Paris is nice"\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -648,6 +651,7 @@ def test_post_conversation_tool_call_fails_with_history(
|
||||
'a:{"toolCallId":"xLDcIljdsDrz0idal7tATWSMm2jhMj47","result":"Unknown tool '
|
||||
"name: 'get_current_weather'. No tools available.\"}\n"
|
||||
'0:"I cannot give you an answer to that."\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -1183,6 +1187,7 @@ def test_post_conversation_with_existing_image_history(
|
||||
assert response_content == (
|
||||
'0:"Hello"\n'
|
||||
'0:" there"\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -1280,6 +1285,7 @@ def test_post_conversation_with_existing_tool_history(
|
||||
'a:{"toolCallId":"xLDcIljdsDrz0idal7tATWSMm2jhMj47","result":{"location":'
|
||||
'"Paris","temperature":22,"unit":"celsius"}}\n'
|
||||
'0:"The current weather in Paris is nice"\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
@@ -1462,6 +1468,7 @@ def test_post_conversation_add_image_to_conversation_with_tool_history(
|
||||
assert response_content == (
|
||||
'0:"I see a cat"\n'
|
||||
'0:" in the picture."\n'
|
||||
f'f:{{"messageId":"{mock_uuid4}"}}\n'
|
||||
'd:{"finishReason":"stop","usage":{"promptTokens":0,"completionTokens":0}}\n'
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
"""Test the post_score_message view."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from rest_framework import status
|
||||
|
||||
from core.factories import UserFactory
|
||||
|
||||
from chat import factories
|
||||
|
||||
pytestmark = pytest.mark.django_db()
|
||||
|
||||
|
||||
def test_score_message_with_positive_sentiment(api_client):
|
||||
"""Test scoring a message with positive sentiment."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
api_client.force_login(chat_conversation.owner)
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
trace_id = "test-trace-123"
|
||||
message_id = f"trace-{trace_id}"
|
||||
|
||||
with patch("langfuse.get_client") as mock_get_client:
|
||||
mock_client = MagicMock()
|
||||
mock_get_client.return_value = mock_client
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": message_id,
|
||||
"value": "positive",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
mock_client.create_score.assert_called_once_with(
|
||||
name="sentiment",
|
||||
value="positive",
|
||||
trace_id=trace_id,
|
||||
score_id=f"{trace_id}-{chat_conversation.owner.pk}",
|
||||
data_type="CATEGORICAL",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == {"status": "OK"}
|
||||
|
||||
|
||||
def test_score_message_with_negative_sentiment(api_client):
|
||||
"""Test scoring a message with negative sentiment."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
api_client.force_login(chat_conversation.owner)
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
trace_id = "test-trace-456"
|
||||
message_id = f"trace-{trace_id}"
|
||||
|
||||
with patch("langfuse.get_client") as mock_get_client:
|
||||
mock_client = MagicMock()
|
||||
mock_get_client.return_value = mock_client
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": message_id,
|
||||
"value": "negative",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
mock_client.create_score.assert_called_once_with(
|
||||
name="sentiment",
|
||||
value="negative",
|
||||
trace_id=trace_id,
|
||||
score_id=f"{trace_id}-{chat_conversation.owner.pk}",
|
||||
data_type="CATEGORICAL",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == {"status": "OK"}
|
||||
|
||||
|
||||
def test_score_message_without_trace_prefix(api_client):
|
||||
"""Test that scoring fails when message_id doesn't have trace prefix."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
api_client.force_login(chat_conversation.owner)
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
with patch("langfuse.get_client") as mock_get_client:
|
||||
mock_client = MagicMock()
|
||||
mock_get_client.return_value = mock_client
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": "invalid-message-id",
|
||||
"value": "positive",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
# Should not call create_score if validation fails
|
||||
mock_client.create_score.assert_not_called()
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
assert "Invalid message_id, no trace attached." in str(response.data)
|
||||
|
||||
|
||||
def test_score_message_with_invalid_value(api_client):
|
||||
"""Test that scoring fails with an invalid sentiment value."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
api_client.force_login(chat_conversation.owner)
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": "trace-test-123",
|
||||
"value": "invalid_sentiment",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
|
||||
def test_score_message_missing_message_id(api_client):
|
||||
"""Test that scoring fails when message_id is missing."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
api_client.force_login(chat_conversation.owner)
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"value": "positive",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
|
||||
def test_score_message_missing_value(api_client):
|
||||
"""Test that scoring fails when value is missing."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
api_client.force_login(chat_conversation.owner)
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": "trace-test-123",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
|
||||
def test_score_message_unauthenticated(api_client):
|
||||
"""Test that unauthenticated users cannot score messages."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": "trace-test-123",
|
||||
"value": "positive",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
|
||||
def test_score_message_for_conversation_of_another_user(api_client):
|
||||
"""Test that a user cannot score messages in a conversation of another user."""
|
||||
chat_conversation = factories.ChatConversationFactory()
|
||||
api_client.force_login(UserFactory())
|
||||
url = f"/api/v1.0/chats/{chat_conversation.pk}/score-message/"
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": "trace-test-123",
|
||||
"value": "positive",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
|
||||
def test_score_message_for_nonexistent_conversation(api_client):
|
||||
"""Test that scoring fails for a non-existent conversation."""
|
||||
user = UserFactory()
|
||||
api_client.force_login(user)
|
||||
url = "/api/v1.0/chats/99999/score-message/"
|
||||
|
||||
response = api_client.post(
|
||||
url,
|
||||
data={
|
||||
"message_id": "trace-test-123",
|
||||
"value": "positive",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
@@ -5,6 +5,7 @@ import logging
|
||||
from django.conf import settings
|
||||
from django.http import StreamingHttpResponse
|
||||
|
||||
import langfuse
|
||||
from rest_framework import decorators, filters, mixins, permissions, status, viewsets
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.response import Response
|
||||
@@ -175,6 +176,51 @@ class ChatViewSet( # pylint: disable=too-many-ancestors
|
||||
|
||||
return Response({"status": "OK"}, status=status.HTTP_200_OK)
|
||||
|
||||
@decorators.action(
|
||||
methods=["post"],
|
||||
detail=True,
|
||||
url_path="score-message",
|
||||
url_name="score-message",
|
||||
)
|
||||
def post_score_message(self, request, pk): # pylint: disable=unused-argument
|
||||
"""Handle POST requests to score a message in the chat conversation.
|
||||
|
||||
This sends the score to Langfuse to the trace_id, which is extracted from the message_id.
|
||||
We enforce the unique score_id to be a combination of trace_id and user_id to avoid
|
||||
multiple scores from the same user for the same message (if the user changes the score
|
||||
it will be updated in Langfuse).
|
||||
|
||||
Args:
|
||||
request: The HTTP request object containing:
|
||||
- message_id: The ID of the message to score.
|
||||
- score: The score to assign to the message (e.g., 1-5).
|
||||
pk: The primary key of the chat conversation.
|
||||
Returns:
|
||||
Response: A response indicating that the message has been scored.
|
||||
"""
|
||||
_conversation = self.get_object() # only to check permissions
|
||||
|
||||
serializer = serializers.ChatMessageCategoricalScoreSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
message_id = serializer.validated_data["message_id"]
|
||||
name = serializer.validated_data["name"]
|
||||
value = serializer.validated_data["value"]
|
||||
|
||||
if not message_id.startswith("trace-"):
|
||||
raise ValidationError("Invalid message_id, no trace attached.")
|
||||
|
||||
trace_id = message_id[len("trace-") :]
|
||||
langfuse.get_client().create_score(
|
||||
name=name,
|
||||
value=value,
|
||||
trace_id=trace_id,
|
||||
score_id=f"{trace_id}-{self.request.user.pk}",
|
||||
data_type="CATEGORICAL",
|
||||
)
|
||||
|
||||
return Response({"status": "OK"}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class LLMConfigurationView(APIView):
|
||||
"""View for listing available LLM models."""
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
<svg width="163" height="40" viewBox="0 0 163 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M25.9806 10.0539C25.9806 9.37231 25.9806 9.03151 25.9098 8.72032C25.7791 8.14516 25.4727 7.62489 25.0331 7.23159C24.7953 7.01879 24.4973 6.8535 23.9012 6.52291L22.378 5.6781C21.8149 5.36579 21.5334 5.20963 21.2428 5.12176C20.7061 4.95941 20.1333 4.95941 19.5965 5.12176C19.3059 5.20963 19.0244 5.36579 18.4613 5.6781L17.8331 6.02651C17.0707 6.44937 16.6894 6.66081 16.5148 6.90692C16.1881 7.36724 16.1884 7.98382 16.5155 8.44382C16.6904 8.68977 17.0718 8.90084 17.8347 9.32298L18.3432 9.60438C18.9402 9.93474 19.2387 10.0999 19.4769 10.3127C19.9172 10.7061 20.2241 11.2267 20.3551 11.8023C20.4259 12.1138 20.4259 12.4549 20.4259 13.1372V13.7195C20.4259 14.5463 20.4259 14.9597 20.5502 15.2263C20.7823 15.7243 21.2975 16.0278 21.8457 15.9894C22.139 15.9688 22.5006 15.7684 23.2237 15.3675L23.9004 14.9925C24.4967 14.6619 24.7948 14.4967 25.0327 14.2839C25.4725 13.8905 25.779 13.3702 25.9098 12.7949C25.9806 12.4837 25.9806 12.1428 25.9806 11.461V10.0539Z" fill="#2845C1"/>
|
||||
<path d="M9.02562 20.1571C8.43534 20.4979 8.1402 20.6683 7.90608 20.8852C7.47335 21.286 7.17597 21.8115 7.05514 22.3888C6.98977 22.7012 6.99563 23.0419 7.00736 23.7234L7.03734 25.4649C7.04843 26.1088 7.05397 26.4307 7.12313 26.7262C7.25092 27.2723 7.53733 27.7683 7.94632 28.152C8.16767 28.3597 8.44369 28.5254 8.99572 28.857L9.61153 29.2268C10.359 29.6756 10.7327 29.9001 11.0331 29.9282C11.5951 29.981 12.1289 29.6724 12.3638 29.1592C12.4893 28.8847 12.4814 28.4489 12.4656 27.5772L12.455 26.9961C12.4426 26.3139 12.4364 25.9728 12.5016 25.6601C12.6221 25.0821 12.9195 24.556 13.3526 24.1548C13.5869 23.9377 13.8823 23.7671 14.4732 23.4259L14.9775 23.1348C15.6935 22.7214 16.0515 22.5147 16.2202 22.2739C16.5355 21.8238 16.5407 21.2259 16.2333 20.7703C16.0689 20.5266 15.7145 20.3137 15.0058 19.8878L14.3426 19.4894C13.7582 19.1382 13.466 18.9627 13.1628 18.863C12.6023 18.6788 11.9984 18.6736 11.4348 18.8479C11.1298 18.9423 10.8346 19.1127 10.2442 19.4536L9.02562 20.1571Z" fill="#2845C1"/>
|
||||
<svg width="139" height="40" viewBox="0 0 139 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M25.9806 10.0539C25.9806 9.37231 25.9806 9.03151 25.9098 8.72032C25.7791 8.14516 25.4727 7.62489 25.0331 7.23159C24.7953 7.0188 24.4973 6.8535 23.9012 6.52291L22.378 5.6781C21.8149 5.36579 21.5334 5.20963 21.2428 5.12176C20.7061 4.95941 20.1333 4.95941 19.5965 5.12176C19.3059 5.20963 19.0244 5.36579 18.4613 5.6781L17.8331 6.02651C17.0707 6.44937 16.6894 6.66081 16.5148 6.90692C16.1881 7.36724 16.1884 7.98382 16.5155 8.44382C16.6904 8.68977 17.0718 8.90084 17.8347 9.32298L18.3432 9.60438C18.9402 9.93474 19.2387 10.0999 19.4769 10.3127C19.9172 10.7061 20.2241 11.2267 20.3551 11.8023C20.4259 12.1138 20.4259 12.4549 20.4259 13.1373V13.7195C20.4259 14.5463 20.4259 14.9597 20.5502 15.2263C20.7823 15.7244 21.2975 16.0278 21.8457 15.9894C22.139 15.9688 22.5006 15.7684 23.2237 15.3675L23.9004 14.9925C24.4967 14.6619 24.7948 14.4967 25.0327 14.2839C25.4725 13.8906 25.779 13.3702 25.9098 12.7949C25.9806 12.4837 25.9806 12.1428 25.9806 11.461V10.0539Z" fill="#2845C1"/>
|
||||
<path d="M9.02562 20.1571C8.43534 20.4979 8.1402 20.6683 7.90608 20.8852C7.47335 21.286 7.17597 21.8115 7.05514 22.3888C6.98977 22.7012 6.99563 23.0419 7.00736 23.7234L7.03734 25.4649C7.04843 26.1088 7.05397 26.4307 7.12313 26.7262C7.25092 27.2723 7.53733 27.7683 7.94632 28.152C8.16767 28.3597 8.44369 28.5254 8.99572 28.857L9.61153 29.2268C10.359 29.6756 10.7327 29.9001 11.0331 29.9283C11.5951 29.981 12.1289 29.6724 12.3638 29.1592C12.4893 28.8847 12.4814 28.4489 12.4656 27.5772L12.455 26.9961C12.4426 26.3139 12.4364 25.9728 12.5016 25.6601C12.6221 25.0821 12.9195 24.556 13.3526 24.1548C13.5869 23.9377 13.8823 23.7671 14.4732 23.4259L14.9775 23.1348C15.6935 22.7214 16.0515 22.5147 16.2202 22.2739C16.5355 21.8238 16.5407 21.2259 16.2333 20.7703C16.0689 20.5266 15.7145 20.3137 15.0058 19.8878L14.3426 19.4894C13.7582 19.1382 13.466 18.9627 13.1628 18.863C12.6023 18.6788 11.9984 18.6736 11.4348 18.8479C11.1298 18.9423 10.8346 19.1127 10.2442 19.4536L9.02562 20.1571Z" fill="#2845C1"/>
|
||||
<path d="M14.8587 29.9461C14.8587 30.6277 14.8587 30.9685 14.9295 31.2797C15.0602 31.8548 15.3666 32.3751 15.8062 32.7684C16.044 32.9812 16.342 33.1465 16.9381 33.4771L18.4613 34.3219C19.0244 34.6342 19.306 34.7904 19.5965 34.8782C20.1333 35.0406 20.7061 35.0406 21.2428 34.8782C21.5334 34.7904 21.8149 34.6342 22.378 34.3219L23.0062 33.9735C23.7686 33.5506 24.1499 33.3392 24.3245 33.0931C24.6512 32.6328 24.6509 32.0162 24.3238 31.5562C24.1489 31.3102 23.7675 31.0992 23.0046 30.677L22.4961 30.3956C21.8991 30.0653 21.6006 29.9001 21.3624 29.6873C20.9222 29.2939 20.6152 28.7733 20.4842 28.1977C20.4134 27.8862 20.4134 27.5451 20.4134 26.8627V26.2805C20.4134 25.4537 20.4134 25.0403 20.2892 24.7737C20.057 24.2757 19.5418 23.9722 18.9936 24.0106C18.7003 24.0312 18.3387 24.2316 17.6156 24.6325L16.9389 25.0075C16.3426 25.3381 16.0445 25.5033 15.8066 25.7161C15.3668 26.1095 15.0603 26.6298 14.9295 27.2051C14.8587 27.5163 14.8587 27.8572 14.8587 28.539V29.9461Z" fill="#2845C1"/>
|
||||
<path d="M26.2528 29.7889C26.843 30.1297 27.1382 30.3001 27.4431 30.3945C28.0065 30.5688 28.6103 30.5636 29.1707 30.3796C29.4739 30.28 29.766 30.1046 30.3504 29.7537L31.8436 28.8569C32.3956 28.5254 32.6716 28.3597 32.893 28.152C33.302 27.7683 33.5884 27.2723 33.7162 26.7262C33.7853 26.4307 33.7909 26.1088 33.802 25.4649L33.8143 24.7467C33.8293 23.875 33.8368 23.4391 33.711 23.1648C33.4757 22.6518 32.9416 22.3437 32.3797 22.397C32.0792 22.4255 31.7057 22.6503 30.9587 23.0999L30.4608 23.3995C29.8762 23.7514 29.5839 23.9273 29.2805 24.0272C28.7197 24.2118 28.1154 24.2173 27.5513 24.0429C27.2462 23.9485 26.9507 23.778 26.3598 23.4368L25.8556 23.1457C25.1395 22.7323 24.7815 22.5256 24.4886 22.4999C23.9411 22.4519 23.4208 22.7463 23.18 23.2403C23.0511 23.5046 23.0439 23.9179 23.0294 24.7446L23.0159 25.5182C23.004 26.1998 22.9981 26.5407 23.0634 26.8531C23.1842 27.4306 23.4816 27.9562 23.9144 28.3572C24.1485 28.5741 24.4438 28.7445 25.0342 29.0854L26.2528 29.7889Z" fill="#2845C1"/>
|
||||
<path d="M26.2528 29.7889C26.843 30.1297 27.1382 30.3001 27.4431 30.3945C28.0065 30.5688 28.6103 30.5636 29.1707 30.3796C29.4739 30.28 29.766 30.1046 30.3504 29.7537L31.8436 28.8569C32.3956 28.5254 32.6716 28.3597 32.893 28.152C33.302 27.7683 33.5884 27.2723 33.7162 26.7262C33.7853 26.4307 33.7909 26.1088 33.802 25.4649L33.8143 24.7467C33.8293 23.875 33.8368 23.4391 33.711 23.1648C33.4757 22.6518 32.9416 22.3438 32.3797 22.397C32.0792 22.4255 31.7057 22.6503 30.9587 23.0999L30.4608 23.3996C29.8762 23.7514 29.5839 23.9273 29.2805 24.0272C28.7197 24.2118 28.1154 24.2173 27.5513 24.0429C27.2462 23.9485 26.9507 23.778 26.3598 23.4368L25.8556 23.1457C25.1395 22.7323 24.7815 22.5256 24.4886 22.4999C23.9411 22.4519 23.4208 22.7463 23.18 23.2403C23.0511 23.5046 23.0439 23.9179 23.0294 24.7446L23.0159 25.5182C23.004 26.1999 22.9981 26.5407 23.0634 26.8531C23.1842 27.4306 23.4816 27.9562 23.9144 28.3572C24.1485 28.5741 24.4438 28.7445 25.0342 29.0854L26.2528 29.7889Z" fill="#2845C1"/>
|
||||
<path d="M31.8137 19.8429C32.404 19.5021 32.6991 19.3317 32.9332 19.1148C33.366 18.714 33.6633 18.1885 33.7842 17.6112C33.8495 17.2988 33.8437 16.9581 33.8319 16.2766L33.802 14.5351C33.7909 13.8912 33.7853 13.5693 33.7162 13.2738C33.5884 12.7277 33.302 12.2317 32.893 11.848C32.6716 11.6403 32.3956 11.4746 31.8436 11.1431L31.2278 10.7732C30.4803 10.3244 30.1066 10.0999 29.8062 10.0718C29.2442 10.019 28.7104 10.3276 28.4755 10.8408C28.35 11.1153 28.3579 11.5511 28.3737 12.4228L28.3843 13.0039C28.3967 13.6861 28.4029 14.0272 28.3377 14.3399C28.2172 14.9179 27.9198 15.444 27.4867 15.8452C27.2524 16.0623 26.957 16.2329 26.3661 16.5741L25.8618 16.8652C25.1458 17.2786 24.7878 17.4853 24.6191 17.7261C24.3038 18.1762 24.2986 18.7741 24.606 19.2297C24.7704 19.4734 25.1248 19.6863 25.8335 20.1122L26.4967 20.5106C27.0811 20.8618 27.3733 21.0373 27.6765 21.137C28.237 21.3212 28.8409 21.3264 29.4045 21.1521C29.7095 21.0577 30.0047 20.8873 30.5951 20.5464L31.8137 19.8429Z" fill="#2845C1"/>
|
||||
<path d="M14.5865 10.2111C13.9962 9.87031 13.7011 9.69991 13.3962 9.60558C12.8327 9.43123 12.229 9.43642 11.6686 9.62044C11.3654 9.72001 11.0732 9.89546 10.4889 10.2464L8.99568 11.1431C8.44365 11.4746 8.16763 11.6404 7.94627 11.848C7.53729 12.2317 7.25088 12.7278 7.12309 13.2738C7.05393 13.5694 7.04839 13.8913 7.0373 14.5351L7.02494 15.2533C7.00993 16.1251 7.00243 16.5609 7.12825 16.8352C7.36357 17.3483 7.89769 17.6563 8.45961 17.603C8.76005 17.5746 9.13355 17.3498 9.88056 16.9002L10.3785 16.6005C10.9631 16.2487 11.2554 16.0728 11.5588 15.9729C12.1196 15.7883 12.7239 15.7828 13.2879 15.9572C13.5931 16.0515 13.8885 16.2221 14.4794 16.5632L14.9837 16.8544C15.6997 17.2678 16.0577 17.4745 16.3507 17.5002C16.8981 17.5482 17.4185 17.2537 17.6593 16.7598C17.7882 16.4955 17.7954 16.0821 17.8098 15.2554L17.8233 14.4819C17.8352 13.8002 17.8412 13.4594 17.7758 13.1469C17.6551 12.5694 17.3577 12.0438 16.9249 11.6429C16.6907 11.426 16.3955 11.2555 15.8051 10.9146L14.5865 10.2111Z" fill="#C83F49"/>
|
||||
<path d="M61.8577 15.5576C62.6931 15.5576 63.468 15.74 64.1819 16.1045C64.8463 16.4367 65.3785 16.8509 65.7781 17.3471C65.8437 17.4285 65.8294 17.5466 65.7498 17.6145L64.3459 18.8122C64.2574 18.8877 64.1236 18.8717 64.0503 18.7814C63.7909 18.4622 63.4929 18.1926 63.1565 17.9727C62.7616 17.7145 62.3285 17.585 61.8577 17.585C61.5237 17.585 61.2353 17.6462 60.9924 17.7676C60.7646 17.8891 60.5895 18.0486 60.468 18.2461C60.3617 18.4436 60.3088 18.6642 60.3088 18.9072C60.3089 19.2716 60.4375 19.5754 60.6955 19.8184C60.969 20.0462 61.319 20.244 61.7444 20.4111C62.1696 20.5782 62.6174 20.7606 63.0881 20.958C63.5742 21.1403 64.03 21.3682 64.4553 21.6416C64.8806 21.8998 65.2225 22.2489 65.4807 22.6895C65.7541 23.1147 65.8908 23.6537 65.8909 24.3066C65.8909 25.0812 65.7012 25.7423 65.3215 26.2891C64.957 26.8206 64.471 27.2309 63.8635 27.5195C63.2559 27.8082 62.5868 27.9531 61.8577 27.9531C60.8706 27.9531 60.0124 27.7707 59.2834 27.4062C58.6116 27.0563 58.0171 26.5962 57.5 26.0269C57.4264 25.9459 57.4354 25.8208 57.5176 25.7485L58.921 24.5135C59.0067 24.4381 59.1377 24.4498 59.2123 24.5363C59.5425 24.9194 59.9081 25.2384 60.3088 25.4922C60.7645 25.7807 61.2733 25.9248 61.8352 25.9248C62.3669 25.9248 62.7698 25.7881 63.0432 25.5146C63.3316 25.2261 63.4758 24.8768 63.4758 24.4668C63.4758 24.0871 63.339 23.7835 63.0657 23.5557C62.8074 23.3278 62.4656 23.13 62.0403 22.9629C61.6149 22.7958 61.1592 22.6208 60.6731 22.4385C60.2024 22.2411 59.7545 22.0057 59.3293 21.7324C58.9041 21.459 58.5539 21.1098 58.2805 20.6846C58.0223 20.244 57.8938 19.6816 57.8938 18.998C57.8938 18.3601 58.0606 17.783 58.3948 17.2666C58.729 16.7349 59.192 16.3165 59.7844 16.0127C60.3919 15.709 61.0831 15.5577 61.8577 15.5576Z" fill="#2845C1"/>
|
||||
<path d="M71.3215 15.5576C72.1569 15.5577 72.9319 15.74 73.6457 16.1045C74.3101 16.4367 74.8424 16.8509 75.2419 17.3471C75.3075 17.4285 75.2933 17.5466 75.2137 17.6144L73.8098 18.8122C73.7213 18.8877 73.5875 18.8717 73.5141 18.7813C73.2548 18.4622 72.9568 18.1927 72.6204 17.9727C72.2255 17.7145 71.7923 17.585 71.3215 17.585C70.9873 17.585 70.6984 17.6461 70.4553 17.7676C70.2275 17.8891 70.0524 18.0486 69.9309 18.2461C69.8246 18.4435 69.7717 18.6642 69.7717 18.9072C69.7718 19.2717 69.9013 19.5754 70.1594 19.8184C70.4328 20.0462 70.782 20.2441 71.2073 20.4111C71.6326 20.5782 72.0811 20.7605 72.552 20.958C73.0379 21.1403 73.494 21.3682 73.9192 21.6416C74.3443 21.8998 74.6864 22.2491 74.9446 22.6895C75.2178 23.1146 75.3547 23.6538 75.3547 24.3066C75.3547 25.0813 75.1641 25.7422 74.7844 26.2891C74.4199 26.8207 73.934 27.2309 73.3264 27.5195C72.7189 27.8081 72.0506 27.9531 71.3215 27.9531C70.3341 27.9531 69.4755 27.7708 68.7463 27.4062C68.0745 27.0563 67.48 26.5962 66.9629 26.0269C66.8893 25.9459 66.8983 25.8208 66.9805 25.7485L68.3839 24.5135C68.4696 24.4381 68.6006 24.4498 68.6752 24.5363C69.0054 24.9194 69.371 25.2384 69.7717 25.4922C70.2273 25.7807 70.7362 25.9247 71.2981 25.9248C71.8298 25.9248 72.2327 25.7881 72.5061 25.5146C72.7946 25.2261 72.9387 24.8768 72.9387 24.4668C72.9387 24.087 72.802 23.7835 72.5286 23.5557C72.2703 23.3278 71.9285 23.13 71.5032 22.9629C71.0779 22.7958 70.622 22.6207 70.136 22.4385C69.6653 22.2411 69.2174 22.0057 68.7922 21.7324C68.3671 21.4591 68.0178 21.1097 67.7444 20.6846C67.4861 20.244 67.3567 19.6816 67.3567 18.998C67.3567 18.3602 67.5236 17.783 67.8577 17.2666C68.1918 16.735 68.655 16.3165 69.2473 16.0127C69.8549 15.7089 70.5468 15.5576 71.3215 15.5576Z" fill="#2845C1"/>
|
||||
<path d="M86.3313 15.5576C87.1668 15.5576 87.9416 15.7399 88.6555 16.1045C89.32 16.4368 89.8521 16.8508 90.2517 17.3471C90.3173 17.4285 90.303 17.5466 90.2235 17.6144L88.8195 18.8122C88.731 18.8877 88.5973 18.8717 88.5239 18.7814C88.2646 18.4622 87.9666 18.1926 87.6301 17.9727C87.2352 17.7144 86.8022 17.585 86.3313 17.585C85.9971 17.585 85.7081 17.6461 85.4651 17.7676C85.2374 17.8891 85.0631 18.0488 84.9416 18.2461C84.8353 18.4436 84.7815 18.6642 84.7815 18.9072C84.7816 19.2716 84.911 19.5754 85.1692 19.8184C85.4426 20.0462 85.7918 20.2441 86.217 20.4111C86.6424 20.5782 87.0909 20.7605 87.5618 20.958C88.0478 21.1403 88.5036 21.3682 88.9289 21.6416C89.3542 21.8998 89.6961 22.249 89.9543 22.6895C90.2276 23.1147 90.3644 23.6537 90.3645 24.3066C90.3645 25.0811 90.1747 25.7423 89.7952 26.2891C89.4306 26.8207 88.9438 27.2309 88.3362 27.5195C87.7286 27.8081 87.0604 27.9531 86.3313 27.9531C85.3439 27.9531 84.4852 27.7708 83.7561 27.4062C83.0843 27.0563 82.4905 26.5961 81.9736 26.0269C81.9 25.9459 81.909 25.8208 81.9911 25.7485L83.3937 24.5136C83.4793 24.4381 83.6104 24.4498 83.685 24.5363C84.0152 24.9194 84.3808 25.2384 84.7815 25.4922C85.2372 25.7808 85.7468 25.9248 86.3088 25.9248C86.8403 25.9248 87.2425 25.788 87.5159 25.5146C87.8044 25.2261 87.9494 24.8769 87.9495 24.4668C87.9495 24.0872 87.8125 23.7835 87.5393 23.5557C87.2811 23.3279 86.9391 23.13 86.5139 22.9629C86.0886 22.7958 85.6328 22.6207 85.1467 22.4385C84.6758 22.241 84.2273 22.0059 83.802 21.7324C83.3768 21.4591 83.0275 21.1097 82.7541 20.6846C82.4959 20.244 82.3664 19.6816 82.3664 18.998C82.3664 18.36 82.5342 17.7831 82.8684 17.2666C83.2026 16.7349 83.6656 16.3165 84.258 16.0127C84.8656 15.709 85.5567 15.5576 86.3313 15.5576Z" fill="#2845C1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M106.191 15.7861C107.239 15.7861 108.128 15.9757 108.857 16.3555C109.586 16.7352 110.133 17.2594 110.498 17.9277C110.877 18.5961 111.067 19.3481 111.067 20.1836V27.5256C111.067 27.636 110.977 27.7256 110.867 27.7256H108.76C108.65 27.7256 108.56 27.636 108.56 27.5256V26.7662C108.56 26.6718 108.438 26.6271 108.372 26.6948C108.27 26.7997 108.159 26.9002 108.037 26.9961C107.626 27.3303 107.148 27.5892 106.601 27.7715C106.054 27.9689 105.5 28.0673 104.938 28.0674C103.814 28.0674 102.894 27.7639 102.18 27.1562C101.466 26.5486 101.11 25.7355 101.11 24.7178C101.11 23.852 101.436 23.1154 102.089 22.5078C102.743 21.9002 103.684 21.4973 104.915 21.2998L108.394 20.7089C108.49 20.6926 108.56 20.6093 108.56 20.5118V20.1836C108.56 19.5002 108.333 18.9686 107.877 18.5889C107.422 18.194 106.829 17.9962 106.1 17.9961C105.508 17.9961 104.968 18.1256 104.482 18.3838C104.071 18.6094 103.717 18.9102 103.422 19.2865C103.351 19.376 103.222 19.3965 103.132 19.3273L101.606 18.1598C101.52 18.0942 101.501 17.9719 101.568 17.8865C102.052 17.2617 102.666 16.7665 103.411 16.4014C104.231 15.9912 105.158 15.7861 106.191 15.7861ZM105.553 22.9639C104.87 23.0702 104.376 23.2671 104.072 23.5557C103.768 23.829 103.616 24.1784 103.616 24.6035C103.616 25.0288 103.775 25.3789 104.094 25.6523C104.428 25.9258 104.877 26.0625 105.439 26.0625C106.138 26.0625 106.753 25.903 107.285 25.584C107.721 25.3222 108.09 24.9882 108.393 24.583C108.508 24.4295 108.56 24.2399 108.56 24.0483V22.7008C108.56 22.5772 108.449 22.4832 108.327 22.5035L105.553 22.9639Z" fill="#2845C1"/>
|
||||
<path d="M95.9868 16.0412C95.9868 16.1517 96.0764 16.2412 96.1868 16.2412H99.5017C99.6121 16.2412 99.7017 16.3308 99.7017 16.4412V18.2971C99.7017 18.4075 99.6121 18.4971 99.5017 18.4971H96.1868C96.0764 18.4971 95.9868 18.5866 95.9868 18.6971V23.6699C95.9868 24.171 96.0708 24.5659 96.2378 24.8545C96.4048 25.1429 96.6403 25.3555 96.9439 25.4922C97.2477 25.6137 97.605 25.6748 98.0151 25.6748C98.4101 25.6748 98.7446 25.652 99.0181 25.6064C99.1739 25.5718 99.3174 25.5347 99.4485 25.4951C99.5829 25.4545 99.7241 25.5522 99.7241 25.6926V27.4814C99.7241 27.5604 99.6778 27.6326 99.6042 27.6613C99.3605 27.7561 99.0888 27.8233 98.7896 27.8623C98.4554 27.923 98.0605 27.9531 97.605 27.9531C96.6936 27.9531 95.926 27.7936 95.3032 27.4746C94.6959 27.1404 94.2325 26.6617 93.9136 26.0391C93.6099 25.4012 93.4585 24.6115 93.4585 23.6699V18.6971C93.4585 18.5866 93.369 18.4971 93.2585 18.4971H91.6087C91.4982 18.4971 91.4087 18.4075 91.4087 18.2971V16.4412C91.4087 16.3308 91.4982 16.2412 91.6087 16.2412H93.2585C93.369 16.2412 93.4585 16.1517 93.4585 16.0412V13.5711C93.4585 13.4606 93.548 13.3711 93.6585 13.3711H95.7868C95.8973 13.3711 95.9868 13.4606 95.9868 13.5711V16.0412Z" fill="#2845C1"/>
|
||||
<path d="M130.563 16.0412C130.563 16.1517 130.653 16.2412 130.763 16.2412H134.077C134.187 16.2412 134.277 16.3308 134.277 16.4412V18.2971C134.277 18.4075 134.187 18.4971 134.077 18.4971H130.763C130.653 18.4971 130.563 18.5866 130.563 18.6971V23.6699C130.563 24.171 130.646 24.5659 130.813 24.8545C130.98 25.1431 131.216 25.3555 131.52 25.4922C131.824 25.6137 132.18 25.6748 132.59 25.6748C132.985 25.6748 133.32 25.652 133.593 25.6064C133.749 25.5718 133.893 25.5347 134.024 25.4951C134.158 25.4545 134.299 25.5522 134.299 25.6925V27.4813C134.299 27.5604 134.253 27.6326 134.179 27.6613C133.936 27.7561 133.665 27.8233 133.366 27.8623C133.032 27.9231 132.636 27.9531 132.18 27.9531C131.269 27.9531 130.502 27.7936 129.879 27.4746C129.272 27.1404 128.809 26.6619 128.49 26.0391C128.186 25.4011 128.034 24.6116 128.034 23.6699V18.6971C128.034 18.5866 127.944 18.4971 127.834 18.4971H126.092C125.982 18.4971 125.892 18.4075 125.892 18.2971V16.4412C125.892 16.3308 125.982 16.2412 126.092 16.2412H127.834C127.944 16.2412 128.034 16.1517 128.034 16.0412V13.5711C128.034 13.4606 128.123 13.3711 128.234 13.3711H130.363C130.473 13.3711 130.563 13.4606 130.563 13.5711V16.0412Z" fill="#2845C1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M56.8209 27.4534C56.8716 27.5844 56.7749 27.7256 56.6344 27.7256H54.0801C53.9969 27.7256 53.9224 27.6741 53.893 27.5964L52.3355 23.4798C52.3061 23.402 52.2316 23.3506 52.1485 23.3506H45.6707C45.5876 23.3506 45.5132 23.4019 45.4837 23.4796L43.9196 27.5966C43.8901 27.6743 43.8157 27.7256 43.7326 27.7256H41.2002C41.0598 27.7256 40.9631 27.5846 41.0136 27.4536L47.0107 11.9034C47.0404 11.8263 47.1146 11.7754 47.1973 11.7754H50.6144C50.697 11.7754 50.7711 11.8262 50.8009 11.9032L56.8209 27.4534ZM46.5361 20.7104C46.4864 20.8413 46.5831 20.9814 46.7231 20.9814H51.1006C51.2405 20.9814 51.3372 20.8415 51.2876 20.7106L49.1032 14.9395C49.038 14.7673 48.7946 14.7672 48.7292 14.9392L46.5361 20.7104Z" fill="#2845C1"/>
|
||||
<path d="M80.1372 27.5256C80.1372 27.636 80.0477 27.7256 79.9372 27.7256H77.8314C77.7209 27.7256 77.6314 27.636 77.6314 27.5256V16.4412C77.6314 16.3308 77.7209 16.2412 77.8314 16.2412H79.9372C80.0477 16.2412 80.1372 16.3308 80.1372 16.4412V27.5256Z" fill="#2845C1"/>
|
||||
<path d="M120.009 15.7861C120.86 15.7861 121.619 15.9758 122.288 16.3555C122.971 16.7352 123.511 17.2977 123.906 18.042C124.301 18.7863 124.499 19.7208 124.499 20.8447V27.5256C124.499 27.636 124.409 27.7256 124.299 27.7256H122.169C122.059 27.7256 121.969 27.636 121.969 27.5256V20.9355C121.969 20.0546 121.741 19.3709 121.286 18.8848C120.83 18.3835 120.206 18.1328 119.417 18.1328C118.915 18.1329 118.475 18.2313 118.095 18.4287C117.715 18.611 117.389 18.8471 117.116 19.1357C116.919 19.3551 116.745 19.5831 116.592 19.8199C116.498 19.9662 116.455 20.1384 116.455 20.3124V27.5256C116.455 27.636 116.365 27.7256 116.255 27.7256H114.149C114.038 27.7256 113.949 27.636 113.949 27.5256V16.4412C113.949 16.3308 114.038 16.2412 114.149 16.2412H116.255C116.365 16.2412 116.455 16.3308 116.455 16.4412V17.0392C116.455 17.1294 116.566 17.1747 116.631 17.1128C117.008 16.7571 117.443 16.4588 117.936 16.2188C118.528 15.9302 119.219 15.7861 120.009 15.7861Z" fill="#2845C1"/>
|
||||
<path d="M78.9067 10.5C79.2105 10.5 79.484 10.5757 79.7271 10.7275C79.9853 10.8794 80.1831 11.0845 80.3198 11.3428C80.4717 11.5858 80.5474 11.8593 80.5474 12.1631C80.5474 12.4668 80.4716 12.7477 80.3198 13.0059C80.1831 13.2641 79.9853 13.4692 79.7271 13.6211C79.484 13.7578 79.2106 13.8262 78.9067 13.8262C78.603 13.8262 78.3222 13.7578 78.064 13.6211C77.8057 13.4692 77.6006 13.2641 77.4487 13.0059C77.2969 12.7477 77.2212 12.4668 77.2212 12.1631C77.2212 11.7074 77.3807 11.32 77.6997 11.001C78.0338 10.667 78.436 10.5 78.9067 10.5Z" fill="#2845C1"/>
|
||||
<rect x="143" y="12" width="20" height="16" rx="8" fill="#C83F49"/>
|
||||
<rect x="143" y="12" width="20" height="16" rx="8" fill="#F6F8F9" fill-opacity="0.9"/>
|
||||
<path d="M156.987 23.7042C156.685 23.798 156.415 23.8485 156.179 23.8485C155.391 23.8485 154.859 23.2137 154.589 21.9369H154.557C153.906 23.3147 152.993 24 151.844 24C150.984 24 150.294 23.6465 149.775 22.9324C149.256 22.2182 149 21.3237 149 20.2417C149 18.9793 149.296 17.9693 149.88 17.183C150.465 16.3968 151.259 16 152.264 16C152.803 16 153.289 16.1659 153.709 16.4905C154.13 16.8224 154.452 17.284 154.675 17.8828H154.701L155.167 16.1515H156.849L155.443 19.9892C155.601 20.8837 155.765 21.4968 155.949 21.8215C156.107 22.1461 156.33 22.312 156.606 22.312C156.764 22.312 156.888 22.2831 157 22.2326L156.987 23.7042ZM154.189 19.9243C154.051 19.1091 153.828 18.4743 153.525 18.0415C153.23 17.6014 152.869 17.385 152.455 17.385C151.916 17.385 151.483 17.6519 151.161 18.1785C150.839 18.7124 150.695 19.3688 150.695 20.1407C150.695 20.8476 150.819 21.4319 151.102 21.908C151.378 22.3841 151.752 22.615 152.218 22.615C152.612 22.615 152.974 22.4058 153.296 22.009C153.624 21.5978 153.893 20.9991 154.11 20.2128L154.189 19.9243Z" fill="#C83F49"/>
|
||||
<path d="M14.5868 10.2111C13.9965 9.87031 13.7013 9.69991 13.3965 9.60558C12.833 9.43123 12.2292 9.43642 11.6688 9.62044C11.3656 9.72001 11.0735 9.89546 10.4891 10.2464L8.99592 11.1431C8.44389 11.4746 8.16788 11.6404 7.94652 11.848C7.53753 12.2317 7.25113 12.7278 7.12334 13.2738C7.05417 13.5694 7.04863 13.8913 7.03755 14.5351L7.02518 15.2533C7.01018 16.1251 7.00267 16.5609 7.12849 16.8352C7.36381 17.3483 7.89793 17.6563 8.45985 17.603C8.76029 17.5746 9.1338 17.3498 9.8808 16.9002L10.3788 16.6005C10.9634 16.2487 11.2557 16.0728 11.5591 15.9729C12.1198 15.7883 12.7242 15.7828 13.2882 15.9572C13.5933 16.0515 13.8888 16.2221 14.4797 16.5632L14.9839 16.8544C15.7 17.2678 16.058 17.4745 16.3509 17.5002C16.8984 17.5482 17.4187 17.2537 17.6596 16.7598C17.7884 16.4955 17.7956 16.0821 17.8101 15.2554L17.8236 14.4819C17.8355 13.8002 17.8414 13.4594 17.7761 13.1469C17.6553 12.5694 17.358 12.0438 16.9251 11.6429C16.691 11.426 16.3958 11.2555 15.8053 10.9146L14.5868 10.2111Z" fill="#C83F49"/>
|
||||
<rect x="13" y="27" width="14" height="9" rx="4.5" fill="#D9D9D9"/>
|
||||
<rect x="13" y="27" width="14" height="9" rx="4.5" fill="#EEF1F4"/>
|
||||
<rect x="13" y="27" width="14" height="9" rx="4.5" fill="url(#paint0_linear_13367_3310)" fill-opacity="0.1"/>
|
||||
<path d="M22.9901 34.2782C22.7635 34.3485 22.5616 34.3864 22.3842 34.3864C21.7931 34.3864 21.3941 33.9103 21.1921 32.9527H21.1675C20.6798 33.986 19.9951 34.5 19.133 34.5C18.4877 34.5 17.9704 34.2349 17.5813 33.6993C17.1921 33.1637 17 32.4928 17 31.6812C17 30.7344 17.2217 29.977 17.6601 29.3873C18.0985 28.7976 18.6946 28.5 19.4483 28.5C19.8522 28.5 20.2167 28.6244 20.532 28.8679C20.8473 29.1168 21.0887 29.463 21.2562 29.9121H21.2759L21.6256 28.6136H22.8867L21.8325 31.4919C21.9507 32.1628 22.0739 32.6226 22.2118 32.8661C22.33 33.1096 22.4975 33.234 22.7044 33.234C22.8227 33.234 22.9163 33.2124 23 33.1745L22.9901 34.2782ZM20.8916 31.4432C20.7882 30.8318 20.6207 30.3557 20.3941 30.0311C20.1724 29.7011 19.9015 29.5388 19.5911 29.5388C19.1872 29.5388 18.8621 29.739 18.6207 30.1339C18.3793 30.5343 18.2709 31.0266 18.2709 31.6055C18.2709 32.1357 18.3645 32.5739 18.5764 32.931C18.7833 33.2881 19.064 33.4612 19.4138 33.4612C19.7094 33.4612 19.9803 33.3043 20.2217 33.0068C20.468 32.6984 20.67 32.2493 20.8325 31.6596L20.8916 31.4432Z" fill="#C83F49"/>
|
||||
<path d="M61.8577 15.8076C62.6931 15.8076 63.468 15.99 64.1819 16.3545C64.8463 16.6867 65.3785 17.1009 65.7781 17.5971C65.8437 17.6785 65.8294 17.7966 65.7498 17.8645L64.3459 19.0622C64.2574 19.1377 64.1237 19.1217 64.0503 19.0314C63.7909 18.7122 63.4929 18.4426 63.1565 18.2227C62.7616 17.9645 62.3285 17.835 61.8577 17.835C61.5237 17.835 61.2353 17.8962 60.9924 18.0176C60.7646 18.1391 60.5895 18.2986 60.468 18.4961C60.3617 18.6936 60.3088 18.9142 60.3088 19.1572C60.3089 19.5216 60.4375 19.8254 60.6956 20.0684C60.969 20.2962 61.319 20.494 61.7444 20.6611C62.1696 20.8282 62.6174 21.0106 63.0881 21.208C63.5742 21.3903 64.03 21.6182 64.4553 21.8916C64.8806 22.1498 65.2225 22.4989 65.4807 22.9395C65.7541 23.3647 65.8908 23.9037 65.8909 24.5566C65.8909 25.3312 65.7012 25.9923 65.3215 26.5391C64.957 27.0706 64.471 27.4809 63.8635 27.7695C63.2559 28.0582 62.5868 28.2031 61.8577 28.2031C60.8706 28.2031 60.0124 28.0207 59.2834 27.6563C58.6116 27.3063 58.0171 26.8462 57.5 26.2769C57.4264 26.1959 57.4354 26.0708 57.5176 25.9985L58.921 24.7635C59.0067 24.6881 59.1377 24.6998 59.2123 24.7863C59.5425 25.1694 59.9081 25.4884 60.3088 25.7422C60.7645 26.0307 61.2733 26.1748 61.8352 26.1748C62.3669 26.1748 62.7698 26.0381 63.0432 25.7647C63.3317 25.4761 63.4758 25.1268 63.4758 24.7168C63.4758 24.3371 63.339 24.0335 63.0657 23.8057C62.8074 23.5778 62.4656 23.38 62.0403 23.2129C61.615 23.0458 61.1592 22.8708 60.6731 22.6885C60.2024 22.4911 59.7545 22.2557 59.3293 21.9824C58.9041 21.709 58.5539 21.3598 58.2805 20.9346C58.0223 20.494 57.8938 19.9316 57.8938 19.248C57.8938 18.6101 58.0606 18.033 58.3948 17.5166C58.729 16.9849 59.192 16.5665 59.7844 16.2627C60.3919 15.959 61.0831 15.8077 61.8577 15.8076Z" fill="#2845C1"/>
|
||||
<path d="M71.3215 15.8076C72.1569 15.8077 72.9319 15.99 73.6457 16.3545C74.3101 16.6867 74.8424 17.1009 75.2419 17.5971C75.3075 17.6785 75.2933 17.7966 75.2137 17.8645L73.8098 19.0622C73.7213 19.1377 73.5875 19.1217 73.5141 19.0313C73.2548 18.7122 72.9568 18.4427 72.6204 18.2227C72.2255 17.9645 71.7923 17.835 71.3215 17.835C70.9873 17.835 70.6984 17.8961 70.4553 18.0176C70.2275 18.1391 70.0524 18.2986 69.9309 18.4961C69.8246 18.6935 69.7717 18.9142 69.7717 19.1572C69.7718 19.5217 69.9013 19.8254 70.1594 20.0684C70.4328 20.2962 70.782 20.4941 71.2073 20.6611C71.6326 20.8282 72.0811 21.0105 72.552 21.208C73.0379 21.3903 73.494 21.6182 73.9192 21.8916C74.3443 22.1498 74.6864 22.4991 74.9446 22.9395C75.2178 23.3646 75.3547 23.9038 75.3547 24.5566C75.3547 25.3313 75.1641 25.9922 74.7844 26.5391C74.4199 27.0707 73.934 27.4809 73.3264 27.7695C72.7189 28.0581 72.0506 28.2031 71.3215 28.2031C70.3341 28.2031 69.4755 28.0208 68.7463 27.6563C68.0745 27.3063 67.48 26.8462 66.9629 26.2769C66.8893 26.1959 66.8983 26.0708 66.9805 25.9985L68.3839 24.7635C68.4696 24.6881 68.6006 24.6998 68.6752 24.7863C69.0054 25.1694 69.371 25.4884 69.7717 25.7422C70.2273 26.0307 70.7362 26.1747 71.2981 26.1748C71.8298 26.1748 72.2327 26.0381 72.5061 25.7647C72.7946 25.4761 72.9387 25.1268 72.9387 24.7168C72.9387 24.3371 72.802 24.0335 72.5286 23.8057C72.2703 23.5778 71.9285 23.38 71.5032 23.2129C71.0779 23.0458 70.622 22.8707 70.136 22.6885C69.6653 22.4911 69.2174 22.2557 68.7922 21.9824C68.3671 21.7091 68.0178 21.3597 67.7444 20.9346C67.4861 20.494 67.3567 19.9316 67.3567 19.248C67.3567 18.6102 67.5236 18.033 67.8577 17.5166C68.1918 16.985 68.655 16.5665 69.2473 16.2627C69.8549 15.9589 70.5468 15.8076 71.3215 15.8076Z" fill="#2845C1"/>
|
||||
<path d="M86.3313 15.8076C87.1668 15.8076 87.9416 15.9899 88.6555 16.3545C89.32 16.6868 89.8522 17.1008 90.2517 17.5971C90.3173 17.6785 90.303 17.7966 90.2235 17.8645L88.8196 19.0622C88.731 19.1377 88.5973 19.1217 88.5239 19.0314C88.2646 18.7122 87.9666 18.4426 87.6301 18.2227C87.2352 17.9644 86.8022 17.835 86.3313 17.835C85.9971 17.835 85.7081 17.8961 85.4651 18.0176C85.2374 18.1391 85.0631 18.2988 84.9416 18.4961C84.8353 18.6936 84.7815 18.9142 84.7815 19.1572C84.7816 19.5216 84.9111 19.8254 85.1692 20.0684C85.4426 20.2962 85.7918 20.4941 86.217 20.6611C86.6424 20.8282 87.0909 21.0105 87.5618 21.208C88.0478 21.3903 88.5037 21.6182 88.929 21.8916C89.3542 22.1498 89.6961 22.499 89.9543 22.9395C90.2277 23.3647 90.3644 23.9037 90.3645 24.5566C90.3645 25.3311 90.1747 25.9923 89.7952 26.5391C89.4306 27.0707 88.9438 27.4809 88.3362 27.7695C87.7286 28.0581 87.0604 28.2031 86.3313 28.2031C85.3439 28.2031 84.4852 28.0208 83.7561 27.6563C83.0844 27.3063 82.4905 26.8461 81.9736 26.2769C81.9 26.1959 81.909 26.0708 81.9911 25.9985L83.3937 24.7636C83.4793 24.6881 83.6104 24.6998 83.685 24.7863C84.0152 25.1694 84.3808 25.4884 84.7815 25.7422C85.2372 26.0308 85.7468 26.1748 86.3088 26.1748C86.8403 26.1748 87.2425 26.038 87.5159 25.7647C87.8044 25.4761 87.9494 25.1269 87.9495 24.7168C87.9495 24.3372 87.8125 24.0335 87.5393 23.8057C87.2811 23.5779 86.9391 23.38 86.5139 23.2129C86.0886 23.0458 85.6328 22.8707 85.1467 22.6885C84.6758 22.491 84.2273 22.2559 83.802 21.9824C83.3768 21.7091 83.0275 21.3597 82.7541 20.9346C82.4959 20.494 82.3665 19.9316 82.3665 19.248C82.3665 18.61 82.5342 18.0331 82.8684 17.5166C83.2026 16.9849 83.6656 16.5665 84.2581 16.2627C84.8656 15.959 85.5567 15.8076 86.3313 15.8076Z" fill="#2845C1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M106.191 16.0361C107.239 16.0361 108.128 16.2257 108.857 16.6055C109.586 16.9852 110.133 17.5094 110.498 18.1777C110.877 18.8461 111.067 19.5981 111.067 20.4336V27.7756C111.067 27.886 110.977 27.9756 110.867 27.9756H108.76C108.65 27.9756 108.56 27.886 108.56 27.7756V27.0162C108.56 26.9218 108.438 26.8771 108.372 26.9448C108.27 27.0497 108.159 27.1502 108.037 27.2461C107.626 27.5803 107.148 27.8392 106.601 28.0215C106.054 28.2189 105.5 28.3173 104.938 28.3174C103.814 28.3174 102.894 28.0139 102.18 27.4063C101.466 26.7986 101.11 25.9855 101.11 24.9678C101.11 24.102 101.436 23.3654 102.089 22.7578C102.743 22.1502 103.684 21.7473 104.915 21.5498L108.394 20.9589C108.49 20.9426 108.56 20.8593 108.56 20.7618V20.4336C108.56 19.7502 108.333 19.2186 107.877 18.8389C107.422 18.444 106.829 18.2462 106.1 18.2461C105.508 18.2461 104.968 18.3756 104.482 18.6338C104.071 18.8594 103.717 19.1602 103.422 19.5365C103.351 19.626 103.222 19.6465 103.132 19.5773L101.606 18.4098C101.52 18.3442 101.501 18.2219 101.568 18.1365C102.052 17.5117 102.666 17.0165 103.411 16.6514C104.231 16.2412 105.158 16.0361 106.191 16.0361ZM105.553 23.2139C104.87 23.3202 104.376 23.5171 104.072 23.8057C103.768 24.079 103.616 24.4284 103.616 24.8535C103.616 25.2788 103.775 25.6289 104.094 25.9023C104.428 26.1758 104.877 26.3125 105.439 26.3125C106.138 26.3125 106.753 26.153 107.285 25.834C107.721 25.5722 108.09 25.2382 108.393 24.833C108.508 24.6795 108.56 24.4899 108.56 24.2983V22.9508C108.56 22.8272 108.449 22.7332 108.327 22.7535L105.553 23.2139Z" fill="#2845C1"/>
|
||||
<path d="M95.9868 16.2912C95.9868 16.4017 96.0764 16.4912 96.1868 16.4912H99.5017C99.6121 16.4912 99.7017 16.5808 99.7017 16.6912V18.5471C99.7017 18.6575 99.6121 18.7471 99.5017 18.7471H96.1868C96.0764 18.7471 95.9868 18.8366 95.9868 18.9471V23.9199C95.9868 24.421 96.0708 24.8159 96.2378 25.1045C96.4048 25.3929 96.6403 25.6055 96.9439 25.7422C97.2477 25.8637 97.605 25.9248 98.0152 25.9248C98.4101 25.9248 98.7447 25.902 99.0181 25.8564C99.1739 25.8218 99.3174 25.7847 99.4485 25.7451C99.5829 25.7045 99.7241 25.8022 99.7241 25.9426V27.7314C99.7241 27.8104 99.6778 27.8826 99.6042 27.9113C99.3605 28.0061 99.0889 28.0733 98.7896 28.1123C98.4554 28.173 98.0606 28.2031 97.605 28.2031C96.6936 28.2031 95.926 28.0436 95.3032 27.7246C94.6959 27.3904 94.2325 26.9117 93.9136 26.2891C93.6099 25.6512 93.4585 24.8615 93.4585 23.9199V18.9471C93.4585 18.8366 93.369 18.7471 93.2585 18.7471H91.6087C91.4982 18.7471 91.4087 18.6575 91.4087 18.5471V16.6912C91.4087 16.5808 91.4982 16.4912 91.6087 16.4912H93.2585C93.369 16.4912 93.4585 16.4017 93.4585 16.2912V13.8211C93.4585 13.7106 93.548 13.6211 93.6585 13.6211H95.7868C95.8973 13.6211 95.9868 13.7106 95.9868 13.8211V16.2912Z" fill="#2845C1"/>
|
||||
<path d="M130.563 16.2912C130.563 16.4017 130.653 16.4912 130.763 16.4912H134.077C134.187 16.4912 134.277 16.5808 134.277 16.6912V18.5471C134.277 18.6575 134.187 18.7471 134.077 18.7471H130.763C130.653 18.7471 130.563 18.8366 130.563 18.9471V23.9199C130.563 24.421 130.646 24.8159 130.813 25.1045C130.98 25.3931 131.216 25.6055 131.52 25.7422C131.824 25.8637 132.18 25.9248 132.59 25.9248C132.985 25.9248 133.32 25.902 133.593 25.8564C133.749 25.8218 133.893 25.7847 134.024 25.7451C134.158 25.7045 134.299 25.8022 134.299 25.9425V27.7313C134.299 27.8104 134.253 27.8826 134.179 27.9113C133.936 28.0061 133.665 28.0733 133.366 28.1123C133.032 28.1731 132.636 28.2031 132.18 28.2031C131.269 28.2031 130.502 28.0436 129.879 27.7246C129.272 27.3904 128.809 26.9119 128.49 26.2891C128.186 25.6511 128.034 24.8616 128.034 23.9199V18.9471C128.034 18.8366 127.944 18.7471 127.834 18.7471H126.092C125.982 18.7471 125.892 18.6575 125.892 18.5471V16.6912C125.892 16.5808 125.982 16.4912 126.092 16.4912H127.834C127.944 16.4912 128.034 16.4017 128.034 16.2912V13.8211C128.034 13.7106 128.123 13.6211 128.234 13.6211H130.363C130.473 13.6211 130.563 13.7106 130.563 13.8211V16.2912Z" fill="#2845C1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M56.8209 27.7034C56.8716 27.8344 56.7749 27.9756 56.6344 27.9756H54.0801C53.9969 27.9756 53.9224 27.9241 53.893 27.8464L52.3355 23.7298C52.3061 23.652 52.2316 23.6006 52.1485 23.6006H45.6707C45.5876 23.6006 45.5132 23.6519 45.4837 23.7296L43.9196 27.8466C43.8901 27.9243 43.8157 27.9756 43.7326 27.9756H41.2002C41.0598 27.9756 40.9631 27.8347 41.0136 27.7036L47.0107 12.1534C47.0404 12.0763 47.1146 12.0254 47.1973 12.0254H50.6144C50.697 12.0254 50.7711 12.0762 50.8009 12.1532L56.8209 27.7034ZM46.5361 20.9604C46.4864 21.0913 46.5831 21.2314 46.7231 21.2314H51.1006C51.2405 21.2314 51.3372 21.0915 51.2876 20.9606L49.1032 15.1895C49.038 15.0173 48.7946 15.0172 48.7292 15.1892L46.5361 20.9604Z" fill="#2845C1"/>
|
||||
<path d="M80.1372 27.7756C80.1372 27.886 80.0477 27.9756 79.9372 27.9756H77.8314C77.7209 27.9756 77.6314 27.886 77.6314 27.7756V16.6912C77.6314 16.5808 77.7209 16.4912 77.8314 16.4912H79.9372C80.0477 16.4912 80.1372 16.5808 80.1372 16.6912V27.7756Z" fill="#2845C1"/>
|
||||
<path d="M120.009 16.0361C120.86 16.0361 121.619 16.2258 122.288 16.6055C122.971 16.9852 123.511 17.5477 123.906 18.292C124.301 19.0363 124.499 19.9708 124.499 21.0947V27.7756C124.499 27.886 124.409 27.9756 124.299 27.9756H122.169C122.059 27.9756 121.969 27.886 121.969 27.7756V21.1855C121.969 20.3046 121.741 19.6209 121.286 19.1348C120.83 18.6335 120.206 18.3828 119.417 18.3828C118.915 18.3829 118.475 18.4813 118.095 18.6787C117.715 18.861 117.389 19.0971 117.116 19.3857C116.919 19.6051 116.745 19.8331 116.592 20.0699C116.498 20.2162 116.455 20.3884 116.455 20.5624V27.7756C116.455 27.886 116.365 27.9756 116.255 27.9756H114.149C114.038 27.9756 113.949 27.886 113.949 27.7756V16.6912C113.949 16.5808 114.038 16.4912 114.149 16.4912H116.255C116.365 16.4912 116.455 16.5808 116.455 16.6912V17.2892C116.455 17.3794 116.566 17.4247 116.631 17.3628C117.008 17.0071 117.443 16.7088 117.936 16.4688C118.528 16.1802 119.219 16.0361 120.009 16.0361Z" fill="#2845C1"/>
|
||||
<path d="M78.9068 10.75C79.2105 10.75 79.484 10.8257 79.7271 10.9775C79.9853 11.1294 80.1831 11.3345 80.3198 11.5928C80.4717 11.8358 80.5474 12.1093 80.5474 12.4131C80.5474 12.7168 80.4716 12.9977 80.3198 13.2559C80.1831 13.5141 79.9853 13.7192 79.7271 13.8711C79.484 14.0078 79.2106 14.0762 78.9068 14.0762C78.603 14.0762 78.3222 14.0078 78.064 13.8711C77.8057 13.7192 77.6006 13.5141 77.4487 13.2559C77.2969 12.9977 77.2212 12.7168 77.2212 12.4131C77.2212 11.9574 77.3807 11.57 77.6997 11.251C78.0338 10.917 78.436 10.75 78.9068 10.75Z" fill="#2845C1"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_13367_3310" x1="20" y1="27" x2="20" y2="36" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#C83F49"/>
|
||||
<stop offset="1" stop-color="#EEF1F4"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,28 @@
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
|
||||
interface ScoreMessageParams {
|
||||
conversationId: string;
|
||||
message_id: string;
|
||||
value: 'positive' | 'negative';
|
||||
}
|
||||
|
||||
export const scoreMessage = async ({
|
||||
conversationId,
|
||||
message_id,
|
||||
value,
|
||||
}: ScoreMessageParams): Promise<void> => {
|
||||
const response = await fetchAPI(`chats/${conversationId}/score-message/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
message_id,
|
||||
value,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
'Failed to score the message',
|
||||
await errorCauses(response),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
useLLMConfiguration,
|
||||
} from '@/features/chat/api/useLLMConfiguration';
|
||||
import { AttachmentList } from '@/features/chat/components/AttachmentList';
|
||||
import { FeedbackButtons } from '@/features/chat/components/FeedbackButtons';
|
||||
import { InputChat } from '@/features/chat/components/InputChat';
|
||||
import { SourceItemList } from '@/features/chat/components/SourceItemList';
|
||||
import { ToolInvocationItem } from '@/features/chat/components/ToolInvocationItem';
|
||||
@@ -559,7 +560,10 @@ export const Chat = ({
|
||||
${shouldApplyStreamingHeight ? `min-height: ${streamingMessageHeight + 70}px;` : ''}
|
||||
`}
|
||||
>
|
||||
<Box $display="block">
|
||||
<Box
|
||||
$display="block"
|
||||
$width={`${message.role === 'user' ? 'auto' : '100%'}`}
|
||||
>
|
||||
{message.experimental_attachments &&
|
||||
message.experimental_attachments.length > 0 && (
|
||||
<Box>
|
||||
@@ -571,6 +575,7 @@ export const Chat = ({
|
||||
)}
|
||||
<Box
|
||||
$radius="8px"
|
||||
$width={`${message.role === 'user' ? 'auto' : '100%'}`}
|
||||
$maxWidth="100%"
|
||||
$padding={`${message.role === 'user' ? '12px' : '0'}`}
|
||||
$margin={{ vertical: 'base' }}
|
||||
@@ -638,6 +643,7 @@ export const Chat = ({
|
||||
$css="color: #222631; font-size: 12px;"
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$justify="space-between"
|
||||
$gap="6px"
|
||||
$margin={{ top: 'base' }}
|
||||
>
|
||||
@@ -713,6 +719,17 @@ export const Chat = ({
|
||||
</Box>
|
||||
);
|
||||
})()}
|
||||
<Box $direction="row" $gap="4px">
|
||||
{/* We should display the button, but disabled if no trace linked */}
|
||||
{conversationId &&
|
||||
message.id &&
|
||||
message.id.startsWith('trace-') && (
|
||||
<FeedbackButtons
|
||||
conversationId={conversationId}
|
||||
messageId={message.id}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{message.parts && isSourceOpen === message.id && (
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useToast } from '@/components';
|
||||
import { scoreMessage } from '@/features/chat/api/useScoreMessage';
|
||||
|
||||
interface FeedbackButtonsProps {
|
||||
conversationId: string | undefined;
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
const ThumbUp = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M6.98683 2.2102C7.63449 1.13117 9.1595 1.02836 9.94591 2.01088C10.3165 2.47409 10.4362 3.09014 10.2658 3.65838L9.61836 5.81531H12.5963C13.9605 5.81547 14.9515 7.11253 14.5929 8.42873L13.2304 13.4242C12.9849 14.3246 12.167 14.9496 11.2338 14.9497H4.48701C4.48261 14.9498 4.4782 14.9504 4.47377 14.9504C4.46935 14.9504 4.46494 14.9498 4.46053 14.9497H2.40395C1.81297 14.9496 1.3336 14.4703 1.3335 13.8793V6.88577C1.33364 6.29479 1.81297 5.81546 2.40395 5.81531H4.37899C4.65463 5.81531 4.91031 5.67038 5.05221 5.4341L6.98683 2.2102ZM8.94306 2.81372C8.71594 2.53004 8.27512 2.55927 8.08795 2.87087L6.15402 6.09478C5.91175 6.49857 5.54322 6.80023 5.11632 6.96312V13.6653H11.2338C11.5877 13.6652 11.8975 13.4277 11.9906 13.0862L13.3531 8.09073C13.4889 7.59167 13.1136 7.09987 12.5963 7.09972H9.33123C8.61423 7.09972 8.1 6.40809 8.30608 5.72123L9.03505 3.28971C9.08409 3.12575 9.04993 2.94742 8.94306 2.81372ZM2.6186 7.09972V13.6653H3.83122V7.09972H2.6186Z"
|
||||
fill="#555E74"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const ThumbDown = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="14"
|
||||
height="13"
|
||||
viewBox="0 0 14 13"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10.2337 0C11.1669 7.56911e-05 11.9848 0.581603 12.2304 1.41911L13.5928 6.06606C13.9516 7.29054 12.9605 8.49766 11.5962 8.4978H8.61901L9.26573 10.5036C9.43623 11.0323 9.31647 11.6052 8.94585 12.0362C8.15943 12.9505 6.63442 12.8547 5.98679 11.8508L4.05218 8.85177C3.91028 8.63201 3.65459 8.4978 3.37897 8.4978H1.40394C0.812993 8.49766 0.333647 8.05181 0.333496 7.50203V0.995775C0.333647 0.44603 0.812973 0.000140027 1.40394 0H10.2337ZM4.1163 7.42877C4.54333 7.58028 4.91166 7.86149 5.15399 8.23719L7.0879 11.2362C7.27505 11.5263 7.71589 11.5535 7.94301 11.2893L7.97994 11.2414C8.05762 11.1242 8.07805 10.9809 8.035 10.8472L7.30604 8.58467C7.09997 7.9457 7.6142 7.30235 8.33118 7.30235H11.5962C12.1136 7.30221 12.4891 6.84482 12.353 6.38048L10.9906 1.73353C10.8975 1.41589 10.5876 1.19552 10.2337 1.19545H4.1163V7.42877ZM1.61859 7.30235H2.83121V1.19545H1.61859V7.30235Z"
|
||||
fill="#555E74"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const FeedbackButtons = ({
|
||||
conversationId,
|
||||
messageId,
|
||||
}: FeedbackButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { showToast } = useToast();
|
||||
|
||||
const handleScore = async (value: 'positive' | 'negative') => {
|
||||
if (!conversationId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await scoreMessage({
|
||||
conversationId,
|
||||
message_id: messageId,
|
||||
value,
|
||||
});
|
||||
|
||||
showToast(
|
||||
'success',
|
||||
value === 'positive'
|
||||
? t('Positive feedback sent')
|
||||
: t('Negative feedback sent'),
|
||||
'check_circle',
|
||||
3000,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error sending feedback:', error);
|
||||
showToast('error', t('Failed to send feedback'), 'error', 3000);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => {
|
||||
void handleScore('positive');
|
||||
}}
|
||||
aria-label={t('Feedback positif')}
|
||||
icon={<ThumbUp />}
|
||||
className="c__button--neutral c__button--neutral--icon action-chat-button"
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => {
|
||||
void handleScore('negative');
|
||||
}}
|
||||
aria-label={t('Feedback Négatif')}
|
||||
icon={<ThumbDown />}
|
||||
className="c__button--neutral c__button--neutral--icon action-chat-button"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -92,6 +92,10 @@ nextjs-portal {
|
||||
}
|
||||
}
|
||||
|
||||
.c__button--neutral.c__button--neutral--icon {
|
||||
padding-right: 4px !important;
|
||||
}
|
||||
|
||||
.c__button--neutral.research-web-button,
|
||||
.c__button--neutral.attach-file-button {
|
||||
padding: 9px !important;
|
||||
|
||||
Reference in New Issue
Block a user