medrax2 / experiments /inspect_logs.py
Adibvafa
Initial commit
eaca108
Raw
History Blame Contribute Delete
6.58 kB
from typing import Optional, List
import argparse
import json
import glob
from pathlib import Path
from datetime import datetime
def get_latest_log() -> str:
"""Find the most recently modified log file in the current directory.
Returns:
str: Path to the most recently modified log file
Raises:
FileNotFoundError: If no log files are found in the current directory
"""
logs = list(Path(".").glob("api_usage_*.json"))
if not logs:
raise FileNotFoundError("No log files found in the current directory.")
return str(max(logs, key=lambda p: p.stat().st_mtime))
def format_cost(entry: dict) -> str:
"""Format cost if available, otherwise return 'N/A'
Args:
entry: Log entry dictionary containing cost information
Returns:
str: Formatted cost string with $ and 4 decimal places, or 'N/A' if cost not found
"""
return f"${entry.get('cost', 'N/A'):.4f}" if "cost" in entry else "N/A"
def print_gpt4_entry(entry: dict) -> None:
"""Print entry for GPT-4 format
Args:
entry: Log entry dictionary in GPT-4 format containing model info, inputs and outputs
"""
print("\n=== Log Entry ===")
print(f"Model: {entry['model']}")
print(f"Case ID: {entry['case_id']}")
print(f"Question ID: {entry['question_id']}")
print("\n=== Model Input ===")
messages = entry["input"]["messages"]
print("System message:", messages[0]["content"])
user_content = messages[1]["content"]
print("\nUser prompt:", user_content[0]["text"])
print("\nImages provided:")
for content in user_content[1:]:
print(f" - {content['image_url']['url']}")
print("\n=== Model Output ===")
print(f"Answer: {entry['model_answer']}")
print(f"Correct: {entry['correct_answer']}")
print("\n=== Usage Stats ===")
print(f"Duration: {entry['duration']}s")
print(f"Cost: {format_cost(entry)}")
print(
f"Tokens: {entry['usage']['total_tokens']}",
f"(prompt: {entry['usage']['prompt_tokens']},",
f"completion: {entry['usage']['completion_tokens']})",
)
def print_llama_entry(entry: dict) -> None:
"""Print entry for Llama-3.2 format
Args:
entry: Log entry dictionary in Llama format containing model info, inputs and outputs
"""
print("\n=== Log Entry ===")
print(f"Model: {entry['model']}")
print(f"Case ID: {entry['case_id']}")
print(f"Question ID: {entry['question_id']}")
print("\n=== Model Input ===")
print(f"Question: {entry['input']['question_data']['question']}")
print("\nImages provided:")
for url in entry["input"]["image_urls"]:
print(f" - {url}")
if entry["input"]["image_captions"]:
print("\nImage captions:")
for caption in entry["input"]["image_captions"]:
if caption:
print(f" - {caption}")
print("\n=== Model Output ===")
print(f"Answer: {entry['model_answer']}")
print(f"Correct: {entry['correct_answer']}")
print("\n=== Usage Stats ===")
print(f"Duration: {entry['duration']}s")
if "usage" in entry:
print(
f"Tokens: {entry['usage']['total_tokens']}",
f"(prompt: {entry['usage']['prompt_tokens']},",
f"completion: {entry['usage']['completion_tokens']})",
)
def determine_model_type(entry: dict) -> str:
"""Determine the model type from the entry
Args:
entry: Log entry dictionary containing model information
Returns:
str: Model type - 'gpt4', 'llama', or 'unknown'
"""
model = entry.get("model", "").lower()
if "gpt-4" in model:
return "gpt4"
elif "llama" in model:
return "llama"
elif "chexagent" in model:
return "chexagent"
elif "medrax" in model:
return "medrax"
else:
return "unknown"
def print_log_entry(
log_file: Optional[str] = None,
num_entries: Optional[int] = None,
model_filter: Optional[str] = None,
) -> None:
"""Print log entries from the specified log file or the latest log file.
Args:
log_file: Path to the log file. If None, uses the latest log file.
num_entries: Number of entries to print. If None, prints all entries.
model_filter: Filter entries by model type ('gpt4' or 'llama'). If None, prints all.
"""
if log_file is None:
log_file = get_latest_log()
print(f"Using latest log file: {log_file}")
entries_printed = 0
total_entries = 0
filtered_entries = 0
with open(log_file, "r") as f:
for line in f:
if line.startswith("HTTP"):
continue
try:
total_entries += 1
entry = json.loads(line)
# Apply model filter if specified
model_type = determine_model_type(entry)
if model_filter and model_type != model_filter:
filtered_entries += 1
continue
if model_type == "gpt4":
print_gpt4_entry(entry)
elif model_type == "llama":
print_llama_entry(entry)
else:
print(f"Unknown model type in entry: {entry['model']}")
continue
print("=" * 50)
entries_printed += 1
if num_entries and entries_printed >= num_entries:
break
except (json.JSONDecodeError, KeyError) as e:
print(f"Error processing entry: {e}")
continue
print(f"\nSummary:")
print(f"Total entries: {total_entries}")
print(f"Entries printed: {entries_printed}")
if model_filter:
print(f"Entries filtered: {filtered_entries}")
def main() -> None:
"""Main entry point for the script"""
parser = argparse.ArgumentParser(
description="Parse and display log entries from API usage logs."
)
parser.add_argument("-l", "--log_file", nargs="?", help="Path to the log file (optional)")
parser.add_argument("-n", "--num_entries", type=int, help="Number of entries to display")
parser.add_argument(
"-m",
"--model",
choices=["gpt4", "llama"],
default="gpt4",
help="Model type to display (default: gpt4)",
)
args = parser.parse_args()
try:
print_log_entry(args.log_file, args.num_entries, args.model)
except FileNotFoundError as e:
print(f"Error: {e}")
exit(1)
if __name__ == "__main__":
main()