import os import logging from pathlib import Path from datetime import datetime import traceback # Налаштування логування logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("jira_assistant.log"), logging.StreamHandler() ] ) logger = logging.getLogger("jira_assistant") # Створення необхідних директорій for directory in ["data", "reports", "temp", "logs"]: Path(directory).mkdir(exist_ok=True, parents=True) # Імпорт необхідних модулів from modules.data_import.csv_importer import JiraCsvImporter from modules.data_analysis.statistics import JiraDataAnalyzer from modules.data_analysis.visualizations import JiraVisualizer from modules.reporting.report_generator import ReportGenerator from modules.core.app_manager import AppManager class JiraAssistantApp: """ Головний клас додатку, який координує роботу всіх компонентів """ def __init__(self): self.app_manager = AppManager() self.current_data = None self.current_analysis = None self.visualizations = None def analyze_csv_file(self, file_path, inactive_days=14, include_ai=False, api_key=None, model_type="openai"): """ Аналіз CSV-файлу Jira Args: file_path (str): Шлях до CSV-файлу inactive_days (int): Кількість днів для визначення неактивних тікетів include_ai (bool): Чи використовувати AI-аналіз api_key (str): API ключ для LLM (якщо include_ai=True) model_type (str): Тип моделі LLM ("openai" або "gemini") Returns: dict: Результати аналізу """ try: logger.info(f"Аналіз файлу: {file_path}") # Завантаження даних csv_importer = JiraCsvImporter(file_path) self.current_data = csv_importer.load_data() if self.current_data is None: return {"error": "Не вдалося завантажити дані з CSV-файлу"} # Аналіз даних analyzer = JiraDataAnalyzer(self.current_data) # Базова статистика stats = analyzer.generate_basic_statistics() # Аналіз неактивних тікетів inactive_issues = analyzer.analyze_inactive_issues(days=inactive_days) # Створення візуалізацій visualizer = JiraVisualizer(self.current_data) self.visualizations = { "status": visualizer.plot_status_counts(), "priority": visualizer.plot_priority_counts(), "type": visualizer.plot_type_counts(), "created_timeline": visualizer.plot_created_timeline(), "inactive": visualizer.plot_inactive_issues(days=inactive_days) } # AI аналіз, якщо потрібен ai_analysis = None if include_ai and api_key: from modules.ai_analysis.llm_connector import LLMConnector llm = LLMConnector(api_key=api_key, model_type=model_type) ai_analysis = llm.analyze_jira_data(stats, inactive_issues) # Генерація звіту report_generator = ReportGenerator(self.current_data, stats, inactive_issues, ai_analysis) report = report_generator.create_markdown_report(inactive_days=inactive_days) # Зберігаємо поточний аналіз self.current_analysis = { "stats": stats, "inactive_issues": inactive_issues, "report": report, "ai_analysis": ai_analysis } return { "report": report, "visualizations": self.visualizations, "ai_analysis": ai_analysis, "error": None } except Exception as e: error_msg = f"Помилка аналізу: {str(e)}\n\n{traceback.format_exc()}" logger.error(error_msg) return {"error": error_msg} def save_report(self, format_type="markdown", include_visualizations=True, filepath=None): """ Збереження звіту у файл Args: format_type (str): Формат звіту ("markdown", "html", "pdf") include_visualizations (bool): Чи включати візуалізації у звіт filepath (str): Шлях для збереження файлу Returns: str: Шлях до збереженого файлу або повідомлення про помилку """ try: if not self.current_analysis or "report" not in self.current_analysis: return "Помилка: спочатку виконайте аналіз даних" # Створення імені файлу, якщо не вказано if not filepath: timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') report_filename = f"jira_report_{timestamp}" reports_dir = Path("reports") if format_type == "markdown": filepath = reports_dir / f"{report_filename}.md" elif format_type == "html": filepath = reports_dir / f"{report_filename}.html" elif format_type == "pdf": filepath = reports_dir / f"{report_filename}.pdf" # Створення генератора звітів report_generator = ReportGenerator( self.current_data, self.current_analysis.get("stats"), self.current_analysis.get("inactive_issues"), self.current_analysis.get("ai_analysis") ) # Збереження звіту saved_path = report_generator.save_report( filepath=filepath, format=format_type, include_visualizations=include_visualizations, visualization_data=self.visualizations if include_visualizations else None ) if saved_path: return f"Звіт успішно збережено: {saved_path}" else: return "Не вдалося зберегти звіт" except Exception as e: error_msg = f"Помилка при збереженні звіту: {str(e)}\n\n{traceback.format_exc()}" logger.error(error_msg) return error_msg def test_jira_connection(self, jira_url, username, api_token): """ Тестування підключення до Jira Args: jira_url (str): URL сервера Jira username (str): Ім'я користувача api_token (str): API токен Returns: bool: True якщо підключення успішне, False інакше """ from modules.data_import.jira_api import JiraConnector return JiraConnector.test_connection(jira_url, username, api_token) # Створення екземпляру додатку app = JiraAssistantApp() # Точка входу для запуску з командного рядка if __name__ == "__main__": from interface import launch_interface launch_interface(app)