import gradio as gr import time import sys from llama_index.llms.google_genai import GoogleGenAI from llama_index.core import Settings from config import * from document_processor import * query_engine = None chunks_df = None def answer_question(question): global query_engine if query_engine is None: return "
❌ System not initialized or document database is empty
", "" try: start_time = time.time() response = query_engine.query(question) retrieved_nodes = query_engine.retriever.retrieve(question) end_time = time.time() processing_time = end_time - start_time sources_html = generate_sources_html(retrieved_nodes) answer_with_time = f"""

📋 Answer:

{response.response}
⏱️ Processing time: {processing_time:.2f} sec
""" return answer_with_time, sources_html except Exception as e: error_msg = f"
❌ Error processing question: {str(e)}
" return error_msg, "" def generate_sources_html(nodes): html = "
" html += "

📚 Sources:

" unique_docs = {} for node in nodes: metadata = node.metadata if hasattr(node, 'metadata') else {} doc_name = metadata.get('document_name', 'unknown') doc_link = metadata.get('document_link', '') doc_key = f"{doc_name}||{doc_link}" if doc_key not in unique_docs: unique_docs[doc_key] = [] unique_docs[doc_key].append(node) for doc_key, doc_nodes in unique_docs.items(): doc_name, doc_link = doc_key.split('||', 1) html += f"
" if doc_link: html += f"

📄 {doc_name}

" else: html += f"

📄 {doc_name}

" html += f"

Found relevant fragments: {len(doc_nodes)}

" html += "
" html += "
" return html def get_documents_display(): documents = get_existing_documents() if not documents: return "
No documents in system yet
" html = f"
" html += f"

📚 {len(documents)} documents in the system:

" html += "
" for i, doc_name in enumerate(documents, 1): html += f"
" html += f"{i}. {doc_name}" html += "
" html += "
" return html def upload_and_process_file(files, doc_names, doc_links): global query_engine, chunks_df if not files: return "No files selected", get_documents_display() if len(files) != len(doc_names) or len(files) != len(doc_links): return "Error: Number of files must match number of document names and links", get_documents_display() results = [] for i, file in enumerate(files): doc_name = doc_names[i].strip() if i < len(doc_names) else "" doc_link = doc_links[i].strip() if i < len(doc_links) else "" if not doc_name: doc_name = file.name.split('/')[-1].replace('.txt', '').replace('.pdf', '') log_message(f"🔄 Starting processing of file {i+1}/{len(files)}: {file.name}") file_info, error = process_uploaded_file(file.name, file.name.split('/')[-1], doc_name, doc_link) if error: results.append(f"❌ {file.name.split('/')[-1]}: {error}") continue query_engine, chunks_df, error = add_to_vector_index(file_info['chunks'], file_info, chunks_df) if error: results.append(f"❌ {file_info['file_name']}: Error adding to database - {error}") else: results.append(f"✅ {file_info['document']}: Successfully processed and added to database") log_message(f"✅ Completed processing: {file_info['document']}") return "\n".join(results), get_documents_display() def create_interface(): with gr.Blocks(title="AIEXP - AI Expert for Regulatory Documentation", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # AIEXP - Artificial Intelligence Expert ## Tool for working with regulatory documentation """) with gr.Tab("🔍 Document Search"): gr.Markdown("### Ask a question about the uploaded documentation") with gr.Row(): with gr.Column(scale=3): question_input = gr.Textbox( label="Your question to the knowledge base", placeholder="Enter your question about the documents...", lines=3 ) ask_btn = gr.Button("🔍 Find Answer", variant="primary", size="lg") gr.Examples( examples=[ "Какой стандарт устанавливает порядок признания протоколов испытаний продукции в области использования атомной энергии?", "Кто несет ответственность за организацию и проведение признания протоколов испытаний продукции?", "В каких случаях могут быть признаны протоколы испытаний, проведенные лабораториями, не включенными в перечисления?", ], inputs=question_input ) with gr.Row(): with gr.Column(scale=2): answer_output = gr.HTML( label="", value="
The answer to your question will appear here...
", ) with gr.Column(scale=1): sources_output = gr.HTML( label="", value="
Sources will appear here...
", ) ask_btn.click( fn=answer_question, inputs=[question_input], outputs=[answer_output, sources_output] ) question_input.submit( fn=answer_question, inputs=[question_input], outputs=[answer_output, sources_output] ) with gr.Tab("📚 Document Management"): gr.Markdown("### Document database and adding new files") with gr.Row(): with gr.Column(scale=2): documents_display = gr.HTML( label="Document list", value=get_documents_display() ) refresh_btn = gr.Button("🔄 Refresh List", variant="secondary") with gr.Column(scale=1): gr.Markdown("#### Upload new documents") gr.Markdown("Supported formats: PDF, TXT") file_upload = gr.File( file_count="multiple", file_types=[".pdf", ".txt"], label="Select files to upload" ) doc_names_input = gr.Textbox( label="Document names (one per line)", placeholder="Enter document names, one per line...", lines=5 ) doc_links_input = gr.Textbox( label="Document links (one per line)", placeholder="Enter document links, one per line...", lines=5 ) upload_btn = gr.Button("📤 Upload and Process", variant="primary") upload_status = gr.Textbox( label="Upload status", lines=8, max_lines=10, interactive=False ) def process_names_and_links(names_text, links_text): names = [name.strip() for name in names_text.split('\n') if name.strip()] links = [link.strip() for link in links_text.split('\n') if link.strip()] return names, links upload_btn.click( fn=lambda files, names, links: upload_and_process_file( files, *process_names_and_links(names, links) ), inputs=[file_upload, doc_names_input, doc_links_input], outputs=[upload_status, documents_display] ) refresh_btn.click( fn=lambda: get_documents_display(), outputs=[documents_display] ) return demo if __name__ == "__main__": log_message("🚀 Starting AIEXP - AI Expert for Regulatory Documentation") llm = GoogleGenAI(model="gemini-2.0-flash", api_key=GOOGLE_API_KEY) Settings.llm = llm query_engine, chunks_df, success = initialize_system() if success: log_message("🌟 Starting web interface...") demo = create_interface() demo.launch( server_name="0.0.0.0", server_port=7860, share=True, debug=False ) else: log_message("❌ Cannot start application due to initialization error") sys.exit(1)