bug fixes

This commit is contained in:
2025-12-30 15:29:22 +01:00
parent f7e62df379
commit bea9c86fa2

158
oai.py
View File

@@ -30,7 +30,7 @@ from packaging import version as pkg_version
import io # Added for custom handler
# App version. Changes by author with new releases.
version = '1.9.5'
version = '1.9.6'
app = typer.Typer()
@@ -369,41 +369,132 @@ class RotatingRichHandler(RotatingFileHandler):
except Exception:
self.handleError(record)
# Get log configuration from DB
# ============================================================================
# LOGGING SETUP - MUST BE DONE AFTER CONFIG IS LOADED
# ============================================================================
# Load log configuration from DB FIRST (before creating handler)
LOG_MAX_SIZE_MB = int(get_config('log_max_size_mb') or "10")
LOG_BACKUP_COUNT = int(get_config('log_backup_count') or "2")
LOG_LEVEL_STR = get_config('log_level') or "info"
LOG_LEVEL = VALID_LOG_LEVELS.get(LOG_LEVEL_STR.lower(), logging.INFO)
# Create the custom rotating handler
app_handler = RotatingRichHandler(
filename=str(log_file),
maxBytes=LOG_MAX_SIZE_MB * 1024 * 1024, # Convert MB to bytes
backupCount=LOG_BACKUP_COUNT,
encoding='utf-8'
)
# Global reference to the handler for dynamic reloading
app_handler = None
app_logger = None
logging.basicConfig(
level=logging.NOTSET,
format="%(message)s", # Rich formats it
datefmt="[%X]",
handlers=[app_handler]
)
def setup_logging():
"""Setup or reset logging configuration with current settings."""
global app_handler, LOG_MAX_SIZE_MB, LOG_BACKUP_COUNT, LOG_LEVEL, app_logger
# Get the root logger
root_logger = logging.getLogger()
# Remove existing handler if present
if app_handler is not None:
root_logger.removeHandler(app_handler)
try:
app_handler.close()
except:
pass
# Check if log file needs immediate rotation
if os.path.exists(log_file):
current_size = os.path.getsize(log_file)
max_bytes = LOG_MAX_SIZE_MB * 1024 * 1024
if current_size >= max_bytes:
# Perform immediate rotation
import shutil
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
backup_file = f"{log_file}.{timestamp}"
try:
shutil.move(str(log_file), backup_file)
except Exception as e:
print(f"Warning: Could not rotate log file: {e}")
# Clean up old backups if exceeding limit
log_dir = os.path.dirname(log_file)
log_basename = os.path.basename(log_file)
backup_pattern = f"{log_basename}.*"
import glob
backups = sorted(glob.glob(os.path.join(log_dir, backup_pattern)))
# Keep only the most recent backups
while len(backups) > LOG_BACKUP_COUNT:
oldest = backups.pop(0)
try:
os.remove(oldest)
except:
pass
# Create new handler with current settings
app_handler = RotatingRichHandler(
filename=str(log_file),
maxBytes=LOG_MAX_SIZE_MB * 1024 * 1024,
backupCount=LOG_BACKUP_COUNT,
encoding='utf-8'
)
# Set handler level to NOTSET so it processes all records
app_handler.setLevel(logging.NOTSET)
# Configure root logger - set to WARNING to suppress third-party library noise
root_logger.setLevel(logging.WARNING)
root_logger.addHandler(app_handler)
# Suppress noisy third-party loggers
# These libraries create DEBUG logs that pollute our log file
logging.getLogger('asyncio').setLevel(logging.WARNING)
logging.getLogger('urllib3').setLevel(logging.WARNING)
logging.getLogger('requests').setLevel(logging.WARNING)
logging.getLogger('httpx').setLevel(logging.WARNING)
logging.getLogger('httpcore').setLevel(logging.WARNING)
logging.getLogger('openai').setLevel(logging.WARNING)
logging.getLogger('openrouter').setLevel(logging.WARNING)
# Get or create app logger and set its level (this filters what gets logged)
app_logger = logging.getLogger("oai_app")
app_logger.setLevel(LOG_LEVEL)
# Don't propagate to avoid root logger filtering
app_logger.propagate = True
return app_logger
app_logger = logging.getLogger("oai_app")
app_logger.setLevel(LOG_LEVEL)
# Initial logging setup
app_logger = setup_logging()
def set_log_level(level_str: str) -> bool:
"""Set the application log level. Returns True if successful."""
global LOG_LEVEL, LOG_LEVEL_STR
global LOG_LEVEL, LOG_LEVEL_STR, app_logger
level_str_lower = level_str.lower()
if level_str_lower not in VALID_LOG_LEVELS:
return False
LOG_LEVEL = VALID_LOG_LEVELS[level_str_lower]
LOG_LEVEL_STR = level_str_lower
app_logger.setLevel(LOG_LEVEL)
# Update the logger level immediately
if app_logger:
app_logger.setLevel(LOG_LEVEL)
return True
def reload_logging_config():
"""Reload logging configuration from database and reinitialize handler."""
global LOG_MAX_SIZE_MB, LOG_BACKUP_COUNT, LOG_LEVEL, LOG_LEVEL_STR, app_logger
# Reload from database
LOG_MAX_SIZE_MB = int(get_config('log_max_size_mb') or "10")
LOG_BACKUP_COUNT = int(get_config('log_backup_count') or "2")
LOG_LEVEL_STR = get_config('log_level') or "info"
LOG_LEVEL = VALID_LOG_LEVELS.get(LOG_LEVEL_STR.lower(), logging.INFO)
# Reinitialize logging
app_logger = setup_logging()
return app_logger
# ============================================================================
# END OF LOGGING SETUP
# ============================================================================
@@ -699,7 +790,7 @@ def show_command_help(command: str):
app_logger.info(f"Displayed detailed help for command: {command}")
# Load configs
# Load configs (AFTER logging is set up)
API_KEY = get_config('api_key')
OPENROUTER_BASE_URL = get_config('base_url') or "https://openrouter.ai/api/v1"
STREAM_ENABLED = get_config('stream_enabled') or "on"
@@ -909,7 +1000,7 @@ def display_paginated_table(table: Table, title: str):
@app.command()
def chat():
global API_KEY, OPENROUTER_BASE_URL, STREAM_ENABLED, MAX_TOKEN, COST_WARNING_THRESHOLD, DEFAULT_ONLINE_MODE, LOG_MAX_SIZE_MB, LOG_BACKUP_COUNT, LOG_LEVEL, LOG_LEVEL_STR
global API_KEY, OPENROUTER_BASE_URL, STREAM_ENABLED, MAX_TOKEN, COST_WARNING_THRESHOLD, DEFAULT_ONLINE_MODE, LOG_MAX_SIZE_MB, LOG_BACKUP_COUNT, LOG_LEVEL, LOG_LEVEL_STR, app_logger
session_max_token = 0
session_system_prompt = ""
session_history = []
@@ -1319,9 +1410,13 @@ def chat():
console.print("[bold yellow]Usage: /middleout on|off (or /middleout to view status)[/]")
continue
elif user_input.lower() == "/reset":
confirm = typer.confirm("Reset conversation context? This clears history and prompt.", default=False)
if not confirm:
console.print("[bold yellow]Reset cancelled.[/]")
try:
confirm = typer.confirm("Reset conversation context? This clears history and prompt.", default=False)
if not confirm:
console.print("[bold yellow]Reset cancelled.[/]")
continue
except (EOFError, KeyboardInterrupt):
console.print("\n[bold yellow]Reset cancelled.[/]")
continue
session_history = []
current_index = -1
@@ -1538,9 +1633,13 @@ def chat():
new_size_mb = 100
set_config('log_max_size_mb', str(new_size_mb))
LOG_MAX_SIZE_MB = new_size_mb
console.print(f"[bold green]Log size limit set to {new_size_mb} MB.[/]")
console.print("[bold yellow]⚠️ Restart the application for this change to take effect.[/]")
app_logger.info(f"Log size limit updated to {new_size_mb} MB (requires restart)")
# Reload logging configuration immediately
app_logger = reload_logging_config()
console.print(f"[bold green]Log size limit set to {new_size_mb} MB and applied immediately.[/]")
console.print(f"[dim cyan]Log file rotated if it exceeded the new limit.[/]")
app_logger.info(f"Log size limit updated to {new_size_mb} MB and reloaded")
except ValueError:
console.print("[bold red]Invalid size. Provide a number in MB.[/]")
elif args.startswith("online"):
@@ -1778,7 +1877,7 @@ def chat():
)
help_table.add_row(
"/config log [size_mb]",
"Set log file size limit in MB. Older logs are rotated automatically. Requires restart.",
"Set log file size limit in MB. Older logs are rotated automatically. Takes effect immediately.",
"/config log 20"
)
help_table.add_row(
@@ -1930,8 +2029,7 @@ def chat():
if not selected_model:
console.print("[bold yellow]Select a model first with '/model'.[/]")
continue
# Process file attachments with PDF support
# Process file attachments with PDF support
content_blocks = []
text_part = user_input
file_attachments = []