422 lines
18 KiB
Python
422 lines
18 KiB
Python
import os
|
|
import sys
|
|
import platform
|
|
import subprocess
|
|
import shutil
|
|
import time
|
|
import ssl
|
|
import tempfile
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
|
|
class Diagnostics:
|
|
|
|
FILENAME = 'report.txt'
|
|
|
|
def __init__(self):
|
|
self.errors = []
|
|
self.warnings = []
|
|
if os.path.exists(self.FILENAME):
|
|
os.remove(self.FILENAME)
|
|
|
|
def log(self, message):
|
|
print(message)
|
|
with open(self.FILENAME, 'a', encoding='utf-8') as f:
|
|
f.write(message + "\n")
|
|
|
|
def start(self):
|
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
self.log(f"Iniciando diagnósticos às {now}\n")
|
|
|
|
def end(self):
|
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
self.log(f"\n\nDiagnósticos concluídos às {now}\n")
|
|
print("\nEnvie estes diagnósticos para mim em ed@edwarddonner.com")
|
|
print(f"Copie e cole a saída acima em um e-mail ou anexe o arquivo {self.FILENAME} que foi criado neste diretório.")
|
|
|
|
|
|
def _log_error(self, message):
|
|
self.log(f"ERRO: {message}")
|
|
self.errors.append(message)
|
|
|
|
def _log_warning(self, message):
|
|
self.log(f"AVISO: {message}")
|
|
self.warnings.append(message)
|
|
|
|
def run(self):
|
|
self.start()
|
|
self._step1_system_info()
|
|
self._step2_check_files()
|
|
self._step3_git_repo()
|
|
self._step4_check_env_file()
|
|
self._step5_anaconda_check()
|
|
self._step6_virtualenv_check()
|
|
self._step7_network_connectivity()
|
|
self._step8_environment_variables()
|
|
self._step9_additional_diagnostics()
|
|
|
|
if self.warnings:
|
|
self.log("\n===== Avisos Encontrados =====")
|
|
self.log("Os avisos abaixo foram identificados. Eles podem não impedir a execução do programa, mas podem provocar comportamentos inesperados:")
|
|
for warning in self.warnings:
|
|
self.log(f"- {warning}")
|
|
|
|
if self.errors:
|
|
self.log("\n===== Erros Encontrados =====")
|
|
self.log("Os problemas críticos a seguir foram encontrados. Solucione-os antes de prosseguir:")
|
|
for error in self.errors:
|
|
self.log(f"- {error}")
|
|
|
|
if not self.errors and not self.warnings:
|
|
self.log("\n✅ Todos os diagnósticos foram concluídos com êxito!")
|
|
|
|
self.end()
|
|
|
|
def _step1_system_info(self):
|
|
self.log("===== Informações do Sistema =====")
|
|
try:
|
|
system = platform.system()
|
|
self.log(f"Sistema Operacional: {system}")
|
|
|
|
if system == "Windows":
|
|
release, version, csd, ptype = platform.win32_ver()
|
|
self.log(f"Release do Windows: {release}")
|
|
self.log(f"Versão do Windows: {version}")
|
|
elif system == "Darwin":
|
|
release, version, machine = platform.mac_ver()
|
|
self.log(f"Versão do macOS: {release}")
|
|
else:
|
|
self.log(f"Plataforma: {platform.platform()}")
|
|
|
|
self.log(f"Arquitetura: {platform.architecture()}")
|
|
self.log(f"Máquina: {platform.machine()}")
|
|
self.log(f"Processador: {platform.processor()}")
|
|
|
|
try:
|
|
import psutil
|
|
ram = psutil.virtual_memory()
|
|
total_ram_gb = ram.total / (1024 ** 3)
|
|
available_ram_gb = ram.available / (1024 ** 3)
|
|
self.log(f"RAM total: {total_ram_gb:.2f} GB")
|
|
self.log(f"RAM disponível: {available_ram_gb:.2f} GB")
|
|
|
|
if available_ram_gb < 2:
|
|
self._log_warning(f"RAM disponível baixa: {available_ram_gb:.2f} GB")
|
|
except ImportError:
|
|
self._log_warning("Módulo psutil não encontrado. Não foi possível determinar as informações de RAM.")
|
|
|
|
total, used, free = shutil.disk_usage(os.path.expanduser("~"))
|
|
free_gb = free / (1024 ** 3)
|
|
self.log(f"Espaço livre em disco: {free_gb:.2f} GB")
|
|
|
|
if free_gb < 5:
|
|
self._log_warning(f"Pouco espaço em disco: {free_gb:.2f} GB livres")
|
|
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação das informações do sistema: {e}")
|
|
|
|
def _step2_check_files(self):
|
|
self.log("\n===== Informações do Sistema de Arquivos =====")
|
|
try:
|
|
current_dir = os.getcwd()
|
|
self.log(f"Diretório atual: {current_dir}")
|
|
|
|
# Verifica permissões de escrita
|
|
test_file = Path(current_dir) / ".test_write_permission"
|
|
try:
|
|
test_file.touch(exist_ok=True)
|
|
test_file.unlink()
|
|
self.log("Permissão de escrita: OK")
|
|
except Exception as e:
|
|
self._log_error(f"Sem permissão de escrita no diretório atual: {e}")
|
|
|
|
self.log("\nArquivos no diretório atual:")
|
|
try:
|
|
for item in sorted(os.listdir(current_dir)):
|
|
self.log(f" - {item}")
|
|
except Exception as e:
|
|
self._log_error(f"Não é possível listar o conteúdo do diretório: {e}")
|
|
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação do sistema de arquivos: {e}")
|
|
|
|
def _step3_git_repo(self):
|
|
self.log("\n===== Informações do Repositório Git =====")
|
|
try:
|
|
result = subprocess.run(['git', 'rev-parse', '--show-toplevel'],
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
if result.returncode == 0:
|
|
git_root = result.stdout.strip()
|
|
self.log(f"Raiz do repositório Git: {git_root}")
|
|
|
|
result = subprocess.run(['git', 'rev-parse', 'HEAD'],
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
if result.returncode == 0:
|
|
self.log(f"Commit atual: {result.stdout.strip()}")
|
|
else:
|
|
self._log_warning(f"Não foi possível obter o commit atual: {result.stderr.strip()}")
|
|
|
|
result = subprocess.run(['git', 'remote', 'get-url', 'origin'],
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
if result.returncode == 0:
|
|
self.log(f"Remoto 'origin': {result.stdout.strip()}")
|
|
else:
|
|
self._log_warning("Remoto 'origin' não configurado")
|
|
else:
|
|
self._log_warning("Não é um repositório Git")
|
|
except FileNotFoundError:
|
|
self._log_warning("Git não está instalado ou não está no PATH")
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação do Git: {e}")
|
|
|
|
def _step4_check_env_file(self):
|
|
self.log("\n===== Verificação do Arquivo .env =====")
|
|
try:
|
|
result = subprocess.run(['git', 'rev-parse', '--show-toplevel'],
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
if result.returncode == 0:
|
|
git_root = result.stdout.strip()
|
|
env_path = os.path.join(git_root, '.env')
|
|
|
|
if os.path.isfile(env_path):
|
|
self.log(f"Arquivo .env localizado em: {env_path}")
|
|
try:
|
|
with open(env_path, 'r') as f:
|
|
has_api_key = any(line.strip().startswith('OPENAI_API_KEY=') for line in f)
|
|
if has_api_key:
|
|
self.log("OPENAI_API_KEY encontrado no arquivo .env")
|
|
else:
|
|
self._log_warning("OPENAI_API_KEY não encontrado no arquivo .env")
|
|
except Exception as e:
|
|
self._log_error(f"Não é possível ler o arquivo .env: {e}")
|
|
else:
|
|
self._log_warning("Arquivo .env não encontrado na raiz do projeto")
|
|
|
|
# Verifica arquivos .env adicionais
|
|
for root, _, files in os.walk(git_root):
|
|
if '.env' in files and os.path.join(root, '.env') != env_path:
|
|
self._log_warning(f"Arquivo .env adicional encontrado em: {os.path.join(root, '.env')}")
|
|
else:
|
|
self._log_warning("Diretório raiz do Git não encontrado. Não é possível realizar a verificação do arquivo .env.")
|
|
except FileNotFoundError:
|
|
self._log_warning("Git não está instalado ou não está no PATH")
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação do arquivo .env: {e}")
|
|
|
|
def _step5_anaconda_check(self):
|
|
self.log("\n===== Verificação do Ambiente Anaconda =====")
|
|
try:
|
|
conda_prefix = os.environ.get('CONDA_PREFIX')
|
|
if conda_prefix:
|
|
self.log("Ambiente Anaconda ativo:")
|
|
self.log(f"Caminho do ambiente: {conda_prefix}")
|
|
self.log(f"Nome do ambiente: {os.path.basename(conda_prefix)}")
|
|
|
|
conda_exe = os.environ.get('CONDA_EXE', 'conda')
|
|
result = subprocess.run([conda_exe, '--version'],
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
if result.returncode == 0:
|
|
self.log(f"Versão do Conda: {result.stdout.strip()}")
|
|
else:
|
|
self._log_warning("Não foi possível determinar a versão do Conda")
|
|
|
|
self._check_python_packages()
|
|
else:
|
|
self.log("Nenhum ambiente Anaconda ativo detectado")
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação do ambiente Anaconda: {e}")
|
|
|
|
def _step6_virtualenv_check(self):
|
|
self.log("\n===== Verificação do Virtualenv =====")
|
|
try:
|
|
virtual_env = os.environ.get('VIRTUAL_ENV')
|
|
if virtual_env:
|
|
self.log("Virtualenv ativo:")
|
|
self.log(f"Caminho do ambiente: {virtual_env}")
|
|
self.log(f"Nome do ambiente: {os.path.basename(virtual_env)}")
|
|
|
|
self._check_python_packages()
|
|
else:
|
|
self.log("Nenhum virtualenv ativo detectado")
|
|
|
|
if not virtual_env and not os.environ.get('CONDA_PREFIX'):
|
|
self._log_warning("Nem virtualenv nem ambiente Anaconda estão ativos")
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação do virtualenv: {e}")
|
|
|
|
def _check_python_packages(self):
|
|
self.log("\nAmbiente Python:")
|
|
self.log(f"Versão do Python: {sys.version}")
|
|
self.log(f"Executável do Python: {sys.executable}")
|
|
|
|
required_packages = ['openai', 'python-dotenv', 'requests', 'gradio', 'transformers']
|
|
|
|
try:
|
|
import pkg_resources
|
|
installed = {pkg.key: pkg.version for pkg in pkg_resources.working_set}
|
|
|
|
self.log("\nVersões dos pacotes necessários:")
|
|
for package in required_packages:
|
|
if package in installed:
|
|
self.log(f"{package}: {installed[package]}")
|
|
else:
|
|
self._log_error(f"Pacote obrigatório '{package}' não está instalado")
|
|
|
|
# Verifica pacotes potencialmente conflitantes
|
|
problem_pairs = [
|
|
('openai', 'openai-python'),
|
|
('python-dotenv', 'dotenv')
|
|
]
|
|
|
|
for pkg1, pkg2 in problem_pairs:
|
|
if pkg1 in installed and pkg2 in installed:
|
|
self._log_warning(f"Pacotes potencialmente conflitantes: {pkg1} e {pkg2}")
|
|
except ImportError:
|
|
self._log_error("Não foi possível importar 'pkg_resources' para verificar os pacotes instalados")
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação de pacotes: {e}")
|
|
|
|
def _step7_network_connectivity(self):
|
|
self.log("\n===== Verificação da Conectividade de Rede =====")
|
|
try:
|
|
self.log(f"Versão do SSL: {ssl.OPENSSL_VERSION}")
|
|
|
|
import requests
|
|
import speedtest # Importa a biblioteca speedtest-cli
|
|
|
|
# Verificação básica de conectividade
|
|
urls = [
|
|
'https://www.google.com',
|
|
'https://www.cloudflare.com'
|
|
]
|
|
|
|
connected = False
|
|
for url in urls:
|
|
try:
|
|
start_time = time.time()
|
|
response = requests.get(url, timeout=10)
|
|
elapsed_time = time.time() - start_time
|
|
response.raise_for_status()
|
|
self.log(f"✅ Conectado a {url}")
|
|
self.log(f" Tempo de resposta: {elapsed_time:.2f}s")
|
|
|
|
if elapsed_time > 2:
|
|
self._log_warning(f"Resposta lenta de {url}: {elapsed_time:.2f}s")
|
|
connected = True
|
|
break
|
|
except requests.exceptions.RequestException as e:
|
|
self._log_warning(f"Falha ao conectar-se a {url}: {e}")
|
|
else:
|
|
self.log("Conectividade básica OK")
|
|
|
|
if not connected:
|
|
self._log_error("Falha ao conectar-se a qualquer URL de teste")
|
|
return
|
|
|
|
# Teste de largura de banda usando speedtest-cli
|
|
self.log("\nRealizando teste de largura de banda com speedtest-cli...")
|
|
try:
|
|
st = speedtest.Speedtest()
|
|
st.get_best_server()
|
|
download_speed = st.download() # Bits por segundo
|
|
upload_speed = st.upload() # Bits por segundo
|
|
|
|
download_mbps = download_speed / 1e6 # Converte para Mbps
|
|
upload_mbps = upload_speed / 1e6
|
|
|
|
self.log(f"Velocidade de download: {download_mbps:.2f} Mbps")
|
|
self.log(f"Velocidade de upload: {upload_mbps:.2f} Mbps")
|
|
|
|
if download_mbps < 1:
|
|
self._log_warning("Velocidade de download baixa")
|
|
if upload_mbps < 0.5:
|
|
self._log_warning("Velocidade de upload baixa")
|
|
except speedtest.ConfigRetrievalError:
|
|
self._log_error("Falha ao obter a configuração do speedtest")
|
|
except Exception as e:
|
|
self._log_warning(f"Falha no teste de largura de banda: {e}")
|
|
|
|
except ImportError:
|
|
self._log_error("Pacotes obrigatórios não estão instalados. Instale-os com 'pip install requests speedtest-cli'")
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação da conectividade de rede: {e}")
|
|
|
|
|
|
def _step8_environment_variables(self):
|
|
self.log("\n===== Verificação das Variáveis de Ambiente =====")
|
|
try:
|
|
# Verifica os caminhos do Python
|
|
pythonpath = os.environ.get('PYTHONPATH')
|
|
if pythonpath:
|
|
self.log("\nPYTHONPATH:")
|
|
for path in pythonpath.split(os.pathsep):
|
|
self.log(f" - {path}")
|
|
else:
|
|
self.log("\nPYTHONPATH não está definido.")
|
|
|
|
self.log("\nsys.path do Python:")
|
|
for path in sys.path:
|
|
self.log(f" - {path}")
|
|
|
|
# Verifica OPENAI_API_KEY
|
|
from dotenv import load_dotenv
|
|
load_dotenv()
|
|
api_key = os.environ.get('OPENAI_API_KEY')
|
|
if api_key:
|
|
self.log("OPENAI_API_KEY definido após chamar load_dotenv()")
|
|
if not api_key.startswith('sk-proj-') or len(api_key) < 12:
|
|
self._log_warning("Formato de OPENAI_API_KEY parece incorreto após chamar load_dotenv()")
|
|
else:
|
|
self._log_warning("Variável de ambiente OPENAI_API_KEY não está definida após chamar load_dotenv()")
|
|
except Exception as e:
|
|
self._log_error(f"Falha na verificação das variáveis de ambiente: {e}")
|
|
|
|
def _step9_additional_diagnostics(self):
|
|
self.log("\n===== Diagnósticos Adicionais =====")
|
|
try:
|
|
# Obtém os caminhos dos diretórios site-packages
|
|
import site
|
|
site_packages_paths = site.getsitepackages()
|
|
if hasattr(site, 'getusersitepackages'):
|
|
site_packages_paths.append(site.getusersitepackages())
|
|
|
|
# Função que verifica se um caminho está dentro de site-packages
|
|
def is_in_site_packages(path):
|
|
return any(os.path.commonpath([path, sp]) == sp for sp in site_packages_paths)
|
|
|
|
# Verifica possíveis conflitos de nome no diretório atual e no sys.path
|
|
conflict_names = ['openai.py', 'dotenv.py']
|
|
|
|
# Verifica o diretório atual
|
|
current_dir = os.getcwd()
|
|
for name in conflict_names:
|
|
conflict_path = os.path.join(current_dir, name)
|
|
if os.path.isfile(conflict_path):
|
|
self._log_warning(f"Encontrado '{name}' no diretório atual, o que pode causar conflitos de importação: {conflict_path}")
|
|
|
|
# Verifica os diretórios em sys.path
|
|
for path in sys.path:
|
|
if not path or is_in_site_packages(path):
|
|
continue # Ignora site-packages e caminhos vazios
|
|
for name in conflict_names:
|
|
conflict_file = os.path.join(path, name)
|
|
if os.path.isfile(conflict_file):
|
|
self._log_warning(f"Potencial conflito de nomenclatura: {conflict_file}")
|
|
|
|
# Verifica o diretório temporário
|
|
try:
|
|
with tempfile.NamedTemporaryFile() as tmp:
|
|
self.log(f"Diretório temporário é gravável: {os.path.dirname(tmp.name)}")
|
|
except Exception as e:
|
|
self._log_error(f"Não é possível gravar no diretório temporário: {e}")
|
|
|
|
except Exception as e:
|
|
self._log_error(f"Falha na execução dos diagnósticos adicionais: {e}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
diagnostics = Diagnostics()
|
|
diagnostics.run()
|
|
|