11from itertools import groupby
2-
2+ import numpy as np
33import streamlit as st
4- from test2text .services .db import DbClient
5-
64
7- def add_new_line (summary ):
8- return summary .replace ("\n " , "<br>" )
5+ from test2text .services .db import DbClient
6+ from test2text .services .utils import unpack_float32
7+ from test2text .services .visualisation .visualize_vectors import minifold_vectors_2d , plot_vectors_2d
98
109
10+
1111def make_a_report ():
12- st .header ("Test2Text Report" )
13-
14- db = DbClient ("./private/requirements.db" )
15-
16- st .subheader ("Table of Contents" )
17-
18- data = db .conn .execute ("""
19- SELECT
20- Requirements.id as req_id,
21- Requirements.external_id as req_external_id,
22- Requirements.summary as req_summary,
23-
24- Annotations.id as anno_id,
25- Annotations.summary as anno_summary,
26-
27- AnnotationsToRequirements.cached_distance as distance,
28-
29- TestCases.id as case_id,
30- TestCases.test_script as test_script,
31- TestCases.test_case as test_case
32- FROM
33- Requirements
34- JOIN AnnotationsToRequirements ON Requirements.id = AnnotationsToRequirements.requirement_id
35- JOIN Annotations ON Annotations.id = AnnotationsToRequirements.annotation_id
36- JOIN CasesToAnnos ON Annotations.id = CasesToAnnos.annotation_id
37- JOIN TestCases ON TestCases.id = CasesToAnnos.case_id
38- ORDER BY
39- Requirements.id, AnnotationsToRequirements.cached_distance, TestCases.id
40- """ )
41-
42- current_annotations = {}
43- current_test_scripts = set ()
44-
45- def write_requirement (req_id , req_external_id , req_summary ,
46- current_annotations : set [tuple ], current_test_scripts : set ):
47- if req_id is None and req_external_id is None :
48- return False
49-
50- with st .expander (f"#{ req_id } Requirement { req_external_id } " ):
51- st .subheader (f"Requirement { req_external_id } " )
52- st .html (f"<p>{ add_new_line (req_summary )} </p>" )
53- st .subheader ("Annotations" )
54- anno , summary , dist = st .columns (3 )
55- with anno :
56- st .write ("Annonation's id" )
57- with summary :
58- st .write ("Summary" )
59- with dist :
60- st .write ("Distance" )
61- for anno_id , anno_summary , distance in current_annotations :
62- anno , summary , dist = st .columns (3 )
63- with anno :
64- st .write (f"{ anno_id } " )
65- with summary :
66- st .html (
67- f"{ add_new_line (anno_summary )} "
68- )
69- with dist :
70- st .write (round (distance , 2 ))
71-
72- st .subheader ("Test Scripts" )
73- for test_script in current_test_scripts :
74- st .markdown (f"- { test_script } " )
75-
76- progress_bar = st .empty ()
77- rows = data .fetchall ()
78- if not rows :
79- st .error ("There is no data to inspect.\n Please upload annotations." )
80- return None
81- max_progress = len (rows )
82- index = 0
83- for (req_id , req_external_id , req_summary ), group in groupby (rows , lambda x : x [0 :3 ]):
84- current_annotations = set ()
85- current_test_scripts = set ()
86- index += 1
87- for _ , _ , _ , anno_id , anno_summary , distance , case_id , test_script , test_case in group :
88- current_annotations .add ((anno_id , anno_summary , distance ))
89- current_test_scripts .add (test_script )
90- write_requirement (req_id = req_id , req_external_id = req_external_id , req_summary = req_summary ,
91- current_annotations = current_annotations , current_test_scripts = current_test_scripts )
92-
93-
94- progress_bar .progress (round (index * 100 / max_progress ), text = "Processing..." )
95- progress_bar .empty ()
96- db .conn .close ()
97-
9812
13+ st .header ("Test2Text Report" )
14+
15+
16+ db = DbClient ("./private/requirements.db" )
17+
18+
19+ def write_annotations (current_annotations : set [tuple ]):
20+ anno , summary , dist = st .columns (3 )
21+ with anno :
22+ st .write ("Annonation's id" )
23+ with summary :
24+ st .write ("Summary" )
25+ with dist :
26+ st .write ("Distance" )
27+ for anno_id , anno_summary , _ , distance in current_annotations :
28+ anno , summary , dist = st .columns (3 )
29+ with anno :
30+ st .write (f"{ anno_id } " )
31+ with summary :
32+ st .write (anno_summary )
33+ with dist :
34+ st .write (round (distance , 2 ))
35+
36+ with st .container (border = True ):
37+ st .subheader ("Filter requirements" )
38+ with st .expander ("🔍 Filters" ):
39+ r_id , summary , embed = st .columns (3 )
40+ with r_id :
41+ filter_id = st .text_input ("ID" , value = "" , key = "filter_id" )
42+ st .info ("Filter by external ID" )
43+ with summary :
44+ filter_summary = st .text_input ("Text content" , value = "" , key = "filter_summary" )
45+ st .info ("Search concrete phrases using SQL like expressions" )
46+ with embed :
47+ filter_embedding = st .text_input ("Smart rearch" , value = "" , key = "filter_embedding" )
48+ st .info ("Search using embeddings" )
49+
50+ where_clauses = []
51+ params = []
52+
53+ if filter_id .strip ():
54+ where_clauses .append ("Requirements.id = ?" )
55+ params .append (filter_id .strip ())
56+
57+ if filter_summary .strip ():
58+ where_clauses .append ("Requirements.summary LIKE ?" )
59+ params .append (f"%{ filter_summary .strip ()} %" )
60+
61+ # TODO embeddings фильтр не реализован
62+ if filter_embedding .strip ():
63+ st .info ("Фильтрация по embeddings не реализована в демо. Используйте другие фильтры." )
64+
65+ where_sql = ""
66+ if where_clauses :
67+ where_sql = f"WHERE { ' AND ' .join (where_clauses )} "
68+
69+
70+ with st .container (border = True ):
71+ st .session_state .update ({"req_form_submitting" : True })
72+ sql = f"""
73+ SELECT
74+ Requirements.id as req_id,
75+ Requirements.external_id as req_external_id,
76+ Requirements.summary as req_summary
77+ FROM
78+ Requirements
79+ { where_sql }
80+ ORDER BY
81+ Requirements.id
82+ """
83+ data = db .conn .execute (sql , params )
84+
85+ requirements_dict = {f"#{ req_id } Requirement { req_external_id } " : req_id for (req_id , req_external_id , _ ) in data .fetchall ()}
86+ st .subheader ("Choose 1 of filtered requirements" )
87+ option = st .selectbox (
88+ "Choose a requirement to work with" ,
89+ requirements_dict .keys (),
90+ key = "filter_req_id"
91+ )
92+
93+ if option :
94+ clause = "Requirements.id = ?"
95+ if clause in where_clauses :
96+ idx = where_clauses .index (clause )
97+ params .insert (idx , requirements_dict [option ])
98+ else :
99+ where_clauses .append (clause )
100+ params .append (requirements_dict [option ])
101+ where_sql = ""
102+ if where_clauses :
103+ where_sql = f"WHERE { ' AND ' .join (where_clauses )} "
104+
105+ sql = f"""
106+ SELECT
107+ Requirements.id as req_id,
108+ Requirements.external_id as req_external_id,
109+ Requirements.summary as req_summary,
110+ Requirements.embedding as req_embedding,
111+
112+ Annotations.id as anno_id,
113+ Annotations.summary as anno_summary,
114+ Annotations.embedding as anno_embedding,
115+
116+ AnnotationsToRequirements.cached_distance as distance,
117+
118+ TestCases.id as case_id,
119+ TestCases.test_script as test_script,
120+ TestCases.test_case as test_case
121+ FROM
122+ Requirements
123+ JOIN AnnotationsToRequirements ON Requirements.id = AnnotationsToRequirements.requirement_id
124+ JOIN Annotations ON Annotations.id = AnnotationsToRequirements.annotation_id
125+ JOIN CasesToAnnos ON Annotations.id = CasesToAnnos.annotation_id
126+ JOIN TestCases ON TestCases.id = CasesToAnnos.case_id
127+ { where_sql }
128+ ORDER BY
129+ Requirements.id, AnnotationsToRequirements.cached_distance, TestCases.id
130+ """
131+
132+ rows = data .fetchall ()
133+ if not rows :
134+ st .error ("There is no data to inspect.\n "
135+ "Please upload annotations and requirements." )
136+ return None
137+
138+ st .subheader ("Filter Test cases" )
139+
140+ with st .expander ("🔍 Filters" ):
141+ radius , limit = st .columns (2 )
142+ with radius :
143+ filter_radius = st .number_input ("Insert a radius" , key = "filter_radius" )
144+ st .info ("Max distance to annotation" )
145+ with limit :
146+ filter_limit = st .text_input ("Limit" , value = "" , key = "filter_limit" )
147+ st .info ("Limit of selected test cases" )
148+
149+ for (req_id , req_external_id , req_summary , req_embedding ), group in groupby (rows , lambda x : x [0 :4 ]):
150+ with st .container (border = True ):
151+ st .subheader (f" Inspect Requirement { req_external_id } " )
152+ st .write (req_summary )
153+ current_test_cases = dict ()
154+ for _ , _ , _ , _ , anno_id , anno_summary , anno_embedding , distance , case_id , test_script , test_case in group :
155+ current_annotation = current_test_cases .get (test_case , set ())
156+ current_test_cases .update ({test_case : current_annotation })
157+ current_test_cases [test_case ].add ((anno_id , anno_summary , anno_embedding , distance ))
158+
159+ t_cs , anno , viz = st .columns (3 )
160+ with t_cs :
161+ with st .container (border = True ):
162+ st .write ("Test Cases" )
163+ st .markdown ("""
164+ <style>
165+ .stRadio > div {
166+ max-width: 350px;
167+ word-break: break-word;
168+ white-space: pre-line;
169+ }
170+ </style>
171+ """ , unsafe_allow_html = True )
172+ st .radio ("" , current_test_cases .keys (), key = "radio_choice" )
173+ if st .session_state ["radio_choice" ]:
174+ with anno :
175+ with st .container (border = True ):
176+ st .write ("Annotations" )
177+ write_annotations (current_annotations = current_test_cases [st .session_state ["radio_choice" ]])
178+
179+ with viz :
180+ with st .container (border = True ):
181+ pass
182+ #req_dot = np.array(unpack_float32(req_embedding)) TODO
183+ #plot_vectors_2d(minifold_vectors_2d(np.array([req_dot])), "Requirements")
184+
185+ db .conn .close ()
186+
187+
99188if __name__ == "__main__" :
100- make_a_report ()
189+ make_a_report ()
0 commit comments