Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -768,103 +768,20 @@ def get_db_stats(vector_store: VectorStoreManager) -> str:
|
|
768 |
# The error occurs because there's likely a `try` statement without a matching `except` or `finally`
|
769 |
# Here are the possible locations and fixes:
|
770 |
|
771 |
-
# Option 1: If it's in the custom CSS definition around that line number
|
772 |
-
custom_css = """
|
773 |
-
.gradio-container {
|
774 |
-
max-width: 1200px;
|
775 |
-
margin: auto;
|
776 |
-
}
|
777 |
-
.gr-prose h1 {
|
778 |
-
font-size: 2.5rem;
|
779 |
-
margin-bottom: 1rem;
|
780 |
-
color: #1a5276;
|
781 |
-
}
|
782 |
-
.gr-prose h3 {
|
783 |
-
font-size: 1.25rem;
|
784 |
-
font-weight: 600;
|
785 |
-
margin-top: 1rem;
|
786 |
-
margin-bottom: 0.5rem;
|
787 |
-
color: #2874a6;
|
788 |
-
}
|
789 |
-
.container {
|
790 |
-
margin: 0 auto;
|
791 |
-
padding: 2rem;
|
792 |
-
}
|
793 |
-
.gr-box {
|
794 |
-
border-radius: 8px;
|
795 |
-
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
796 |
-
padding: 1rem;
|
797 |
-
margin-bottom: 1rem;
|
798 |
-
background-color: #f9f9f9;
|
799 |
-
}
|
800 |
-
.footer {
|
801 |
-
text-align: center;
|
802 |
-
font-size: 0.8rem;
|
803 |
-
color: #666;
|
804 |
-
margin-top: 2rem;
|
805 |
-
}
|
806 |
-
""" # Make sure this closing triple quote is present
|
807 |
|
808 |
-
# Option 2: If it's in the main function, make sure all try blocks have matching except clauses
|
809 |
-
def main():
|
810 |
-
"""Main function to run the RAG application"""
|
811 |
-
# Path for configuration file
|
812 |
-
CONFIG_FILE_PATH = "rag_config.json"
|
813 |
-
|
814 |
-
# Try to load configuration from file, or use defaults
|
815 |
-
if os.path.exists(CONFIG_FILE_PATH):
|
816 |
-
config = Config.from_file(CONFIG_FILE_PATH)
|
817 |
-
else:
|
818 |
-
config = Config(
|
819 |
-
local_dir="./chroma_db", # Store Chroma files in dedicated directory
|
820 |
-
collection_name="markdown_docs"
|
821 |
-
)
|
822 |
-
# Save default configuration
|
823 |
-
config.save_to_file(CONFIG_FILE_PATH)
|
824 |
-
|
825 |
-
print(f"Starting Document Knowledge Assistant v{VERSION}")
|
826 |
-
print(f"Log file: {log_file}")
|
827 |
-
|
828 |
-
try:
|
829 |
-
# Initialize vector store manager with existing collection
|
830 |
-
vector_store = VectorStoreManager(config)
|
831 |
-
|
832 |
-
# Initialize RAG system without API keys initially
|
833 |
-
rag_system = RAGSystem(vector_store, config)
|
834 |
-
|
835 |
-
# Create the Gradio interface with custom CSS
|
836 |
-
with gr.Blocks(title="Document Knowledge Assistant", css=custom_css) as app:
|
837 |
-
# Interface code here...
|
838 |
-
pass # Replace with actual UI code
|
839 |
-
|
840 |
-
# Launch the interface
|
841 |
-
app.launch(
|
842 |
-
share=False,
|
843 |
-
server_name="0.0.0.0",
|
844 |
-
server_port=7860,
|
845 |
-
debug=False
|
846 |
-
)
|
847 |
-
|
848 |
-
except Exception as e: # Make sure there's an except clause for every try
|
849 |
-
logger.critical(f"Error starting application: {e}")
|
850 |
-
print(f"Error starting application: {e}")
|
851 |
-
sys.exit(1)
|
852 |
|
853 |
-
|
854 |
-
|
855 |
-
# Option 4: Complete fix for the most likely scenario - an incomplete try block in the main function
|
856 |
-
def main_fixed():
|
857 |
"""Main function to run the RAG application"""
|
858 |
# Path for configuration file
|
859 |
CONFIG_FILE_PATH = "rag_config.json"
|
860 |
|
861 |
-
# Try to load configuration from file, or use defaults
|
862 |
try:
|
|
|
863 |
if os.path.exists(CONFIG_FILE_PATH):
|
864 |
config = Config.from_file(CONFIG_FILE_PATH)
|
865 |
else:
|
866 |
config = Config(
|
867 |
-
local_dir="./chroma_db",
|
868 |
collection_name="markdown_docs"
|
869 |
)
|
870 |
# Save default configuration
|
@@ -879,17 +796,244 @@ def main_fixed():
|
|
879 |
# Initialize RAG system without API keys initially
|
880 |
rag_system = RAGSystem(vector_store, config)
|
881 |
|
882 |
-
# Create the Gradio interface
|
883 |
with gr.Blocks(title="Document Knowledge Assistant", css=custom_css) as app:
|
884 |
-
#
|
885 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
886 |
|
887 |
-
# Launch the interface
|
888 |
app.launch(
|
889 |
-
share=False,
|
890 |
-
server_name="0.0.0.0",
|
891 |
-
server_port=7860,
|
892 |
-
debug=False
|
|
|
|
|
|
|
893 |
)
|
894 |
except Exception as e:
|
895 |
logger.critical(f"Error starting application: {e}")
|
|
|
768 |
# The error occurs because there's likely a `try` statement without a matching `except` or `finally`
|
769 |
# Here are the possible locations and fixes:
|
770 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
771 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
772 |
|
773 |
+
def main():
|
|
|
|
|
|
|
774 |
"""Main function to run the RAG application"""
|
775 |
# Path for configuration file
|
776 |
CONFIG_FILE_PATH = "rag_config.json"
|
777 |
|
|
|
778 |
try:
|
779 |
+
# Try to load configuration from file, or use defaults
|
780 |
if os.path.exists(CONFIG_FILE_PATH):
|
781 |
config = Config.from_file(CONFIG_FILE_PATH)
|
782 |
else:
|
783 |
config = Config(
|
784 |
+
local_dir="./chroma_db", # Store Chroma files in dedicated directory
|
785 |
collection_name="markdown_docs"
|
786 |
)
|
787 |
# Save default configuration
|
|
|
796 |
# Initialize RAG system without API keys initially
|
797 |
rag_system = RAGSystem(vector_store, config)
|
798 |
|
799 |
+
# Create the Gradio interface with custom CSS
|
800 |
with gr.Blocks(title="Document Knowledge Assistant", css=custom_css) as app:
|
801 |
+
gr.Markdown(f"# Document Knowledge Assistant v{VERSION}")
|
802 |
+
gr.Markdown("Ask questions about your documents and get comprehensive AI-powered answers")
|
803 |
+
|
804 |
+
# Main layout
|
805 |
+
with gr.Row():
|
806 |
+
# Left column for asking questions
|
807 |
+
with gr.Column(scale=3):
|
808 |
+
with gr.Box():
|
809 |
+
gr.Markdown("### Ask Your Question")
|
810 |
+
query_input = gr.Textbox(
|
811 |
+
label="",
|
812 |
+
placeholder="What would you like to know about your documents?",
|
813 |
+
lines=3
|
814 |
+
)
|
815 |
+
|
816 |
+
with gr.Row():
|
817 |
+
query_button = gr.Button("Ask Question", variant="primary", scale=3)
|
818 |
+
clear_button = gr.Button("Clear", variant="secondary", scale=1)
|
819 |
+
|
820 |
+
with gr.Box():
|
821 |
+
gr.Markdown("### Answer")
|
822 |
+
response_output = gr.Markdown()
|
823 |
+
|
824 |
+
# Right column for settings
|
825 |
+
with gr.Column(scale=1):
|
826 |
+
# API Keys and model selection
|
827 |
+
with gr.Accordion("AI Model Settings", open=True):
|
828 |
+
gr.Markdown("### AI Configuration")
|
829 |
+
model_choice = gr.Radio(
|
830 |
+
choices=["openai", "gemini"],
|
831 |
+
value="openai",
|
832 |
+
label="AI Provider",
|
833 |
+
info=f"Select your preferred AI model"
|
834 |
+
)
|
835 |
+
|
836 |
+
api_key_input = gr.Textbox(
|
837 |
+
label="API Key",
|
838 |
+
placeholder="Enter your API key here...",
|
839 |
+
type="password",
|
840 |
+
info="Your key is not stored between sessions"
|
841 |
+
)
|
842 |
+
|
843 |
+
save_key_button = gr.Button("Save API Key", variant="primary")
|
844 |
+
api_status = gr.Markdown("")
|
845 |
+
|
846 |
+
# Advanced search controls
|
847 |
+
with gr.Accordion("Advanced Settings", open=False):
|
848 |
+
gr.Markdown("### Search & Response Settings")
|
849 |
+
num_results = gr.Slider(
|
850 |
+
minimum=3,
|
851 |
+
maximum=15,
|
852 |
+
value=config.default_top_k,
|
853 |
+
step=1,
|
854 |
+
label="Documents to search",
|
855 |
+
info="Higher values provide more context"
|
856 |
+
)
|
857 |
+
|
858 |
+
temperature_slider = gr.Slider(
|
859 |
+
minimum=0.0,
|
860 |
+
maximum=1.0,
|
861 |
+
value=config.temperature,
|
862 |
+
step=0.05,
|
863 |
+
label="Creativity",
|
864 |
+
info="Lower = more factual, Higher = more creative"
|
865 |
+
)
|
866 |
+
|
867 |
+
max_tokens_slider = gr.Slider(
|
868 |
+
minimum=500,
|
869 |
+
maximum=4000,
|
870 |
+
value=config.max_tokens,
|
871 |
+
step=100,
|
872 |
+
label="Response Length",
|
873 |
+
info="Maximum words in response"
|
874 |
+
)
|
875 |
+
|
876 |
+
# Database stats - simplified
|
877 |
+
with gr.Accordion("System Info", open=False):
|
878 |
+
stats_display = gr.Markdown(get_db_stats(vector_store))
|
879 |
+
|
880 |
+
gr.Markdown(f"""
|
881 |
+
**System Details:**
|
882 |
+
- Version: {VERSION}
|
883 |
+
- Embedding: {vector_store.embedding_engine.model_name}
|
884 |
+
- Device: {vector_store.embedding_engine.device}
|
885 |
+
""")
|
886 |
+
refresh_button = gr.Button("Refresh", variant="secondary", size="sm")
|
887 |
+
|
888 |
+
# Hidden element for search results (not visible to user)
|
889 |
+
with gr.Accordion("Debug Information", open=False, visible=False):
|
890 |
+
search_output = gr.Markdown()
|
891 |
+
|
892 |
+
# Query history at the bottom (optional section)
|
893 |
+
with gr.Accordion("Recent Questions", open=False):
|
894 |
+
history_list = gr.Dataframe(
|
895 |
+
headers=["Time", "Question", "Model"],
|
896 |
+
datatype=["str", "str", "str"],
|
897 |
+
row_count=5,
|
898 |
+
col_count=(3, "fixed"),
|
899 |
+
interactive=False
|
900 |
+
)
|
901 |
+
|
902 |
+
# Footer
|
903 |
+
gr.Markdown(
|
904 |
+
"""<div class="footer">Document Knowledge Assistant helps you get insights from your documents using AI.
|
905 |
+
Powered by Retrieval Augmented Generation.</div>"""
|
906 |
+
)
|
907 |
+
|
908 |
+
# Query history storage
|
909 |
+
query_history = []
|
910 |
+
|
911 |
+
# Function to update API key based on selected model
|
912 |
+
def update_api_key(api_key, model):
|
913 |
+
if not api_key.strip():
|
914 |
+
return "❌ API key cannot be empty"
|
915 |
+
|
916 |
+
if model == "openai":
|
917 |
+
success = rag_system.setup_openai(api_key)
|
918 |
+
model_name = f"OpenAI {config.openai_model}"
|
919 |
+
else:
|
920 |
+
success = rag_system.setup_gemini(api_key)
|
921 |
+
model_name = f"Google {config.gemini_model}"
|
922 |
+
|
923 |
+
if success:
|
924 |
+
return f"✅ {model_name} connected successfully"
|
925 |
+
else:
|
926 |
+
return f"❌ Connection failed. Please check your API key and try again."
|
927 |
+
|
928 |
+
# Query function that returns both response and search results
|
929 |
+
def query_and_search(query, n_results, model, temperature, max_tokens):
|
930 |
+
# Update configuration with current UI values
|
931 |
+
config.temperature = float(temperature)
|
932 |
+
config.max_tokens = int(max_tokens)
|
933 |
+
|
934 |
+
start_time = datetime.now()
|
935 |
+
|
936 |
+
if not query.strip():
|
937 |
+
return "Please enter a question to get an answer.", "", query_history[-5:] if query_history else []
|
938 |
+
|
939 |
+
try:
|
940 |
+
# Verify that API keys are configured
|
941 |
+
if (model == "openai" and rag_system.openai_client is None) or \
|
942 |
+
(model == "gemini" and not rag_system.gemini_configured):
|
943 |
+
return "Please configure your API key first. Enter your API key in the settings panel and click 'Save API Key'.", "", query_history[-5:] if query_history else []
|
944 |
+
|
945 |
+
# Call the RAG system's query and generate function
|
946 |
+
response, search_output_text = rag_system.query_and_generate(
|
947 |
+
query=query,
|
948 |
+
n_results=int(n_results),
|
949 |
+
model=model
|
950 |
+
)
|
951 |
+
|
952 |
+
# Add to history
|
953 |
+
timestamp = datetime.now().strftime("%H:%M")
|
954 |
+
query_history.append([timestamp, query, model])
|
955 |
+
|
956 |
+
# Keep only the last 100 queries
|
957 |
+
if len(query_history) > 100:
|
958 |
+
query_history.pop(0)
|
959 |
+
|
960 |
+
# Update the history display with the most recent entries (reverse chronological)
|
961 |
+
recent_history = list(reversed(query_history[-5:])) if len(query_history) >= 5 else list(reversed(query_history))
|
962 |
+
|
963 |
+
# Calculate elapsed time
|
964 |
+
elapsed_time = (datetime.now() - start_time).total_seconds()
|
965 |
+
|
966 |
+
# Add subtle timing information to the response
|
967 |
+
response_with_timing = f"{response}\n\n<small>Answered in {elapsed_time:.1f}s</small>"
|
968 |
+
|
969 |
+
return response_with_timing, search_output_text, recent_history
|
970 |
+
|
971 |
+
except Exception as e:
|
972 |
+
error_msg = f"Error processing query: {str(e)}"
|
973 |
+
logger.error(error_msg)
|
974 |
+
logger.error(traceback.format_exc())
|
975 |
+
return "I encountered an error while processing your question. Please try again or check your API key settings.", "", query_history[-5:] if query_history else []
|
976 |
+
|
977 |
+
# Function to clear the input and results
|
978 |
+
def clear_inputs():
|
979 |
+
return "", "", "", query_history[-5:] if query_history else []
|
980 |
+
|
981 |
+
# Set up events
|
982 |
+
save_key_button.click(
|
983 |
+
fn=update_api_key,
|
984 |
+
inputs=[api_key_input, model_choice],
|
985 |
+
outputs=api_status
|
986 |
+
)
|
987 |
+
|
988 |
+
query_button.click(
|
989 |
+
fn=query_and_search,
|
990 |
+
inputs=[query_input, num_results, model_choice, temperature_slider, max_tokens_slider],
|
991 |
+
outputs=[response_output, search_output, history_list]
|
992 |
+
)
|
993 |
+
|
994 |
+
refresh_button.click(
|
995 |
+
fn=lambda: get_db_stats(vector_store),
|
996 |
+
inputs=None,
|
997 |
+
outputs=stats_display
|
998 |
+
)
|
999 |
+
|
1000 |
+
clear_button.click(
|
1001 |
+
fn=clear_inputs,
|
1002 |
+
inputs=None,
|
1003 |
+
outputs=[query_input, response_output, search_output, history_list]
|
1004 |
+
)
|
1005 |
+
|
1006 |
+
# Handle Enter key in query input
|
1007 |
+
query_input.submit(
|
1008 |
+
fn=query_and_search,
|
1009 |
+
inputs=[query_input, num_results, model_choice, temperature_slider, max_tokens_slider],
|
1010 |
+
outputs=[response_output, search_output, history_list]
|
1011 |
+
)
|
1012 |
+
|
1013 |
+
# Auto-fill examples
|
1014 |
+
examples = [
|
1015 |
+
["What are the main features of this application?"],
|
1016 |
+
["How does the retrieval augmented generation work?"],
|
1017 |
+
["Can you explain the embedding models used in this system?"],
|
1018 |
+
]
|
1019 |
+
|
1020 |
+
gr.Examples(
|
1021 |
+
examples=examples,
|
1022 |
+
inputs=query_input,
|
1023 |
+
outputs=[response_output, search_output, history_list],
|
1024 |
+
fn=lambda q: query_and_search(q, num_results.value, model_choice.value, temperature_slider.value, max_tokens_slider.value),
|
1025 |
+
cache_examples=False,
|
1026 |
+
)
|
1027 |
|
1028 |
+
# Launch the interface with a nice theme
|
1029 |
app.launch(
|
1030 |
+
share=False, # Set to True to create a public link
|
1031 |
+
server_name="0.0.0.0", # Listen on all interfaces
|
1032 |
+
server_port=7860, # Default Gradio port
|
1033 |
+
debug=False, # Set to True during development
|
1034 |
+
auth=None, # Add (username, password) tuple for basic auth
|
1035 |
+
favicon_path="favicon.ico" if os.path.exists("favicon.ico") else None,
|
1036 |
+
show_error=True
|
1037 |
)
|
1038 |
except Exception as e:
|
1039 |
logger.critical(f"Error starting application: {e}")
|