import gradio as gr from openai import OpenAI import os import glob from pypdf import PdfReader # Initialize client using Hugging Face routing client = OpenAI( base_url="https://router.huggingface.co/v1", api_key=os.environ.get("HF_TOKEN"), ) # --- Document Context Logic --- DOCS_DIR = "docs" # Folder for your JMeter cheat sheets, project specs, etc. def load_pdf_context(): """Reads all PDFs in the DOCS_DIR once at startup and extracts text.""" context = "" if not os.path.exists(DOCS_DIR): os.makedirs(DOCS_DIR) print(f"Created '{DOCS_DIR}' directory. Upload your PDFs here.") return context pdf_files = glob.glob(os.path.join(DOCS_DIR, "*.pdf")) if not pdf_files: print("No PDFs found in the docs folder.") return context print(f"Loading {len(pdf_files)} PDF(s) into context...") for file_path in pdf_files: try: reader = PdfReader(file_path) context += f"\n--- Start Document: {os.path.basename(file_path)} ---\n" for page in reader.pages: text = page.extract_text() if text: context += text + "\n" context += f"--- End Document: {os.path.basename(file_path)} ---\n\n" except Exception as e: print(f"Error loading {file_path}: {e}") return context DOCUMENT_CONTEXT = load_pdf_context() # ----------------------------------- def respond(message, history): # System Message tailored for an experienced Dev learning JMeter system_content = ( "You are a highly experienced Performance Engineer and Apache JMeter expert. " "The user you are helping is an experienced software developer who is new to JMeter and stress testing. " "Skip basic programming concepts and focus strictly on JMeter architecture (Test Plans, Thread Groups, Samplers, Listeners, Timers), " "performance testing theory (Load vs. Stress vs. Spike testing), and best practices (e.g., using JSR223 Samplers with Groovy instead of BeanShell, running in CLI/non-GUI mode). " "Be concise, technical, and highly practical. Provide code snippets or XML structures where helpful.\n\n" "Here is the project-specific context and documentation you should use to answer questions:\n" f"{DOCUMENT_CONTEXT}" ) messages = [{"role": "system", "content": system_content}] # Add conversation history for val in history: if val['role'] == 'user': messages.append({"role": "user", "content": val['content']}) else: messages.append({"role": "assistant", "content": val['content']}) # Process the current message user_content = [] if message["text"]: user_content.append({"type": "text", "text": message["text"]}) # Image/File handling placeholder for file in message["files"]: pass messages.append({"role": "user", "content": user_content}) response = "" try: stream = client.chat.completions.create( # You can keep this model or switch to another available on HF-Pro model="Qwen/Qwen2.5-Coder-32B-Instruct:nscale", messages=messages, stream=True ) for chunk in stream: if hasattr(chunk, 'choices') and len(chunk.choices) > 0: token = chunk.choices[0].delta.content if token: response += token yield response except Exception as e: yield f"Error encountered: {str(e)} - Please verify the model endpoint or your API token." # Interface Setup demo = gr.ChatInterface( respond, multimodal=True, title="Apache JMeter Performance Expert ⚙️", description="Your technical guide for building robust JMeter test plans, analyzing performance metrics, and executing effective stress tests. Backed by your project documentation.", examples=[ {"text": "What is the difference between a Load Test and a Stress Test?"}, {"text": "How do I extract a dynamic token from a JSON response to use in my next request?"}, {"text": "Why should I run my tests in non-GUI mode, and what is the command for it?"} ] ) if __name__ == "__main__": demo.launch()