|
1 | 1 | require "test_helper" |
2 | 2 |
|
3 | 3 | class AIBackend::AnthropicTest < ActiveSupport::TestCase |
| 4 | + include ActionDispatch::TestProcess::FixtureFile |
4 | 5 | setup do |
5 | 6 | @conversation = conversations(:hello_claude) |
6 | 7 | @assistant = assistants(:keith_claude35) |
@@ -304,4 +305,128 @@ class AIBackend::AnthropicTest < ActiveSupport::TestCase |
304 | 305 | assert_equal "openmeteo_get_current_and_todays_weather", tool_calls.dig(0, :function, :name) |
305 | 306 | end |
306 | 307 | end |
| 308 | + |
| 309 | + test "preceding_conversation_messages processes PDF documents" do |
| 310 | + # Create a new conversation with a message that has a PDF document |
| 311 | + assistant = assistants(:keith_claude35) |
| 312 | + assistant.language_model.update!(supports_pdf: true) |
| 313 | + |
| 314 | + # Verify supports_pdf? works |
| 315 | + assert assistant.supports_pdf?, "Assistant should support PDF processing" |
| 316 | + |
| 317 | + conversation = Conversation.create!( |
| 318 | + user: users(:keith), |
| 319 | + assistant: assistant, |
| 320 | + title: "PDF Test Conversation" |
| 321 | + ) |
| 322 | + |
| 323 | + # Create a simple PDF file for testing |
| 324 | + pdf_content = "%PDF-1.4\n1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\n2 0 obj\n<<\n/Type /Pages\n/Kids [3 0 R]\n/Count 1\n>>\nendobj\n3 0 obj\n<<\n/Type /Page\n/Parent 2 0 R\n/MediaBox [0 0 612 792]\n/Contents 4 0 R\n>>\nendobj\n4 0 obj\n<<\n/Length 44\n>>\nstream\nBT\n/F1 12 Tf\n72 720 Td\n(Hello World) Tj\nET\nendstream\nendobj\nxref\n0 5\n0000000000 65535 f \n0000000009 00000 n \n0000000058 00000 n \n0000000115 00000 n \n0000000200 00000 n \ntrailer\n<<\n/Size 5\n/Root 1 0 R\n>>\nstartxref\n294\n%%EOF" |
| 325 | + |
| 326 | + # Create a temporary PDF file |
| 327 | + test_file = Tempfile.new(["test", ".pdf"]) |
| 328 | + test_file.write(pdf_content) |
| 329 | + test_file.rewind |
| 330 | + |
| 331 | + # Create a message with PDF attachment |
| 332 | + message = conversation.messages.create!( |
| 333 | + role: "user", |
| 334 | + content_text: "Please analyze this PDF", |
| 335 | + assistant: assistant |
| 336 | + ) |
| 337 | + |
| 338 | + # Attach the PDF file |
| 339 | + document = message.documents.create!( |
| 340 | + file: fixture_file_upload(test_file.path, "application/pdf"), |
| 341 | + filename: "test.pdf" |
| 342 | + ) |
| 343 | + |
| 344 | + # Verify the document was created and is a PDF |
| 345 | + assert document.has_document_pdf?, "Document should be identified as a PDF" |
| 346 | + |
| 347 | + # Create a second message to test with |
| 348 | + second_message = conversation.messages.create!( |
| 349 | + role: "assistant", |
| 350 | + content_text: "I'll analyze the PDF for you", |
| 351 | + assistant: assistant |
| 352 | + ) |
| 353 | + |
| 354 | + anthropic = AIBackend::Anthropic.new(users(:keith), assistant, conversation, second_message) |
| 355 | + messages = anthropic.send(:preceding_conversation_messages) |
| 356 | + |
| 357 | + |
| 358 | + # Find the message with PDF content |
| 359 | + pdf_message = messages.find { |m| m[:content].is_a?(Array) && m[:content].any? { |c| c[:text]&.include?("PDF Document: test.pdf") } } |
| 360 | + |
| 361 | + assert pdf_message, "Should find a message with PDF content. Messages: #{messages.inspect}" |
| 362 | + assert_equal "user", pdf_message[:role] |
| 363 | + |
| 364 | + # Check that the PDF content was processed (either successfully or with error message) |
| 365 | + pdf_content_part = pdf_message[:content].find { |c| c[:text]&.include?("PDF Document: test.pdf") } |
| 366 | + assert pdf_content_part, "Should find PDF content part" |
| 367 | + # The PDF extraction might fail with our test PDF, so we check for either success or error message |
| 368 | + assert pdf_content_part[:text].include?("PDF Document: test.pdf"), "Should include PDF document reference" |
| 369 | + # Since our test PDF is not valid, we expect the error message |
| 370 | + assert pdf_content_part[:text].include?("Unable to extract text from this PDF"), "Should include error message for failed PDF extraction" |
| 371 | + |
| 372 | + test_file.close |
| 373 | + test_file.unlink |
| 374 | + end |
| 375 | + |
| 376 | + test "preceding_conversation_messages handles PDF extraction errors gracefully" do |
| 377 | + # Create a new conversation with a message that has a corrupted PDF document |
| 378 | + assistant = assistants(:keith_claude35) |
| 379 | + assistant.language_model.update!(supports_pdf: true) |
| 380 | + |
| 381 | + conversation = Conversation.create!( |
| 382 | + user: users(:keith), |
| 383 | + assistant: assistant, |
| 384 | + title: "PDF Error Test Conversation" |
| 385 | + ) |
| 386 | + |
| 387 | + # Create a corrupted PDF file |
| 388 | + corrupted_pdf_content = "%PDF-1.4\ncorrupted content" |
| 389 | + |
| 390 | + # Create a temporary PDF file |
| 391 | + test_file = Tempfile.new(["test", ".pdf"]) |
| 392 | + test_file.write(corrupted_pdf_content) |
| 393 | + test_file.rewind |
| 394 | + |
| 395 | + # Create a message with corrupted PDF attachment |
| 396 | + message = conversation.messages.create!( |
| 397 | + role: "user", |
| 398 | + content_text: "Please analyze this PDF", |
| 399 | + assistant: assistant |
| 400 | + ) |
| 401 | + |
| 402 | + # Attach the corrupted PDF file |
| 403 | + message.documents.create!( |
| 404 | + file: fixture_file_upload(test_file.path, "application/pdf"), |
| 405 | + filename: "corrupted.pdf" |
| 406 | + ) |
| 407 | + |
| 408 | + # Create a second message to test with |
| 409 | + second_message = conversation.messages.create!( |
| 410 | + role: "assistant", |
| 411 | + content_text: "I'll try to analyze the PDF for you", |
| 412 | + assistant: assistant |
| 413 | + ) |
| 414 | + |
| 415 | + anthropic = AIBackend::Anthropic.new(users(:keith), assistant, conversation, second_message) |
| 416 | + messages = anthropic.send(:preceding_conversation_messages) |
| 417 | + |
| 418 | + # Find the message with PDF content |
| 419 | + pdf_message = messages.find { |m| m[:content].is_a?(Array) && m[:content].any? { |c| c[:text]&.include?("PDF Document: corrupted.pdf") } } |
| 420 | + |
| 421 | + assert pdf_message, "Should find a message with PDF content" |
| 422 | + assert_equal "user", pdf_message[:role] |
| 423 | + |
| 424 | + # Check that the error message was included |
| 425 | + pdf_content_part = pdf_message[:content].find { |c| c[:text]&.include?("PDF Document: corrupted.pdf") } |
| 426 | + assert pdf_content_part, "Should find PDF content part" |
| 427 | + assert_includes pdf_content_part[:text], "Unable to extract text from this PDF" |
| 428 | + |
| 429 | + test_file.close |
| 430 | + test_file.unlink |
| 431 | + end |
307 | 432 | end |
0 commit comments