Spaces:
Sleeping
Sleeping
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."
|