1+ import streamlit as st
2+ import os
3+ import re
4+ from menu import menu_with_redirect
5+ from utils import load_yaml_file_with_db_prompts
6+
7+ # Redirect to app.py if not logged in, otherwise show the navigation menu
8+ menu_with_redirect ()
9+
10+ # Verify the user's role
11+ if st .session_state .user_type not in ["admin" ]:
12+ st .warning ("You do not have permission to view this page." )
13+ st .stop ()
14+
15+ st .markdown ("# Admin Responses" )
16+ st .markdown ("View previously asked user questions, AI-generated answers, and source documents." )
17+
18+ def parse_responses_file ():
19+ """Parse the responses.txt file and return a list of question-answer pairs with context"""
20+ responses_file = "responses.txt"
21+ if not os .path .exists (responses_file ):
22+ return []
23+
24+ responses = []
25+ try :
26+ with open (responses_file , 'r' , encoding = 'utf-8' ) as f :
27+ lines = f .read ().strip ().split ('\n ' )
28+
29+ for line in lines :
30+ if line .strip ():
31+ parsed_response = parse_response_line (line )
32+ if parsed_response :
33+ responses .append (parsed_response )
34+
35+ except Exception as e :
36+ st .error (f"Error reading responses file: { str (e )} " )
37+ return []
38+
39+ return responses
40+
41+ def parse_response_line (line ):
42+ """Parse a single response line that contains Document objects"""
43+ try :
44+ # Extract the input (question)
45+ input_match = re .search (r"'input': '((?:[^'\\]|\\.)*)'" , line )
46+ question = input_match .group (1 ) if input_match else "No question found"
47+ question = question .replace ("\\ '" , "'" ).replace ("\\ n" , "\n " )
48+
49+ # Extract the answer
50+ answer_match = re .search (r"'answer': '((?:[^'\\]|\\.)*)'(?=\})" , line )
51+ answer = answer_match .group (1 ) if answer_match else "No answer found"
52+ answer = answer .replace ("\\ '" , "'" ).replace ("\\ n" , "\n " )
53+
54+ # Extract documents from context
55+ documents = []
56+ doc_pattern = r"Document\(id='([^']*)', metadata=\{([^}]*)\}, page_content='((?:[^'\\]|\\.)*)'\)"
57+ doc_matches = re .findall (doc_pattern , line )
58+
59+ for doc_match in doc_matches :
60+ doc_id , metadata_str , content = doc_match
61+
62+ # Parse metadata
63+ metadata = {'id' : doc_id }
64+ metadata_pairs = re .findall (r"'([^']*)': '([^']*)'" , metadata_str )
65+ for key , value in metadata_pairs :
66+ metadata [key ] = value
67+
68+ documents .append ({
69+ 'id' : doc_id ,
70+ 'metadata' : metadata ,
71+ 'page_content' : content .replace ("\\ '" , "'" ).replace ("\\ n" , "\n " )
72+ })
73+
74+ return {
75+ 'input' : question ,
76+ 'answer' : answer ,
77+ 'context' : documents
78+ }
79+
80+ except Exception as e :
81+ return {
82+ 'input' : "Error parsing question" ,
83+ 'answer' : f"Error parsing answer: { str (e )[:100 ]} " ,
84+ 'context' : []
85+ }
86+
87+ def display_source_document (doc , index ):
88+ """Display a source document with metadata"""
89+ st .markdown (f"**:page_facing_up: Document { index + 1 } **" )
90+
91+ # Display content
92+ content = doc .get ('page_content' , '' )
93+ st .markdown ("**Content:**" )
94+ st .text (content )
95+
96+ # Display metadata
97+ st .markdown ("**Metadata:**" )
98+ metadata = doc .get ('metadata' , {})
99+
100+ for key , value in metadata .items ():
101+ st .write (f"- **{ key .title ()} :** { value } " )
102+
103+ # Load and display responses
104+ config_data = load_yaml_file_with_db_prompts ("config.yaml" )
105+ k_value = config_data .get ("nr_retrieved_documents" )
106+ print (k_value )
107+
108+ responses = parse_responses_file ()
109+
110+ if responses :
111+ st .markdown (f"### Overview ({ len (responses )} responses found)" )
112+
113+ # Search functionality
114+ search_term = st .text_input ("Search questions or answers:" , placeholder = "Enter search term..." )
115+
116+ # Filter responses based on search term
117+ if search_term :
118+ display_responses = [
119+ response for response in responses
120+ if search_term .lower () in response .get ('input' , '' ).lower () or
121+ search_term .lower () in response .get ('answer' , '' ).lower ()
122+ ]
123+ st .success (f"Found { len (display_responses )} matching responses" )
124+ else :
125+ display_responses = responses
126+
127+ st .markdown ("---" )
128+
129+ # Display each response
130+ for i , response in enumerate (reversed (display_responses )):
131+ question = response .get ('input' , 'No question found' )
132+ answer = response .get ('answer' , 'No answer found' )
133+ context = response .get ('context' , [])
134+
135+ # Display question in an expander
136+ question_preview = question [:80 ] + '...' if len (question ) > 80 else question
137+ with st .expander (f"**Q{ len (display_responses ) - i } :** { question_preview } " , expanded = False ):
138+ if len (question ) > 80 :
139+ st .markdown (f"**Full Question:** { question } " )
140+
141+ st .markdown ("**Answer:**" )
142+ st .markdown (answer )
143+
144+ # Display source documents
145+ if context :
146+ displayed_docs = context [:k_value ] if k_value else context
147+ st .markdown (f"**Source Documents ({ len (displayed_docs )} of { len (context )} ):**" )
148+
149+ for doc_idx , doc in enumerate (displayed_docs ):
150+ display_source_document (doc , doc_idx )
151+ if doc_idx < len (displayed_docs ) - 1 :
152+ st .markdown ("---" )
153+ else :
154+ st .info ("No source documents found." )
155+ else :
156+ st .info ("No responses found. The responses.txt file is empty or doesn't exist." )
0 commit comments