Skip to content

Commit 959b293

Browse files
committed
added admin response feature
Signed-off-by: lochan paudel <lochanpaudel10@gmail.com>
1 parent 16c2a9d commit 959b293

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

src/mvt/menu.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def authenticated_menu():
2121
st.sidebar.page_link("pages/build_knowledgebase.py", label="Build Knowledge Base")
2222
st.sidebar.page_link("pages/prompt_management.py", label="Prompt Management")
2323
st.sidebar.page_link("pages/user_management.py", label="User Management")
24+
st.sidebar.page_link("pages/admin_responses.py", label="Admin Responses")
2425
st.sidebar.page_link("app.py", label="About")
2526

2627
def unauthenticated_menu():

src/mvt/pages/admin_responses.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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

Comments
 (0)