Spaces:
Running
Running
Commit
Β·
8455de3
1
Parent(s):
062db00
updated doc-mcp app
Browse files- app.py +103 -34
- rag/query.py +0 -2
app.py
CHANGED
@@ -791,74 +791,125 @@ with gr.Blocks(title="Doc-MCP") as demo:
|
|
791 |
|
792 |
with gr.Row():
|
793 |
with gr.Column(scale=2):
|
794 |
-
# Repository selection
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
802 |
refresh_repos_btn = gr.Button(
|
803 |
-
"π Refresh
|
804 |
)
|
805 |
|
806 |
# Query mode selection
|
807 |
query_mode = gr.Radio(
|
808 |
choices=["default", "text_search", "hybrid"],
|
809 |
-
label="
|
810 |
value="default",
|
811 |
-
info="default:
|
812 |
)
|
813 |
|
814 |
# Query input
|
815 |
query_input = gr.Textbox(
|
816 |
-
label="Your
|
817 |
-
placeholder="
|
818 |
lines=3,
|
|
|
819 |
)
|
820 |
|
821 |
-
query_btn = gr.Button("
|
822 |
|
823 |
# Response display as text area
|
824 |
response_output = gr.Textbox(
|
825 |
-
label="Response",
|
826 |
-
value="Your
|
827 |
lines=10,
|
828 |
interactive=False,
|
|
|
829 |
)
|
830 |
|
831 |
with gr.Column(scale=2):
|
832 |
-
gr.Markdown("### Source
|
|
|
833 |
|
834 |
# Source nodes display as JSON
|
835 |
sources_output = gr.JSON(
|
836 |
-
label="Source
|
837 |
value={
|
838 |
-
"message": "Source
|
|
|
839 |
},
|
840 |
)
|
841 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
842 |
def get_available_docs_repo():
|
843 |
"""
|
844 |
-
List the available docs of repositories
|
845 |
|
846 |
Returns:
|
847 |
-
|
848 |
"""
|
849 |
try:
|
850 |
repos = get_available_repositories()
|
851 |
-
|
|
|
|
|
852 |
except Exception as e:
|
853 |
print(f"Error refreshing repository list: {e}")
|
854 |
-
return gr.Dropdown(choices=[], value=None)
|
855 |
|
856 |
# Simple query handler
|
857 |
def handle_query(repo: str, mode: str, query: str):
|
858 |
"""
|
859 |
Handle query request - returns raw data from retriever
|
860 |
Args:
|
861 |
-
repo: Selected repository
|
862 |
mode: Query mode (default, text_search, hybrid)
|
863 |
query: User's query
|
864 |
Returns:
|
@@ -867,8 +918,8 @@ with gr.Blocks(title="Doc-MCP") as demo:
|
|
867 |
if not query.strip():
|
868 |
return {"error": "Please enter a query."}
|
869 |
|
870 |
-
if not repo:
|
871 |
-
return {"error": "Please select a repository."}
|
872 |
|
873 |
try:
|
874 |
# Import QueryRetriever here to avoid circular imports
|
@@ -895,8 +946,8 @@ with gr.Blocks(title="Doc-MCP") as demo:
|
|
895 |
This function is designed to support Retrieval-Augmented Generation (RAG) by extracting
|
896 |
the most relevant context chunks from indexed documentation sources.
|
897 |
Args:
|
898 |
-
repo: Selected repository
|
899 |
-
mode: Query mode
|
900 |
query: User's query
|
901 |
Returns:
|
902 |
Tuple of (response_text, source_nodes_json)
|
@@ -914,24 +965,42 @@ with gr.Blocks(title="Doc-MCP") as demo:
|
|
914 |
|
915 |
return response_text, source_nodes
|
916 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
917 |
refresh_repos_btn.click(
|
918 |
fn=get_available_docs_repo,
|
919 |
outputs=[repo_dropdown],
|
920 |
-
api_name="
|
921 |
)
|
922 |
|
923 |
-
#
|
924 |
query_btn.click(
|
925 |
fn=make_query,
|
926 |
-
inputs=[
|
927 |
outputs=[response_output, sources_output],
|
928 |
-
api_name="
|
929 |
)
|
930 |
|
931 |
# Also allow Enter key to trigger query
|
932 |
query_input.submit(
|
933 |
fn=make_query,
|
934 |
-
inputs=[
|
935 |
outputs=[response_output, sources_output],
|
936 |
show_api=False,
|
937 |
)
|
@@ -1149,4 +1218,4 @@ with gr.Blocks(title="Doc-MCP") as demo:
|
|
1149 |
|
1150 |
|
1151 |
if __name__ == "__main__":
|
1152 |
-
demo.launch(mcp_server=True
|
|
|
791 |
|
792 |
with gr.Row():
|
793 |
with gr.Column(scale=2):
|
794 |
+
# Repository selection - Dropdown that becomes textbox when selected
|
795 |
+
with gr.Row():
|
796 |
+
repo_dropdown = gr.Dropdown(
|
797 |
+
choices=get_available_repositories() or ["No repositories available"],
|
798 |
+
label="π Select Documentation Repository",
|
799 |
+
value=None,
|
800 |
+
interactive=True,
|
801 |
+
allow_custom_value=True,
|
802 |
+
info="Choose from available repositories"
|
803 |
+
)
|
804 |
+
|
805 |
+
# Hidden textbox that will become visible when repo is selected
|
806 |
+
selected_repo_textbox = gr.Textbox(
|
807 |
+
label="π― Selected Repository",
|
808 |
+
value="",
|
809 |
+
interactive=False,
|
810 |
+
visible=False,
|
811 |
+
info="Currently selected repository for querying"
|
812 |
+
)
|
813 |
+
|
814 |
refresh_repos_btn = gr.Button(
|
815 |
+
"π Refresh Repository List", variant="secondary", size="sm"
|
816 |
)
|
817 |
|
818 |
# Query mode selection
|
819 |
query_mode = gr.Radio(
|
820 |
choices=["default", "text_search", "hybrid"],
|
821 |
+
label="π Search Strategy",
|
822 |
value="default",
|
823 |
+
info="β’ default: Semantic similarity (AI understanding)\nβ’ text_search: Keyword matching\nβ’ hybrid: Combined approach for best results",
|
824 |
)
|
825 |
|
826 |
# Query input
|
827 |
query_input = gr.Textbox(
|
828 |
+
label="π Ask About Your Documentation",
|
829 |
+
placeholder="How do I implement a custom component? What are the available API endpoints? How to configure the system?",
|
830 |
lines=3,
|
831 |
+
info="Ask natural language questions about your documentation"
|
832 |
)
|
833 |
|
834 |
+
query_btn = gr.Button("π Search Documentation", variant="primary", size="lg")
|
835 |
|
836 |
# Response display as text area
|
837 |
response_output = gr.Textbox(
|
838 |
+
label="π€ AI Assistant Response",
|
839 |
+
value="Your AI-powered documentation response will appear here with contextual information and source citations...",
|
840 |
lines=10,
|
841 |
interactive=False,
|
842 |
+
info="Generated using Nebius LLM with retrieved documentation context"
|
843 |
)
|
844 |
|
845 |
with gr.Column(scale=2):
|
846 |
+
gr.Markdown("### π Source References")
|
847 |
+
gr.Markdown("View the exact documentation sources used to generate the response, with relevance scores and GitHub links.")
|
848 |
|
849 |
# Source nodes display as JSON
|
850 |
sources_output = gr.JSON(
|
851 |
+
label="π Source Citations & Metadata",
|
852 |
value={
|
853 |
+
"message": "Source documentation excerpts with relevance scores will appear here after your query...",
|
854 |
+
"info": "Each source includes file path, relevance score, and content snippet"
|
855 |
},
|
856 |
)
|
857 |
|
858 |
+
# Event handlers
|
859 |
+
def handle_repo_selection(selected_repo):
|
860 |
+
"""Handle repository selection from dropdown"""
|
861 |
+
if not selected_repo or selected_repo in ["No repositories available", ""]:
|
862 |
+
return (
|
863 |
+
gr.Dropdown(visible=True), # Keep dropdown visible
|
864 |
+
gr.Textbox(visible=False, value=""), # Hide textbox
|
865 |
+
gr.Button(interactive=False) # Disable query button
|
866 |
+
)
|
867 |
+
else:
|
868 |
+
return (
|
869 |
+
gr.Dropdown(visible=False), # Hide dropdown
|
870 |
+
gr.Textbox(visible=True, value=selected_repo), # Show textbox with selected repo
|
871 |
+
gr.Button(interactive=True) # Enable query button
|
872 |
+
)
|
873 |
+
|
874 |
+
def reset_repo_selection():
|
875 |
+
"""Reset to show dropdown again"""
|
876 |
+
try:
|
877 |
+
repos = get_available_repositories() or ["No repositories available"]
|
878 |
+
return (
|
879 |
+
gr.Dropdown(choices=repos, value=None, visible=True), # Show dropdown with refreshed choices
|
880 |
+
gr.Textbox(visible=False, value=""), # Hide textbox
|
881 |
+
gr.Button(interactive=False) # Disable query button
|
882 |
+
)
|
883 |
+
except Exception as e:
|
884 |
+
print(f"Error refreshing repository list: {e}")
|
885 |
+
return (
|
886 |
+
gr.Dropdown(choices=["Error loading repositories"], value=None, visible=True),
|
887 |
+
gr.Textbox(visible=False, value=""),
|
888 |
+
gr.Button(interactive=False)
|
889 |
+
)
|
890 |
+
|
891 |
def get_available_docs_repo():
|
892 |
"""
|
893 |
+
List the available docs of repositories - should be called first to list out all the available repo docs to chat with
|
894 |
|
895 |
Returns:
|
896 |
+
Updated dropdown with available repositories
|
897 |
"""
|
898 |
try:
|
899 |
repos = get_available_repositories()
|
900 |
+
if not repos:
|
901 |
+
repos = ["No repositories available - Please ingest documentation first"]
|
902 |
+
return gr.Dropdown(choices=repos, value=None)
|
903 |
except Exception as e:
|
904 |
print(f"Error refreshing repository list: {e}")
|
905 |
+
return gr.Dropdown(choices=["Error loading repositories"], value=None)
|
906 |
|
907 |
# Simple query handler
|
908 |
def handle_query(repo: str, mode: str, query: str):
|
909 |
"""
|
910 |
Handle query request - returns raw data from retriever
|
911 |
Args:
|
912 |
+
repo: Selected repository from textbox
|
913 |
mode: Query mode (default, text_search, hybrid)
|
914 |
query: User's query
|
915 |
Returns:
|
|
|
918 |
if not query.strip():
|
919 |
return {"error": "Please enter a query."}
|
920 |
|
921 |
+
if not repo or repo in ["No repositories available", "Error loading repositories", ""]:
|
922 |
+
return {"error": "Please select a valid repository."}
|
923 |
|
924 |
try:
|
925 |
# Import QueryRetriever here to avoid circular imports
|
|
|
946 |
This function is designed to support Retrieval-Augmented Generation (RAG) by extracting
|
947 |
the most relevant context chunks from indexed documentation sources.
|
948 |
Args:
|
949 |
+
repo: Selected repository from the textbox input
|
950 |
+
mode: Query mode (default, text_search, hybrid)
|
951 |
query: User's query
|
952 |
Returns:
|
953 |
Tuple of (response_text, source_nodes_json)
|
|
|
965 |
|
966 |
return response_text, source_nodes
|
967 |
|
968 |
+
# Wire up events
|
969 |
+
|
970 |
+
# Handle repository selection from dropdown
|
971 |
+
repo_dropdown.change(
|
972 |
+
fn=handle_repo_selection,
|
973 |
+
inputs=[repo_dropdown],
|
974 |
+
outputs=[repo_dropdown, selected_repo_textbox, query_btn],
|
975 |
+
show_api=False
|
976 |
+
)
|
977 |
+
|
978 |
+
# Handle refresh button - resets to dropdown view
|
979 |
+
refresh_repos_btn.click(
|
980 |
+
fn=reset_repo_selection,
|
981 |
+
outputs=[repo_dropdown, selected_repo_textbox, query_btn],
|
982 |
+
show_api=False
|
983 |
+
)
|
984 |
+
|
985 |
+
# Also provide API endpoint for listing repositories
|
986 |
refresh_repos_btn.click(
|
987 |
fn=get_available_docs_repo,
|
988 |
outputs=[repo_dropdown],
|
989 |
+
api_name="list_available_docs",
|
990 |
)
|
991 |
|
992 |
+
# Query button uses the textbox value (not dropdown)
|
993 |
query_btn.click(
|
994 |
fn=make_query,
|
995 |
+
inputs=[selected_repo_textbox, query_mode, query_input], # Use textbox, not dropdown
|
996 |
outputs=[response_output, sources_output],
|
997 |
+
api_name="query_documentation",
|
998 |
)
|
999 |
|
1000 |
# Also allow Enter key to trigger query
|
1001 |
query_input.submit(
|
1002 |
fn=make_query,
|
1003 |
+
inputs=[selected_repo_textbox, query_mode, query_input], # Use textbox, not dropdown
|
1004 |
outputs=[response_output, sources_output],
|
1005 |
show_api=False,
|
1006 |
)
|
|
|
1218 |
|
1219 |
|
1220 |
if __name__ == "__main__":
|
1221 |
+
demo.launch(mcp_server=True)
|
rag/query.py
CHANGED
@@ -60,8 +60,6 @@ class QueryRetriever:
|
|
60 |
response_mode="refine",
|
61 |
)
|
62 |
|
63 |
-
|
64 |
-
|
65 |
response = query_engine.query(query)
|
66 |
nodes = []
|
67 |
for node in response.source_nodes:
|
|
|
60 |
response_mode="refine",
|
61 |
)
|
62 |
|
|
|
|
|
63 |
response = query_engine.query(query)
|
64 |
nodes = []
|
65 |
for node in response.source_nodes:
|