MSTR-Robotics-magerdaniel 0.2.10__tar.gz → 0.3.0__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 (26) hide show
  1. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0/MSTR_Robotics_magerdaniel.egg-info}/PKG-INFO +8 -2
  2. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/MSTR_Robotics_magerdaniel.egg-info/SOURCES.txt +5 -3
  3. {MSTR_Robotics_magerdaniel-0.2.10/MSTR_Robotics_magerdaniel.egg-info → mstr_robotics_magerdaniel-0.3.0}/PKG-INFO +9 -3
  4. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/mstr_robotics/_connectors.py +45 -3
  5. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/mstr_robotics/_helper.py +40 -27
  6. mstr_robotics_magerdaniel-0.3.0/mstr_robotics/_lu_data.py +53 -0
  7. mstr_robotics_magerdaniel-0.3.0/mstr_robotics/_mod_prj_obj.py +67 -0
  8. mstr_robotics_magerdaniel-0.3.0/mstr_robotics/ai_openAi_faisst.py +250 -0
  9. mstr_robotics_magerdaniel-0.3.0/mstr_robotics/dossier.py +203 -0
  10. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/mstr_robotics/mstr_classes.py +34 -7
  11. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/mstr_robotics/mstr_pandas.py +10 -1
  12. mstr_robotics_magerdaniel-0.3.0/mstr_robotics/prepare_AI_data.py +229 -0
  13. mstr_robotics_magerdaniel-0.3.0/mstr_robotics/read_out_prj_obj.py +856 -0
  14. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/mstr_robotics/report.py +196 -92
  15. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/setup.py +1 -1
  16. MSTR_Robotics_magerdaniel-0.2.10/mstr_robotics/_lu_data.py +0 -49
  17. MSTR_Robotics_magerdaniel-0.2.10/mstr_robotics/jup_schema_monitor.ipynb +0 -567
  18. MSTR_Robotics_magerdaniel-0.2.10/mstr_robotics/read_out_prj_obj.py +0 -318
  19. MSTR_Robotics_magerdaniel-0.2.10/notebooks/jup_schema_monitor.ipynb +0 -567
  20. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/LICENSE +0 -0
  21. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/MANIFEST.in +0 -0
  22. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/MSTR_Robotics_magerdaniel.egg-info/dependency_links.txt +0 -0
  23. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/MSTR_Robotics_magerdaniel.egg-info/top_level.txt +0 -0
  24. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/README.md +0 -0
  25. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/mstr_robotics/__init__.py +0 -0
  26. {MSTR_Robotics_magerdaniel-0.2.10 → mstr_robotics_magerdaniel-0.3.0}/setup.cfg +0 -0
@@ -1,12 +1,18 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: MSTR_Robotics_magerdaniel
3
- Version: 0.2.10
3
+ Version: 0.3.0
4
4
  Summary: MicroStrateg(P)ython
5
5
  Home-page: https://github.com/magerdaniel
6
6
  Author: Daniel Mager
7
7
  Author-email: "danielmager@gmx.de"
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
+ Dynamic: author
11
+ Dynamic: author-email
12
+ Dynamic: description
13
+ Dynamic: description-content-type
14
+ Dynamic: home-page
15
+ Dynamic: summary
10
16
 
11
17
  Hi,
12
18
 
@@ -10,9 +10,11 @@ mstr_robotics/__init__.py
10
10
  mstr_robotics/_connectors.py
11
11
  mstr_robotics/_helper.py
12
12
  mstr_robotics/_lu_data.py
13
- mstr_robotics/jup_schema_monitor.ipynb
13
+ mstr_robotics/_mod_prj_obj.py
14
+ mstr_robotics/ai_openAi_faisst.py
15
+ mstr_robotics/dossier.py
14
16
  mstr_robotics/mstr_classes.py
15
17
  mstr_robotics/mstr_pandas.py
18
+ mstr_robotics/prepare_AI_data.py
16
19
  mstr_robotics/read_out_prj_obj.py
17
- mstr_robotics/report.py
18
- notebooks/jup_schema_monitor.ipynb
20
+ mstr_robotics/report.py
@@ -1,12 +1,18 @@
1
- Metadata-Version: 2.1
2
- Name: MSTR-Robotics-magerdaniel
3
- Version: 0.2.10
1
+ Metadata-Version: 2.2
2
+ Name: MSTR_Robotics_magerdaniel
3
+ Version: 0.3.0
4
4
  Summary: MicroStrateg(P)ython
5
5
  Home-page: https://github.com/magerdaniel
6
6
  Author: Daniel Mager
7
7
  Author-email: "danielmager@gmx.de"
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
+ Dynamic: author
11
+ Dynamic: author-email
12
+ Dynamic: description
13
+ Dynamic: description-content-type
14
+ Dynamic: home-page
15
+ Dynamic: summary
10
16
 
11
17
  Hi,
12
18
 
@@ -5,6 +5,16 @@ i_msic=msic()
5
5
 
6
6
  class mstr_api():
7
7
 
8
+ def get_prj_tbl(self,conn):
9
+ inst_u = f"{conn.base_url}/api/model/tables"
10
+ r = conn.get(inst_u)
11
+ return r
12
+
13
+ def get_dossier_prp_l(self,conn,dossier_id):
14
+ endpoint = f'/api/documents/{dossier_id}/prompts'
15
+ prp_l = conn.get(endpoint=endpoint).json()
16
+ return prp_l
17
+
8
18
  def get_ele_prp_ans(self,conn,report_id,instance_id,prompt_id,att_form_str=None,offset=0, limit=200):
9
19
  #get availeble objects from an element prompt
10
20
  #be carefull, this can be an performance issue
@@ -23,6 +33,10 @@ class mstr_api():
23
33
  offset += limit
24
34
  return all_values
25
35
 
36
+ def create_dossier_instance(self, conn, dossier_id, body=None, error_msg=None):
37
+ endpoint = f'{conn.base_url}/api/dossiers/{dossier_id}/instances'
38
+ return conn.post(url=endpoint, json=body).json()["mid"]
39
+
26
40
  def get_prp_ans(self,conn,report_id,instance_id,prompt_id,offset=0, limit=200):
27
41
  #get availeble objects from an object prompt
28
42
  rest_limit=limit
@@ -30,7 +44,7 @@ class mstr_api():
30
44
  while rest_limit>=0:
31
45
  inst_u = f'{conn.base_url}/api/reports/{report_id}/instances/{instance_id}/prompts/{prompt_id}/objects?offset={offset}&limit={limit}'
32
46
  r = conn.get(inst_u, headers=conn.headers)
33
- prp_ans_base_l.append(r.json()["objects"])
47
+ prp_ans_base_l.extend(r.json()["objects"])
34
48
  rest_limit=int(r.headers["x-mstr-total-count"])-offset
35
49
  offset +=limit
36
50
 
@@ -62,12 +76,12 @@ class mstr_api():
62
76
 
63
77
  return resp
64
78
 
65
- def get_project_name(self, conn):
79
+ def get_project_name(self, conn,project_id):
66
80
  #provides a readable project name for humans
67
81
  project_resp = conn.get(f'{conn.base_url}/api/projects')
68
82
  project_name=""
69
83
  for p in project_resp.json():
70
- if p["id"] == conn.headers["X-MSTR-ProjectID"]:
84
+ if p["id"] == project_id:
71
85
  project_name= p["name"]
72
86
 
73
87
  if project_name!="":
@@ -80,6 +94,16 @@ class mstr_api():
80
94
  r = conn.get(inst_u, headers=conn.headers)
81
95
  return r.json()
82
96
 
97
+ def get_custom_group(self,conn, custom_group_id, show_expression_as="tokens"):
98
+ url = f'{conn.base_url}/api/model/customGroups/{custom_group_id}?showExpressionAs={show_expression_as}'
99
+ custom_group_def = conn.get(url)
100
+ return custom_group_def.json()
101
+
102
+ def get_consolidation(self,conn, consolidation_id):
103
+ url = f'{conn.base_url}/api/model/consolidations/{consolidation_id}'
104
+ consolidation_def = conn.get(url)
105
+ return consolidation_def.json()
106
+
83
107
  def get_hier_att(self,conn,hier_id,displayForms="All",offset=0, limit=200):
84
108
  #Available displayForms: all, browseForms, reportDisplayForms, customForms, unknown
85
109
  #I develope initially to get the form_ids for attribute qualification prompts
@@ -104,6 +128,12 @@ class mstr_api():
104
128
  rep_sql=conn.get(url)
105
129
  return rep_sql
106
130
 
131
+ def get_report_all_def(self,conn,report_id, show_expression_as="tokens",show_filter_tokens="true",show_advanced_properties="true"):
132
+ url=f'{conn.base_url}/api/model/reports/{report_id}?showExpressionAs={show_expression_as}&showFilterTokens={show_filter_tokens}&showAdvancedProperties={show_advanced_properties}'
133
+ #print(url)
134
+ report_def=conn.get(url)
135
+ return report_def.json()
136
+
107
137
  def get_report_raw(self,conn,report_id,instance_id):
108
138
  #normaly I use the report libraries from mstrio
109
139
  # to fetch the data. Sometimes they bring back an error. so this one is for trouble
@@ -149,6 +179,18 @@ class mstr_api():
149
179
 
150
180
  return {"metric_val_l":raw_val_l,"metric_guid_l":regam_job_metric_guid_l}
151
181
 
182
+ def get_dossier_def(self,conn,dossier_id):
183
+ url = f'{conn.base_url}/api/v2/dossiers/{dossier_id}/definition'
184
+ doss_hier = conn.get(url)
185
+ return doss_hier.json()
186
+
187
+ def get_dossier_detail(self, conn, dossier_id, instance_id, chapter_key, vis_id):
188
+ url = f"{conn.base_url}/api/v2/dossiers/{dossier_id}/instances/"
189
+ url += f"{instance_id}/chapters/{chapter_key}/visualizations/{vis_id}?offset=0&limit=1000"
190
+ return conn.get(url).json()
191
+
192
+
193
+
152
194
  def ZZZ_get_cube_data(self,conn,cube_id,instance_id,offset,limit) :
153
195
  inst_u = f'{conn.base_url}/api/v2/cubes/{cube_id}/instances/{instance_id}?offset={offset}&limit={limit}'
154
196
  cube_ds = conn.get(inst_u, headers=conn.headers)
@@ -91,7 +91,22 @@ class msic():
91
91
  return key_l
92
92
 
93
93
  def get_comon_val_l(self,list_1,list_2):
94
- return list(set(list_1).intersection(list_2))
94
+ #return list(set(list_1).intersection(list_2))
95
+ matches = []
96
+ for item in list_1:
97
+ if item in list_2:
98
+ matches.append(item)
99
+ return matches
100
+
101
+ def keep_cols_from_dict_l(self,list_l,keep_cols):
102
+ clean_l = []
103
+ for e in list_l:
104
+ new_d = {}
105
+ for m in self.get_comon_val_l(keep_cols, list_2=e.keys()):
106
+ new_d[m] = e[m]
107
+
108
+ clean_l.append(new_d.copy())
109
+ return clean_l
95
110
 
96
111
  def list_to_dict(self,list_in_l, col_l):
97
112
  #merge do lists into one dict
@@ -108,43 +123,41 @@ class msic():
108
123
  dict_l.append(dict_d.copy())
109
124
  return dict_l
110
125
 
111
- def add_prefix_to_dict_keys(self,dict, dpn_prefix):
126
+ def add_prefix_to_dict_keys(self,dict, dpn_prefix, dict_cols= []):
112
127
  #adds a prefix to the keys of a dict
113
128
  # use case here is to distinct i.e. between the object_id and the depn_object_id
114
129
  new_dict = {}
130
+ include=0
115
131
  if dpn_prefix==None:
116
132
  return dict
117
133
  for key, value in dict.items():
118
- new_key = dpn_prefix + key
119
- new_dict[new_key] = value
134
+ if dict_cols==[]:
135
+ include=1
136
+
137
+ if key in dict_cols:
138
+ include = 1
139
+
140
+ if include==1:
141
+ new_key = dpn_prefix + key
142
+ new_dict[new_key] = value
143
+
120
144
  return new_dict
121
145
 
122
- """
123
- class sql_server_obj():
124
- pass
146
+ def rem_dbl_dict_in_l (self,dict_l):
147
+
148
+ tuple_l = set(tuple(sorted(d.items())) for d in dict_l)
125
149
 
150
+ #tuple_l =list(set(tuple(keys) for keys in dict_l))
151
+ # Convert tuples back to dictionaries
152
+ unique_dict_l = [dict(t) for t in tuple_l]
126
153
 
127
- class ZZZ_df_helper():
154
+ return unique_dict_l
128
155
 
129
- def clean_double_col(self, df, postfix_left="_x", postfix_right="_y"):
130
- # postfix_left gets removed
131
- # postfix_right gets deleted
132
- doubles_y = [col for col in df.columns if col.endswith(postfix_right)]
133
- df.drop(columns=doubles_y, inplace=True)
134
- df.columns = [col.replace(postfix_left, '') for col in df.columns]
135
- return df
156
+ def rem_dbl_in_l(self,list_l):
157
+ list_l = list(set(list_l))
158
+ return list_l
136
159
 
137
- def rem_att_id_forms(self,df,postfix="@ID"):
138
- df.columns = [col.replace(postfix, '') for col in df.columns]
139
- return df
160
+ def sort_dict_by_key_in_l(self,dict_l,sort_key, reverse=False):
161
+ return sorted(dict_l, key=lambda x: x.get(sort_key, None), reverse=reverse)
140
162
 
141
163
 
142
- def flag_folder_df(self,flag_path_d_l, obj_df, obj_path="path", flag_path="flag_path"):
143
- flag_path_df = pd.DataFrame.from_dict(flag_path_d_l)
144
- unique_str = flag_path_df[flag_path].unique()
145
- matching_rows_df = obj_df[obj_df['path'].str.contains('|'.join(unique_str))]
146
- flaged_obj_df = pd.merge(matching_rows_df, flag_path_df, left_on=matching_rows_df['path']
147
- .str.extract(f'({"|".join(unique_str)})')[0],
148
- right_on='flag_path')
149
- return flaged_obj_df
150
- """
@@ -0,0 +1,53 @@
1
+
2
+ class lu_mstr_md:
3
+
4
+ def lu_object_type(self):
5
+ return [
6
+ {'PA_OBJ_TYPE_ID': '6', 'PA_OBJ_TYPE_DESC': 'Custom Group', 'MD_OBJ_TYPE_ID': '1',
7
+ 'MD_OBJ_TYPE_BEZ': 'Filter'},
8
+ {'PA_OBJ_TYPE_ID': '8', 'PA_OBJ_TYPE_DESC': 'Data Import Cube', 'MD_OBJ_TYPE_ID': '3',
9
+ 'MD_OBJ_TYPE_BEZ': 'Report'},
10
+ {'PA_OBJ_TYPE_ID': '16', 'PA_OBJ_TYPE_DESC': 'Filter', 'MD_OBJ_TYPE_ID': '1', 'MD_OBJ_TYPE_BEZ': 'Filter'},
11
+ {'PA_OBJ_TYPE_ID': '40', 'PA_OBJ_TYPE_DESC': 'Template', 'MD_OBJ_TYPE_ID': '2',
12
+ 'MD_OBJ_TYPE_BEZ': 'Template'},
13
+ {'PA_OBJ_TYPE_ID': '31', 'PA_OBJ_TYPE_DESC': 'SQL Report', 'MD_OBJ_TYPE_ID': '3',
14
+ 'MD_OBJ_TYPE_BEZ': 'Report'},
15
+ {'PA_OBJ_TYPE_ID': '19', 'PA_OBJ_TYPE_DESC': 'SQL Report', 'MD_OBJ_TYPE_ID': '3',
16
+ 'MD_OBJ_TYPE_BEZ': 'Report'},
17
+ {'PA_OBJ_TYPE_ID': '23', 'PA_OBJ_TYPE_DESC': 'Metric', 'MD_OBJ_TYPE_ID': '4', 'MD_OBJ_TYPE_BEZ': 'Metric'},
18
+ {'PA_OBJ_TYPE_ID': '107', 'PA_OBJ_TYPE_DESC': 'User Folder', 'MD_OBJ_TYPE_ID': '8',
19
+ 'MD_OBJ_TYPE_BEZ': 'Folder'},
20
+ {'PA_OBJ_TYPE_ID': '2', 'PA_OBJ_TYPE_DESC': 'Attribute Element Prompt', 'MD_OBJ_TYPE_ID': '10',
21
+ 'MD_OBJ_TYPE_BEZ': 'Prompt'},
22
+ {'PA_OBJ_TYPE_ID': '37', 'PA_OBJ_TYPE_DESC': 'Embedded Prompt', 'MD_OBJ_TYPE_ID': '10',
23
+ 'MD_OBJ_TYPE_BEZ': 'Prompt'},
24
+ {'PA_OBJ_TYPE_ID': '58', 'PA_OBJ_TYPE_DESC': 'Level prompt', 'MD_OBJ_TYPE_ID': '10',
25
+ 'MD_OBJ_TYPE_BEZ': 'Prompt'},
26
+ {'PA_OBJ_TYPE_ID': '24', 'PA_OBJ_TYPE_DESC': 'Object Prompt', 'MD_OBJ_TYPE_ID': '10',
27
+ 'MD_OBJ_TYPE_BEZ': 'Prompt'},
28
+ {'PA_OBJ_TYPE_ID': '28', 'PA_OBJ_TYPE_DESC': 'Prompt', 'MD_OBJ_TYPE_ID': '10', 'MD_OBJ_TYPE_BEZ': 'Prompt'},
29
+ {'PA_OBJ_TYPE_ID': '57', 'PA_OBJ_TYPE_DESC': 'Prompt Expression Draft', 'MD_OBJ_TYPE_ID': '10',
30
+ 'MD_OBJ_TYPE_BEZ': 'Prompt'},
31
+ {'PA_OBJ_TYPE_ID': '36', 'PA_OBJ_TYPE_DESC': 'Value Prompt', 'MD_OBJ_TYPE_ID': '10',
32
+ 'MD_OBJ_TYPE_BEZ': 'Prompt'},
33
+ {'PA_OBJ_TYPE_ID': '1', 'PA_OBJ_TYPE_DESC': 'Attribute', 'MD_OBJ_TYPE_ID': '12',
34
+ 'MD_OBJ_TYPE_BEZ': 'Attribute'},
35
+ {'PA_OBJ_TYPE_ID': '15', 'PA_OBJ_TYPE_DESC': 'Fact', 'MD_OBJ_TYPE_ID': '13', 'MD_OBJ_TYPE_BEZ': 'Fact'},
36
+ {'PA_OBJ_TYPE_ID': '102', 'PA_OBJ_TYPE_DESC': 'System Hierarchy', 'MD_OBJ_TYPE_ID': '14',
37
+ 'MD_OBJ_TYPE_BEZ': 'Dimension'},
38
+ {'PA_OBJ_TYPE_ID': '103', 'PA_OBJ_TYPE_DESC': 'User Hierarchy', 'MD_OBJ_TYPE_ID': '14',
39
+ 'MD_OBJ_TYPE_BEZ': 'Dimension'},
40
+ {'PA_OBJ_TYPE_ID': '35', 'PA_OBJ_TYPE_DESC': 'Transformation', 'MD_OBJ_TYPE_ID': '43',
41
+ 'MD_OBJ_TYPE_BEZ': 'Role'},
42
+ {'PA_OBJ_TYPE_ID': '5', 'PA_OBJ_TYPE_DESC': 'Consolidation', 'MD_OBJ_TYPE_ID': '47',
43
+ 'MD_OBJ_TYPE_BEZ': 'Consolidation'},
44
+ {'PA_OBJ_TYPE_ID': '7', 'PA_OBJ_TYPE_DESC': 'Document', 'MD_OBJ_TYPE_ID': '55',
45
+ 'MD_OBJ_TYPE_BEZ': 'DocumentDefinition'},
46
+ {'PA_OBJ_TYPE_ID': '14', 'PA_OBJ_TYPE_DESC': 'Dossier', 'MD_OBJ_TYPE_ID': '55',
47
+ 'MD_OBJ_TYPE_BEZ': 'DocumentDefinition'},
48
+ {'PA_OBJ_TYPE_ID': '110', 'PA_OBJ_TYPE_DESC': 'Security Filter', 'MD_OBJ_TYPE_ID': '58',
49
+ 'MD_OBJ_TYPE_BEZ': 'Security Filter'},
50
+ {'PA_OBJ_TYPE_ID': '-1', 'PA_OBJ_TYPE_DESC': 'Search', 'MD_OBJ_TYPE_ID': '39', 'MD_OBJ_TYPE_BEZ': 'Search'},
51
+ {'PA_OBJ_TYPE_ID': '-2', 'PA_OBJ_TYPE_DESC': 'Shortcut', 'MD_OBJ_TYPE_ID': '18',
52
+ 'MD_OBJ_TYPE_BEZ': 'Shortcut'},
53
+ ]
@@ -0,0 +1,67 @@
1
+ from mstr_robotics.mstr_classes import mstr_global
2
+ from mstr_robotics._connectors import mstr_api
3
+ from mstr_robotics._helper import str_func
4
+
5
+ class bld_short_cuts:
6
+
7
+ def __init__(self):
8
+ self.str= str_func()
9
+ #self.rep = rep
10
+ self.glob = mstr_global()
11
+ self.mstr_api = mstr_api()
12
+
13
+ def bld_short_cut(self,conn,folder_id,object_id,
14
+ object_type,new_name,object_desc):
15
+ #In Version 11 update 7, it's not possible to define a free name and description
16
+ # when creating a short cut. Thus I create the shurt cut first and rename it later
17
+ short_cut_obj_rep = self.mstr_api.cr_short_cut(conn=conn,object_id=object_id,object_type=object_type,folder_id=folder_id)
18
+ self.mstr_api.rename_object(conn=conn, object_id=short_cut_obj_rep.json()["id"], object_type=18, new_name=new_name, desc_str=object_desc)
19
+
20
+ def run_short_cut_build(self, conn,project_id,short_cut_df,folder_id,df_key_cols_d=None):
21
+ #requiers as imput a pandas data frame with 4 colmuns
22
+ # object_id, object_type, object_name, object_desc
23
+ conn.select_project(project_id)
24
+ if not df_key_cols_d:
25
+ df_key_cols_d={"object_id":"Object@GUID",
26
+ "object_type":"OBJECT_TYPE_ID",
27
+ "object_name":"Object@Name",
28
+ "object_desc":"OBJECT_DESC"}
29
+
30
+ #before adding new short cuts to the shortcut folder, all shortcuts gonna be deleted
31
+ self.clean_shortcut_folder(conn=conn,folder_id=folder_id)
32
+ short_cut_folder_j = f'{{"folderId": "{folder_id}"}}'
33
+ #iterrating throuh all the objects in the list
34
+ short_cut_df.reset_index()
35
+ for index, obj in short_cut_df.iterrows():
36
+ #short_cut_url = f'{conn.base_url}/objects/{obj[2]}/type/{str(obj[4])}/shortcuts'
37
+ try:
38
+ if obj[df_key_cols_d["object_type"]]!=str(18):
39
+ print(obj[df_key_cols_d["object_id"]] +"____"+ str(obj[df_key_cols_d["object_type"]]))
40
+ print("Create short: "+obj[df_key_cols_d["object_name"]]+" of type: "+str(obj[df_key_cols_d["object_type"]]) )
41
+ self.bld_short_cut(conn=conn
42
+ ,folder_id=folder_id
43
+ ,object_id=obj[df_key_cols_d["object_id"]]
44
+ ,object_type=obj[df_key_cols_d["object_type"]]
45
+ ,new_name=obj[df_key_cols_d["object_name"]]
46
+ #max lentgh of descriptions in MSTR
47
+ ,object_desc=self.str._get_first_x_chars(str_=str(obj[df_key_cols_d["object_desc"]]),i=249)
48
+ )
49
+ else:
50
+ print(f'Obect: {obj[2]} is a shortcut. MSTR does not allow short cuts o short cuts,'
51
+ f' thus they are not supported' )
52
+ except Exception as err:
53
+ print(f'Obect: {obj[2]} hasn not been created. The error is {err}')
54
+
55
+ return
56
+ #@logger
57
+ def clean_shortcut_folder(self,conn,folder_id):
58
+ existing_obj_l = self.glob.get_folder_obj_l(conn=conn, folder_id=folder_id)
59
+ obj_l = self._get_col_from_obj_l(dict_l=existing_obj_l, key_col="id")
60
+ self.glob._delete_object(conn=conn,existing_obj_l=existing_obj_l)
61
+
62
+ #@logger
63
+ def _get_col_from_obj_l(self, dict_l=None, key_col=None):
64
+ key_val_l = []
65
+ for o in dict_l:
66
+ key_val_l.append(o[key_col])
67
+ return key_val_l
@@ -0,0 +1,250 @@
1
+ import os
2
+ import pandas as pd
3
+ from langchain.vectorstores import FAISS
4
+ from langchain.embeddings import OpenAIEmbeddings
5
+ from openai import OpenAI
6
+ from flashtext import KeywordProcessor
7
+ from itertools import chain
8
+ from mstr_robotics.report import prompts,cube,rep
9
+ from mstr_robotics.mstr_pandas import df_helper
10
+ from mstr_robotics._helper import msic
11
+ from mstr_robotics.prepare_AI_data import map_objects
12
+ import json
13
+
14
+ i_KeywordProcessor = KeywordProcessor()
15
+ i_chain=chain()
16
+ i_rep=rep()
17
+ i_prompts=prompts()
18
+ i_df_helper=df_helper()
19
+ i_cube=cube()
20
+ i_map_objects=map_objects()
21
+ i_msic=msic()
22
+
23
+ class vectorDB_faisst():
24
+
25
+ def __init__(self,sKey):
26
+ #self.sKey=sKey
27
+ os.environ["OPENAI_API_KEY"] = sKey
28
+ self.i_embeddings = OpenAIEmbeddings()
29
+
30
+ def load_vector_store(self,key_l):
31
+ # Flatten and ensure all items are strings
32
+ # Create FAISS vector store
33
+ vector_store = FAISS.from_texts(key_l, self.i_embeddings)
34
+
35
+ return vector_store
36
+
37
+ def load_keyword_processor(self,key_l):
38
+ for val in key_l:
39
+ i_KeywordProcessor.add_keyword(val)
40
+ return i_KeywordProcessor
41
+
42
+ def extract_keywords(self,msg_t):
43
+ keywords_l = i_KeywordProcessor.extract_keywords(msg_t)
44
+ return keywords_l
45
+
46
+ class run_chat_request():
47
+
48
+ def __init__(self,cube_obj_prp_rel_id
49
+ ,cube_RAG_form_val_ans_id
50
+ ,cube_att_form_def_id
51
+ ,rep_dos_id
52
+ ,mstr_rag_col_d):
53
+
54
+ self.cube_obj_prp_rel_id=cube_obj_prp_rel_id
55
+ self.cube_RAG_form_val_ans_id=cube_RAG_form_val_ans_id
56
+ self.rep_dos_id=rep_dos_id
57
+ self.mstr_rag_col_d=mstr_rag_col_d
58
+ self.cube_att_form_def_id=cube_att_form_def_id
59
+
60
+
61
+ def bld_AI_filt_prp_ans(self,conn,vector_store,filter_d):
62
+ # print(json_f)
63
+ # v_andOr_s="And"
64
+ # att_filt_prp_id="1F21042E4FC08886A9D7E4920CA4EC59"
65
+ # met_filt_prp_id="14B57F1F46127BC6E6F746888BC3C7CB"
66
+ prp_ans_d_l = []
67
+
68
+ # ={}
69
+ last_p_ans_d_j = {}
70
+
71
+ for f in list(filter_d.keys()):
72
+ print(f)
73
+ results = vector_store.similarity_search_with_score(query=f, top_k=1)
74
+
75
+ filter_obj_name = results[0][0].page_content
76
+ #print(filter_obj_name)
77
+ #print(self.mstr_rag_col_d)
78
+ filt_obj_rag_df = i_map_objects.get_rag_rep_prp_df(conn, cube_id=self.cube_obj_prp_rel_id, rep_dos_id=self.rep_dos_id,
79
+ key_word_l=[filter_obj_name],mstr_rag_col_d=self.mstr_rag_col_d)
80
+
81
+ filt_obj_rag_df = filt_obj_rag_df[filt_obj_rag_df['prp_subType'].isin(['prompt_expression'])]
82
+
83
+ operator = next(iter(filter_d[f]))
84
+ filter_val_l = filter_d[f][operator]
85
+ #print("DDDDDDDDDDDDDDDDD")
86
+ #print(filt_obj_rag_df)
87
+ d_prp_ans_d = {}
88
+ for index, obj in filt_obj_rag_df.iterrows():
89
+ d_prp_ans_d["prompt_id"] = obj["prompt_id"]
90
+ d_prp_ans_d["prp_subType"] = obj["prp_subType"]
91
+ d_prp_ans_d["object_id"] = obj["object_id"]
92
+ d_prp_ans_d["obj_type"] = obj["obj_type"]
93
+ d_prp_ans_d["operator"] = operator
94
+ if obj["obj_type"] == "attribute":
95
+ if operator in ("In", "notIn"):
96
+
97
+ filter_val_df = i_map_objects.get_rag_rep_prp_df(conn, cube_id=self.cube_RAG_form_val_ans_id,
98
+ rep_dos_id=self.rep_dos_id, key_word_l=filter_val_l,mstr_rag_col_d=self.mstr_rag_col_d)
99
+ filt_df = pd.merge(filt_obj_rag_df[["prompt_id", "prp_subType", "object_id", "obj_type"]],
100
+ filter_val_df[
101
+ ["prompt_id", "prp_subType", "attribute_id", "attribute_name", "form_id",
102
+ "form_name", "form_dataType", "key"]],
103
+ left_on=['object_id'], right_on=['attribute_id'], how='inner')
104
+ filt_df = i_df_helper.clean_double_col(df=filt_df)
105
+ #print(filt_df)
106
+ filter_val_l = []
107
+ for index, f_form_ele in filt_df.iterrows():
108
+ form_id = f_form_ele["form_id"]
109
+ form_dataType = f_form_ele["form_dataType"]
110
+ filter_val_l.append(f_form_ele["key"])
111
+
112
+ att_exp_ans_d = {"att_id": d_prp_ans_d["object_id"], "att_form_id": form_id,
113
+ "form_data_type": form_dataType, "operator": operator,
114
+ "filter_val_l": filter_val_l}
115
+
116
+ att_exp_ans_d = i_prompts.bld_att_exp_prp_l(prp_job_ans_d=att_exp_ans_d)
117
+ d_prp_ans_d["prp_ans_d"] = att_exp_ans_d
118
+ prp_ans_d_l.append(d_prp_ans_d.copy())
119
+ #print(d_prp_ans_d)
120
+
121
+ else:
122
+ col_id = i_cube.get_RAG_cube_col_mstr_id(cube_id=self.cube_att_form_def_id, col_name="attribute_id",mstr_rag_col_d=self.mstr_rag_col_d)
123
+ attr_elements = col_id + ":" + obj["object_id"]
124
+ df = i_cube.quick_query_cube(conn, cube_id=self.cube_att_form_def_id, attribute_l=None, metric_l=None,
125
+ attr_elements=attr_elements)
126
+
127
+ for index, form in df.iterrows():
128
+ if int(form["display_form_nr"]) > 0:
129
+ att_exp_ans_d = {"att_id": form["attribute_id"], "att_form_id": form["form_id"],
130
+ "form_data_type": form["REST_form_type"], "operator": operator,
131
+ "filter_val_l": filter_val_l}
132
+
133
+ att_exp_ans_d = i_prompts.bld_att_exp_prp(prp_job_ans_d=att_exp_ans_d)
134
+ d_prp_ans_d["prp_ans_d"] = att_exp_ans_d
135
+ prp_ans_d_l.append(d_prp_ans_d.copy())
136
+ #print(d_prp_ans_d)
137
+
138
+ if obj["obj_type"] == "metric":
139
+ metric_exp_prp = {}
140
+ metric_exp_prp["met_id"] = obj["object_id"]
141
+ metric_exp_prp["data_type"] = "Real"
142
+ metric_exp_prp["operator"] = operator
143
+ metric_exp_prp["filter_val_l"] = filter_val_l
144
+ metric_exp_prp["level"] = "default"
145
+ d_prp_ans_d["prp_ans_d"] = i_prompts.bld_metric_exp_prp(metric_exp_prp=metric_exp_prp.copy())
146
+ prp_ans_d_l.append(d_prp_ans_d.copy())
147
+ #print(print(d_prp_ans_d))
148
+
149
+ # prp_ans_d_l.append(last_p_ans_d_j.copy())
150
+ return prp_ans_d_l
151
+
152
+ def bld_ai_obj_ans_prp(self,conn,json_t_d):
153
+ key_l = []
154
+ col_id = i_cube.get_RAG_cube_col_mstr_id(cube_id=self.cube_obj_prp_rel_id, col_name="object_id",mstr_rag_col_d=self.mstr_rag_col_d)
155
+ obj_l = []
156
+ template_obj_d = {}
157
+
158
+ for obj_type in json_t_d["template"].keys():
159
+ for obj in json_t_d["template"][obj_type]:
160
+ template_obj_d = {"obj_type": obj_type, "obj": obj}
161
+ obj_l.append(template_obj_d.copy())
162
+
163
+ for obj in obj_l:
164
+ key_l.append(obj["obj"])
165
+
166
+ template_obj_rag_df = i_map_objects.get_rag_rep_prp_df(conn, cube_id=self.cube_obj_prp_rel_id, rep_dos_id=self.rep_dos_id,
167
+ key_word_l=key_l,mstr_rag_col_d=self.mstr_rag_col_d)
168
+ template_obj_rag_df = template_obj_rag_df[template_obj_rag_df['prp_subType'].isin(['prompt_objects'])]
169
+ template_obj_rag_df = template_obj_rag_df[['prompt_id', 'prp_subType', "object_id", "obj_type"]]
170
+
171
+ template_obj_rag_df.rename(columns={'object_id': 'id', 'obj_type': 'type'}, inplace=True)
172
+ prp_ans_d_l = template_obj_rag_df.groupby(['prompt_id']).apply(
173
+ lambda x: x[['id', 'type']].to_dict(orient='records')).to_dict()
174
+ obj_prp_ans_l = []
175
+ for prp in prp_ans_d_l:
176
+ obj_prp_ans_d = {}
177
+ obj_prp_ans_d["id"] = prp
178
+ obj_prp_ans_d["type"] = "OBJECTS"
179
+ obj_prp_ans_d["answers"] = prp_ans_d_l[prp]
180
+ obj_prp_ans_l.append(obj_prp_ans_d)
181
+
182
+ return obj_prp_ans_l
183
+
184
+ def merge_exp_prp_ans_l(self,ai_prp_filt_ans_d):
185
+ prp_ans_l = []
186
+ prp_id_l = i_msic.get_key_form_dict_l(dict_l=ai_prp_filt_ans_d, key="prompt_id")
187
+ prp_ans_d_all = {}
188
+ operand_X = "AND"
189
+ for prp_id in prp_id_l:
190
+ prp_ans_d_all[prp_id] = []
191
+
192
+ for prp_ans in ai_prp_filt_ans_d:
193
+ for prp_id in prp_ans_d_all.keys():
194
+ if prp_ans["prompt_id"] == prp_id:
195
+ prp_ans_d_all[prp_id].append(prp_ans["prp_ans_d"])
196
+
197
+ for prp_id in prp_ans_d_all:
198
+ # print(prp_ans_d_all[prp_id])
199
+ prp_ans_d_all[prp_id] = i_prompts.bld_exp_operands_d(p_ans_d_d_l=prp_ans_d_all[prp_id], operator="AND")
200
+
201
+ for prp_ans_id in prp_ans_d_all:
202
+ for prp in ai_prp_filt_ans_d:
203
+ if prp_ans_id == prp["prompt_id"]:
204
+ if prp["prp_subType"] == "prompt_expression" and prp["obj_type"] == "attribute":
205
+ prp_ans_l.append(i_prompts.bld_prp_exp_d(prompt_id=prp_ans_id,
206
+ p_ans_d_j=prp_ans_d_all[prp_ans_id], operator="And"))
207
+
208
+ if prp["prp_subType"] == "prompt_expression" and prp["obj_type"] == "metric":
209
+ prp_ans_l.append(i_prompts.frame_metric_exp_prp(prompt_id=prp_ans_id, p_ans_d_j=prp_ans_d_all[prp_ans_id]))
210
+ break
211
+ return prp_ans_l
212
+
213
+ def save_AI_rep(self, conn, rep_wizzard_id, prompt_answ, ai_rep_name, ai_rep_folder_id):
214
+ instance_id = i_rep.open_Instance(conn=conn, report_id=rep_wizzard_id)
215
+ first_draft = i_rep.set_inst_prompt_ans(conn=conn, report_id=rep_wizzard_id, instance_id=instance_id,
216
+ prompt_answ=prompt_answ)
217
+ rep_id = i_rep.save_rep_inst(conn=conn, instance_id=instance_id, rep_name=ai_rep_name
218
+ , save_mode="OVERWRITE"
219
+ , promptOption="static"
220
+ , setCurrentAsDefaultAnswer=True)
221
+
222
+ return rep_id
223
+
224
+
225
+ class openAI():
226
+
227
+ def __init__(self,sKey):
228
+ #self.sKey=sKey
229
+ os.environ["OPENAI_API_KEY"] = sKey
230
+ self.i_embeddings = OpenAIEmbeddings()
231
+
232
+ def check_trans_chatGPT(self,sKey,messages,*args,**kwargs):
233
+ chat_completion = self.call_open_AI(sKey=sKey,messages=messages,*args,**kwargs)
234
+ js = json.loads(chat_completion.json())
235
+ return js
236
+
237
+ def call_open_AI(self, sKey, messages, max_tokens=1000, temperature=0.3, model="gpt-4o-mini"):
238
+ # This is the default and can be omitted
239
+ client = OpenAI(api_key=sKey)
240
+
241
+ chat_completion = client.chat.completions.create(
242
+ messages=messages,
243
+ # model="gpt-3.5-turbo",
244
+ model=model,
245
+ max_tokens=max_tokens,
246
+ temperature=temperature
247
+ )
248
+ js = json.loads(chat_completion.json())
249
+ return js
250
+