hi
Browse files- app.py +153 -22
- chatbot_page.py +8 -4
app.py
CHANGED
@@ -422,8 +422,23 @@ def create_ui() -> gr.Blocks:
|
|
422 |
transform: scale(1.02);
|
423 |
}
|
424 |
|
425 |
-
/*
|
426 |
-
.gr-dataframe td:nth-child(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
cursor: default;
|
428 |
}
|
429 |
|
@@ -554,6 +569,7 @@ def create_ui() -> gr.Blocks:
|
|
554 |
with gr.Row():
|
555 |
analyze_next_btn = gr.Button("β‘ Analyze Next Repository", variant="primary", size="lg", scale=1)
|
556 |
analyze_all_btn = gr.Button("π Analyze All Repositories", variant="secondary", size="lg", scale=1)
|
|
|
557 |
with gr.Column(scale=2):
|
558 |
status_box_analysis = gr.Textbox(label="π Analysis Status", interactive=False, lines=2)
|
559 |
|
@@ -599,6 +615,26 @@ def create_ui() -> gr.Blocks:
|
|
599 |
|
600 |
gr.Markdown("π‘ **Tip:** Click on any repository name to explore it in detail!")
|
601 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
602 |
# Modal popup for repository action selection
|
603 |
with gr.Row():
|
604 |
with gr.Column():
|
@@ -802,14 +838,14 @@ def create_ui() -> gr.Blocks:
|
|
802 |
status = "Status: Keywords extracted. User requirements saved for analysis."
|
803 |
return final_keywords_str, status, user_requirements
|
804 |
|
805 |
-
def handle_dataframe_select(evt: gr.SelectData, df_data) -> Tuple[str, Any, Any]:
|
806 |
-
"""Handle dataframe row selection -
|
807 |
print(f"DEBUG: Selection event triggered!")
|
808 |
print(f"DEBUG: evt = {evt}")
|
809 |
print(f"DEBUG: df_data type = {type(df_data)}")
|
810 |
|
811 |
if evt is None:
|
812 |
-
return "", gr.update(visible=False), gr.update()
|
813 |
|
814 |
try:
|
815 |
# Get the selected row and column from the event
|
@@ -817,23 +853,41 @@ def create_ui() -> gr.Blocks:
|
|
817 |
col_idx = evt.index[1]
|
818 |
print(f"DEBUG: Selected row {row_idx}, column {col_idx}")
|
819 |
|
820 |
-
# Only respond to clicks on the repo ID column (column 0)
|
821 |
-
if col_idx != 0:
|
822 |
-
print(f"DEBUG: Clicked on column {col_idx}, ignoring (only repo ID column responds)")
|
823 |
-
return "", gr.update(visible=False), gr.update()
|
824 |
-
|
825 |
# Handle pandas DataFrame
|
826 |
if isinstance(df_data, pd.DataFrame) and not df_data.empty and row_idx < len(df_data):
|
827 |
-
# Get the repository ID from the first column
|
828 |
-
repo_id = df_data.iloc[row_idx, 0] # First column contains repo id
|
829 |
-
print(f"DEBUG: Extracted repo_id = '{repo_id}'")
|
830 |
|
831 |
-
#
|
832 |
-
if
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
837 |
else:
|
838 |
print(f"DEBUG: df_data is not a DataFrame or row_idx {row_idx} out of range")
|
839 |
|
@@ -841,7 +895,7 @@ def create_ui() -> gr.Blocks:
|
|
841 |
print(f"DEBUG: Exception occurred: {e}")
|
842 |
logger.error(f"Error handling dataframe selection: {e}")
|
843 |
|
844 |
-
return "", gr.update(visible=False), gr.update()
|
845 |
|
846 |
def handle_analyze_all_repos(repo_ids: List[str], user_requirements: str, progress=gr.Progress()) -> Tuple[pd.DataFrame, str, pd.DataFrame, Any]:
|
847 |
"""Analyzes all repositories in the CSV file with progress tracking."""
|
@@ -973,6 +1027,71 @@ def create_ui() -> gr.Blocks:
|
|
973 |
"""Handle closing the modal."""
|
974 |
return gr.update(visible=False)
|
975 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
976 |
# --- Component Event Wiring ---
|
977 |
|
978 |
# Initialize chatbot with welcome message on app load
|
@@ -1062,18 +1181,30 @@ def create_ui() -> gr.Blocks:
|
|
1062 |
outputs=[repo_action_modal]
|
1063 |
)
|
1064 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1065 |
# Add dataframe selection event
|
1066 |
df_output.select(
|
1067 |
fn=handle_dataframe_select,
|
1068 |
inputs=[df_output],
|
1069 |
-
outputs=[selected_repo_display, repo_action_modal, tabs]
|
1070 |
)
|
1071 |
|
1072 |
# Add selection event for top repositories dataframe too
|
1073 |
top_repos_df.select(
|
1074 |
fn=handle_dataframe_select,
|
1075 |
inputs=[top_repos_df],
|
1076 |
-
outputs=[selected_repo_display, repo_action_modal, tabs]
|
|
|
|
|
|
|
|
|
|
|
|
|
1077 |
)
|
1078 |
|
1079 |
return app
|
|
|
422 |
transform: scale(1.02);
|
423 |
}
|
424 |
|
425 |
+
/* Make content columns (strengths, weaknesses, speciality) clickable for text expansion */
|
426 |
+
.gr-dataframe td:nth-child(2),
|
427 |
+
.gr-dataframe td:nth-child(3),
|
428 |
+
.gr-dataframe td:nth-child(4) {
|
429 |
+
cursor: pointer;
|
430 |
+
transition: all 0.3s ease;
|
431 |
+
}
|
432 |
+
|
433 |
+
.gr-dataframe td:nth-child(2):hover,
|
434 |
+
.gr-dataframe td:nth-child(3):hover,
|
435 |
+
.gr-dataframe td:nth-child(4):hover {
|
436 |
+
background-color: rgba(102, 126, 234, 0.08);
|
437 |
+
box-shadow: inset 0 0 0 1px rgba(102, 126, 234, 0.2);
|
438 |
+
}
|
439 |
+
|
440 |
+
/* Relevance column - not clickable */
|
441 |
+
.gr-dataframe td:nth-child(5) {
|
442 |
cursor: default;
|
443 |
}
|
444 |
|
|
|
569 |
with gr.Row():
|
570 |
analyze_next_btn = gr.Button("β‘ Analyze Next Repository", variant="primary", size="lg", scale=1)
|
571 |
analyze_all_btn = gr.Button("π Analyze All Repositories", variant="secondary", size="lg", scale=1)
|
572 |
+
reset_all_btn = gr.Button("π Reset Everything", variant="stop", size="lg", scale=1)
|
573 |
with gr.Column(scale=2):
|
574 |
status_box_analysis = gr.Textbox(label="π Analysis Status", interactive=False, lines=2)
|
575 |
|
|
|
615 |
|
616 |
gr.Markdown("π‘ **Tip:** Click on any repository name to explore it in detail!")
|
617 |
|
618 |
+
# Text expansion modal for showing full content
|
619 |
+
with gr.Row():
|
620 |
+
with gr.Column():
|
621 |
+
text_expansion_modal = gr.Column(visible=False)
|
622 |
+
with text_expansion_modal:
|
623 |
+
gr.Markdown("### π Full Content View")
|
624 |
+
expanded_content_title = gr.Textbox(
|
625 |
+
label="Content Type",
|
626 |
+
interactive=False,
|
627 |
+
info="Full text content for the selected field"
|
628 |
+
)
|
629 |
+
expanded_content_text = gr.Textbox(
|
630 |
+
label="Full Text",
|
631 |
+
lines=10,
|
632 |
+
interactive=False,
|
633 |
+
show_copy_button=True,
|
634 |
+
info="Complete untruncated content"
|
635 |
+
)
|
636 |
+
close_text_modal_btn = gr.Button("β Close", size="lg")
|
637 |
+
|
638 |
# Modal popup for repository action selection
|
639 |
with gr.Row():
|
640 |
with gr.Column():
|
|
|
838 |
status = "Status: Keywords extracted. User requirements saved for analysis."
|
839 |
return final_keywords_str, status, user_requirements
|
840 |
|
841 |
+
def handle_dataframe_select(evt: gr.SelectData, df_data) -> Tuple[str, Any, Any, str, str, Any]:
|
842 |
+
"""Handle dataframe row selection - repo ID shows modal, content columns show full text."""
|
843 |
print(f"DEBUG: Selection event triggered!")
|
844 |
print(f"DEBUG: evt = {evt}")
|
845 |
print(f"DEBUG: df_data type = {type(df_data)}")
|
846 |
|
847 |
if evt is None:
|
848 |
+
return "", gr.update(visible=False), gr.update(), "", "", gr.update(visible=False)
|
849 |
|
850 |
try:
|
851 |
# Get the selected row and column from the event
|
|
|
853 |
col_idx = evt.index[1]
|
854 |
print(f"DEBUG: Selected row {row_idx}, column {col_idx}")
|
855 |
|
|
|
|
|
|
|
|
|
|
|
856 |
# Handle pandas DataFrame
|
857 |
if isinstance(df_data, pd.DataFrame) and not df_data.empty and row_idx < len(df_data):
|
|
|
|
|
|
|
858 |
|
859 |
+
# Column mapping: 0=repo, 1=strength, 2=weakness, 3=speciality, 4=relevance
|
860 |
+
if col_idx == 1: # Strengths column
|
861 |
+
full_text = str(df_data.iloc[row_idx, 1])
|
862 |
+
repo_name = str(df_data.iloc[row_idx, 0])
|
863 |
+
title = f"Strengths - {repo_name}"
|
864 |
+
return "", gr.update(visible=False), gr.update(), title, full_text, gr.update(visible=True)
|
865 |
+
|
866 |
+
elif col_idx == 2: # Weaknesses column
|
867 |
+
full_text = str(df_data.iloc[row_idx, 2])
|
868 |
+
repo_name = str(df_data.iloc[row_idx, 0])
|
869 |
+
title = f"Weaknesses - {repo_name}"
|
870 |
+
return "", gr.update(visible=False), gr.update(), title, full_text, gr.update(visible=True)
|
871 |
+
|
872 |
+
elif col_idx == 3: # Speciality column
|
873 |
+
full_text = str(df_data.iloc[row_idx, 3])
|
874 |
+
repo_name = str(df_data.iloc[row_idx, 0])
|
875 |
+
title = f"Speciality - {repo_name}"
|
876 |
+
return "", gr.update(visible=False), gr.update(), title, full_text, gr.update(visible=True)
|
877 |
+
|
878 |
+
elif col_idx == 0: # Repository name column - show action modal
|
879 |
+
repo_id = df_data.iloc[row_idx, 0]
|
880 |
+
print(f"DEBUG: Extracted repo_id = '{repo_id}'")
|
881 |
+
|
882 |
+
if repo_id and str(repo_id).strip() and str(repo_id).strip() != 'nan':
|
883 |
+
clean_repo_id = str(repo_id).strip()
|
884 |
+
logger.info(f"Showing modal for repository: {clean_repo_id}")
|
885 |
+
return clean_repo_id, gr.update(visible=True), gr.update(), "", "", gr.update(visible=False)
|
886 |
+
|
887 |
+
# For other columns (like relevance), do nothing
|
888 |
+
else:
|
889 |
+
print(f"DEBUG: Clicked on column {col_idx}, no action defined")
|
890 |
+
return "", gr.update(visible=False), gr.update(), "", "", gr.update(visible=False)
|
891 |
else:
|
892 |
print(f"DEBUG: df_data is not a DataFrame or row_idx {row_idx} out of range")
|
893 |
|
|
|
895 |
print(f"DEBUG: Exception occurred: {e}")
|
896 |
logger.error(f"Error handling dataframe selection: {e}")
|
897 |
|
898 |
+
return "", gr.update(visible=False), gr.update(), "", "", gr.update(visible=False)
|
899 |
|
900 |
def handle_analyze_all_repos(repo_ids: List[str], user_requirements: str, progress=gr.Progress()) -> Tuple[pd.DataFrame, str, pd.DataFrame, Any]:
|
901 |
"""Analyzes all repositories in the CSV file with progress tracking."""
|
|
|
1027 |
"""Handle closing the modal."""
|
1028 |
return gr.update(visible=False)
|
1029 |
|
1030 |
+
def handle_close_text_modal() -> Any:
|
1031 |
+
"""Handle closing the text expansion modal."""
|
1032 |
+
return gr.update(visible=False)
|
1033 |
+
|
1034 |
+
def handle_reset_everything() -> Tuple[List[str], int, str, pd.DataFrame, pd.DataFrame, Any, Any, Any, List[Dict[str, str]], str, str, str]:
|
1035 |
+
"""Reset everything to initial state - clear all data, CSV, and UI components."""
|
1036 |
+
try:
|
1037 |
+
# Clear the CSV file
|
1038 |
+
if os.path.exists(CSV_FILE):
|
1039 |
+
os.remove(CSV_FILE)
|
1040 |
+
logger.info("CSV file deleted for reset")
|
1041 |
+
|
1042 |
+
# Create empty dataframe
|
1043 |
+
empty_df = pd.DataFrame(columns=["repo id", "strength", "weaknesses", "speciality", "relevance rating"])
|
1044 |
+
|
1045 |
+
# Reset state variables
|
1046 |
+
repo_ids_reset = []
|
1047 |
+
current_idx_reset = 0
|
1048 |
+
user_requirements_reset = ""
|
1049 |
+
|
1050 |
+
# Reset status
|
1051 |
+
status_reset = "Status: Everything has been reset. Ready to start fresh!"
|
1052 |
+
|
1053 |
+
# Reset UI components
|
1054 |
+
current_requirements_reset = "No requirements extracted yet."
|
1055 |
+
extracted_keywords_reset = ""
|
1056 |
+
|
1057 |
+
# Reset chatbot to initial message
|
1058 |
+
chatbot_reset = [{"role": "assistant", "content": CHATBOT_INITIAL_MESSAGE}]
|
1059 |
+
|
1060 |
+
logger.info("Complete system reset performed")
|
1061 |
+
|
1062 |
+
return (
|
1063 |
+
repo_ids_reset, # repo_ids_state
|
1064 |
+
current_idx_reset, # current_repo_idx_state
|
1065 |
+
user_requirements_reset, # user_requirements_state
|
1066 |
+
empty_df, # df_output
|
1067 |
+
empty_df, # top_repos_df
|
1068 |
+
gr.update(visible=False), # top_repos_section
|
1069 |
+
gr.update(visible=False), # repo_action_modal
|
1070 |
+
gr.update(visible=False), # text_expansion_modal
|
1071 |
+
chatbot_reset, # chatbot
|
1072 |
+
status_reset, # status_box_analysis
|
1073 |
+
current_requirements_reset, # current_requirements_display
|
1074 |
+
extracted_keywords_reset # extracted_keywords_output
|
1075 |
+
)
|
1076 |
+
|
1077 |
+
except Exception as e:
|
1078 |
+
logger.error(f"Error during reset: {e}")
|
1079 |
+
error_status = f"Reset failed: {e}"
|
1080 |
+
return (
|
1081 |
+
[], # repo_ids_state
|
1082 |
+
0, # current_repo_idx_state
|
1083 |
+
"", # user_requirements_state
|
1084 |
+
pd.DataFrame(), # df_output
|
1085 |
+
pd.DataFrame(), # top_repos_df
|
1086 |
+
gr.update(visible=False), # top_repos_section
|
1087 |
+
gr.update(visible=False), # repo_action_modal
|
1088 |
+
gr.update(visible=False), # text_expansion_modal
|
1089 |
+
[{"role": "assistant", "content": CHATBOT_INITIAL_MESSAGE}], # chatbot
|
1090 |
+
error_status, # status_box_analysis
|
1091 |
+
"No requirements extracted yet.", # current_requirements_display
|
1092 |
+
"" # extracted_keywords_output
|
1093 |
+
)
|
1094 |
+
|
1095 |
# --- Component Event Wiring ---
|
1096 |
|
1097 |
# Initialize chatbot with welcome message on app load
|
|
|
1181 |
outputs=[repo_action_modal]
|
1182 |
)
|
1183 |
|
1184 |
+
# Text expansion modal events
|
1185 |
+
close_text_modal_btn.click(
|
1186 |
+
fn=handle_close_text_modal,
|
1187 |
+
outputs=[text_expansion_modal]
|
1188 |
+
)
|
1189 |
+
|
1190 |
# Add dataframe selection event
|
1191 |
df_output.select(
|
1192 |
fn=handle_dataframe_select,
|
1193 |
inputs=[df_output],
|
1194 |
+
outputs=[selected_repo_display, repo_action_modal, tabs, expanded_content_title, expanded_content_text, text_expansion_modal]
|
1195 |
)
|
1196 |
|
1197 |
# Add selection event for top repositories dataframe too
|
1198 |
top_repos_df.select(
|
1199 |
fn=handle_dataframe_select,
|
1200 |
inputs=[top_repos_df],
|
1201 |
+
outputs=[selected_repo_display, repo_action_modal, tabs, expanded_content_title, expanded_content_text, text_expansion_modal]
|
1202 |
+
)
|
1203 |
+
|
1204 |
+
# Reset button event
|
1205 |
+
reset_all_btn.click(
|
1206 |
+
fn=handle_reset_everything,
|
1207 |
+
outputs=[repo_ids_state, current_repo_idx_state, user_requirements_state, df_output, top_repos_df, top_repos_section, repo_action_modal, text_expansion_modal, chatbot, status_box_analysis, current_requirements_display, extracted_keywords_output]
|
1208 |
)
|
1209 |
|
1210 |
return app
|
chatbot_page.py
CHANGED
@@ -4,9 +4,11 @@ import os
|
|
4 |
|
5 |
# System prompt for the chatbot
|
6 |
CHATBOT_SYSTEM_PROMPT = (
|
7 |
-
"
|
8 |
-
"Engage in a natural conversation, ask clarifying questions about their needs, such as their use case
|
9 |
"Keep your responses concise and focused on helping the user."
|
|
|
|
|
10 |
)
|
11 |
|
12 |
# Store the conversation
|
@@ -44,10 +46,12 @@ def extract_keywords_from_conversation(history):
|
|
44 |
# Combine all user and assistant messages into a single string
|
45 |
conversation = "\n".join([f"User: {msg[0]}\nAssistant: {msg[1]}" for msg in history if msg[1]])
|
46 |
system_prompt = (
|
47 |
-
"You are an expert at helping
|
48 |
-
"Given a conversation, extract about 5 keywords that would be most useful for searching Hugging Face
|
49 |
"Return only the keywords as a comma-separated list."
|
50 |
"Use keywords that are specific to the user's use case and features they are looking for."
|
|
|
|
|
51 |
)
|
52 |
user_prompt = (
|
53 |
"Conversation:\n" + conversation + "\n\nExtract about 5 keywords for Hugging Face repo search."
|
|
|
4 |
|
5 |
# System prompt for the chatbot
|
6 |
CHATBOT_SYSTEM_PROMPT = (
|
7 |
+
"Your goal is to undertsand what the user needs in their ideal Hugging Face repository. Specifically a Hugging Face Space. "
|
8 |
+
"Engage in a natural conversation, ask clarifying questions about their needs, such as their use case or specific features they are looking for. "
|
9 |
"Keep your responses concise and focused on helping the user."
|
10 |
+
"When you feel you have gathered enough detailed information about their requirements, ask the user to end chat."
|
11 |
+
|
12 |
)
|
13 |
|
14 |
# Store the conversation
|
|
|
46 |
# Combine all user and assistant messages into a single string
|
47 |
conversation = "\n".join([f"User: {msg[0]}\nAssistant: {msg[1]}" for msg in history if msg[1]])
|
48 |
system_prompt = (
|
49 |
+
"You are an expert at helping find Hugging Face Spaces. You must look at the conversation carefully."
|
50 |
+
"Given a conversation, extract about 5 keywords that would be most useful for searching Hugging Face Spaces.. "
|
51 |
"Return only the keywords as a comma-separated list."
|
52 |
"Use keywords that are specific to the user's use case and features they are looking for."
|
53 |
+
"Dont use very generic search words like programming, language, hugging face, ML, AI, etc."
|
54 |
+
|
55 |
)
|
56 |
user_prompt = (
|
57 |
"Conversation:\n" + conversation + "\n\nExtract about 5 keywords for Hugging Face repo search."
|