geekydraco commited on
Commit
f0d892a
·
verified ·
1 Parent(s): dc93941

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +218 -0
  2. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces # must be imported before torch/other CUDA-touching modules (ZeroGPU requirement)
2
+
3
+ import time
4
+ from pathlib import Path
5
+ import sys
6
+ import os
7
+ import logging
8
+
9
+ # ==========================================
10
+ # 0. Fix sys.path BEFORE importing anything from src/
11
+ # (src/generators/__init__.py etc. do bare "from generators.xxx import ..."
12
+ # imports that require the src/ folder itself to already be on sys.path)
13
+ # ==========================================
14
+ project_root = Path(__file__).parent.resolve()
15
+ sys.path.insert(0, str(project_root))
16
+ sys.path.insert(0, str(project_root / "src"))
17
+
18
+ import gradio as gr
19
+ import torch
20
+ from src.config import load_config
21
+ from src.models.load_model import ModelLoader
22
+ from src.generators.program_generator import GenerationPipeline
23
+ from src.generators.text_to_mongo_generator import TextToMongoGenerator
24
+ from src.vectorDB.index_manager import IndexManager
25
+ from src.rag.rag_pipeline import RAGPipeline
26
+
27
+ # Configure logging
28
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
29
+ logger = logging.getLogger(__name__)
30
+
31
+ # Environment variables to suppress warnings
32
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
33
+ os.environ["PYTORCH_MPS_HIGH_WATERMARK_RATIO"] = "0.0"
34
+ os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
35
+
36
+ # ==========================================
37
+ # 1. Load Configuration & Models
38
+ # ==========================================
39
+ logger.info("Loading configuration...")
40
+ config = load_config("configs/config.yaml")
41
+
42
+ logger.info("Initializing Model Loader...")
43
+ model_loader = ModelLoader(config)
44
+ tokenizer = model_loader.load_tokenizer()
45
+ base_model = model_loader.load_base_model()
46
+
47
+ # Try to load the Fine-Tuned (LoRA) model if it exists
48
+ lora_path = Path(config.lora.output_dir)
49
+ if lora_path.exists() and (lora_path / "adapter_config.json").exists():
50
+ logger.info(f"✅ Found LoRA adapter at {lora_path}. Loading Fine-Tuned model...")
51
+ finetuned_model = model_loader.autodetect_saved_model(str(lora_path))
52
+ else:
53
+ logger.warning("⚠️ No LoRA adapter found. Fine-Tuned model will fallback to Base model.")
54
+ finetuned_model = base_model
55
+
56
+ # ==========================================
57
+ # 2. Setup Generation Pipelines
58
+ # ==========================================
59
+ logger.info("Setting up generation pipelines...")
60
+ base_pipeline = GenerationPipeline(base_model, tokenizer, config.generation)
61
+ finetuned_pipeline = GenerationPipeline(finetuned_model, tokenizer, config.generation)
62
+
63
+ base_generator = TextToMongoGenerator(base_pipeline, config)
64
+ finetuned_generator = TextToMongoGenerator(finetuned_pipeline, config)
65
+
66
+ # ==========================================
67
+ # 3. Setup RAG Pipeline (Optional)
68
+ # ==========================================
69
+ rag_pipeline = None
70
+ try:
71
+ index_manager = IndexManager(
72
+ embedding_model=config.embedding.external_model,
73
+ language=config.retrieval.structural_language,
74
+ semantic_weight=1.0 - config.retrieval.structural_weight_alpha,
75
+ ast_weight=config.retrieval.structural_weight_alpha,
76
+ save_dir="data/indices"
77
+ )
78
+
79
+ if index_manager._indices_exist():
80
+ index_manager.load_indices()
81
+ rag_pipeline = RAGPipeline(
82
+ retriever=index_manager,
83
+ generator=finetuned_pipeline,
84
+ config=config.generation
85
+ )
86
+ logger.info("✅ RAG Pipeline initialized successfully.")
87
+ else:
88
+ logger.warning("⚠️ RAG indices not found in 'data/indices'. RAG feature will be disabled.")
89
+ except Exception as e:
90
+ logger.error(f"⚠️ Could not initialize RAG pipeline: {e}")
91
+
92
+
93
+ # ==========================================
94
+ # 4. Gradio Generation Logic
95
+ # ==========================================
96
+ @spaces.GPU(duration=60) # requests a shared GPU for up to 60s per call; models are already placed at module scope above
97
+ def generate_mongo_query(question: str, model_choice: str, use_rag: bool, top_k: int):
98
+ if not question.strip():
99
+ return "Please enter a valid question.", "Latency: N/A"
100
+
101
+ start_time = time.time()
102
+
103
+ # RAG Generation
104
+ if use_rag and rag_pipeline is not None:
105
+ generated_query, context_metadata = rag_pipeline.generate_with_rag(question, top_k=int(top_k))
106
+ latency = (time.time() - start_time) * 1000
107
+
108
+ # Format context for display
109
+ context_str = "Retrieved Context:\n" + "-" * 30 + "\n"
110
+ for i, ctx in enumerate(context_metadata[:int(top_k)]):
111
+ q = ctx.get('question', 'N/A')
112
+ mql = ctx.get('generated_mongodb_query', ctx.get('mongodb_query', 'N/A'))
113
+ context_str += f"[{i + 1}] Q: {q}\n MQL: {mql}\n\n"
114
+
115
+ return generated_query, f"⏱️ Latency: {latency:.2f} ms\n\n{context_str}"
116
+
117
+ # Standard Generation (Base or Fine-Tuned)
118
+ else:
119
+ if model_choice == "Fine-Tuned (LoRA)":
120
+ result = finetuned_generator.generate_single(question)
121
+ else:
122
+ result = base_generator.generate_single(question)
123
+
124
+ latency = result['latency_ms']
125
+ info_text = f"⏱️ Latency: {latency:.2f} ms\nModel: {model_choice}"
126
+ return result['generated_query'], info_text
127
+
128
+
129
+ # ==========================================
130
+ # 5. Build Gradio UI
131
+ # ==========================================
132
+ with gr.Blocks(title="Text-to-MongoDB Generator", theme=gr.themes.Soft()) as demo:
133
+ gr.Markdown(
134
+ """
135
+ # 🚀 Text-to-MongoDB Query Generator
136
+ Convert natural language questions into executable MongoDB queries using **Base**, **Fine-Tuned**, or **RAG-enhanced** models.
137
+ """
138
+ )
139
+
140
+ with gr.Row():
141
+ # Left Column: Inputs
142
+ with gr.Column(scale=3):
143
+ question_input = gr.Textbox(
144
+ label="Natural Language Question",
145
+ placeholder="e.g., How many singers do we have?",
146
+ lines=2,
147
+ info="Type your question about the database here."
148
+ )
149
+
150
+ with gr.Row():
151
+ model_choice = gr.Radio(
152
+ choices=["Base Model", "Fine-Tuned (LoRA)"],
153
+ value="Fine-Tuned (LoRA)",
154
+ label="Model Selection"
155
+ )
156
+ use_rag = gr.Checkbox(
157
+ label="🧠 Use RAG (Retrieval-Augmented Generation)",
158
+ value=False,
159
+ info="Requires pre-built indices"
160
+ )
161
+
162
+ with gr.Accordion("⚙️ RAG Settings", open=False):
163
+ top_k_slider = gr.Slider(
164
+ minimum=1, maximum=10, value=3, step=1,
165
+ label="Top-K Retrieved Contexts",
166
+ info="Number of similar examples to retrieve from the vector database."
167
+ )
168
+
169
+ generate_btn = gr.Button("Generate MongoDB Query", variant="primary", size="lg")
170
+
171
+ # Right Column: Outputs
172
+ with gr.Column(scale=2):
173
+ query_output = gr.Code(
174
+ label="Generated MongoDB Query",
175
+ language="javascript",
176
+ lines=6,
177
+ interactive=False
178
+ )
179
+ info_output = gr.Textbox(
180
+ label="Generation Info & Context",
181
+ lines=8,
182
+ interactive=False,
183
+ max_lines=15
184
+ )
185
+
186
+ gr.Markdown("---")
187
+ gr.Markdown("### 💡 Example Questions")
188
+ gr.Examples(
189
+ examples=[
190
+ ["How many singers do we have?"],
191
+ ["What is the average age of all singers from France?"],
192
+ ["Show the name and release year of the song by the youngest singer."],
193
+ ["Find the number of pets whose weight is heavier than 10."],
194
+ ["What are the different countries with singers above age 20?"],
195
+ ["List the name and date of each battle."],
196
+ ],
197
+ inputs=[question_input],
198
+ cache_examples=False
199
+ )
200
+
201
+ # Link button to function
202
+ generate_btn.click(
203
+ fn=generate_mongo_query,
204
+ inputs=[question_input, model_choice, use_rag, top_k_slider],
205
+ outputs=[query_output, info_output]
206
+ )
207
+
208
+ # ==========================================
209
+ # 6. Launch the App
210
+ # ==========================================
211
+ if __name__ == "__main__":
212
+ # Launch locally on port 7860
213
+ demo.launch(
214
+ server_name="0.0.0.0", # Makes it accessible on your local network
215
+ server_port=7860,
216
+ share=False, # Set to True if you want a public temporary URL
217
+ show_error=True
218
+ )
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ spaces
2
+ gradio==5.9.1
3
+ torch==2.5.1
4
+ transformers==4.46.3
5
+ peft==0.13.2
6
+ faiss-cpu==1.9.0.post1
7
+ numpy==2.1.3
8
+ PyYAML==6.0.2
9
+ huggingface-hub==0.26.2
10
+ tqdm==4.67.1