|
|
import shutil |
|
|
from pathlib import Path |
|
|
|
|
|
import pytest |
|
|
from langchain_core.messages import AIMessage, HumanMessage |
|
|
from langchain_core.prompts.chat import ChatPromptTemplate |
|
|
from langflow.schema.message import Message |
|
|
from langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER |
|
|
from platformdirs import user_cache_dir |
|
|
|
|
|
|
|
|
@pytest.fixture |
|
|
def langflow_cache_dir(tmp_path): |
|
|
"""Create a temporary langflow cache directory.""" |
|
|
cache_dir = tmp_path / "langflow" |
|
|
cache_dir.mkdir(parents=True) |
|
|
return cache_dir |
|
|
|
|
|
|
|
|
@pytest.fixture |
|
|
def sample_image(langflow_cache_dir): |
|
|
"""Create a sample image file for testing.""" |
|
|
|
|
|
flow_dir = langflow_cache_dir / "test_flow" |
|
|
flow_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
|
|
|
image_path = flow_dir / "test_image.png" |
|
|
|
|
|
import base64 |
|
|
|
|
|
image_content = base64.b64decode( |
|
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==" |
|
|
) |
|
|
image_path.write_bytes(image_content) |
|
|
|
|
|
|
|
|
real_cache_dir = Path(user_cache_dir("langflow")) |
|
|
real_cache_dir.mkdir(parents=True, exist_ok=True) |
|
|
real_flow_dir = real_cache_dir / "test_flow" |
|
|
real_flow_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
|
|
|
real_image_path = real_flow_dir / "test_image.png" |
|
|
shutil.copy2(str(image_path), str(real_image_path)) |
|
|
|
|
|
return image_path |
|
|
|
|
|
|
|
|
def test_message_prompt_serialization(): |
|
|
template = "Hello, {name}!" |
|
|
message = Message.from_template(template, name="Langflow") |
|
|
assert message.text == "Hello, Langflow!" |
|
|
|
|
|
prompt = message.load_lc_prompt() |
|
|
assert isinstance(prompt, ChatPromptTemplate) |
|
|
assert prompt.messages[0].content == "Hello, Langflow!" |
|
|
|
|
|
|
|
|
def test_message_from_human_text(): |
|
|
"""Test creating a message from human text.""" |
|
|
text = "Hello, AI!" |
|
|
message = Message(text=text, sender=MESSAGE_SENDER_USER) |
|
|
lc_message = message.to_lc_message() |
|
|
|
|
|
assert isinstance(lc_message, HumanMessage) |
|
|
assert lc_message.content == text |
|
|
|
|
|
|
|
|
def test_message_from_ai_text(): |
|
|
"""Test creating a message from AI text.""" |
|
|
text = "Hello, Human!" |
|
|
message = Message(text=text, sender=MESSAGE_SENDER_AI) |
|
|
lc_message = message.to_lc_message() |
|
|
|
|
|
assert isinstance(lc_message, AIMessage) |
|
|
assert lc_message.content == text |
|
|
|
|
|
|
|
|
def test_message_with_single_image(sample_image): |
|
|
"""Test creating a message with text and an image.""" |
|
|
text = "Check out this image" |
|
|
|
|
|
file_path = f"test_flow/{sample_image.name}" |
|
|
message = Message(text=text, sender=MESSAGE_SENDER_USER, files=[file_path]) |
|
|
lc_message = message.to_lc_message() |
|
|
|
|
|
assert isinstance(lc_message, HumanMessage) |
|
|
assert isinstance(lc_message.content, list) |
|
|
assert len(lc_message.content) == 2 |
|
|
|
|
|
|
|
|
assert lc_message.content[0] == {"type": "text", "text": text} |
|
|
|
|
|
|
|
|
assert lc_message.content[1]["type"] == "image_url" |
|
|
assert "url" in lc_message.content[1]["image_url"] |
|
|
assert lc_message.content[1]["image_url"]["url"].startswith("data:image/png;base64,") |
|
|
|
|
|
|
|
|
def test_message_with_multiple_images(sample_image, langflow_cache_dir): |
|
|
"""Test creating a message with multiple images.""" |
|
|
|
|
|
flow_dir = langflow_cache_dir / "test_flow" |
|
|
second_image = flow_dir / "second_image.png" |
|
|
shutil.copy2(str(sample_image), str(second_image)) |
|
|
|
|
|
|
|
|
real_cache_dir = Path(user_cache_dir("langflow")) / "test_flow" |
|
|
real_cache_dir.mkdir(parents=True, exist_ok=True) |
|
|
real_second_image = real_cache_dir / "second_image.png" |
|
|
shutil.copy2(str(sample_image), str(real_second_image)) |
|
|
|
|
|
text = "Multiple images" |
|
|
message = Message( |
|
|
text=text, |
|
|
sender=MESSAGE_SENDER_USER, |
|
|
files=[f"test_flow/{sample_image.name}", f"test_flow/{second_image.name}"], |
|
|
) |
|
|
lc_message = message.to_lc_message() |
|
|
|
|
|
assert isinstance(lc_message, HumanMessage) |
|
|
assert isinstance(lc_message.content, list) |
|
|
assert len(lc_message.content) == 3 |
|
|
|
|
|
|
|
|
assert lc_message.content[0] == {"type": "text", "text": text} |
|
|
|
|
|
|
|
|
assert all( |
|
|
content["type"] == "image_url" and content["image_url"]["url"].startswith("data:image/png;base64,") |
|
|
for content in lc_message.content[1:] |
|
|
) |
|
|
|
|
|
|
|
|
def test_message_with_invalid_image_path(): |
|
|
"""Test handling of invalid image path.""" |
|
|
file_path = "test_flow/non_existent.png" |
|
|
message = Message(text="Invalid image", sender=MESSAGE_SENDER_USER, files=[file_path]) |
|
|
|
|
|
with pytest.raises(FileNotFoundError): |
|
|
message.to_lc_message() |
|
|
|
|
|
|
|
|
def test_message_without_sender(): |
|
|
"""Test message creation without sender specification.""" |
|
|
|
|
|
message = Message(text="Test message") |
|
|
|
|
|
assert message.text == "Test message" |
|
|
assert message.sender is None |
|
|
|
|
|
|
|
|
def test_message_serialization(): |
|
|
"""Test message serialization to dict.""" |
|
|
message = Message(text="Test message", sender=MESSAGE_SENDER_USER) |
|
|
serialized = message.model_dump() |
|
|
|
|
|
assert serialized["text"] == "Test message" |
|
|
assert serialized["sender"] == MESSAGE_SENDER_USER |
|
|
|
|
|
|
|
|
def test_message_to_lc_without_sender(): |
|
|
"""Test converting a message without sender to langchain message.""" |
|
|
message = Message(text="Test message") |
|
|
|
|
|
lc_message = message.to_lc_message() |
|
|
assert isinstance(lc_message, HumanMessage) |
|
|
assert lc_message.content == "Test message" |
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(autouse=True) |
|
|
def cleanup(): |
|
|
yield |
|
|
|
|
|
cache_dir = Path(user_cache_dir("langflow")) |
|
|
if cache_dir.exists(): |
|
|
shutil.rmtree(str(cache_dir)) |
|
|
|