Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -371,6 +371,8 @@ def process_code_blocks(text):
|
|
| 371 |
processed_text = re.sub(pattern, replace_code_block, text, flags=re.DOTALL)
|
| 372 |
return processed_text
|
| 373 |
|
|
|
|
|
|
|
| 374 |
def create_ui():
|
| 375 |
# Get local time
|
| 376 |
local_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
@@ -597,89 +599,182 @@ def create_ui():
|
|
| 597 |
def handle_clone(repo_url, github_token, branch):
|
| 598 |
if not repo_url:
|
| 599 |
return "⚠️ URL repository diperlukan!", [], []
|
|
|
|
| 600 |
success, message = analyzer.clone_repository(repo_url, github_token, branch)
|
|
|
|
| 601 |
if success:
|
| 602 |
-
files
|
| 603 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 604 |
return message, [], []
|
| 605 |
|
| 606 |
-
def
|
| 607 |
-
if not
|
| 608 |
return "<div class='file-list'>Belum ada file yang dipilih</div>"
|
|
|
|
| 609 |
html = "<div class='file-list'>"
|
| 610 |
-
|
| 611 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 612 |
html += "</div>"
|
| 613 |
return html
|
| 614 |
|
| 615 |
-
|
| 616 |
-
|
| 617 |
-
|
| 618 |
-
|
| 619 |
-
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
|
| 628 |
-
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
)
|
| 632 |
-
|
| 633 |
-
send_button.click(
|
| 634 |
-
fn=handle_chat,
|
| 635 |
-
inputs=[
|
| 636 |
-
chat_input,
|
| 637 |
-
chat_history,
|
| 638 |
-
provider,
|
| 639 |
-
model_dropdown,
|
| 640 |
-
xai_key,
|
| 641 |
-
gemini_key,
|
| 642 |
-
file_selector
|
| 643 |
-
],
|
| 644 |
-
outputs=chat_history,
|
| 645 |
-
show_progress=True
|
| 646 |
-
).then(
|
| 647 |
-
fn=lambda: gr.update(value=""),
|
| 648 |
-
outputs=chat_input
|
| 649 |
-
)
|
| 650 |
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 668 |
|
| 669 |
-
#
|
| 670 |
-
|
| 671 |
-
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 683 |
|
| 684 |
return app
|
| 685 |
|
|
|
|
| 371 |
processed_text = re.sub(pattern, replace_code_block, text, flags=re.DOTALL)
|
| 372 |
return processed_text
|
| 373 |
|
| 374 |
+
analyzer = RepoAnalyzer()
|
| 375 |
+
|
| 376 |
def create_ui():
|
| 377 |
# Get local time
|
| 378 |
local_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
| 599 |
def handle_clone(repo_url, github_token, branch):
|
| 600 |
if not repo_url:
|
| 601 |
return "⚠️ URL repository diperlukan!", [], []
|
| 602 |
+
|
| 603 |
success, message = analyzer.clone_repository(repo_url, github_token, branch)
|
| 604 |
+
|
| 605 |
if success:
|
| 606 |
+
# Get files with metadata for better display
|
| 607 |
+
files = []
|
| 608 |
+
file_metadata = []
|
| 609 |
+
|
| 610 |
+
for file_path in analyzer.repo_content.keys():
|
| 611 |
+
files.append(file_path)
|
| 612 |
+
content = analyzer.repo_content[file_path]
|
| 613 |
+
size = len(content.encode('utf-8'))
|
| 614 |
+
file_metadata.append({
|
| 615 |
+
'path': file_path,
|
| 616 |
+
'size': f"{size / 1024:.1f} KB",
|
| 617 |
+
'lines': len(content.splitlines())
|
| 618 |
+
})
|
| 619 |
+
|
| 620 |
+
# Create rich HTML display for clone status
|
| 621 |
+
status_html = f"""
|
| 622 |
+
<div style="padding: 1rem; background: #f0f8ff; border-radius: 8px; border: 1px solid #add8e6;">
|
| 623 |
+
<h3 style="margin-top: 0;">✅ Repository berhasil di-clone!</h3>
|
| 624 |
+
<p><strong>Nama:</strong> {analyzer.current_repo}</p>
|
| 625 |
+
<p><strong>Jumlah file:</strong> {len(files)}</p>
|
| 626 |
+
<p><strong>Status:</strong> Siap untuk analisis</p>
|
| 627 |
+
</div>
|
| 628 |
+
"""
|
| 629 |
+
|
| 630 |
+
# Create initial file list display
|
| 631 |
+
file_list_html = create_file_list_html(file_metadata)
|
| 632 |
+
|
| 633 |
+
return status_html, files, file_list_html
|
| 634 |
return message, [], []
|
| 635 |
|
| 636 |
+
def create_file_list_html(file_metadata):
|
| 637 |
+
if not file_metadata:
|
| 638 |
return "<div class='file-list'>Belum ada file yang dipilih</div>"
|
| 639 |
+
|
| 640 |
html = "<div class='file-list'>"
|
| 641 |
+
html += "<style>\n"
|
| 642 |
+
html += ".file-list { max-height: 300px; overflow-y: auto; }\n"
|
| 643 |
+
html += ".file-item { display: flex; justify-content: space-between; padding: 8px; border-bottom: 1px solid #eee; }\n"
|
| 644 |
+
html += ".file-item:hover { background: #f5f5f5; }\n"
|
| 645 |
+
html += ".file-info { display: flex; gap: 1rem; color: #666; font-size: 0.9em; }\n"
|
| 646 |
+
html += "</style>"
|
| 647 |
+
|
| 648 |
+
for metadata in file_metadata:
|
| 649 |
+
html += f"""
|
| 650 |
+
<div class='file-item'>
|
| 651 |
+
<div class='file-path'>{metadata['path']}</div>
|
| 652 |
+
<div class='file-info'>
|
| 653 |
+
<span>{metadata['size']}</span>
|
| 654 |
+
<span>{metadata['lines']} lines</span>
|
| 655 |
+
</div>
|
| 656 |
+
</div>
|
| 657 |
+
"""
|
| 658 |
html += "</div>"
|
| 659 |
return html
|
| 660 |
|
| 661 |
+
def update_file_list(selected):
|
| 662 |
+
if not selected:
|
| 663 |
+
return "<div class='file-list'>Belum ada file yang dipilih</div>"
|
| 664 |
+
|
| 665 |
+
file_metadata = []
|
| 666 |
+
for file_path in selected:
|
| 667 |
+
if file_path in analyzer.repo_content:
|
| 668 |
+
content = analyzer.repo_content[file_path]
|
| 669 |
+
size = len(content.encode('utf-8'))
|
| 670 |
+
file_metadata.append({
|
| 671 |
+
'path': file_path,
|
| 672 |
+
'size': f"{size / 1024:.1f} KB",
|
| 673 |
+
'lines': len(content.splitlines())
|
| 674 |
+
})
|
| 675 |
+
|
| 676 |
+
return create_file_list_html(file_metadata)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
|
| 678 |
+
# Modified handle_chat function with better file context handling
|
| 679 |
+
async def handle_chat(message, history, provider_choice, model_name, xai_key, gemini_key, selected_files):
|
| 680 |
+
if not analyzer.current_repo:
|
| 681 |
+
yield history + [[message, "⚠️ Mohon clone repository terlebih dahulu sebelum mengajukan pertanyaan."]]
|
| 682 |
+
return
|
| 683 |
+
|
| 684 |
+
history = history or []
|
| 685 |
+
history.append([message, ""])
|
| 686 |
+
|
| 687 |
+
try:
|
| 688 |
+
# Improved file context formatting
|
| 689 |
+
file_context = ""
|
| 690 |
+
if selected_files:
|
| 691 |
+
file_context = "\n\nAnalisis berdasarkan file yang dipilih:\n"
|
| 692 |
+
for file in selected_files:
|
| 693 |
+
content = analyzer.repo_content.get(file, "")
|
| 694 |
+
file_context += f"\n### File: {file}\n```\n{content}\n```\n"
|
| 695 |
+
|
| 696 |
+
enhanced_message = f"{message}\n{file_context}"
|
| 697 |
+
|
| 698 |
+
# Rest of the handle_chat function remains the same
|
| 699 |
+
full_response = ""
|
| 700 |
+
if provider_choice == AIProvider.XAI:
|
| 701 |
+
async for chunk in analyzer.stream_xai_response(enhanced_message, xai_key, model_name):
|
| 702 |
+
chunk = process_code_blocks(chunk)
|
| 703 |
+
full_response += chunk
|
| 704 |
+
await asyncio.sleep(0.08)
|
| 705 |
+
history[-1][1] = full_response
|
| 706 |
+
yield history
|
| 707 |
+
|
| 708 |
+
elif provider_choice == AIProvider.GEMINI:
|
| 709 |
+
async for chunk in analyzer.stream_gemini_response(enhanced_message, gemini_key or DEFAULT_GEMINI_KEY):
|
| 710 |
+
chunk = process_code_blocks(chunk)
|
| 711 |
+
full_response += chunk
|
| 712 |
+
await asyncio.sleep(0.08)
|
| 713 |
+
history[-1][1] = full_response
|
| 714 |
+
yield history
|
| 715 |
+
|
| 716 |
+
else: # OLLAMA
|
| 717 |
+
response = analyze_with_ollama(model_name, enhanced_message)
|
| 718 |
+
response = process_code_blocks(response)
|
| 719 |
+
words = response.split()
|
| 720 |
+
for i in range(len(words)):
|
| 721 |
+
full_response = " ".join(words[:i+1])
|
| 722 |
+
await asyncio.sleep(0.08)
|
| 723 |
+
history[-1][1] = full_response
|
| 724 |
+
yield history
|
| 725 |
+
|
| 726 |
+
except Exception as e:
|
| 727 |
+
history[-1][1] = f"⚠️ Error: {str(e)}"
|
| 728 |
+
yield history
|
| 729 |
|
| 730 |
+
# Add additional CSS for improved repository display
|
| 731 |
+
gr.Markdown("""
|
| 732 |
+
<style>
|
| 733 |
+
/* Additional styles for repository content */
|
| 734 |
+
.repo-status {
|
| 735 |
+
margin: 1rem 0;
|
| 736 |
+
padding: 1rem;
|
| 737 |
+
background: #f0f8ff;
|
| 738 |
+
border-radius: 8px;
|
| 739 |
+
border: 1px solid #add8e6;
|
| 740 |
+
}
|
| 741 |
+
.file-list {
|
| 742 |
+
border: 1px solid #ddd;
|
| 743 |
+
border-radius: 8px;
|
| 744 |
+
margin-top: 1rem;
|
| 745 |
+
background: white;
|
| 746 |
+
}
|
| 747 |
+
.file-item {
|
| 748 |
+
transition: background-color 0.2s;
|
| 749 |
+
}
|
| 750 |
+
.file-info {
|
| 751 |
+
opacity: 0.7;
|
| 752 |
+
}
|
| 753 |
+
.file-path {
|
| 754 |
+
font-family: monospace;
|
| 755 |
+
overflow: hidden;
|
| 756 |
+
text-overflow: ellipsis;
|
| 757 |
+
white-space: nowrap;
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
/* Improved scrollbars for file list */
|
| 761 |
+
.file-list::-webkit-scrollbar {
|
| 762 |
+
width: 8px;
|
| 763 |
+
height: 8px;
|
| 764 |
+
}
|
| 765 |
+
.file-list::-webkit-scrollbar-track {
|
| 766 |
+
background: #f1f1f1;
|
| 767 |
+
border-radius: 4px;
|
| 768 |
+
}
|
| 769 |
+
.file-list::-webkit-scrollbar-thumb {
|
| 770 |
+
background: #888;
|
| 771 |
+
border-radius: 4px;
|
| 772 |
+
}
|
| 773 |
+
.file-list::-webkit-scrollbar-thumb:hover {
|
| 774 |
+
background: #555;
|
| 775 |
+
}
|
| 776 |
+
</style>
|
| 777 |
+
""")
|
| 778 |
|
| 779 |
return app
|
| 780 |
|