alita-sdk 0.3.117__py3-none-any.whl → 0.3.119__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- alita_sdk/community/analysis/jira_analyse/api_wrapper.py +18 -14
- alita_sdk/langchain/document_loaders/AlitaConfluenceLoader.py +58 -2
- alita_sdk/langchain/interfaces/loaders.py +1 -1
- alita_sdk/utils/logging.py +93 -0
- {alita_sdk-0.3.117.dist-info → alita_sdk-0.3.119.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.117.dist-info → alita_sdk-0.3.119.dist-info}/RECORD +9 -8
- {alita_sdk-0.3.117.dist-info → alita_sdk-0.3.119.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.117.dist-info → alita_sdk-0.3.119.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.117.dist-info → alita_sdk-0.3.119.dist-info}/top_level.txt +0 -0
@@ -15,7 +15,7 @@ from elitea_analyse.jira.jira_issues import JiraIssues
|
|
15
15
|
|
16
16
|
from alita_tools.elitea_base import BaseToolApiWrapper
|
17
17
|
from ....tools.artifact import ArtifactWrapper
|
18
|
-
|
18
|
+
from ....utils.logging import with_streamlit_logs
|
19
19
|
|
20
20
|
logger = logging.getLogger(__name__)
|
21
21
|
|
@@ -59,9 +59,21 @@ class JiraAnalyseWrapper(BaseToolApiWrapper):
|
|
59
59
|
Get projects a user has access to and merge them with issues count.
|
60
60
|
after_date: str
|
61
61
|
date after which issues are considered
|
62
|
+
project_keys: str
|
63
|
+
one or more projects keys separated with comma
|
62
64
|
"""
|
63
65
|
project_keys = project_keys or self.project_keys
|
64
66
|
|
67
|
+
dispatch_custom_event(
|
68
|
+
name="thinking_step",
|
69
|
+
data={
|
70
|
+
"message": f"I am extracting number of all issues with initial parameters:\
|
71
|
+
project keys: {project_keys}, after date: {after_date}",
|
72
|
+
"tool_name": "get_number_off_all_issues",
|
73
|
+
"toolkit": "analyse_jira",
|
74
|
+
},
|
75
|
+
)
|
76
|
+
|
65
77
|
project_df = jira_projects_overview(
|
66
78
|
after_date, project_keys=project_keys, jira=self.jira
|
67
79
|
)
|
@@ -72,22 +84,12 @@ class JiraAnalyseWrapper(BaseToolApiWrapper):
|
|
72
84
|
f"projects_overview_{project_keys}.csv",
|
73
85
|
csv_options={"index": False},
|
74
86
|
)
|
75
|
-
dispatch_custom_event(
|
76
|
-
name="jira_projects_overview",
|
77
|
-
data={
|
78
|
-
"project_keys": project_keys,
|
79
|
-
"after_date": after_date,
|
80
|
-
"files": [f"projects_overview_{project_keys}.csv"],
|
81
|
-
"project_count": len(project_df),
|
82
|
-
"columns": project_df.columns.tolist(),
|
83
|
-
},
|
84
|
-
)
|
85
|
-
|
86
87
|
return {
|
87
88
|
"projects": project_df["key"].tolist(),
|
88
89
|
"projects_summary": project_df.to_string(),
|
89
90
|
}
|
90
91
|
|
92
|
+
@with_streamlit_logs(tool_name="get_jira_issues")
|
91
93
|
def get_jira_issues(
|
92
94
|
self,
|
93
95
|
closed_issues_based_on: int,
|
@@ -100,7 +102,8 @@ class JiraAnalyseWrapper(BaseToolApiWrapper):
|
|
100
102
|
"""
|
101
103
|
Extract Jira issues for the specified projects.
|
102
104
|
closed_issues_based_on: int
|
103
|
-
define whether issues can be thought as
|
105
|
+
define whether issues can be thought as
|
106
|
+
closed based on their status (1) or not empty resolved date (2)
|
104
107
|
resolved_after: str
|
105
108
|
resolved after date (i.e. 2023-01-01)
|
106
109
|
updated_after: str
|
@@ -112,6 +115,7 @@ class JiraAnalyseWrapper(BaseToolApiWrapper):
|
|
112
115
|
project_keys: str
|
113
116
|
one or more projects keys separated with comma
|
114
117
|
"""
|
118
|
+
|
115
119
|
if not (
|
116
120
|
(
|
117
121
|
closed_issues_based_on == 1
|
@@ -122,7 +126,7 @@ class JiraAnalyseWrapper(BaseToolApiWrapper):
|
|
122
126
|
return (
|
123
127
|
"ERROR: Check input parameters closed_issues_based_on and closed_status"
|
124
128
|
)
|
125
|
-
|
129
|
+
|
126
130
|
project_keys = project_keys or self.project_keys
|
127
131
|
|
128
132
|
dispatch_custom_event(
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from io import BytesIO
|
2
|
-
from typing import Optional
|
2
|
+
from typing import Optional, List
|
3
3
|
|
4
|
+
import requests
|
4
5
|
from PIL import Image
|
5
6
|
from langchain_community.document_loaders import ConfluenceLoader
|
6
7
|
from langchain_community.document_loaders.confluence import ContentFormat
|
@@ -9,7 +10,7 @@ from pdf2image import convert_from_bytes
|
|
9
10
|
from reportlab.graphics import renderPM
|
10
11
|
from svglib.svglib import svg2rlg
|
11
12
|
|
12
|
-
from
|
13
|
+
from src.alita_sdk.langchain.tools.utils import image_to_byte_array, bytes_to_base64
|
13
14
|
|
14
15
|
Image.MAX_IMAGE_PIXELS = 300_000_000
|
15
16
|
|
@@ -73,6 +74,61 @@ class AlitaConfluenceLoader(ConfluenceLoader):
|
|
73
74
|
kwargs['content_format'] = mapping.get(content_formant, ContentFormat.VIEW)
|
74
75
|
return super().load(**kwargs)
|
75
76
|
|
77
|
+
def process_attachment(
|
78
|
+
self,
|
79
|
+
page_id: str,
|
80
|
+
ocr_languages: Optional[str] = None,
|
81
|
+
) -> List[str]:
|
82
|
+
"""
|
83
|
+
Process attachments from a Confluence page and extract text from them.
|
84
|
+
Note: if the attachment is corrupted, it will be skipped and an error will be logged.
|
85
|
+
"""
|
86
|
+
|
87
|
+
try:
|
88
|
+
from PIL import Image # noqa: F401
|
89
|
+
except ImportError:
|
90
|
+
raise ImportError(
|
91
|
+
"`Pillow` package not found, " "please run `pip install Pillow`"
|
92
|
+
)
|
93
|
+
|
94
|
+
attachments = self.confluence.get_attachments_from_content(page_id)["results"]
|
95
|
+
texts = []
|
96
|
+
for attachment in attachments:
|
97
|
+
media_type = attachment["metadata"]["mediaType"]
|
98
|
+
absolute_url = self.base_url + attachment["_links"]["download"]
|
99
|
+
title = attachment["title"]
|
100
|
+
try:
|
101
|
+
if media_type == "application/pdf":
|
102
|
+
text = title + self.process_pdf(absolute_url, ocr_languages)
|
103
|
+
elif (
|
104
|
+
media_type == "image/png"
|
105
|
+
or media_type == "image/jpg"
|
106
|
+
or media_type == "image/jpeg"
|
107
|
+
):
|
108
|
+
text = title + self.process_image(absolute_url, ocr_languages)
|
109
|
+
elif (
|
110
|
+
media_type == "application/vnd.openxmlformats-officedocument"
|
111
|
+
".wordprocessingml.document"
|
112
|
+
):
|
113
|
+
text = title + self.process_doc(absolute_url)
|
114
|
+
elif media_type == "application/vnd.ms-excel":
|
115
|
+
text = title + self.process_xls(absolute_url)
|
116
|
+
# elif media_type == "image/svg+xml":
|
117
|
+
# text = title + self.process_svg(absolute_url, ocr_languages)
|
118
|
+
else:
|
119
|
+
continue
|
120
|
+
texts.append(text)
|
121
|
+
except requests.HTTPError as e:
|
122
|
+
if e.response.status_code == 404:
|
123
|
+
print(f"Attachment not found at {absolute_url}") # noqa: T201
|
124
|
+
continue
|
125
|
+
else:
|
126
|
+
raise
|
127
|
+
except Exception as e:
|
128
|
+
print(f"Error processing attachment {absolute_url}: {e}")
|
129
|
+
continue
|
130
|
+
return texts
|
131
|
+
|
76
132
|
def process_pdf(
|
77
133
|
self,
|
78
134
|
link: str,
|
@@ -19,7 +19,7 @@ from ..document_loaders.AlitaCSVLoader import AlitaCSVLoader
|
|
19
19
|
from ..document_loaders.AlitaExcelLoader import AlitaExcelLoader
|
20
20
|
from ..document_loaders.AlitaDirectoryLoader import AlitaDirectoryLoader
|
21
21
|
from ..document_loaders.AlitaGitRepoLoader import AlitaGitRepoLoader
|
22
|
-
from
|
22
|
+
from alita_tools.confluence.loader import AlitaConfluenceLoader
|
23
23
|
from ..document_loaders.AlitaBDDScenariosLoader import BDDScenariosLoader
|
24
24
|
from ..document_loaders.AlitaJiraLoader import AlitaJiraLoader
|
25
25
|
|
@@ -0,0 +1,93 @@
|
|
1
|
+
import logging
|
2
|
+
from functools import wraps
|
3
|
+
|
4
|
+
from langchain_core.callbacks import dispatch_custom_event
|
5
|
+
|
6
|
+
|
7
|
+
class StreamlitCallbackHandler(logging.Handler):
|
8
|
+
"""Custom logging handler to send logs to Streamlit."""
|
9
|
+
|
10
|
+
def __init__(self, tool_name: str = "logging"):
|
11
|
+
super().__init__()
|
12
|
+
self.tool_name = tool_name
|
13
|
+
|
14
|
+
def emit(self, record):
|
15
|
+
"""Emit a log record."""
|
16
|
+
if record.levelno < logging.INFO:
|
17
|
+
return # Ignore debug logs
|
18
|
+
|
19
|
+
log_entry = self.format(record)
|
20
|
+
dispatch_custom_event(
|
21
|
+
name="thinking_step",
|
22
|
+
data={
|
23
|
+
"message": log_entry,
|
24
|
+
"tool_name": self.tool_name,
|
25
|
+
"toolkit": "logging", # ? or pass the toolkit name
|
26
|
+
},
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
def setup_streamlit_logging(
|
31
|
+
logger_name: str = "", tool_name="logging"
|
32
|
+
) -> StreamlitCallbackHandler:
|
33
|
+
"""
|
34
|
+
Attach a StreamlitCallbackHandler to the given logger (default: root).
|
35
|
+
Returns the handler so you can remove it later if needed.
|
36
|
+
"""
|
37
|
+
logger = logging.getLogger(logger_name)
|
38
|
+
handler = StreamlitCallbackHandler(tool_name)
|
39
|
+
|
40
|
+
# Avoid duplicate handlers
|
41
|
+
if not any(isinstance(h, StreamlitCallbackHandler) for h in logger.handlers):
|
42
|
+
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
43
|
+
handler.setFormatter(formatter)
|
44
|
+
logger.addHandler(handler)
|
45
|
+
|
46
|
+
return handler
|
47
|
+
|
48
|
+
|
49
|
+
# Decorator version
|
50
|
+
def with_streamlit_logs(logger_name: str = "", tool_name="logging"):
|
51
|
+
"""
|
52
|
+
Decorator to temporarily attach a StreamlitCallbackHandler to a function's logger.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
logger_name (str): Name of the logger to attach the handler to.
|
56
|
+
Use an empty string "" for the root logger.
|
57
|
+
tool_name (str): Name of the tool to display in Streamlit logs.
|
58
|
+
|
59
|
+
Behavior:
|
60
|
+
- Attaches a StreamlitCallbackHandler before the function runs.
|
61
|
+
- Forwards all INFO and higher log messages—including those
|
62
|
+
from 3rd-party libraries using the specified logger—to Streamlit
|
63
|
+
via dispatch_custom_event.
|
64
|
+
- Automatically removes the handler after the function completes,
|
65
|
+
even if an exception occurs.
|
66
|
+
|
67
|
+
Example:
|
68
|
+
@with_streamlit_logs(logger_name="my_logger", tool_name="my_tool")
|
69
|
+
def my_function():
|
70
|
+
logging.info("This is a log message.")
|
71
|
+
# Logs from 3rd-party libraries using "my_logger" will also be sent to Streamlit.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
The decorated function with Streamlit logging enabled during its execution.
|
75
|
+
"""
|
76
|
+
|
77
|
+
def decorator(func):
|
78
|
+
@wraps(func)
|
79
|
+
def wrapper(*args, **kwargs):
|
80
|
+
logger = logging.getLogger(logger_name)
|
81
|
+
handler = StreamlitCallbackHandler(tool_name=tool_name)
|
82
|
+
handler.setFormatter(
|
83
|
+
logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
84
|
+
)
|
85
|
+
logger.addHandler(handler)
|
86
|
+
try:
|
87
|
+
return func(*args, **kwargs)
|
88
|
+
finally:
|
89
|
+
logger.removeHandler(handler)
|
90
|
+
|
91
|
+
return wrapper
|
92
|
+
|
93
|
+
return decorator
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: alita_sdk
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.119
|
4
4
|
Summary: SDK for building langchain agents using resouces from Alita
|
5
5
|
Author-email: Artem Rozumenko <artyom.rozumenko@gmail.com>, Mikalai Biazruchka <mikalai_biazruchka@epam.com>, Roman Mitusov <roman_mitusov@epam.com>, Ivan Krakhmaliuk <lifedjik@gmail.com>
|
6
6
|
Project-URL: Homepage, https://projectalita.ai
|
@@ -11,7 +11,7 @@ alita_sdk/community/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
11
11
|
alita_sdk/community/utils.py,sha256=lvuCJaNqVPHOORJV6kIPcXJcdprVW_TJvERtYAEgpjM,249
|
12
12
|
alita_sdk/community/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
alita_sdk/community/analysis/jira_analyse/__init__.py,sha256=Rm-HKEi_HIxrgHdq9mZ-XzxMKLXm8-81eJwJT2lar-c,5945
|
14
|
-
alita_sdk/community/analysis/jira_analyse/api_wrapper.py,sha256=
|
14
|
+
alita_sdk/community/analysis/jira_analyse/api_wrapper.py,sha256=JqGSxg_3x0ErzII31UZkY3V7jo9i8Gb5d_pW7lPIOSA,9522
|
15
15
|
alita_sdk/community/browseruse/__init__.py,sha256=uAxPZEX7ihpt8HtcGDFrzTNv9WcklT1wG1ItTwUO8y4,3601
|
16
16
|
alita_sdk/community/browseruse/api_wrapper.py,sha256=Y05NKWfTROPmBxe8ZFIELSGBX5v3RTNP30OTO2Tj8uI,10838
|
17
17
|
alita_sdk/langchain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -27,7 +27,7 @@ alita_sdk/langchain/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
27
27
|
alita_sdk/langchain/agents/xml_chat.py,sha256=Mx7PK5T97_GrFCwHHZ3JZP42S7MwtUzV0W-_8j6Amt8,6212
|
28
28
|
alita_sdk/langchain/document_loaders/AlitaBDDScenariosLoader.py,sha256=4kFU1ijrM1Jw7cywQv8mUiBHlE6w-uqfzSZP4hUV5P4,3771
|
29
29
|
alita_sdk/langchain/document_loaders/AlitaCSVLoader.py,sha256=TBJuIFqweLDtd0JxgfPqrcY5eED-M617CT_EInp6Lmg,1949
|
30
|
-
alita_sdk/langchain/document_loaders/AlitaConfluenceLoader.py,sha256=
|
30
|
+
alita_sdk/langchain/document_loaders/AlitaConfluenceLoader.py,sha256=wpZxN9tKSzRACROu4NYQ020wuIVgvuI14_EPQ_CbrU4,8316
|
31
31
|
alita_sdk/langchain/document_loaders/AlitaDirectoryLoader.py,sha256=fKezkgvIcLG7S2PVJp1a8sZd6C4XQKNZKAFC87DbQts,7003
|
32
32
|
alita_sdk/langchain/document_loaders/AlitaDocxMammothLoader.py,sha256=dBf0JkWMrNBCB4zJ3fjtOxci0OzZuDimMGSPYS7W6Oo,4848
|
33
33
|
alita_sdk/langchain/document_loaders/AlitaExcelLoader.py,sha256=fC7L_NzkGZSirYvJhXSbuc37e2FNtNgETQamkKVqcTQ,1457
|
@@ -42,7 +42,7 @@ alita_sdk/langchain/document_loaders/utils.py,sha256=ifh0UJiweIb2iEb2_THJy2pbAnT
|
|
42
42
|
alita_sdk/langchain/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
43
43
|
alita_sdk/langchain/interfaces/kwextractor.py,sha256=kSJA9L8g8UArmHu7Bd9dIO0Rrq86JPUb8RYNlnN68FQ,3072
|
44
44
|
alita_sdk/langchain/interfaces/llm_processor.py,sha256=oX5feXsQ5D-8q3Mf40Txltv3kkHKb2xBeNPwecy5yDQ,8442
|
45
|
-
alita_sdk/langchain/interfaces/loaders.py,sha256=
|
45
|
+
alita_sdk/langchain/interfaces/loaders.py,sha256=7btXnGW-wODBoF5Jlv9ljPlkMzJU4NwA8E_v_VzsIHg,3326
|
46
46
|
alita_sdk/langchain/interfaces/splitters.py,sha256=tW65-Ejj9VYyxXFZNgPts_CKILQ18bWp_1bZ-24FKGc,3630
|
47
47
|
alita_sdk/langchain/retrievers/AlitaRetriever.py,sha256=osChtJxUlfpsFESpJSE5mnJAkxTXnzgFZnC6l5mUlbo,6148
|
48
48
|
alita_sdk/langchain/retrievers/VectorstoreRetriever.py,sha256=CWZbqle5sjEWxFbmn1-ZuMYUgQLQb_b6sCK1d1KxeWE,2012
|
@@ -88,12 +88,13 @@ alita_sdk/tools/vectorstore.py,sha256=F-DoHxPa4UVsKB-FEd-wWa59QGQifKMwcSNcZ5WZOK
|
|
88
88
|
alita_sdk/utils/AlitaCallback.py,sha256=cvpDhR4QLVCNQci6CO6TEUrUVDZU9_CRSwzcHGm3SGw,7356
|
89
89
|
alita_sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
90
|
alita_sdk/utils/evaluate.py,sha256=iM1P8gzBLHTuSCe85_Ng_h30m52hFuGuhNXJ7kB1tgI,1872
|
91
|
+
alita_sdk/utils/logging.py,sha256=hBE3qAzmcLMdamMp2YRXwOOK9P4lmNaNhM76kntVljs,3124
|
91
92
|
alita_sdk/utils/streamlit.py,sha256=zp8owZwHI3HZplhcExJf6R3-APtWx-z6s5jznT2hY_k,29124
|
92
93
|
alita_sdk/utils/utils.py,sha256=dM8whOJAuFJFe19qJ69-FLzrUp6d2G-G6L7d4ss2XqM,346
|
93
|
-
alita_sdk-0.3.
|
94
|
+
alita_sdk-0.3.119.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
94
95
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
95
96
|
tests/test_jira_analysis.py,sha256=I0cErH5R_dHVyutpXrM1QEo7jfBuKWTmDQvJBPjx18I,3281
|
96
|
-
alita_sdk-0.3.
|
97
|
-
alita_sdk-0.3.
|
98
|
-
alita_sdk-0.3.
|
99
|
-
alita_sdk-0.3.
|
97
|
+
alita_sdk-0.3.119.dist-info/METADATA,sha256=Icr-9s7-kw-d_4ZHMiPJOkUgvyx_X5mB9xLYNiYWHj4,7075
|
98
|
+
alita_sdk-0.3.119.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
99
|
+
alita_sdk-0.3.119.dist-info/top_level.txt,sha256=SWRhxB7Et3cOy3RkE5hR7OIRnHoo3K8EXzoiNlkfOmc,25
|
100
|
+
alita_sdk-0.3.119.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|