2023-04-07 23:05:08 +00:00
import logging
import os
import random
2023-04-12 12:39:54 +00:00
import re
2023-04-07 23:05:08 +00:00
import time
from logging import LogRecord
2023-04-12 12:39:54 +00:00
from colorama import Fore
2023-04-07 23:05:08 +00:00
from colorama import Style
import speak
from config import Config
from config import Singleton
cfg = Config ( )
2023-04-07 23:05:20 +00:00
'''
Logger that handle titles in different colors .
Outputs logs in console , activity . log , and errors . log
For console handler : simulates typing
'''
2023-04-07 23:05:08 +00:00
class Logger ( metaclass = Singleton ) :
def __init__ ( self ) :
# create log directory if it doesn't exist
log_dir = os . path . join ( ' .. ' , ' logs ' )
if not os . path . exists ( log_dir ) :
os . makedirs ( log_dir )
log_file = " activity.log "
error_file = " error.log "
console_formatter = AutoGptFormatter ( ' %(title_color)s %(message)s ' )
2023-04-12 12:39:54 +00:00
# Create a handler for console which simulate typing
self . typing_console_handler = TypingConsoleHandler ( )
self . typing_console_handler . setLevel ( logging . INFO )
self . typing_console_handler . setFormatter ( console_formatter )
# Create a handler for console without typing simulation
self . console_handler = ConsoleHandler ( )
self . console_handler . setLevel ( logging . DEBUG )
2023-04-07 23:05:08 +00:00
self . console_handler . setFormatter ( console_formatter )
# Info handler in activity.log
self . file_handler = logging . FileHandler ( os . path . join ( log_dir , log_file ) )
2023-04-12 17:27:49 +00:00
self . file_handler . setLevel ( logging . DEBUG )
2023-04-07 23:05:08 +00:00
info_formatter = AutoGptFormatter ( ' %(asctime)s %(levelname)s %(title)s %(message_no_color)s ' )
self . file_handler . setFormatter ( info_formatter )
# Error handler error.log
error_handler = logging . FileHandler ( os . path . join ( log_dir , error_file ) )
error_handler . setLevel ( logging . ERROR )
error_formatter = AutoGptFormatter (
' %(asctime)s %(levelname)s %(module)s : %(funcName)s : %(lineno)d %(title)s %(message_no_color)s ' )
error_handler . setFormatter ( error_formatter )
2023-04-12 12:39:54 +00:00
self . typing_logger = logging . getLogger ( ' TYPER ' )
self . typing_logger . addHandler ( self . typing_console_handler )
self . typing_logger . addHandler ( self . file_handler )
self . typing_logger . addHandler ( error_handler )
self . typing_logger . setLevel ( logging . DEBUG )
self . logger = logging . getLogger ( ' LOGGER ' )
2023-04-07 23:05:08 +00:00
self . logger . addHandler ( self . console_handler )
self . logger . addHandler ( self . file_handler )
self . logger . addHandler ( error_handler )
2023-04-12 12:39:54 +00:00
self . logger . setLevel ( logging . DEBUG )
2023-04-07 23:05:08 +00:00
2023-04-12 12:43:32 +00:00
def typewriter_log (
2023-04-07 23:05:08 +00:00
self ,
title = ' ' ,
title_color = ' ' ,
content = ' ' ,
speak_text = False ,
level = logging . INFO ) :
if speak_text and cfg . speak_mode :
speak . say_text ( f " { title } . { content } " )
if content :
if isinstance ( content , list ) :
content = " " . join ( content )
else :
content = " "
2023-04-12 12:39:54 +00:00
self . typing_logger . log ( level , content , extra = { ' title ' : title , ' color ' : title_color } )
def debug (
self ,
message ,
title = ' ' ,
title_color = ' ' ,
) :
2023-04-12 12:43:32 +00:00
self . _log ( title , title_color , message , logging . DEBUG )
2023-04-12 12:39:54 +00:00
def warn (
self ,
message ,
title = ' ' ,
title_color = ' ' ,
) :
2023-04-12 12:43:32 +00:00
self . _log ( title , title_color , message , logging . WARN )
2023-04-12 12:39:54 +00:00
def error (
self ,
title ,
message = ' '
) :
2023-04-12 12:43:32 +00:00
self . _log ( title , Fore . RED , message , logging . ERROR )
2023-04-12 12:39:54 +00:00
2023-04-12 12:43:32 +00:00
def _log (
2023-04-12 12:39:54 +00:00
self ,
title = ' ' ,
title_color = ' ' ,
message = ' ' ,
level = logging . INFO ) :
if message :
if isinstance ( message , list ) :
message = " " . join ( message )
self . logger . log ( level , message , extra = { ' title ' : title , ' color ' : title_color } )
2023-04-07 23:05:08 +00:00
def set_level ( self , level ) :
self . logger . setLevel ( level )
2023-04-12 12:39:54 +00:00
self . typing_logger . setLevel ( level )
2023-04-07 23:05:08 +00:00
2023-04-12 20:38:53 +00:00
def double_check ( self , additionalText = None ) :
if not additionalText :
additionalText = " Please ensure you ' ve setup and configured everything correctly. Read https://github.com/Torantulino/Auto-GPT#readme to double check. You can also create a github issue or join the discord and ask there! "
2023-04-07 23:05:08 +00:00
2023-04-12 20:38:53 +00:00
self . typewriter_log ( " DOUBLE CHECK CONFIGURATION " , Fore . YELLOW , additionalText )
2023-04-07 23:05:08 +00:00
2023-04-07 23:05:20 +00:00
'''
Output stream to console using simulated typing
'''
2023-04-07 23:05:08 +00:00
class TypingConsoleHandler ( logging . StreamHandler ) :
def emit ( self , record ) :
min_typing_speed = 0.05
max_typing_speed = 0.01
msg = self . format ( record )
try :
words = msg . split ( )
for i , word in enumerate ( words ) :
print ( word , end = " " , flush = True )
if i < len ( words ) - 1 :
print ( " " , end = " " , flush = True )
typing_speed = random . uniform ( min_typing_speed , max_typing_speed )
time . sleep ( typing_speed )
# type faster after each word
min_typing_speed = min_typing_speed * 0.95
max_typing_speed = max_typing_speed * 0.95
print ( )
except Exception :
self . handleError ( record )
2023-04-12 21:05:14 +00:00
2023-04-12 12:39:54 +00:00
class ConsoleHandler ( logging . StreamHandler ) :
def emit ( self , record ) :
msg = self . format ( record )
try :
print ( msg )
except Exception :
self . handleError ( record )
2023-04-07 23:05:08 +00:00
2023-04-12 20:12:25 +00:00
2023-04-07 23:05:08 +00:00
class AutoGptFormatter ( logging . Formatter ) :
2023-04-13 09:05:36 +00:00
"""
Allows to handle custom placeholders ' title_color ' and ' message_no_color ' .
To use this formatter , make sure to pass ' color ' , ' title ' as log extras .
"""
2023-04-07 23:05:08 +00:00
def format ( self , record : LogRecord ) - > str :
2023-04-12 12:39:54 +00:00
if ( hasattr ( record , ' color ' ) ) :
record . title_color = getattr ( record , ' color ' ) + getattr ( record , ' title ' ) + " " + Style . RESET_ALL
else :
record . title_color = getattr ( record , ' title ' )
2023-04-07 23:05:08 +00:00
if hasattr ( record , ' msg ' ) :
record . message_no_color = remove_color_codes ( getattr ( record , ' msg ' ) )
else :
record . message_no_color = ' '
return super ( ) . format ( record )
def remove_color_codes ( s : str ) - > str :
ansi_escape = re . compile ( r ' \ x1B(?:[@-Z \\ -_]| \ [[0-?]*[ -/]*[@-~]) ' )
return ansi_escape . sub ( ' ' , s )
logger = Logger ( )