Spaces:
Runtime error
Runtime error
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 protected]" | |
) | |
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) |