Update app.py
Browse files
app.py
CHANGED
@@ -180,22 +180,13 @@ def read_csv_to_dataframe() -> pd.DataFrame:
|
|
180 |
return pd.DataFrame()
|
181 |
|
182 |
def format_dataframe_for_display(df: pd.DataFrame) -> pd.DataFrame:
|
183 |
-
"""
|
184 |
if df.empty:
|
185 |
return df
|
186 |
|
187 |
-
#
|
188 |
-
|
189 |
-
|
190 |
-
# Apply formatting only for display
|
191 |
-
if not display_df.empty:
|
192 |
-
display_df['repo id'] = display_df['repo id'].apply(lambda x: format_text_for_dataframe(x, 50))
|
193 |
-
display_df['strength'] = display_df['strength'].apply(lambda x: format_text_for_dataframe(x, 180))
|
194 |
-
display_df['weaknesses'] = display_df['weaknesses'].apply(lambda x: format_text_for_dataframe(x, 180))
|
195 |
-
display_df['speciality'] = display_df['speciality'].apply(lambda x: format_text_for_dataframe(x, 150))
|
196 |
-
# Keep relevance rating as is since it should be short
|
197 |
-
|
198 |
-
return display_df
|
199 |
|
200 |
def analyze_and_update_single_repo(repo_id: str, user_requirements: str = "") -> Tuple[str, str, pd.DataFrame]:
|
201 |
"""
|
@@ -261,7 +252,7 @@ def analyze_and_update_single_repo(repo_id: str, user_requirements: str = "") ->
|
|
261 |
logger.error(f"Failed to write CSV for {repo_id} on retry: {retry_error}")
|
262 |
|
263 |
logger.info(f"Successfully analyzed and updated CSV for {repo_id}")
|
264 |
-
return combined_content, summary,
|
265 |
|
266 |
except Exception as e:
|
267 |
logger.error(f"An error occurred during analysis of {repo_id}: {e}")
|
@@ -389,37 +380,41 @@ def create_ui() -> gr.Blocks:
|
|
389 |
border-radius: 4px;
|
390 |
}
|
391 |
|
392 |
-
/* Improved dataframe styling */
|
393 |
.gr-dataframe {
|
394 |
-
max-height:
|
395 |
overflow-y: auto;
|
|
|
396 |
}
|
397 |
|
398 |
.gr-dataframe table {
|
399 |
-
table-layout:
|
400 |
width: 100%;
|
|
|
401 |
}
|
402 |
|
403 |
.gr-dataframe th,
|
404 |
.gr-dataframe td {
|
405 |
-
padding:
|
406 |
vertical-align: top;
|
407 |
word-wrap: break-word;
|
408 |
overflow-wrap: break-word;
|
409 |
-
max-height:
|
410 |
overflow-y: auto;
|
|
|
|
|
411 |
}
|
412 |
|
413 |
.gr-dataframe th:nth-child(1),
|
414 |
-
.gr-dataframe td:nth-child(1) { width:
|
415 |
.gr-dataframe th:nth-child(2),
|
416 |
-
.gr-dataframe td:nth-child(2) { width:
|
417 |
.gr-dataframe th:nth-child(3),
|
418 |
-
.gr-dataframe td:nth-child(3) { width:
|
419 |
.gr-dataframe th:nth-child(4),
|
420 |
-
.gr-dataframe td:nth-child(4) { width:
|
421 |
.gr-dataframe th:nth-child(5),
|
422 |
-
.gr-dataframe td:nth-child(5) { width:
|
423 |
|
424 |
/* Make repository names clickable */
|
425 |
.gr-dataframe td:nth-child(1) {
|
@@ -435,24 +430,13 @@ def create_ui() -> gr.Blocks:
|
|
435 |
transform: scale(1.02);
|
436 |
}
|
437 |
|
438 |
-
/*
|
439 |
.gr-dataframe td:nth-child(2),
|
440 |
.gr-dataframe td:nth-child(3),
|
441 |
-
.gr-dataframe td:nth-child(4)
|
442 |
-
cursor: pointer;
|
443 |
-
transition: all 0.3s ease;
|
444 |
-
}
|
445 |
-
|
446 |
-
.gr-dataframe td:nth-child(2):hover,
|
447 |
-
.gr-dataframe td:nth-child(3):hover,
|
448 |
-
.gr-dataframe td:nth-child(4):hover {
|
449 |
-
background-color: rgba(102, 126, 234, 0.08);
|
450 |
-
box-shadow: inset 0 0 0 1px rgba(102, 126, 234, 0.2);
|
451 |
-
}
|
452 |
-
|
453 |
-
/* Relevance column - not clickable */
|
454 |
.gr-dataframe td:nth-child(5) {
|
455 |
cursor: default;
|
|
|
456 |
}
|
457 |
|
458 |
.gr-dataframe tbody tr:hover {
|
@@ -494,15 +478,42 @@ def create_ui() -> gr.Blocks:
|
|
494 |
});
|
495 |
});
|
496 |
|
497 |
-
//
|
498 |
let lastSelectedTab = null;
|
499 |
-
setInterval(function() {
|
500 |
const currentSelectedTab = document.querySelector('.gr-tab-nav button.selected');
|
501 |
if (currentSelectedTab && currentSelectedTab !== lastSelectedTab) {
|
502 |
lastSelectedTab = currentSelectedTab;
|
503 |
-
scrollToTop
|
504 |
}
|
505 |
-
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
506 |
});
|
507 |
</script>
|
508 |
"""
|
@@ -634,9 +645,9 @@ def create_ui() -> gr.Blocks:
|
|
634 |
interactive=False
|
635 |
)
|
636 |
|
637 |
-
gr.Markdown("π‘ **Tip:** Click on
|
638 |
|
639 |
-
# Text expansion modal for showing full content
|
640 |
with gr.Row():
|
641 |
with gr.Column():
|
642 |
text_expansion_modal = gr.Column(visible=False)
|
@@ -860,7 +871,7 @@ def create_ui() -> gr.Blocks:
|
|
860 |
return final_keywords_str, status, user_requirements
|
861 |
|
862 |
def handle_dataframe_select(evt: gr.SelectData, df_data) -> Tuple[str, Any, Any, str, str, Any]:
|
863 |
-
"""Handle dataframe row selection - repo ID shows modal
|
864 |
print(f"DEBUG: Selection event triggered!")
|
865 |
print(f"DEBUG: evt = {evt}")
|
866 |
print(f"DEBUG: df_data type = {type(df_data)}")
|
@@ -877,31 +888,7 @@ def create_ui() -> gr.Blocks:
|
|
877 |
# Handle pandas DataFrame
|
878 |
if isinstance(df_data, pd.DataFrame) and not df_data.empty and row_idx < len(df_data):
|
879 |
|
880 |
-
|
881 |
-
if col_idx in [1, 2, 3]: # Strength, Weakness, or Speciality columns
|
882 |
-
repo_name = str(df_data.iloc[row_idx, 0])
|
883 |
-
|
884 |
-
# Read full data from CSV file to get untruncated text
|
885 |
-
full_df = read_csv_to_dataframe()
|
886 |
-
|
887 |
-
# Find the matching row in the full data
|
888 |
-
matching_rows = full_df[full_df['repo id'] == repo_name]
|
889 |
-
if not matching_rows.empty:
|
890 |
-
full_row = matching_rows.iloc[0]
|
891 |
-
|
892 |
-
if col_idx == 1: # Strengths column
|
893 |
-
full_text = str(full_row['strength'])
|
894 |
-
title = f"Strengths - {repo_name}"
|
895 |
-
elif col_idx == 2: # Weaknesses column
|
896 |
-
full_text = str(full_row['weaknesses'])
|
897 |
-
title = f"Weaknesses - {repo_name}"
|
898 |
-
elif col_idx == 3: # Speciality column
|
899 |
-
full_text = str(full_row['speciality'])
|
900 |
-
title = f"Speciality - {repo_name}"
|
901 |
-
|
902 |
-
return "", gr.update(visible=False), gr.update(), title, full_text, gr.update(visible=True)
|
903 |
-
|
904 |
-
elif col_idx == 0: # Repository name column - show action modal
|
905 |
repo_id = df_data.iloc[row_idx, 0]
|
906 |
print(f"DEBUG: Extracted repo_id = '{repo_id}'")
|
907 |
|
@@ -910,9 +897,9 @@ def create_ui() -> gr.Blocks:
|
|
910 |
logger.info(f"Showing modal for repository: {clean_repo_id}")
|
911 |
return clean_repo_id, gr.update(visible=True), gr.update(), "", "", gr.update(visible=False)
|
912 |
|
913 |
-
# For
|
914 |
else:
|
915 |
-
print(f"DEBUG: Clicked on column {col_idx},
|
916 |
return "", gr.update(visible=False), gr.update(), "", "", gr.update(visible=False)
|
917 |
else:
|
918 |
print(f"DEBUG: df_data is not a DataFrame or row_idx {row_idx} out of range")
|
@@ -1200,7 +1187,8 @@ def create_ui() -> gr.Blocks:
|
|
1200 |
explore_repo_btn.click(
|
1201 |
fn=handle_explore_repo,
|
1202 |
inputs=[selected_repo_display],
|
1203 |
-
outputs=[repo_action_modal, tabs, repo_components["repo_explorer_input"]]
|
|
|
1204 |
)
|
1205 |
cancel_modal_btn.click(
|
1206 |
fn=handle_cancel_modal,
|
|
|
180 |
return pd.DataFrame()
|
181 |
|
182 |
def format_dataframe_for_display(df: pd.DataFrame) -> pd.DataFrame:
|
183 |
+
"""Returns dataframe with full text (no truncation) for display."""
|
184 |
if df.empty:
|
185 |
return df
|
186 |
|
187 |
+
# Return the dataframe as-is without any text truncation
|
188 |
+
# This will show the full text content in the CSV display
|
189 |
+
return df.copy()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
|
191 |
def analyze_and_update_single_repo(repo_id: str, user_requirements: str = "") -> Tuple[str, str, pd.DataFrame]:
|
192 |
"""
|
|
|
252 |
logger.error(f"Failed to write CSV for {repo_id} on retry: {retry_error}")
|
253 |
|
254 |
logger.info(f"Successfully analyzed and updated CSV for {repo_id}")
|
255 |
+
return combined_content, summary, df
|
256 |
|
257 |
except Exception as e:
|
258 |
logger.error(f"An error occurred during analysis of {repo_id}: {e}")
|
|
|
380 |
border-radius: 4px;
|
381 |
}
|
382 |
|
383 |
+
/* Improved dataframe styling for full text display */
|
384 |
.gr-dataframe {
|
385 |
+
max-height: 600px;
|
386 |
overflow-y: auto;
|
387 |
+
overflow-x: auto;
|
388 |
}
|
389 |
|
390 |
.gr-dataframe table {
|
391 |
+
table-layout: auto;
|
392 |
width: 100%;
|
393 |
+
min-width: 1200px;
|
394 |
}
|
395 |
|
396 |
.gr-dataframe th,
|
397 |
.gr-dataframe td {
|
398 |
+
padding: 12px 15px;
|
399 |
vertical-align: top;
|
400 |
word-wrap: break-word;
|
401 |
overflow-wrap: break-word;
|
402 |
+
max-height: 200px;
|
403 |
overflow-y: auto;
|
404 |
+
white-space: pre-wrap;
|
405 |
+
line-height: 1.4;
|
406 |
}
|
407 |
|
408 |
.gr-dataframe th:nth-child(1),
|
409 |
+
.gr-dataframe td:nth-child(1) { width: 200px; min-width: 200px; }
|
410 |
.gr-dataframe th:nth-child(2),
|
411 |
+
.gr-dataframe td:nth-child(2) { width: 300px; min-width: 300px; }
|
412 |
.gr-dataframe th:nth-child(3),
|
413 |
+
.gr-dataframe td:nth-child(3) { width: 300px; min-width: 300px; }
|
414 |
.gr-dataframe th:nth-child(4),
|
415 |
+
.gr-dataframe td:nth-child(4) { width: 250px; min-width: 250px; }
|
416 |
.gr-dataframe th:nth-child(5),
|
417 |
+
.gr-dataframe td:nth-child(5) { width: 150px; min-width: 150px; }
|
418 |
|
419 |
/* Make repository names clickable */
|
420 |
.gr-dataframe td:nth-child(1) {
|
|
|
430 |
transform: scale(1.02);
|
431 |
}
|
432 |
|
433 |
+
/* Content columns - readable styling with scroll for long text */
|
434 |
.gr-dataframe td:nth-child(2),
|
435 |
.gr-dataframe td:nth-child(3),
|
436 |
+
.gr-dataframe td:nth-child(4),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
437 |
.gr-dataframe td:nth-child(5) {
|
438 |
cursor: default;
|
439 |
+
font-size: 0.9rem;
|
440 |
}
|
441 |
|
442 |
.gr-dataframe tbody tr:hover {
|
|
|
478 |
});
|
479 |
});
|
480 |
|
481 |
+
// Enhanced listener for programmatic tab changes (button-triggered navigation)
|
482 |
let lastSelectedTab = null;
|
483 |
+
const checkInterval = setInterval(function() {
|
484 |
const currentSelectedTab = document.querySelector('.gr-tab-nav button.selected');
|
485 |
if (currentSelectedTab && currentSelectedTab !== lastSelectedTab) {
|
486 |
lastSelectedTab = currentSelectedTab;
|
487 |
+
setTimeout(scrollToTop, 100);
|
488 |
}
|
489 |
+
}, 100);
|
490 |
+
|
491 |
+
// Additional scroll trigger for repo explorer navigation
|
492 |
+
window.addEventListener('repoExplorerNavigation', function() {
|
493 |
+
setTimeout(scrollToTop, 200);
|
494 |
+
});
|
495 |
+
|
496 |
+
// Watch for specific tab transitions to repo explorer
|
497 |
+
const repoExplorerObserver = new MutationObserver(function(mutations) {
|
498 |
+
mutations.forEach(function(mutation) {
|
499 |
+
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
500 |
+
const target = mutation.target;
|
501 |
+
if (target.textContent && target.textContent.includes('π Repo Explorer') && target.classList.contains('selected')) {
|
502 |
+
setTimeout(scrollToTop, 150);
|
503 |
+
}
|
504 |
+
}
|
505 |
+
});
|
506 |
+
});
|
507 |
+
|
508 |
+
// Start observing for repo explorer specific changes
|
509 |
+
setTimeout(function() {
|
510 |
+
const repoExplorerTab = Array.from(document.querySelectorAll('.gr-tab-nav button')).find(btn =>
|
511 |
+
btn.textContent && btn.textContent.includes('π Repo Explorer')
|
512 |
+
);
|
513 |
+
if (repoExplorerTab) {
|
514 |
+
repoExplorerObserver.observe(repoExplorerTab, { attributes: true });
|
515 |
+
}
|
516 |
+
}, 1000);
|
517 |
});
|
518 |
</script>
|
519 |
"""
|
|
|
645 |
interactive=False
|
646 |
)
|
647 |
|
648 |
+
gr.Markdown("π‘ **Tip:** Full text is displayed directly in the table. Click on repository names to explore or visit them!")
|
649 |
|
650 |
+
# Text expansion modal for showing full content (kept for backwards compatibility)
|
651 |
with gr.Row():
|
652 |
with gr.Column():
|
653 |
text_expansion_modal = gr.Column(visible=False)
|
|
|
871 |
return final_keywords_str, status, user_requirements
|
872 |
|
873 |
def handle_dataframe_select(evt: gr.SelectData, df_data) -> Tuple[str, Any, Any, str, str, Any]:
|
874 |
+
"""Handle dataframe row selection - only repo ID (column 0) shows modal since full text is now displayed directly."""
|
875 |
print(f"DEBUG: Selection event triggered!")
|
876 |
print(f"DEBUG: evt = {evt}")
|
877 |
print(f"DEBUG: df_data type = {type(df_data)}")
|
|
|
888 |
# Handle pandas DataFrame
|
889 |
if isinstance(df_data, pd.DataFrame) and not df_data.empty and row_idx < len(df_data):
|
890 |
|
891 |
+
if col_idx == 0: # Repository name column - show action modal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
892 |
repo_id = df_data.iloc[row_idx, 0]
|
893 |
print(f"DEBUG: Extracted repo_id = '{repo_id}'")
|
894 |
|
|
|
897 |
logger.info(f"Showing modal for repository: {clean_repo_id}")
|
898 |
return clean_repo_id, gr.update(visible=True), gr.update(), "", "", gr.update(visible=False)
|
899 |
|
900 |
+
# For content columns (1,2,3) and relevance (4), do nothing since full text is shown directly
|
901 |
else:
|
902 |
+
print(f"DEBUG: Clicked on column {col_idx}, full text already shown in table")
|
903 |
return "", gr.update(visible=False), gr.update(), "", "", gr.update(visible=False)
|
904 |
else:
|
905 |
print(f"DEBUG: df_data is not a DataFrame or row_idx {row_idx} out of range")
|
|
|
1187 |
explore_repo_btn.click(
|
1188 |
fn=handle_explore_repo,
|
1189 |
inputs=[selected_repo_display],
|
1190 |
+
outputs=[repo_action_modal, tabs, repo_components["repo_explorer_input"]],
|
1191 |
+
js="() => { setTimeout(() => { window.scrollTo({top: 0, behavior: 'smooth'}); window.dispatchEvent(new Event('repoExplorerNavigation')); }, 150); }"
|
1192 |
)
|
1193 |
cancel_modal_btn.click(
|
1194 |
fn=handle_cancel_modal,
|