debug-parse12.js 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. const fs = require('fs');
  2. const content = fs.readFileSync('temp/rich-outline-fail_57_1779015509994.txt', 'utf-8');
  3. const marker = '========== AI 原始响应 ';
  4. const markerIdx = content.indexOf(marker);
  5. const headerEndIdx = content.indexOf(' ==========', markerIdx);
  6. const aiStart = content.indexOf('\n', headerEndIdx) + 1;
  7. const aiEnd = content.indexOf('\n\n', aiStart);
  8. const aiResponse = content.substring(aiStart, aiEnd);
  9. console.log('String length (UTF-16 code units):', aiResponse.length);
  10. // The issue: JSON.parse uses UTF-16 code unit positions, but the JSON is actually UTF-8 encoded
  11. // when transmitted over the network. The LLM returns UTF-8 bytes, but in Node.js when we get
  12. // the response as a string, it's decoded to UTF-16.
  13. // Wait - actually JSON.parse should work correctly with UTF-16 strings in JavaScript.
  14. // Let me check if there's actually a malformed character somewhere.
  15. // Try using a simple character-by-character JSON parser approach to find the issue
  16. const pos = 1624;
  17. console.log('\nAnalyzing around position', pos);
  18. // Get the actual bytes via TextEncoder
  19. const encoder = new TextEncoder();
  20. const decoder = new TextDecoder('utf-8');
  21. // Let's check the raw bytes of the string
  22. const uint8Array = encoder.encode(aiResponse);
  23. console.log('Encoded bytes length:', uint8Array.length);
  24. // Check bytes around position 1624 (in UTF-16 string)
  25. console.log('\nBytes around UTF-16 position', pos, ':');
  26. for (let i = Math.max(0, pos - 5); i < Math.min(uint8Array.length, pos + 10); i++) {
  27. console.log(' byte', i, ':', uint8Array[i], '(char:', String.fromCharCode(uint8Array[i]), ')');
  28. }
  29. // Now let's try to find where the actual byte-level position differs from UTF-16 position
  30. // by counting UTF-8 multi-byte characters before position 1624
  31. let utf8Offset = 0;
  32. let utf16Offset = 0;
  33. let lastAsciiBefore1624 = -1;
  34. let lastAsciiUtf8BytePos = -1;
  35. for (let i = 0; i < aiResponse.length && utf16Offset < 1624; i++) {
  36. const code = aiResponse.charCodeAt(i);
  37. if (code <= 0x7F) {
  38. // ASCII - 1 byte in UTF-8, 1 code unit in UTF-16
  39. if (utf16Offset === 1623) {
  40. lastAsciiBefore1624 = code;
  41. lastAsciiUtf8BytePos = utf8Offset;
  42. }
  43. utf8Offset += 1;
  44. utf16Offset += 1;
  45. } else if (code <= 0x7FF) {
  46. // 2-byte UTF-8
  47. utf8Offset += 2;
  48. utf16Offset += 1;
  49. } else if (code <= 0xFFFF) {
  50. // 3-byte UTF-8 (most CJK characters)
  51. utf8Offset += 3;
  52. utf16Offset += 1;
  53. } else {
  54. // 4-byte UTF-8 (emoji, etc)
  55. utf8Offset += 4;
  56. utf16Offset += 2;
  57. }
  58. }
  59. console.log('\nAt UTF-16 position 1624:');
  60. console.log(' Corresponding UTF-8 byte position would be around:', utf8Offset);
  61. console.log(' Last ASCII char (at UTF-16 1623):', lastAsciiBefore1624, '(code:', lastAsciiBefore1624, ')');
  62. // Now let's check what JSON.parse says the error position actually means
  63. // In JSON parse errors, "position" is the character offset in the string
  64. // Let's see if position 1624 in the string is actually where the issue is
  65. console.log('\n=== Direct parse attempt ===');
  66. try {
  67. JSON.parse(aiResponse);
  68. } catch(e) {
  69. console.log('Error:', e.message);
  70. const match = e.message.match(/position (\d+)/);
  71. if (match) {
  72. const errorPos = parseInt(match[1]);
  73. console.log('Error position:', errorPos);
  74. console.log('Character at error position:', JSON.stringify(aiResponse[errorPos]));
  75. console.log('Context:', JSON.stringify(aiResponse.substring(Math.max(0, errorPos-50), errorPos+50)));
  76. // Check if char at errorPos is the start of a multi-byte sequence
  77. const code = aiResponse.charCodeAt(errorPos);
  78. console.log('Code point at errorPos:', code, 'hex:', code.toString(16));
  79. }
  80. }