ws-bom-robot-app 0.0.40__tar.gz → 0.0.41__tar.gz

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.
Files changed (75) hide show
  1. {ws_bom_robot_app-0.0.40/ws_bom_robot_app.egg-info → ws_bom_robot_app-0.0.41}/PKG-INFO +1 -1
  2. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/setup.py +1 -1
  3. ws_bom_robot_app-0.0.41/ws_bom_robot_app/llm/vector_store/integration/jira.py +118 -0
  4. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41/ws_bom_robot_app.egg-info}/PKG-INFO +1 -1
  5. ws_bom_robot_app-0.0.40/ws_bom_robot_app/llm/vector_store/integration/jira.py +0 -114
  6. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/MANIFEST.in +0 -0
  7. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/README.md +0 -0
  8. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/pyproject.toml +0 -0
  9. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/requirements.txt +0 -0
  10. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/setup.cfg +0 -0
  11. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/__init__.py +0 -0
  12. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/auth.py +0 -0
  13. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/config.py +0 -0
  14. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/cron_manager.py +0 -0
  15. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/__init__.py +0 -0
  16. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/agent_description.py +0 -0
  17. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/agent_handler.py +0 -0
  18. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/agent_lcel.py +0 -0
  19. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/api.py +0 -0
  20. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/defaut_prompt.py +0 -0
  21. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/main.py +0 -0
  22. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/models/__init__.py +0 -0
  23. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/models/api.py +0 -0
  24. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/models/base.py +0 -0
  25. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/models/kb.py +0 -0
  26. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/providers/__init__.py +0 -0
  27. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/providers/llm_manager.py +0 -0
  28. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/settings.py +0 -0
  29. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/tools/__init__.py +0 -0
  30. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/tools/models/__init__.py +0 -0
  31. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/tools/models/main.py +0 -0
  32. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/tools/tool_builder.py +0 -0
  33. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/tools/tool_manager.py +0 -0
  34. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/tools/utils.py +0 -0
  35. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/__init__.py +0 -0
  36. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/agent.py +0 -0
  37. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/chunker.py +0 -0
  38. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/download.py +0 -0
  39. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/kb.py +0 -0
  40. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/print.py +0 -0
  41. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/secrets.py +0 -0
  42. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/utils/webhooks.py +0 -0
  43. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/__init__.py +0 -0
  44. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/db/__init__.py +0 -0
  45. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/db/base.py +0 -0
  46. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/db/chroma.py +0 -0
  47. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/db/faiss.py +0 -0
  48. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/db/manager.py +0 -0
  49. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/db/qdrant.py +0 -0
  50. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/generator.py +0 -0
  51. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/__init__.py +0 -0
  52. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/azure.py +0 -0
  53. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/base.py +0 -0
  54. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/confluence.py +0 -0
  55. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/dropbox.py +0 -0
  56. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/gcs.py +0 -0
  57. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/github.py +0 -0
  58. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/googledrive.py +0 -0
  59. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/manager.py +0 -0
  60. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/s3.py +0 -0
  61. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/sftp.py +0 -0
  62. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/sharepoint.py +0 -0
  63. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/sitemap.py +0 -0
  64. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/integration/slack.py +0 -0
  65. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/loader/__init__.py +0 -0
  66. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/loader/base.py +0 -0
  67. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/loader/docling.py +0 -0
  68. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/llm/vector_store/loader/json_loader.py +0 -0
  69. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/main.py +0 -0
  70. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/task_manager.py +0 -0
  71. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app/util.py +0 -0
  72. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app.egg-info/SOURCES.txt +0 -0
  73. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app.egg-info/dependency_links.txt +0 -0
  74. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app.egg-info/requires.txt +0 -0
  75. {ws_bom_robot_app-0.0.40 → ws_bom_robot_app-0.0.41}/ws_bom_robot_app.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ws_bom_robot_app
3
- Version: 0.0.40
3
+ Version: 0.0.41
4
4
  Summary: A FastAPI application serving ws bom/robot/llm platform ai.
5
5
  Home-page: https://github.com/websolutespa/bom
6
6
  Author: Websolute Spa
@@ -4,7 +4,7 @@ _requirements = [line.split('#')[0].strip() for line in open("requirements.txt")
4
4
 
5
5
  setup(
6
6
  name="ws_bom_robot_app",
7
- version="0.0.40",
7
+ version="0.0.41",
8
8
  description="A FastAPI application serving ws bom/robot/llm platform ai.",
9
9
  long_description=open("README.md", encoding='utf-8').read(),
10
10
  long_description_content_type="text/markdown",
@@ -0,0 +1,118 @@
1
+ import asyncio, os
2
+ from ws_bom_robot_app.llm.vector_store.integration.base import IntegrationStrategy
3
+ from langchain_core.documents import Document
4
+ from ws_bom_robot_app.llm.vector_store.loader.base import Loader
5
+ from pydantic import BaseModel, Field, AliasChoices
6
+ from typing import Any, Optional, Union
7
+ from unstructured_ingest.interfaces import ProcessorConfig, ReadConfig
8
+ from unstructured_ingest.connector.jira import SimpleJiraConfig, JiraAccessConfig, JiraSourceConnector, JiraIngestDoc, nested_object_to_field_getter, _get_id_fields_for_issue, _get_project_fields_for_issue
9
+ from unstructured_ingest.runner import JiraRunner
10
+
11
+
12
+ class JiraParams(BaseModel):
13
+ """
14
+ JiraParams is a Pydantic model that represents the parameters required to interact with a Jira instance.
15
+
16
+ Attributes:
17
+ url (str): The URL of the Jira instance, e.g., 'https://example.atlassian.net'.
18
+ access_token (str): The access token for authenticating with the Jira API.
19
+ user_email (str): The email address of the Jira user.
20
+ projects (list[str]): A list of project keys or IDs to interact with, e.g., ['SCRUM', 'PROJ1'].
21
+ boards (Optional[list[str]]): An optional list of board IDs to interact with. Defaults to None, e.g., ['1', '2'].
22
+ issues (Optional[list[str]]): An optional list of issue keys or IDs to interact with. Defaults to None, e.g., ['SCRUM-1', 'PROJ1-1'].
23
+ """
24
+ url: str = Field(..., pattern=r'^https?:\/\/.+')
25
+ access_token: str = Field(..., validation_alias=AliasChoices("accessToken","access_token"), min_length=1)
26
+ user_email: str = Field(validation_alias=AliasChoices("userEmail","user_email"), min_length=1)
27
+ projects: list[str]
28
+ boards: Optional[list[str]] | None = None
29
+ issues: Optional[list[str]] | None = None
30
+
31
+ class Jira(IntegrationStrategy):
32
+ def __init__(self, knowledgebase_path: str, data: dict[str, Union[str,int,list]]):
33
+ super().__init__(knowledgebase_path, data)
34
+ self.__data = JiraParams.model_validate(self.data)
35
+ def working_subdirectory(self) -> str:
36
+ return 'jira'
37
+ def run(self) -> None:
38
+ access_config = JiraAccessConfig(
39
+ api_token=self.__data.access_token
40
+ )
41
+ config = SimpleJiraConfig(
42
+ user_email=self.__data.user_email,
43
+ url = self.__data.url,
44
+ access_config=access_config,
45
+ projects=self.__data.projects,
46
+ boards=self.__data.boards,
47
+ issues=self.__data.issues
48
+ )
49
+ # runner override: waiting for v2 migration https://github.com/Unstructured-IO/unstructured-ingest/issues/106
50
+ runner = _JiraRunner(
51
+ connector_config=config,
52
+ processor_config=ProcessorConfig(reprocess=False,verbose=False,num_processes=2,raise_on_error=False),
53
+ read_config=ReadConfig(download_dir=self.working_directory,re_download=True,preserve_downloads=True,download_only=True),
54
+ partition_config=None,
55
+ retry_strategy_config=None
56
+ )
57
+ runner.run()
58
+ async def load(self) -> list[Document]:
59
+ await asyncio.to_thread(self.run)
60
+ await asyncio.sleep(1)
61
+ return await Loader(self.working_directory).load()
62
+
63
+
64
+ # region override
65
+ class _JiraIngestDoc(JiraIngestDoc):
66
+ def _get_dropdown_custom_fields_for_issue(issue: dict, c_sep=" " * 5, r_sep="\n") -> str:
67
+ def _parse_value(value: Any) -> Any:
68
+ if isinstance(value, dict):
69
+ _candidate = ["displayName", "name", "value"]
70
+ for item in _candidate:
71
+ if item in value:
72
+ return value[item]
73
+ return value
74
+ def _remap_custom_fields(fields: dict):
75
+ remapped_fields = {}
76
+ for field_key, field_value in fields.items():
77
+ new_key = next((map_item["name"] for map_item in _JiraSourceConnector.CUSTOM_FIELDS if field_key == map_item["id"]), field_key)
78
+ if new_key != field_value:
79
+ remapped_fields[new_key] = field_value
80
+ return remapped_fields
81
+ filtered_fields = {key: _parse_value(value) for key, value in issue.items() if value is not None and type(value) not in [list]}
82
+ custom_fields =_remap_custom_fields(filtered_fields)
83
+ return (r_sep + c_sep ).join([f"{key}: {value}{r_sep}" for key, value in custom_fields.items()])
84
+ def __init__(self, *args, **kwargs):
85
+ super().__init__(*args, **kwargs)
86
+ _issue = self.issue
87
+ _nested: dict = nested_object_to_field_getter(_issue["fields"])
88
+ document = "\n\n\n".join(
89
+ [
90
+ _get_id_fields_for_issue(_issue),
91
+ _get_project_fields_for_issue(_nested),
92
+ _JiraIngestDoc._get_dropdown_custom_fields_for_issue(_nested)
93
+ ],
94
+ )
95
+ _full_filename = str(self.filename)
96
+ _file_extension = _full_filename.split(".")[-1]
97
+ _file_without_extension = _full_filename.replace(f".{_file_extension}","")
98
+ os.makedirs(os.path.dirname(_file_without_extension), exist_ok=True)
99
+ with open(f"{_file_without_extension}_extra.{_file_extension}", "w", encoding="utf8") as f:
100
+ f.write(document)
101
+
102
+ class _JiraSourceConnector(JiraSourceConnector):
103
+ CUSTOM_FIELDS: list | None = None
104
+ def __set_custom_fields(self) -> None:
105
+ _custom_fields = self.jira.get_all_custom_fields()
106
+ _JiraSourceConnector.CUSTOM_FIELDS = [{"id":item["id"],"name":item["name"]} for item in _custom_fields]
107
+ self._jira = None # fix serialization
108
+ def __init__(self, *args, **kwargs):
109
+ super().__init__(*args, **kwargs)
110
+ if not _JiraSourceConnector.CUSTOM_FIELDS:
111
+ self.__set_custom_fields()
112
+ def get_ingest_docs(self) -> list[_JiraIngestDoc]:
113
+ return [_JiraIngestDoc(**item.__dict__) for item in super().get_ingest_docs()]
114
+
115
+ class _JiraRunner(JiraRunner):
116
+ def get_source_connector_cls(self):
117
+ return _JiraSourceConnector
118
+ # endregion
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ws_bom_robot_app
3
- Version: 0.0.40
3
+ Version: 0.0.41
4
4
  Summary: A FastAPI application serving ws bom/robot/llm platform ai.
5
5
  Home-page: https://github.com/websolutespa/bom
6
6
  Author: Websolute Spa
@@ -1,114 +0,0 @@
1
- import asyncio
2
- from ws_bom_robot_app.llm.vector_store.integration.base import IntegrationStrategy
3
- from unstructured_ingest.interfaces import ProcessorConfig, ReadConfig
4
- from unstructured_ingest.connector.jira import SimpleJiraConfig, JiraAccessConfig
5
- from unstructured_ingest.runner import JiraRunner
6
- from langchain_core.documents import Document
7
- from ws_bom_robot_app.llm.vector_store.loader.base import Loader
8
- from pydantic import BaseModel, Field, AliasChoices
9
- from typing import Optional, Union
10
- import requests
11
- import unstructured_ingest.connector.jira
12
-
13
- class JiraParams(BaseModel):
14
- """
15
- JiraParams is a Pydantic model that represents the parameters required to interact with a Jira instance.
16
-
17
- Attributes:
18
- url (str): The URL of the Jira instance, e.g., 'https://example.atlassian.net'.
19
- access_token (str): The access token for authenticating with the Jira API.
20
- user_email (str): The email address of the Jira user.
21
- projects (list[str]): A list of project keys or IDs to interact with, e.g., ['SCRUM', 'PROJ1'].
22
- boards (Optional[list[str]]): An optional list of board IDs to interact with. Defaults to None, e.g., ['1', '2'].
23
- issues (Optional[list[str]]): An optional list of issue keys or IDs to interact with. Defaults to None, e.g., ['SCRUM-1', 'PROJ1-1'].
24
- """
25
- url: str
26
- access_token: str = Field(validation_alias=AliasChoices("accessToken","access_token"))
27
- user_email: str = Field(validation_alias=AliasChoices("userEmail","user_email"))
28
- projects: list[str]
29
- boards: Optional[list[str]] | None = None
30
- issues: Optional[list[str]] | None = None
31
- fieldsMappingUrl: Optional[str] | None = None
32
-
33
- class Jira(IntegrationStrategy):
34
- DEFAULT_C_SEP = " " * 5
35
- DEFAULT_R_SEP = "\n"
36
- def __init__(self, knowledgebase_path: str, data: dict[str, Union[str,int,list]]):
37
- super().__init__(knowledgebase_path, data)
38
- self.__data = JiraParams.model_validate(self.data)
39
- def working_subdirectory(self) -> str:
40
- return 'jira'
41
- def run(self) -> None:
42
- unstructured_ingest.connector.jira._get_dropdown_fields_for_issue = self._get_dropdown_fields_for_issue
43
- access_config = JiraAccessConfig(
44
- api_token=self.__data.access_token
45
- )
46
- config = SimpleJiraConfig(
47
- user_email=self.__data.user_email,
48
- url = self.__data.url,
49
- access_config=access_config,
50
- projects=self.__data.projects,
51
- boards=self.__data.boards,
52
- issues=self.__data.issues
53
- )
54
- runner = JiraRunner(
55
- connector_config=config,
56
- processor_config=ProcessorConfig(reprocess=False,verbose=False,num_processes=2,raise_on_error=False),
57
- read_config=ReadConfig(download_dir=self.working_directory,re_download=True,preserve_downloads=True,download_only=True),
58
- partition_config=None,
59
- retry_strategy_config=None
60
- )
61
- runner.run()
62
- async def load(self) -> list[Document]:
63
- await asyncio.to_thread(self.run)
64
- await asyncio.sleep(1)
65
- return await Loader(self.working_directory).load()
66
-
67
- def _remap_custom_fields(self, field_list):
68
- auth = (self.__data.user_email, self.__data.access_token)
69
- response = requests.get(self.__data.fieldsMappingUrl, auth=auth)
70
-
71
- if response.status_code == 200:
72
- mapper: dict = response.json()
73
- remapped_field_list = {}
74
- for field_key, field_value in field_list.items():
75
- new_key = None
76
- for map_item in mapper:
77
- if field_key == map_item["id"]:
78
- # Usa il nome mappato come nuova chiave
79
- new_key = map_item["name"]
80
- break
81
-
82
- if new_key is None:
83
- new_key = field_key
84
-
85
- remapped_field_list[new_key] = field_value
86
-
87
- return remapped_field_list
88
-
89
- def _get_dropdown_fields_for_issue(self, issue, c_sep=DEFAULT_C_SEP, r_sep=DEFAULT_R_SEP):
90
- all_fields = {}
91
- for key, value in issue.items():
92
- if value is not None:
93
- if isinstance(value, list) and (len(value) > 0):
94
- all_fields[key] = value
95
- else:
96
- all_fields[key] = value
97
- mapped_fields = self._remap_custom_fields(all_fields)
98
- return f"""
99
- IssueType:{issue["issuetype"]["name"]}
100
- {r_sep}
101
- Status:{issue["status"]["name"]}
102
- {r_sep}
103
- Priority:{issue["priority"]}
104
- {r_sep}
105
- AssigneeID_Name:{issue["assignee"]["accountId"]}{c_sep}{issue["assignee"]["displayName"]}
106
- {r_sep}
107
- ReporterAdr_Name:{issue["reporter"]["emailAddress"]}{c_sep}{issue["reporter"]["displayName"]}
108
- {r_sep}
109
- Labels:{c_sep.join(issue["labels"])}
110
- {r_sep}
111
- Components:{c_sep.join([component["name"] for component in issue["components"]])}
112
- {r_sep}
113
- {(r_sep + c_sep ).join([f"{key}:{value}{r_sep}" for key, value in mapped_fields.items()])}
114
- """