import gradio as gr import os from pathlib import Path from datetime import datetime import matplotlib.pyplot as plt import logging logger = logging.getLogger("jira_assistant_interface") def launch_interface(app): """ Запуск інтерфейсу користувача Gradio Args: app: Екземпляр JiraAssistantApp """ # Функція для обробки завантаження та аналізу CSV def analyze_csv(file_obj, inactive_days, include_ai): if file_obj is None: return "Помилка: файл не вибрано", None, None, None, None try: logger.info(f"Отримано файл: {file_obj.name}, тип: {type(file_obj)}") # Створення тимчасового файлу temp_file_path = os.path.join("temp", f"temp_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv") # У Gradio 5.19.0 об'єкт файлу має різну структуру # file_obj може бути шляхом до файлу або містити атрибут 'name' if hasattr(file_obj, 'name'): source_path = file_obj.name # Копіювання файлу import shutil shutil.copy2(source_path, temp_file_path) else: # Якщо це не шлях до файлу, ймовірно це вже самі дані with open(temp_file_path, "w", encoding="utf-8") as f: f.write(str(file_obj)) # Аналіз даних api_key = os.getenv("OPENAI_API_KEY") if include_ai else None result = app.analyze_csv_file( temp_file_path, inactive_days=inactive_days, include_ai=include_ai, api_key=api_key ) # Видалення тимчасового файлу try: os.remove(temp_file_path) except: pass if result.get("error"): return result.get("error"), None, None, None, None return ( result.get("report", ""), result.get("visualizations", {}).get("status"), result.get("visualizations", {}).get("priority"), result.get("visualizations", {}).get("created_timeline"), result.get("ai_analysis", "AI аналіз буде доступний у наступних версіях додатку.") ) except Exception as e: import traceback error_msg = f"Помилка аналізу: {str(e)}\n\n{traceback.format_exc()}" logger.error(error_msg) return error_msg, None, None, None, None # Функція для збереження звіту def save_report_handler(report_text, format_type, include_visualizations): if not report_text: return "Помилка: спочатку виконайте аналіз даних" return app.save_report( format_type=format_type, include_visualizations=include_visualizations ) # Функція для тестування підключення до Jira def test_jira_connection_handler(url, username, api_token): if not url or not username or not api_token: return "Помилка: необхідно заповнити всі поля (URL, користувач, API токен)" success = app.test_jira_connection(url, username, api_token) if success: return "✅ Успішне підключення до Jira API" else: return "❌ Помилка підключення до Jira. Перевірте введені дані." # Створення інтерфейсу Gradio with gr.Blocks(title="Jira AI Assistant") as interface: gr.Markdown("# 🔍 Jira AI Assistant") with gr.Tabs(): with gr.Tab("CSV Аналіз"): with gr.Row(): with gr.Column(scale=1): file_input = gr.File(label="Завантажити CSV файл Jira") inactive_days = gr.Slider(minimum=1, maximum=90, value=14, step=1, label="Кількість днів для визначення неактивних тікетів") include_ai = gr.Checkbox(label="Включити AI аналіз", value=False) analyze_btn = gr.Button("Аналізувати", variant="primary") with gr.Accordion("Збереження звіту", open=False): format_type = gr.Dropdown( choices=["markdown", "html", "pdf"], value="markdown", label="Формат звіту" ) include_visualizations = gr.Checkbox( label="Включити візуалізації", value=True ) save_btn = gr.Button("Зберегти звіт") save_output = gr.Textbox(label="Статус збереження") with gr.Column(scale=2): with gr.Tabs(): with gr.Tab("Звіт"): report_output = gr.Markdown() with gr.Tab("Візуалізації"): with gr.Row(): status_plot = gr.Plot(label="Статуси тікетів") priority_plot = gr.Plot(label="Пріоритети тікетів") timeline_plot = gr.Plot(label="Часова шкала") with gr.Tab("AI Аналіз"): ai_output = gr.Markdown() # Встановлюємо обробники подій analyze_btn.click( analyze_csv, inputs=[file_input, inactive_days, include_ai], outputs=[report_output, status_plot, priority_plot, timeline_plot, ai_output] ) save_btn.click( save_report_handler, inputs=[report_output, format_type, include_visualizations], outputs=[save_output] ) with gr.Tab("Jira API"): gr.Markdown("## Підключення до Jira API") with gr.Row(): jira_url = gr.Textbox( label="Jira URL", placeholder="https://your-company.atlassian.net" ) jira_username = gr.Textbox( label="Ім'я користувача Jira", placeholder="email@example.com" ) jira_api_token = gr.Textbox( label="Jira API Token", type="password" ) test_connection_btn = gr.Button("Тестувати з'єднання") connection_status = gr.Textbox(label="Статус підключення") test_connection_btn.click( test_jira_connection_handler, inputs=[jira_url, jira_username, jira_api_token], outputs=[connection_status] ) gr.Markdown("## ⚠️ Ця функція буде доступна у наступних версіях") with gr.Tab("AI Асистенти"): gr.Markdown("## AI Асистенти для Jira") gr.Markdown("⚠️ Ця функція буде доступна у наступних версіях") with gr.Accordion("Зразок інтерфейсу"): question = gr.Textbox( label="Запитання", placeholder="Наприклад: Які тікети мають найвищий пріоритет?", lines=2 ) answer = gr.Markdown(label="Відповідь") with gr.Tab("Інтеграції"): gr.Markdown("## Інтеграції з зовнішніми системами") gr.Markdown("⚠️ Ця функція буде доступна у наступних версіях") with gr.Accordion("Slack інтеграція"): slack_channel = gr.Textbox( label="Slack канал", placeholder="#project-updates" ) slack_message = gr.Textbox( label="Повідомлення", placeholder="Тижневий звіт по проекту", lines=3 ) slack_send_btn = gr.Button("Надіслати у Slack", interactive=False) # Запуск інтерфейсу interface.launch() # Можливість запустити інтерфейс самостійно (для тестування) if __name__ == "__main__": import sys sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from app import JiraAssistantApp app_instance = JiraAssistantApp() launch_interface(app_instance)