123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
"""
|
|
Simple debug logger for AI prompts and responses.
|
|
Writes files chronologically to gateway/test-chat/ai/ with sequential numbering.
|
|
"""
|
|
import os
|
|
import json
|
|
from datetime import datetime, UTC
|
|
from typing import Any, Optional
|
|
|
|
|
|
def _getDebugDir() -> str:
|
|
"""Get the debug directory path."""
|
|
gatewayDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
return os.path.join(gatewayDir, 'test-chat', 'ai')
|
|
|
|
|
|
def _getNextSequenceNumber() -> int:
|
|
"""Get the next sequence number by counting existing files."""
|
|
debugDir = _getDebugDir()
|
|
if not os.path.exists(debugDir):
|
|
return 1
|
|
|
|
# Count existing numbered files
|
|
files = [f for f in os.listdir(debugDir) if f.startswith(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'))]
|
|
return len(files) + 1
|
|
|
|
|
|
def _formatJsonReadable(data: Any) -> str:
|
|
"""
|
|
Format JSON data in a readable line-by-line structure.
|
|
Handles both structured objects and text representations of dicts/lists.
|
|
|
|
Args:
|
|
data: The data to format
|
|
|
|
Returns:
|
|
Formatted string representation
|
|
"""
|
|
try:
|
|
# First try to parse if it's a string representation
|
|
if isinstance(data, str):
|
|
try:
|
|
# Try to parse as JSON first
|
|
parsed = json.loads(data)
|
|
data = parsed
|
|
except json.JSONDecodeError:
|
|
# Try to evaluate as Python literal (for dict/list strings)
|
|
try:
|
|
import ast
|
|
parsed = ast.literal_eval(data)
|
|
if isinstance(parsed, (dict, list)):
|
|
data = parsed
|
|
except (ValueError, SyntaxError):
|
|
# If all parsing fails, treat as plain text
|
|
pass
|
|
|
|
# Convert to JSON string with proper indentation
|
|
if isinstance(data, (dict, list)):
|
|
jsonStr = json.dumps(data, ensure_ascii=False, default=str, indent=2)
|
|
else:
|
|
jsonStr = str(data)
|
|
|
|
# Split into lines and add line numbers for better readability
|
|
lines = jsonStr.split('\n')
|
|
formattedLines = []
|
|
|
|
for i, line in enumerate(lines, 1):
|
|
# Add line number and proper spacing
|
|
lineNum = f"{i:3d}: "
|
|
formattedLines.append(f"{lineNum}{line}")
|
|
|
|
return '\n'.join(formattedLines)
|
|
except Exception:
|
|
# Fallback to string representation if JSON formatting fails
|
|
return str(data)
|
|
|
|
|
|
def writeDebugFile(content: str, fileType: str, data: Optional[Any] = None) -> None:
|
|
"""
|
|
Write debug content to a file with sequential numbering.
|
|
|
|
Args:
|
|
content: The main content to write
|
|
fileType: Type of file (e.g., 'prompt', 'response', 'placeholders')
|
|
data: Optional additional data to include as JSON
|
|
"""
|
|
try:
|
|
debugDir = _getDebugDir()
|
|
os.makedirs(debugDir, exist_ok=True)
|
|
|
|
seqNum = _getNextSequenceNumber()
|
|
ts = datetime.now(UTC).strftime('%Y%m%d-%H%M%S')
|
|
# Add 3-digit sequence number for uniqueness
|
|
tsWithSeq = f"{ts}-{seqNum:03d}"
|
|
|
|
filename = f"{tsWithSeq}-{fileType}.txt"
|
|
filepath = os.path.join(debugDir, filename)
|
|
|
|
with open(filepath, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
# If structured data provided, also append a human-readable section to the main .txt
|
|
try:
|
|
if data is not None:
|
|
formatted = _formatJsonReadable(data)
|
|
with open(filepath, 'a', encoding='utf-8') as f:
|
|
f.write("\n\n=== FORMATTED DATA (human-readable) ===\n")
|
|
f.write(formatted)
|
|
f.write("\n")
|
|
except Exception:
|
|
pass
|
|
|
|
# If additional data provided, write it as a separate JSON file with readable formatting
|
|
if data is not None:
|
|
jsonFilename = f"{tsWithSeq}-{fileType}_data.json"
|
|
jsonFilepath = os.path.join(debugDir, jsonFilename)
|
|
with open(jsonFilepath, 'w', encoding='utf-8') as f:
|
|
formattedData = _formatJsonReadable(data)
|
|
f.write(formattedData)
|
|
|
|
except Exception as e:
|
|
# Silent fail - don't break the main flow
|
|
pass
|