Spaces:
Runtime error
Runtime error
робочий варіант AI Аналізу
Browse files- interface.py +5 -14
- modules/ai_analysis/llm_connector.py +77 -19
- requirements.txt +12 -9
interface.py
CHANGED
@@ -15,9 +15,10 @@ def launch_interface(app):
|
|
15 |
app: Екземпляр JiraAssistantApp
|
16 |
"""
|
17 |
# Функція для обробки завантаження та аналізу CSV
|
|
|
18 |
def analyze_csv(file_obj, inactive_days, include_ai):
|
19 |
if file_obj is None:
|
20 |
-
return "Помилка: файл не вибрано", None
|
21 |
|
22 |
try:
|
23 |
logger.info(f"Отримано файл: {file_obj.name}, тип: {type(file_obj)}")
|
@@ -54,13 +55,10 @@ def launch_interface(app):
|
|
54 |
pass
|
55 |
|
56 |
if result.get("error"):
|
57 |
-
return result.get("error"), None
|
58 |
|
59 |
return (
|
60 |
result.get("report", ""),
|
61 |
-
result.get("visualizations", {}).get("status"),
|
62 |
-
result.get("visualizations", {}).get("priority"),
|
63 |
-
result.get("visualizations", {}).get("created_timeline"),
|
64 |
result.get("ai_analysis", "AI аналіз буде доступний у наступних версіях додатку.")
|
65 |
)
|
66 |
|
@@ -68,7 +66,7 @@ def launch_interface(app):
|
|
68 |
import traceback
|
69 |
error_msg = f"Помилка аналізу: {str(e)}\n\n{traceback.format_exc()}"
|
70 |
logger.error(error_msg)
|
71 |
-
return error_msg, None
|
72 |
|
73 |
# Функція для збереження звіту
|
74 |
def save_report_handler(report_text, format_type, include_visualizations):
|
@@ -235,13 +233,6 @@ def launch_interface(app):
|
|
235 |
with gr.Tab("Звіт"):
|
236 |
report_output = gr.Markdown()
|
237 |
|
238 |
-
with gr.Tab("Візуалізації"):
|
239 |
-
with gr.Row():
|
240 |
-
status_plot = gr.Plot(label="Статуси тікетів")
|
241 |
-
priority_plot = gr.Plot(label="Пріоритети тікетів")
|
242 |
-
|
243 |
-
timeline_plot = gr.Plot(label="Часова шкала")
|
244 |
-
|
245 |
with gr.Tab("AI Аналіз"):
|
246 |
ai_output = gr.Markdown()
|
247 |
|
@@ -249,7 +240,7 @@ def launch_interface(app):
|
|
249 |
analyze_btn.click(
|
250 |
analyze_csv,
|
251 |
inputs=[file_input, inactive_days, include_ai],
|
252 |
-
outputs=[report_output,
|
253 |
)
|
254 |
|
255 |
save_btn.click(
|
|
|
15 |
app: Екземпляр JiraAssistantApp
|
16 |
"""
|
17 |
# Функція для обробки завантаження та аналізу CSV
|
18 |
+
# Змініть функцію analyze_csv, щоб вона повертала тільки звіт та AI аналіз
|
19 |
def analyze_csv(file_obj, inactive_days, include_ai):
|
20 |
if file_obj is None:
|
21 |
+
return "Помилка: файл не вибрано", None
|
22 |
|
23 |
try:
|
24 |
logger.info(f"Отримано файл: {file_obj.name}, тип: {type(file_obj)}")
|
|
|
55 |
pass
|
56 |
|
57 |
if result.get("error"):
|
58 |
+
return result.get("error"), None
|
59 |
|
60 |
return (
|
61 |
result.get("report", ""),
|
|
|
|
|
|
|
62 |
result.get("ai_analysis", "AI аналіз буде доступний у наступних версіях додатку.")
|
63 |
)
|
64 |
|
|
|
66 |
import traceback
|
67 |
error_msg = f"Помилка аналізу: {str(e)}\n\n{traceback.format_exc()}"
|
68 |
logger.error(error_msg)
|
69 |
+
return error_msg, None
|
70 |
|
71 |
# Функція для збереження звіту
|
72 |
def save_report_handler(report_text, format_type, include_visualizations):
|
|
|
233 |
with gr.Tab("Звіт"):
|
234 |
report_output = gr.Markdown()
|
235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
with gr.Tab("AI Аналіз"):
|
237 |
ai_output = gr.Markdown()
|
238 |
|
|
|
240 |
analyze_btn.click(
|
241 |
analyze_csv,
|
242 |
inputs=[file_input, inactive_days, include_ai],
|
243 |
+
outputs=[report_output, ai_output]
|
244 |
)
|
245 |
|
246 |
save_btn.click(
|
modules/ai_analysis/llm_connector.py
CHANGED
@@ -18,7 +18,7 @@ class LLMConnector:
|
|
18 |
|
19 |
Args:
|
20 |
api_key (str): API ключ для доступу до LLM.
|
21 |
-
|
22 |
model_type (str): Тип моделі ("openai" або "gemini")
|
23 |
"""
|
24 |
self.model_type = model_type.lower()
|
@@ -29,8 +29,12 @@ class LLMConnector:
|
|
29 |
if not self.api_key:
|
30 |
logger.warning("API ключ OpenAI не вказано")
|
31 |
|
32 |
-
self.model = "gpt-
|
33 |
-
|
|
|
|
|
|
|
|
|
34 |
|
35 |
elif self.model_type == "gemini":
|
36 |
self.api_key = api_key or os.getenv("GEMINI_API_KEY")
|
@@ -38,7 +42,7 @@ class LLMConnector:
|
|
38 |
if not self.api_key:
|
39 |
logger.warning("API ключ Gemini не вказано")
|
40 |
|
41 |
-
self.model = "gemini-
|
42 |
|
43 |
else:
|
44 |
raise ValueError(f"Непідтримуваний тип моделі: {model_type}")
|
@@ -150,18 +154,26 @@ class LLMConnector:
|
|
150 |
if not self.api_key:
|
151 |
return "Не вказано API ключ OpenAI"
|
152 |
|
153 |
-
# Створення запиту до LLM
|
154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
model=self.model,
|
156 |
-
messages=
|
157 |
-
{"role": "system", "content": """Ви аналітик Jira з досвідом у процесах розробки ПЗ.
|
158 |
-
Проаналізуйте надані дані про тікети та надайте корисні інсайти та рекомендації
|
159 |
-
для покращення процесу. Будьте конкретними та орієнтованими на дії.
|
160 |
-
Виділіть сильні та слабкі сторони, а також потенційні ризики та можливості.
|
161 |
-
Аналіз повинен бути структурованим і легким для сприйняття менеджерами проекту."""},
|
162 |
-
{"role": "user", "content": f"Проаналізуйте наступні дані Jira та надайте рекомендації:\n\n{data_summary}"}
|
163 |
-
],
|
164 |
temperature=temperature,
|
|
|
165 |
)
|
166 |
|
167 |
# Отримання результату
|
@@ -271,7 +283,7 @@ class LLMConnector:
|
|
271 |
messages.append({"role": "user", "content": question})
|
272 |
|
273 |
# Відправлення запиту
|
274 |
-
response =
|
275 |
model=self.model,
|
276 |
messages=messages,
|
277 |
temperature=temperature,
|
@@ -314,7 +326,7 @@ class LLMConnector:
|
|
314 |
else:
|
315 |
format_instruction = "Створіть звіт у простому текстовому форматі."
|
316 |
|
317 |
-
response =
|
318 |
model=self.model,
|
319 |
messages=[
|
320 |
{"role": "system", "content": f"""Ви аналітик, який створює професійні звіти на основі даних Jira.
|
@@ -443,7 +455,7 @@ class AIAgentManager:
|
|
443 |
|
444 |
# Відправлення запиту до LLM
|
445 |
if self.llm_connector.model_type == "openai":
|
446 |
-
response =
|
447 |
model=self.llm_connector.model,
|
448 |
messages=messages,
|
449 |
temperature=temperature,
|
@@ -456,8 +468,54 @@ class AIAgentManager:
|
|
456 |
return result
|
457 |
|
458 |
elif self.llm_connector.model_type == "gemini":
|
459 |
-
#
|
460 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
461 |
|
462 |
except Exception as e:
|
463 |
logger.error(f"Помилка при виконанні задачі агентом '{agent_name}': {e}")
|
|
|
18 |
|
19 |
Args:
|
20 |
api_key (str): API ключ для доступу до LLM.
|
21 |
+
Якщо None, спробує використати змінну середовища.
|
22 |
model_type (str): Тип моделі ("openai" або "gemini")
|
23 |
"""
|
24 |
self.model_type = model_type.lower()
|
|
|
29 |
if not self.api_key:
|
30 |
logger.warning("API ключ OpenAI не вказано")
|
31 |
|
32 |
+
self.model = "gpt-4o-mini" # Оновлено стандартну модель
|
33 |
+
|
34 |
+
# Використовуємо новий спосіб ініціалізації клієнта OpenAI
|
35 |
+
# без проксі та інших застарілих параметрів
|
36 |
+
from openai import OpenAI
|
37 |
+
self.client = OpenAI(api_key=self.api_key)
|
38 |
|
39 |
elif self.model_type == "gemini":
|
40 |
self.api_key = api_key or os.getenv("GEMINI_API_KEY")
|
|
|
42 |
if not self.api_key:
|
43 |
logger.warning("API ключ Gemini не вказано")
|
44 |
|
45 |
+
self.model = "gemini-2.0-flash" # Оновлена модель для Gemini
|
46 |
|
47 |
else:
|
48 |
raise ValueError(f"Непідтримуваний тип моделі: {model_type}")
|
|
|
154 |
if not self.api_key:
|
155 |
return "Не вказано API ключ OpenAI"
|
156 |
|
157 |
+
# Створення запиту до LLM з новим API
|
158 |
+
system_prompt = """Ви аналітик Jira з досвідом у процесах розробки ПЗ.
|
159 |
+
Проаналізуйте надані дані про тікети та надайте корисні інсайти та рекомендації
|
160 |
+
для покращення процесу. Будьте конкретними та орієнтованими на дії.
|
161 |
+
Виділіть сильні та слабкі сторони, а також потенційні ризики та можливості.
|
162 |
+
Аналіз повинен бути структурованим і легким для сприйняття менеджерами проекту."""
|
163 |
+
|
164 |
+
user_prompt = f"Проаналізуйте наступні дані Jira та надайте рекомендації:\n\n{data_summary}"
|
165 |
+
|
166 |
+
messages = [
|
167 |
+
{"role": "system", "content": system_prompt},
|
168 |
+
{"role": "user", "content": user_prompt}
|
169 |
+
]
|
170 |
+
|
171 |
+
# Надсилання запиту через новий клієнт OpenAI
|
172 |
+
response = self.client.chat.completions.create(
|
173 |
model=self.model,
|
174 |
+
messages=messages,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
temperature=temperature,
|
176 |
+
max_tokens=2048
|
177 |
)
|
178 |
|
179 |
# Отримання результату
|
|
|
283 |
messages.append({"role": "user", "content": question})
|
284 |
|
285 |
# Відправлення запиту
|
286 |
+
response = self.client.chat.completions.create(
|
287 |
model=self.model,
|
288 |
messages=messages,
|
289 |
temperature=temperature,
|
|
|
326 |
else:
|
327 |
format_instruction = "Створіть звіт у простому текстовому форматі."
|
328 |
|
329 |
+
response = self.client.chat.completions.create(
|
330 |
model=self.model,
|
331 |
messages=[
|
332 |
{"role": "system", "content": f"""Ви аналітик, який створює професійні звіти на основі даних Jira.
|
|
|
455 |
|
456 |
# Відправлення запиту до LLM
|
457 |
if self.llm_connector.model_type == "openai":
|
458 |
+
response = self.llm_connector.client.chat.completions.create(
|
459 |
model=self.llm_connector.model,
|
460 |
messages=messages,
|
461 |
temperature=temperature,
|
|
|
468 |
return result
|
469 |
|
470 |
elif self.llm_connector.model_type == "gemini":
|
471 |
+
# Реалізуємо запит до Gemini API через прямий HTTP запит
|
472 |
+
url = f"https://generativelanguage.googleapis.com/v1beta/models/{self.llm_connector.model}:generateContent?key={self.llm_connector.api_key}"
|
473 |
+
|
474 |
+
# Формування системного промпта та запиту користувача
|
475 |
+
system_prompt = agent["system_prompt"]
|
476 |
+
user_content = ""
|
477 |
+
|
478 |
+
if context:
|
479 |
+
user_content += f"Контекст: {context}\n\n"
|
480 |
+
|
481 |
+
user_content += task
|
482 |
+
|
483 |
+
# Формування повного запиту
|
484 |
+
payload = {
|
485 |
+
"contents": [
|
486 |
+
{
|
487 |
+
"parts": [
|
488 |
+
{
|
489 |
+
"text": f"{system_prompt}\n\n{user_content}"
|
490 |
+
}
|
491 |
+
]
|
492 |
+
}
|
493 |
+
],
|
494 |
+
"generationConfig": {
|
495 |
+
"temperature": temperature,
|
496 |
+
"maxOutputTokens": 2048
|
497 |
+
}
|
498 |
+
}
|
499 |
+
|
500 |
+
# Відправлення запиту
|
501 |
+
headers = {"Content-Type": "application/json"}
|
502 |
+
response = requests.post(url, headers=headers, json=payload)
|
503 |
+
|
504 |
+
# Обробка відповіді
|
505 |
+
if response.status_code == 200:
|
506 |
+
response_data = response.json()
|
507 |
+
|
508 |
+
# Отримання тексту відповіді
|
509 |
+
if 'candidates' in response_data and len(response_data['candidates']) > 0:
|
510 |
+
if 'content' in response_data['candidates'][0]:
|
511 |
+
content = response_data['candidates'][0]['content']
|
512 |
+
if 'parts' in content and len(content['parts']) > 0:
|
513 |
+
result = content['parts'][0].get('text', '')
|
514 |
+
logger.info(f"Успішно отримано результат від агента '{agent_name}' (Gemini)")
|
515 |
+
return result
|
516 |
+
|
517 |
+
logger.error(f"Помилка при запиті до Gemini API: {response.text}")
|
518 |
+
return f"Помилка при запиті до Gemini API: статус {response.status_code}"
|
519 |
|
520 |
except Exception as e:
|
521 |
logger.error(f"Помилка при виконанні задачі агентом '{agent_name}': {e}")
|
requirements.txt
CHANGED
@@ -1,9 +1,12 @@
|
|
1 |
-
gradio
|
2 |
-
jira
|
3 |
-
pandas
|
4 |
-
numpy
|
5 |
-
matplotlib
|
6 |
-
seaborn
|
7 |
-
python-dotenv
|
8 |
-
markdown
|
9 |
-
pathlib
|
|
|
|
|
|
|
|
1 |
+
gradio>=5.19.0
|
2 |
+
jira>=3.5.2
|
3 |
+
pandas>=2.1.0
|
4 |
+
numpy>=1.26.0
|
5 |
+
matplotlib>=3.7.2
|
6 |
+
seaborn>=0.12.2
|
7 |
+
python-dotenv>=1.0.0
|
8 |
+
markdown>=3.4.4
|
9 |
+
pathlib>=1.0.1
|
10 |
+
google-generativeai>=0.3.2
|
11 |
+
openai>=1.12.0
|
12 |
+
httpx>=0.27.0
|