Spaces:
Running
on
Zero
Running
on
Zero
Asmit Nayak
commited on
Commit
·
b49a99a
1
Parent(s):
9012453
Add detailed results table and CSV download functionality
Browse files
app.py
CHANGED
|
@@ -865,11 +865,6 @@ def create_interface():
|
|
| 865 |
results_display = gr.HTML(
|
| 866 |
value="<div style='text-align: center; padding: 40px; color: var(--body-text-color); opacity: 0.7;'>Enter a URL and click analyze to see results here.</div>"
|
| 867 |
)
|
| 868 |
-
|
| 869 |
-
results_dataframe = gr.Dataframe(
|
| 870 |
-
label="Detailed Results (Scroll right to see all columns)",
|
| 871 |
-
visible=False
|
| 872 |
-
)
|
| 873 |
|
| 874 |
with gr.Column(scale=3):
|
| 875 |
# Screenshot section - only screenshot in right column
|
|
@@ -932,7 +927,70 @@ def create_interface():
|
|
| 932 |
interactive=False
|
| 933 |
)
|
| 934 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 935 |
# Event handlers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 936 |
def handle_url_analysis(url, api_key):
|
| 937 |
"""Handle URL analysis with screenshot capture."""
|
| 938 |
print(f"[CONSOLE] handle_url_analysis called with URL: {url}")
|
|
@@ -949,7 +1007,8 @@ def create_interface():
|
|
| 949 |
gr.update(visible=True), # Show placeholder initially
|
| 950 |
gr.update(visible=False), # Hide screenshot initially
|
| 951 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Preparing analysis...</div>", # Clear previous errors
|
| 952 |
-
gr.update(visible=False) # Hide dataframe
|
|
|
|
| 953 |
)
|
| 954 |
|
| 955 |
analysis_generator = take_screenshot_and_process(url, api_key)
|
|
@@ -976,7 +1035,8 @@ def create_interface():
|
|
| 976 |
gr.update(visible=False), # Hide placeholder
|
| 977 |
gr.update(value=image_path, visible=True, label="📷 Original Screenshot"), # Show original screenshot
|
| 978 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Analysis in progress...</div>", # Clear previous errors
|
| 979 |
-
gr.update(visible=False)
|
|
|
|
| 980 |
)
|
| 981 |
else:
|
| 982 |
yield (
|
|
@@ -984,7 +1044,8 @@ def create_interface():
|
|
| 984 |
gr.update(visible=True), # Keep placeholder visible
|
| 985 |
gr.update(visible=False), # Hide screenshot
|
| 986 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Analysis in progress...</div>", # Clear previous errors
|
| 987 |
-
gr.update(visible=False)
|
|
|
|
| 988 |
)
|
| 989 |
else:
|
| 990 |
print(f"[CONSOLE] Received final result with {len(dataframe_result)} rows")
|
|
@@ -1000,7 +1061,8 @@ def create_interface():
|
|
| 1000 |
gr.update(visible=False), # Hide placeholder
|
| 1001 |
gr.update(value=final_image, visible=True, label="🎯 Annotated Screenshot (Analysis Complete)") if final_image else gr.update(visible=False),
|
| 1002 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Processing results...</div>", # Clear previous errors
|
| 1003 |
-
gr.update(visible=False)
|
|
|
|
| 1004 |
)
|
| 1005 |
break
|
| 1006 |
|
|
@@ -1027,9 +1089,9 @@ def create_interface():
|
|
| 1027 |
.replace("<", "_x13x_") \
|
| 1028 |
.replace(">", "_x14x_") \
|
| 1029 |
.replace("|", "_x15x_")
|
| 1030 |
-
|
| 1031 |
save_url = save_url + "__" + str(uuid.uuid4()).replace("-", "_")
|
| 1032 |
-
|
| 1033 |
save_dict = {
|
| 1034 |
save_url: final_result
|
| 1035 |
}
|
|
@@ -1040,7 +1102,7 @@ def create_interface():
|
|
| 1040 |
annotated_image_path = final_image if final_image else original_image
|
| 1041 |
print(f"[CONSOLE] Using image for dataset upload: {dataset_image_path} (original: {original_image}, final: {final_image})")
|
| 1042 |
print(f"[CONSOLE] Using annotated image for display: {annotated_image_path} (original: {original_image}, final: {final_image})")
|
| 1043 |
-
|
| 1044 |
if dataset_image_path and os.path.exists(dataset_image_path) and annotated_image_path and os.path.exists(annotated_image_path):
|
| 1045 |
try:
|
| 1046 |
# Load the original image using PIL
|
|
@@ -1063,16 +1125,20 @@ def create_interface():
|
|
| 1063 |
print(f"[CONSOLE] Warning: Image path not found or invalid: {dataset_image_path}")
|
| 1064 |
image_df = pd.DataFrame([{"id": save_url, "image": None, "annotated_image": None}])
|
| 1065 |
|
| 1066 |
-
dataset_upload.update_dataset_with_new_splits(save_dict)
|
| 1067 |
-
dataset_upload.update_dataset_with_new_images(image_df, scheduler=scheduler, dataset_dir=dataset_dir, jsonl_path=jsonl_path)
|
| 1068 |
-
|
|
|
|
|
|
|
|
|
|
| 1069 |
# Show final results with annotated screenshot
|
| 1070 |
yield (
|
| 1071 |
final_status,
|
| 1072 |
gr.update(visible=False), # Hide placeholder
|
| 1073 |
gr.update(value=final_image, visible=True, label="🎯 Annotated Screenshot (Analysis Complete)") if final_image else gr.update(visible=False),
|
| 1074 |
results_html,
|
| 1075 |
-
gr.update(value=final_result, visible=True)
|
|
|
|
| 1076 |
)
|
| 1077 |
|
| 1078 |
# Clean up temporary files after successful display
|
|
@@ -1089,7 +1155,8 @@ def create_interface():
|
|
| 1089 |
gr.update(visible=True), # Show placeholder again
|
| 1090 |
gr.update(visible=False, label="Website Screenshot"), # Hide screenshot and reset label
|
| 1091 |
"<div style='color: #ef4444; text-align: center; background-color: var(--block-background-fill); padding: 15px; border-radius: 8px; border: 1px solid #ef4444; opacity: 0.9;'>Analysis failed. Please check your Gemini API key and try again.</div>",
|
| 1092 |
-
gr.update(visible=False)
|
|
|
|
| 1093 |
)
|
| 1094 |
|
| 1095 |
except Exception as e:
|
|
@@ -1103,7 +1170,8 @@ def create_interface():
|
|
| 1103 |
gr.update(visible=True), # Show placeholder again
|
| 1104 |
gr.update(visible=False, label="Website Screenshot"), # Hide screenshot and reset label
|
| 1105 |
f"<div style='color: #ef4444; text-align: center; background-color: var(--block-background-fill); padding: 15px; border-radius: 8px; border: 1px solid #ef4444; opacity: 0.9;'>{error_msg}</div>",
|
| 1106 |
-
gr.update(visible=False)
|
|
|
|
| 1107 |
)
|
| 1108 |
if e.__class__ == gr.exceptions.Error:
|
| 1109 |
raise e
|
|
@@ -1113,7 +1181,7 @@ def create_interface():
|
|
| 1113 |
analyze_url_btn.click(
|
| 1114 |
fn=handle_url_analysis,
|
| 1115 |
inputs=[url_input, gemini_api_key],
|
| 1116 |
-
outputs=[status_text, screenshot_placeholder, screenshot_display, results_display, results_dataframe],
|
| 1117 |
show_progress="full"
|
| 1118 |
)
|
| 1119 |
|
|
@@ -1144,9 +1212,13 @@ if __name__ == "__main__":
|
|
| 1144 |
|
| 1145 |
from py_files.utils import decrypt_system_prompts
|
| 1146 |
|
| 1147 |
-
if
|
| 1148 |
-
print(f"[CONSOLE]
|
| 1149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1150 |
|
| 1151 |
print(f"[CONSOLE] ===== STARTING GRADIO APPLICATION =====")
|
| 1152 |
print(f"[CONSOLE] Creating Gradio interface...")
|
|
|
|
| 865 |
results_display = gr.HTML(
|
| 866 |
value="<div style='text-align: center; padding: 40px; color: var(--body-text-color); opacity: 0.7;'>Enter a URL and click analyze to see results here.</div>"
|
| 867 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 868 |
|
| 869 |
with gr.Column(scale=3):
|
| 870 |
# Screenshot section - only screenshot in right column
|
|
|
|
| 927 |
interactive=False
|
| 928 |
)
|
| 929 |
|
| 930 |
+
# Detailed results table spanning both columns (full width)
|
| 931 |
+
results_dataframe = gr.Dataframe(
|
| 932 |
+
label="Detailed Results (Scroll right to see all columns)",
|
| 933 |
+
visible=False
|
| 934 |
+
)
|
| 935 |
+
|
| 936 |
+
# Download button for results CSV
|
| 937 |
+
download_btn = gr.DownloadButton(
|
| 938 |
+
label="📥 Download Results as CSV",
|
| 939 |
+
visible=False,
|
| 940 |
+
variant="secondary"
|
| 941 |
+
)
|
| 942 |
+
|
| 943 |
# Event handlers
|
| 944 |
+
def save_results_to_csv(df, url):
|
| 945 |
+
"""Save the results dataframe to a CSV file named after the analyzed site."""
|
| 946 |
+
if df is None or (isinstance(df, pd.DataFrame) and df.empty):
|
| 947 |
+
return None
|
| 948 |
+
|
| 949 |
+
# Create a safe filename from the URL
|
| 950 |
+
safe_filename = url.lower().replace("http://", "").replace("https://", "").strip().replace("www.", "") \
|
| 951 |
+
.replace(".", "_") \
|
| 952 |
+
.replace("/", "_") \
|
| 953 |
+
.replace("-", "_") \
|
| 954 |
+
.replace("=", "_") \
|
| 955 |
+
.replace("?", "_") \
|
| 956 |
+
.replace("&", "_") \
|
| 957 |
+
.replace("%", "_") \
|
| 958 |
+
.replace(":", "_") \
|
| 959 |
+
.replace("#", "_") \
|
| 960 |
+
.replace("'", "_") \
|
| 961 |
+
.replace('"', "_") \
|
| 962 |
+
.replace("*", "_") \
|
| 963 |
+
.replace("<", "_") \
|
| 964 |
+
.replace(">", "_") \
|
| 965 |
+
.replace("|", "_") \
|
| 966 |
+
.replace(" ", "_")
|
| 967 |
+
|
| 968 |
+
# Trim if too long and ensure it doesn't end with underscore
|
| 969 |
+
safe_filename = safe_filename[:100].rstrip("_")
|
| 970 |
+
|
| 971 |
+
# Create final filename
|
| 972 |
+
csv_filename = f"{safe_filename}.csv"
|
| 973 |
+
|
| 974 |
+
# Create a temporary file for download
|
| 975 |
+
temp_csv = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.csv', prefix='analysis_')
|
| 976 |
+
csv_path = temp_csv.name
|
| 977 |
+
temp_csv.close()
|
| 978 |
+
|
| 979 |
+
# Save dataframe to CSV
|
| 980 |
+
if isinstance(df, pd.DataFrame):
|
| 981 |
+
df.to_csv(csv_path, index=False)
|
| 982 |
+
else:
|
| 983 |
+
# If it's not a DataFrame, try to convert it
|
| 984 |
+
pd.DataFrame(df).to_csv(csv_path, index=False)
|
| 985 |
+
|
| 986 |
+
# Rename to the site-specific filename for download
|
| 987 |
+
final_path = os.path.join(os.path.dirname(csv_path), csv_filename)
|
| 988 |
+
shutil.copy(csv_path, final_path)
|
| 989 |
+
os.remove(csv_path)
|
| 990 |
+
|
| 991 |
+
print(f"[CONSOLE] CSV file created for download: {final_path} (filename: {csv_filename})")
|
| 992 |
+
return final_path
|
| 993 |
+
|
| 994 |
def handle_url_analysis(url, api_key):
|
| 995 |
"""Handle URL analysis with screenshot capture."""
|
| 996 |
print(f"[CONSOLE] handle_url_analysis called with URL: {url}")
|
|
|
|
| 1007 |
gr.update(visible=True), # Show placeholder initially
|
| 1008 |
gr.update(visible=False), # Hide screenshot initially
|
| 1009 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Preparing analysis...</div>", # Clear previous errors
|
| 1010 |
+
gr.update(visible=False), # Hide dataframe
|
| 1011 |
+
gr.update(visible=False) # Hide download button
|
| 1012 |
)
|
| 1013 |
|
| 1014 |
analysis_generator = take_screenshot_and_process(url, api_key)
|
|
|
|
| 1035 |
gr.update(visible=False), # Hide placeholder
|
| 1036 |
gr.update(value=image_path, visible=True, label="📷 Original Screenshot"), # Show original screenshot
|
| 1037 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Analysis in progress...</div>", # Clear previous errors
|
| 1038 |
+
gr.update(visible=False),
|
| 1039 |
+
gr.update(visible=False) # Hide download button
|
| 1040 |
)
|
| 1041 |
else:
|
| 1042 |
yield (
|
|
|
|
| 1044 |
gr.update(visible=True), # Keep placeholder visible
|
| 1045 |
gr.update(visible=False), # Hide screenshot
|
| 1046 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Analysis in progress...</div>", # Clear previous errors
|
| 1047 |
+
gr.update(visible=False),
|
| 1048 |
+
gr.update(visible=False) # Hide download button
|
| 1049 |
)
|
| 1050 |
else:
|
| 1051 |
print(f"[CONSOLE] Received final result with {len(dataframe_result)} rows")
|
|
|
|
| 1061 |
gr.update(visible=False), # Hide placeholder
|
| 1062 |
gr.update(value=final_image, visible=True, label="🎯 Annotated Screenshot (Analysis Complete)") if final_image else gr.update(visible=False),
|
| 1063 |
"<div style='text-align: center; padding: 20px; color: var(--body-text-color); opacity: 0.7;'>Processing results...</div>", # Clear previous errors
|
| 1064 |
+
gr.update(visible=False),
|
| 1065 |
+
gr.update(visible=False) # Hide download button
|
| 1066 |
)
|
| 1067 |
break
|
| 1068 |
|
|
|
|
| 1089 |
.replace("<", "_x13x_") \
|
| 1090 |
.replace(">", "_x14x_") \
|
| 1091 |
.replace("|", "_x15x_")
|
| 1092 |
+
|
| 1093 |
save_url = save_url + "__" + str(uuid.uuid4()).replace("-", "_")
|
| 1094 |
+
|
| 1095 |
save_dict = {
|
| 1096 |
save_url: final_result
|
| 1097 |
}
|
|
|
|
| 1102 |
annotated_image_path = final_image if final_image else original_image
|
| 1103 |
print(f"[CONSOLE] Using image for dataset upload: {dataset_image_path} (original: {original_image}, final: {final_image})")
|
| 1104 |
print(f"[CONSOLE] Using annotated image for display: {annotated_image_path} (original: {original_image}, final: {final_image})")
|
| 1105 |
+
|
| 1106 |
if dataset_image_path and os.path.exists(dataset_image_path) and annotated_image_path and os.path.exists(annotated_image_path):
|
| 1107 |
try:
|
| 1108 |
# Load the original image using PIL
|
|
|
|
| 1125 |
print(f"[CONSOLE] Warning: Image path not found or invalid: {dataset_image_path}")
|
| 1126 |
image_df = pd.DataFrame([{"id": save_url, "image": None, "annotated_image": None}])
|
| 1127 |
|
| 1128 |
+
# dataset_upload.update_dataset_with_new_splits(save_dict)
|
| 1129 |
+
# dataset_upload.update_dataset_with_new_images(image_df, scheduler=scheduler, dataset_dir=dataset_dir, jsonl_path=jsonl_path)
|
| 1130 |
+
|
| 1131 |
+
# Prepare CSV for download
|
| 1132 |
+
csv_file_path = save_results_to_csv(final_result, url)
|
| 1133 |
+
|
| 1134 |
# Show final results with annotated screenshot
|
| 1135 |
yield (
|
| 1136 |
final_status,
|
| 1137 |
gr.update(visible=False), # Hide placeholder
|
| 1138 |
gr.update(value=final_image, visible=True, label="🎯 Annotated Screenshot (Analysis Complete)") if final_image else gr.update(visible=False),
|
| 1139 |
results_html,
|
| 1140 |
+
gr.update(value=final_result, visible=True),
|
| 1141 |
+
gr.update(value=csv_file_path, visible=True) if csv_file_path else gr.update(visible=False)
|
| 1142 |
)
|
| 1143 |
|
| 1144 |
# Clean up temporary files after successful display
|
|
|
|
| 1155 |
gr.update(visible=True), # Show placeholder again
|
| 1156 |
gr.update(visible=False, label="Website Screenshot"), # Hide screenshot and reset label
|
| 1157 |
"<div style='color: #ef4444; text-align: center; background-color: var(--block-background-fill); padding: 15px; border-radius: 8px; border: 1px solid #ef4444; opacity: 0.9;'>Analysis failed. Please check your Gemini API key and try again.</div>",
|
| 1158 |
+
gr.update(visible=False),
|
| 1159 |
+
gr.update(visible=False) # Hide download button
|
| 1160 |
)
|
| 1161 |
|
| 1162 |
except Exception as e:
|
|
|
|
| 1170 |
gr.update(visible=True), # Show placeholder again
|
| 1171 |
gr.update(visible=False, label="Website Screenshot"), # Hide screenshot and reset label
|
| 1172 |
f"<div style='color: #ef4444; text-align: center; background-color: var(--block-background-fill); padding: 15px; border-radius: 8px; border: 1px solid #ef4444; opacity: 0.9;'>{error_msg}</div>",
|
| 1173 |
+
gr.update(visible=False),
|
| 1174 |
+
gr.update(visible=False) # Hide download button
|
| 1175 |
)
|
| 1176 |
if e.__class__ == gr.exceptions.Error:
|
| 1177 |
raise e
|
|
|
|
| 1181 |
analyze_url_btn.click(
|
| 1182 |
fn=handle_url_analysis,
|
| 1183 |
inputs=[url_input, gemini_api_key],
|
| 1184 |
+
outputs=[status_text, screenshot_placeholder, screenshot_display, results_display, results_dataframe, download_btn],
|
| 1185 |
show_progress="full"
|
| 1186 |
)
|
| 1187 |
|
|
|
|
| 1212 |
|
| 1213 |
from py_files.utils import decrypt_system_prompts
|
| 1214 |
|
| 1215 |
+
if os.path.exists("./system_prompt.txt") and os.path.exists("./system_prompt_thinking.txt"):
|
| 1216 |
+
print(f"[CONSOLE] System prompts already decrypted, skipping decryption step")
|
| 1217 |
+
else:
|
| 1218 |
+
print(f"[CONSOLE] Decrypting system prompts...")
|
| 1219 |
+
if not decrypt_system_prompts():
|
| 1220 |
+
print(f"[CONSOLE] Failed to decrypt system prompts, exiting...")
|
| 1221 |
+
exit(1)
|
| 1222 |
|
| 1223 |
print(f"[CONSOLE] ===== STARTING GRADIO APPLICATION =====")
|
| 1224 |
print(f"[CONSOLE] Creating Gradio interface...")
|