Mohamed284 commited on
Commit
19f7ee7
·
1 Parent(s): fe61f1d
Files changed (3) hide show
  1. .env +0 -10
  2. app.py +46 -28
  3. main.ipynb +175 -130
.env CHANGED
@@ -1,4 +1,3 @@
1
- <<<<<<< HEAD
2
  # API Configuration
3
  OPENAI_API_KEY="d1c9ed1ca70b9721dee1087d93f9662a"
4
  GEMINI_API_KEY="AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
@@ -6,13 +5,4 @@ GEMINI_API_KEY="AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
6
  # GCP_API_KEY="AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
7
 
8
  GEMINI_API_KEY_1= "AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
9
- =======
10
- # API Configuration
11
- OPENAI_API_KEY="d1c9ed1ca70b9721dee1087d93f9662a"
12
- GEMINI_API_KEY="AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
13
- # GCP_PROJECT_ID="1008673779731"
14
- # GCP_API_KEY="AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
15
-
16
- GEMINI_API_KEY_1= "AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
17
- >>>>>>> 51466f9c2c65701d4b45dd8e842e1a151f75959b
18
  GEMINI_API_KEY_2= "AIzaSyDzQSzM9vA6Le36V65I2meN5URclq4JSx0"
 
 
1
  # API Configuration
2
  OPENAI_API_KEY="d1c9ed1ca70b9721dee1087d93f9662a"
3
  GEMINI_API_KEY="AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
 
5
  # GCP_API_KEY="AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
6
 
7
  GEMINI_API_KEY_1= "AIzaSyDDWHYpQKQ5glnQn5Q-kMTjliwpNfYBpeY"
 
 
 
 
 
 
 
 
 
8
  GEMINI_API_KEY_2= "AIzaSyDzQSzM9vA6Le36V65I2meN5URclq4JSx0"
app.py CHANGED
@@ -1,5 +1,4 @@
1
- # Optimized RAG System with E5-Mistral Embeddings and Gemini Flash Generation
2
-
3
  import json
4
  import logging
5
  import re
@@ -18,30 +17,27 @@ from langchain_core.documents import Document
18
  from collections import defaultdict
19
  import hashlib
20
  from tqdm import tqdm
21
-
22
  from dotenv import load_dotenv
 
23
  load_dotenv()
24
 
25
  # --- Configuration ---
26
  FAISS_INDEX_PATH = "faiss_index"
27
  BM25_INDEX_PATH = "bm25_index.pkl"
28
-
29
  CACHE_VERSION = "v1"
30
  embedding_model = "e5-mistral-7b-instruct"
31
- generation_model = "gemini-1.5-flash"
32
  data_file_name = "AskNatureNet_data_enhanced.json"
 
 
 
33
 
34
  # Initialize clients
35
  OPENAI_API_CONFIG = {
36
  "api_key": os.getenv("OPENAI_API_KEY"),
37
  "base_url": "https://chat-ai.academiccloud.de/v1"
38
-
39
  }
40
  client = OpenAI(**OPENAI_API_CONFIG)
41
-
42
- # Configure Gemini
43
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
44
- gemini_model = genai.GenerativeModel(generation_model)
45
 
46
  logging.basicConfig(level=logging.INFO)
47
  logger = logging.getLogger(__name__)
@@ -175,10 +171,16 @@ class EnhancedRetriever:
175
  @lru_cache(maxsize=500)
176
  def _hyde_expansion(self, query: str) -> str:
177
  try:
178
- response = gemini_model.generate_content(
179
- f"Generate a technical draft about biomimicry for: {query}\nInclude domain-specific terms."
 
 
 
 
 
 
180
  )
181
- return response.text
182
  except Exception as e:
183
  logger.error(f"HyDE Error: {str(e)}")
184
  return query
@@ -211,19 +213,32 @@ class EnhancedRetriever:
211
  # --- Generation System ---
212
  SYSTEM_PROMPT = """**Biomimicry Expert Guidelines**
213
  1. Base answers strictly on context
214
- 2. **Bold** technical terms
215
- 3. Must Include reference links at the end of the response
 
216
 
217
  Context: {context}"""
218
 
219
  @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=20))
220
- def get_ai_response(query: str, context: str) -> str:
221
  try:
222
- response = gemini_model.generate_content(
223
- f"{SYSTEM_PROMPT.format(context=context)}\nQuestion: {query}\nProvide a detailed technical answer:"
224
- )
225
- logger.info(f"Raw Response: {response.text}")
226
- return _postprocess_response(response.text)
 
 
 
 
 
 
 
 
 
 
 
 
227
  except Exception as e:
228
  logger.error(f"Generation Error: {str(e)}")
229
  return "I'm unable to generate a response right now. Please try again later."
@@ -237,17 +252,17 @@ def _postprocess_response(response: str) -> str:
237
  documents = load_and_chunk_data(data_file_name)
238
  retriever = EnhancedRetriever(documents)
239
 
240
- def generate_response(question: str) -> str:
241
  try:
242
  context = retriever.retrieve(question)
243
- return get_ai_response(question, context) if context else "No relevant information found."
244
  except Exception as e:
245
  logger.error(f"Pipeline Error: {str(e)}")
246
  return "An error occurred processing your request."
247
 
248
  # --- Gradio Interface ---
249
- def chat_interface(question: str, history: List[Tuple[str, str]]):
250
- response = generate_response(question)
251
  return "", history + [(question, response)]
252
 
253
  with gr.Blocks(title="AskNature BioRAG Expert", theme=gr.themes.Soft()) as demo:
@@ -257,12 +272,15 @@ with gr.Blocks(title="AskNature BioRAG Expert", theme=gr.themes.Soft()) as demo:
257
  with gr.Row():
258
  question = gr.Textbox(placeholder="Ask about biomimicry (e.g. 'How does Werewool use coral proteins to make fibers?')",
259
  label="Inquiry", scale=4)
 
260
  clear_btn = gr.Button("Clear History", variant="secondary")
261
 
262
- gr.Markdown("""<div style="text-align: center; color: #4a7c59;">
263
- <small>Powered by AskNature's Database |
264
- Explore nature's blueprints at <a href="https://asknature.org">asknature.org</a></small></div>""")
265
- question.submit(chat_interface, [question, chatbot], [question, chatbot])
 
 
266
  clear_btn.click(lambda: [], None, chatbot)
267
 
268
  if __name__ == "__main__":
 
1
+ # Combined Llama 3 and Gemini Flash Chatbot
 
2
  import json
3
  import logging
4
  import re
 
17
  from collections import defaultdict
18
  import hashlib
19
  from tqdm import tqdm
 
20
  from dotenv import load_dotenv
21
+
22
  load_dotenv()
23
 
24
  # --- Configuration ---
25
  FAISS_INDEX_PATH = "faiss_index"
26
  BM25_INDEX_PATH = "bm25_index.pkl"
 
27
  CACHE_VERSION = "v1"
28
  embedding_model = "e5-mistral-7b-instruct"
 
29
  data_file_name = "AskNatureNet_data_enhanced.json"
30
+ CHUNK_SIZE = 800
31
+ OVERLAP = 200
32
+ EMBEDDING_BATCH_SIZE = 32
33
 
34
  # Initialize clients
35
  OPENAI_API_CONFIG = {
36
  "api_key": os.getenv("OPENAI_API_KEY"),
37
  "base_url": "https://chat-ai.academiccloud.de/v1"
 
38
  }
39
  client = OpenAI(**OPENAI_API_CONFIG)
 
 
40
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
 
41
 
42
  logging.basicConfig(level=logging.INFO)
43
  logger = logging.getLogger(__name__)
 
171
  @lru_cache(maxsize=500)
172
  def _hyde_expansion(self, query: str) -> str:
173
  try:
174
+ response = client.chat.completions.create(
175
+ model="meta-llama-3-70b-instruct",
176
+ messages=[{
177
+ "role": "user",
178
+ "content": f"Generate a technical draft about biomimicry for: {query}\nInclude domain-specific terms."
179
+ }],
180
+ temperature=0.5,
181
+ max_tokens=200
182
  )
183
+ return response.choices[0].message.content
184
  except Exception as e:
185
  logger.error(f"HyDE Error: {str(e)}")
186
  return query
 
213
  # --- Generation System ---
214
  SYSTEM_PROMPT = """**Biomimicry Expert Guidelines**
215
  1. Base answers strictly on context
216
+ 2. Cite sources as [Source]
217
+ 3. **Bold** technical terms
218
+ 4. Include reference links
219
 
220
  Context: {context}"""
221
 
222
  @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=20))
223
+ def get_ai_response(query: str, context: str, model: str) -> str:
224
  try:
225
+ if model == "gemini-2.0-flash":
226
+ gemini_model = genai.GenerativeModel(model)
227
+ response = gemini_model.generate_content(
228
+ f"{SYSTEM_PROMPT.format(context=context)}\nQuestion: {query}\nProvide a detailed technical answer:"
229
+ )
230
+ return _postprocess_response(response.text)
231
+ elif model == "meta-llama-3-70b-instruct":
232
+ response = client.chat.completions.create(
233
+ model=model,
234
+ messages=[
235
+ {"role": "system", "content": SYSTEM_PROMPT.format(context=context)},
236
+ {"role": "user", "content": f"Question: {query}\nProvide a detailed technical answer:"}
237
+ ],
238
+ temperature=0.4,
239
+ max_tokens=2000
240
+ )
241
+ return _postprocess_response(response.choices[0].message.content)
242
  except Exception as e:
243
  logger.error(f"Generation Error: {str(e)}")
244
  return "I'm unable to generate a response right now. Please try again later."
 
252
  documents = load_and_chunk_data(data_file_name)
253
  retriever = EnhancedRetriever(documents)
254
 
255
+ def generate_response(question: str, model: str) -> str:
256
  try:
257
  context = retriever.retrieve(question)
258
+ return get_ai_response(question, context, model) if context else "No relevant information found."
259
  except Exception as e:
260
  logger.error(f"Pipeline Error: {str(e)}")
261
  return "An error occurred processing your request."
262
 
263
  # --- Gradio Interface ---
264
+ def chat_interface(question: str, history: List[Tuple[str, str]], model: str):
265
+ response = generate_response(question, model)
266
  return "", history + [(question, response)]
267
 
268
  with gr.Blocks(title="AskNature BioRAG Expert", theme=gr.themes.Soft()) as demo:
 
272
  with gr.Row():
273
  question = gr.Textbox(placeholder="Ask about biomimicry (e.g. 'How does Werewool use coral proteins to make fibers?')",
274
  label="Inquiry", scale=4)
275
+ model_selector = gr.Dropdown(choices=["gemini-2.0-flash", "meta-llama-3-70b-instruct"], label="Generation Model", value="gemini-2.0-flash")
276
  clear_btn = gr.Button("Clear History", variant="secondary")
277
 
278
+ gr.Markdown("""
279
+ <div style="text-align: center; color: #4a7c59;">
280
+ <small>Powered by AskNature's Database |
281
+ Explore nature's blueprints at <a href="https://asknature.org">asknature.org</a></small>
282
+ </div>""")
283
+ question.submit(chat_interface, [question, chatbot, model_selector], [question, chatbot])
284
  clear_btn.click(lambda: [], None, chatbot)
285
 
286
  if __name__ == "__main__":
main.ipynb CHANGED
@@ -606,8 +606,8 @@
606
  "import pickle\n",
607
  "from typing import List, Tuple, Optional\n",
608
  "import gradio as gr\n",
609
- "from openai import OpenAI \n",
610
- "from google import genai \n",
611
  "from functools import lru_cache\n",
612
  "from tenacity import retry, stop_after_attempt, wait_exponential\n",
613
  "from langchain_community.retrievers import BM25Retriever\n",
@@ -616,24 +616,18 @@
616
  "from langchain_core.documents import Document\n",
617
  "from collections import defaultdict\n",
618
  "import hashlib\n",
619
- "from tqdm import tqdm \n",
620
  "\n",
621
  "from dotenv import load_dotenv\n",
622
  "load_dotenv()\n",
 
623
  "# --- Configuration ---\n",
624
  "FAISS_INDEX_PATH = \"faiss_index\"\n",
625
  "BM25_INDEX_PATH = \"bm25_index.pkl\"\n",
626
- "CACHE_VERSION = \"v1\" # Increment when data format changes\n",
627
- "embedding_model = \"e5-mistral-7b-instruct\" # OpenAI embedding model\n",
628
- "generation_model = \"gemini-2.0-flash\" # Gemini generation model\n",
629
  "data_file_name = \"AskNatureNet_data_enhanced.json\"\n",
630
- "API_CONFIG = {\n",
631
- " \"gemini_api_key\": os.getenv(\"GEMINI_API_KEY\") # Gemini API key for generation\n",
632
- "}\n",
633
- "\n",
634
- "CHUNK_SIZE = 800\n",
635
- "OVERLAP = 200\n",
636
- "EMBEDDING_BATCH_SIZE = 32 # Batch size for embedding API calls\n",
637
  "\n",
638
  "# Initialize clients\n",
639
  "OPENAI_API_CONFIG = {\n",
@@ -641,7 +635,11 @@
641
  " \"base_url\": \"https://chat-ai.academiccloud.de/v1\"\n",
642
  "}\n",
643
  "client = OpenAI(**OPENAI_API_CONFIG)\n",
644
- "gemini_client = genai.Client(api_key=API_CONFIG[\"gemini_api_key\"]) # Gemini client for generation\n",
 
 
 
 
645
  "logging.basicConfig(level=logging.INFO)\n",
646
  "logger = logging.getLogger(__name__)\n",
647
  "\n",
@@ -651,13 +649,12 @@
651
  " with open(file_path, \"rb\") as f:\n",
652
  " return hashlib.md5(f.read()).hexdigest()\n",
653
  "\n",
654
- "# --- Custom Embedding Handler with Progress Tracking ---\n",
655
  "class MistralEmbeddings(Embeddings):\n",
656
- " \"\"\"E5-Mistral-7B embedding adapter with error handling and progress tracking\"\"\"\n",
657
  " def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
658
  " embeddings = []\n",
659
  " try:\n",
660
- " # Process in batches with progress tracking\n",
661
  " for i in tqdm(range(0, len(texts), EMBEDDING_BATCH_SIZE), desc=\"Embedding Progress\"):\n",
662
  " batch = texts[i:i + EMBEDDING_BATCH_SIZE]\n",
663
  " response = client.embeddings.create(\n",
@@ -674,7 +671,7 @@
674
  " def embed_query(self, text: str) -> List[float]:\n",
675
  " return self.embed_documents([text])[0]\n",
676
  "\n",
677
- "# --- Data Processing with Cache Validation ---\n",
678
  "def load_and_chunk_data(file_path: str) -> List[Document]:\n",
679
  " \"\"\"Enhanced chunking with metadata preservation\"\"\"\n",
680
  " current_hash = get_data_hash(file_path)\n",
@@ -775,9 +772,8 @@
775
  " @lru_cache(maxsize=500)\n",
776
  " def _hyde_expansion(self, query: str) -> str:\n",
777
  " try:\n",
778
- " response = gemini_client.models.generate_content( # Use Gemini client for HyDE\n",
779
- " model=generation_model,\n",
780
- " contents=f\"Generate a technical draft about biomimicry for: {query}\\nInclude domain-specific terms.\"\n",
781
  " )\n",
782
  " return response.text\n",
783
  " except Exception as e:\n",
@@ -811,20 +807,19 @@
811
  "\n",
812
  "# --- Generation System ---\n",
813
  "SYSTEM_PROMPT = \"\"\"**Biomimicry Expert Guidelines**\n",
814
- "1. Base answers strictly on context\n",
815
  "2. **Bold** technical terms\n",
816
- "3. Include reference links at the end of the response\n",
817
  "\n",
818
  "Context: {context}\"\"\"\n",
819
  "\n",
820
  "@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=20))\n",
821
  "def get_ai_response(query: str, context: str) -> str:\n",
822
  " try:\n",
823
- " response = gemini_client.models.generate_content( # Use Gemini client for generation\n",
824
- " model=generation_model,\n",
825
- " contents=f\"{SYSTEM_PROMPT.format(context=context)}\\nQuestion: {query}\\nProvide a detailed technical answer:\"\n",
826
  " )\n",
827
- " logger.info(f\"Raw Response: {response.text}\") # Log raw response\n",
828
  " return _postprocess_response(response.text)\n",
829
  " except Exception as e:\n",
830
  " logger.error(f\"Generation Error: {str(e)}\")\n",
@@ -835,7 +830,7 @@
835
  " response = re.sub(r\"\\*\\*([\\w-]+)\\*\\*\", r\"**\\1**\", response)\n",
836
  " return response\n",
837
  "\n",
838
- "# --- Optimized Pipeline ---\n",
839
  "documents = load_and_chunk_data(data_file_name)\n",
840
  "retriever = EnhancedRetriever(documents)\n",
841
  "\n",
@@ -861,11 +856,9 @@
861
  " label=\"Inquiry\", scale=4)\n",
862
  " clear_btn = gr.Button(\"Clear History\", variant=\"secondary\")\n",
863
  " \n",
864
- " gr.Markdown(\"\"\"\n",
865
- " <div style=\"text-align: center; color: #4a7c59;\">\n",
866
- " <small>Powered by AskNature's Database | \n",
867
- " Explore nature's blueprints at <a href=\"https://asknature.org\">asknature.org</a></small>\n",
868
- " </div>\"\"\")\n",
869
  " question.submit(chat_interface, [question, chatbot], [question, chatbot])\n",
870
  " clear_btn.click(lambda: [], None, chatbot)\n",
871
  "\n",
@@ -884,16 +877,69 @@
884
  "cell_type": "code",
885
  "execution_count": null,
886
  "metadata": {},
887
- "outputs": [],
888
- "source": []
889
- },
890
- {
891
- "cell_type": "code",
892
- "execution_count": null,
893
- "metadata": {},
894
- "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895
  "source": [
896
- "# Optimized RAG System with E5-Mistral Embeddings and Gemini Flash Generation with Rate Control\n",
897
  "import json\n",
898
  "import logging\n",
899
  "import re\n",
@@ -901,8 +947,8 @@
901
  "import pickle\n",
902
  "from typing import List, Tuple, Optional\n",
903
  "import gradio as gr\n",
904
- "from openai import OpenAI # For embeddings\n",
905
- "from google import genai # For generation\n",
906
  "from functools import lru_cache\n",
907
  "from tenacity import retry, stop_after_attempt, wait_exponential\n",
908
  "from langchain_community.retrievers import BM25Retriever\n",
@@ -911,41 +957,20 @@
911
  "from langchain_core.documents import Document\n",
912
  "from collections import defaultdict\n",
913
  "import hashlib\n",
914
- "from tqdm import tqdm # For progress tracking\n",
915
- "import time # For rate limit testing\n",
916
- "from threading import Thread # For concurrent requests\n",
917
- "\n",
918
  "from dotenv import load_dotenv\n",
 
919
  "load_dotenv()\n",
920
  "\n",
921
  "# --- Configuration ---\n",
922
  "FAISS_INDEX_PATH = \"faiss_index\"\n",
923
  "BM25_INDEX_PATH = \"bm25_index.pkl\"\n",
924
- "CACHE_VERSION = \"v1\" # Increment when data format changes\n",
925
- "embedding_model = \"e5-mistral-7b-instruct\" # OpenAI embedding model\n",
926
- "generation_model = \"gemini-2.0-flash\" # Gemini generation model\n",
927
  "data_file_name = \"AskNatureNet_data_enhanced.json\"\n",
928
- "EMBEDDING_BATCH_SIZE = 32 # Batch size for embedding API calls\n",
929
- "\n",
930
- "# List of Gemini API keys\n",
931
- "GEMINI_API_KEYS = [\n",
932
- " os.getenv(\"GEMINI_API_KEY_1\"),\n",
933
- " os.getenv(\"GEMINI_API_KEY_2\")\n",
934
- "]\n",
935
- "\n",
936
- "current_key_index = 0\n",
937
- "\n",
938
- "def get_gemini_client():\n",
939
- " global current_key_index\n",
940
- " api_key = GEMINI_API_KEYS[current_key_index]\n",
941
- " print(f\"Using Gemini API Key: {api_key}\")\n",
942
- " return genai.Client(api_key=api_key)\n",
943
- "\n",
944
- "def switch_gemini_key():\n",
945
- " global current_key_index\n",
946
- " current_key_index = (current_key_index + 1) % len(GEMINI_API_KEYS)\n",
947
- " print(f\"Switched to Gemini API Key: {GEMINI_API_KEYS[current_key_index]}\")\n",
948
- " return get_gemini_client()\n",
949
  "\n",
950
  "# Initialize clients\n",
951
  "OPENAI_API_CONFIG = {\n",
@@ -953,7 +978,8 @@
953
  " \"base_url\": \"https://chat-ai.academiccloud.de/v1\"\n",
954
  "}\n",
955
  "client = OpenAI(**OPENAI_API_CONFIG)\n",
956
- "gemini_client = get_gemini_client() # Initialize with the first key\n",
 
957
  "logging.basicConfig(level=logging.INFO)\n",
958
  "logger = logging.getLogger(__name__)\n",
959
  "\n",
@@ -963,13 +989,12 @@
963
  " with open(file_path, \"rb\") as f:\n",
964
  " return hashlib.md5(f.read()).hexdigest()\n",
965
  "\n",
966
- "# --- Custom Embedding Handler with Progress Tracking ---\n",
967
  "class MistralEmbeddings(Embeddings):\n",
968
- " \"\"\"E5-Mistral-7B embedding adapter with error handling and progress tracking\"\"\"\n",
969
  " def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
970
  " embeddings = []\n",
971
  " try:\n",
972
- " # Process in batches with progress tracking\n",
973
  " for i in tqdm(range(0, len(texts), EMBEDDING_BATCH_SIZE), desc=\"Embedding Progress\"):\n",
974
  " batch = texts[i:i + EMBEDDING_BATCH_SIZE]\n",
975
  " response = client.embeddings.create(\n",
@@ -986,7 +1011,7 @@
986
  " def embed_query(self, text: str) -> List[float]:\n",
987
  " return self.embed_documents([text])[0]\n",
988
  "\n",
989
- "# --- Data Processing with Cache Validation ---\n",
990
  "def load_and_chunk_data(file_path: str) -> List[Document]:\n",
991
  " \"\"\"Enhanced chunking with metadata preservation\"\"\"\n",
992
  " current_hash = get_data_hash(file_path)\n",
@@ -1087,11 +1112,16 @@
1087
  " @lru_cache(maxsize=500)\n",
1088
  " def _hyde_expansion(self, query: str) -> str:\n",
1089
  " try:\n",
1090
- " response = gemini_client.models.generate_content( # Use Gemini client for HyDE\n",
1091
- " model=generation_model,\n",
1092
- " contents=f\"Generate a technical draft about biomimicry for: {query}\\nInclude domain-specific terms.\"\n",
 
 
 
 
 
1093
  " )\n",
1094
- " return response.text\n",
1095
  " except Exception as e:\n",
1096
  " logger.error(f\"HyDE Error: {str(e)}\")\n",
1097
  " return query\n",
@@ -1124,28 +1154,34 @@
1124
  "# --- Generation System ---\n",
1125
  "SYSTEM_PROMPT = \"\"\"**Biomimicry Expert Guidelines**\n",
1126
  "1. Base answers strictly on context\n",
1127
- "2. **Bold** technical terms\n",
1128
- "3. Include reference links at the end of the response\n",
 
1129
  "\n",
1130
  "Context: {context}\"\"\"\n",
1131
  "\n",
1132
  "@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=20))\n",
1133
- "def get_ai_response(query: str, context: str) -> str:\n",
1134
- " global gemini_client\n",
1135
  " try:\n",
1136
- " # Simulate a rate limit error for testing\n",
1137
- " if \"test\" in query.lower():\n",
1138
- " raise Exception(\"Simulated rate limit error\")\n",
1139
- " \n",
1140
- " response = gemini_client.models.generate_content( # Use Gemini client for generation\n",
1141
- " model=generation_model,\n",
1142
- " contents=f\"{SYSTEM_PROMPT.format(context=context)}\\nQuestion: {query}\\nProvide a detailed technical answer:\"\n",
1143
- " )\n",
1144
- " logger.info(f\"Raw Response: {response.text}\") # Log raw response\n",
1145
- " return _postprocess_response(response.text)\n",
 
 
 
 
 
 
 
1146
  " except Exception as e:\n",
1147
  " logger.error(f\"Generation Error: {str(e)}\")\n",
1148
- " gemini_client = switch_gemini_key() # Switch to the next API key\n",
1149
  " return \"I'm unable to generate a response right now. Please try again later.\"\n",
1150
  "\n",
1151
  "def _postprocess_response(response: str) -> str:\n",
@@ -1153,21 +1189,21 @@
1153
  " response = re.sub(r\"\\*\\*([\\w-]+)\\*\\*\", r\"**\\1**\", response)\n",
1154
  " return response\n",
1155
  "\n",
1156
- "# --- Optimized Pipeline ---\n",
1157
  "documents = load_and_chunk_data(data_file_name)\n",
1158
  "retriever = EnhancedRetriever(documents)\n",
1159
  "\n",
1160
- "def generate_response(question: str) -> str:\n",
1161
  " try:\n",
1162
  " context = retriever.retrieve(question)\n",
1163
- " return get_ai_response(question, context) if context else \"No relevant information found.\"\n",
1164
  " except Exception as e:\n",
1165
  " logger.error(f\"Pipeline Error: {str(e)}\")\n",
1166
  " return \"An error occurred processing your request.\"\n",
1167
  "\n",
1168
  "# --- Gradio Interface ---\n",
1169
- "def chat_interface(question: str, history: List[Tuple[str, str]]):\n",
1170
- " response = generate_response(question)\n",
1171
  " return \"\", history + [(question, response)]\n",
1172
  "\n",
1173
  "with gr.Blocks(title=\"AskNature BioRAG Expert\", theme=gr.themes.Soft()) as demo:\n",
@@ -1177,6 +1213,7 @@
1177
  " with gr.Row():\n",
1178
  " question = gr.Textbox(placeholder=\"Ask about biomimicry (e.g. 'How does Werewool use coral proteins to make fibers?')\",\n",
1179
  " label=\"Inquiry\", scale=4)\n",
 
1180
  " clear_btn = gr.Button(\"Clear History\", variant=\"secondary\")\n",
1181
  " \n",
1182
  " gr.Markdown(\"\"\"\n",
@@ -1184,40 +1221,48 @@
1184
  " <small>Powered by AskNature's Database | \n",
1185
  " Explore nature's blueprints at <a href=\"https://asknature.org\">asknature.org</a></small>\n",
1186
  " </div>\"\"\")\n",
1187
- " question.submit(chat_interface, [question, chatbot], [question, chatbot])\n",
1188
  " clear_btn.click(lambda: [], None, chatbot)\n",
1189
  "\n",
1190
- "# --- Rate Limit Testing ---\n",
1191
- "def test_rate_limit():\n",
1192
- " \"\"\"Simulate high-volume requests to test rate limit handling\"\"\"\n",
1193
- " test_questions = [\n",
1194
- " \"How do coral proteins help make eco-friendly fabrics without dyes?\",\n",
1195
- " \"What environmental problems do coral-inspired textiles solve?\",\n",
1196
- " \"What is industrial symbiosis and how does the Kalundborg example work?\",\n",
1197
- " \"How do Metavision sensors work like human eyes to save energy?\",\n",
1198
- " \"How does TISSIUM copy skin proteins for medical adhesives?\",\n",
1199
- " \"How does DNA-level design create better fibers inspired by nature?\",\n",
1200
- " \"Why is industrial symbiosis hard to implement despite benefits?\",\n",
1201
- " \"How can biological systems inspire sustainable manufacturing?\",\n",
1202
- " \"What other industries can use protein-based materials like Werewool?\",\n",
1203
- " \"How could event-based cameras improve security systems?\",\n",
1204
- " \"Design a factory network that works like coral reef partnerships - what features would it need?\"\n",
1205
- " ]\n",
1206
- "\n",
1207
- " for i, question in enumerate(test_questions):\n",
1208
- " print(f\"\\nSending query {i+1}: {question}\")\n",
1209
- " response = generate_response(question)\n",
1210
- " print(f\"Response: {response}\")\n",
1211
- " time.sleep(0.5) # Add a small delay between requests\n",
1212
- "\n",
1213
- "# Run the rate limit test in a separate thread\n",
1214
  "if __name__ == \"__main__\":\n",
1215
- " gradio_thread = Thread(target=demo.launch, kwargs={\"show_error\": True})\n",
1216
- " gradio_thread.start()\n",
1217
- " time.sleep(5)\n",
1218
- " test_rate_limit()"
1219
  ]
1220
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1221
  {
1222
  "cell_type": "code",
1223
  "execution_count": null,
 
606
  "import pickle\n",
607
  "from typing import List, Tuple, Optional\n",
608
  "import gradio as gr\n",
609
+ "from openai import OpenAI\n",
610
+ "import google.generativeai as genai\n",
611
  "from functools import lru_cache\n",
612
  "from tenacity import retry, stop_after_attempt, wait_exponential\n",
613
  "from langchain_community.retrievers import BM25Retriever\n",
 
616
  "from langchain_core.documents import Document\n",
617
  "from collections import defaultdict\n",
618
  "import hashlib\n",
619
+ "from tqdm import tqdm\n",
620
  "\n",
621
  "from dotenv import load_dotenv\n",
622
  "load_dotenv()\n",
623
+ "\n",
624
  "# --- Configuration ---\n",
625
  "FAISS_INDEX_PATH = \"faiss_index\"\n",
626
  "BM25_INDEX_PATH = \"bm25_index.pkl\"\n",
627
+ "CACHE_VERSION = \"v1\"\n",
628
+ "embedding_model = \"e5-mistral-7b-instruct\"\n",
629
+ "generation_model = \"gemini-2.0-flash\"\n",
630
  "data_file_name = \"AskNatureNet_data_enhanced.json\"\n",
 
 
 
 
 
 
 
631
  "\n",
632
  "# Initialize clients\n",
633
  "OPENAI_API_CONFIG = {\n",
 
635
  " \"base_url\": \"https://chat-ai.academiccloud.de/v1\"\n",
636
  "}\n",
637
  "client = OpenAI(**OPENAI_API_CONFIG)\n",
638
+ "\n",
639
+ "# Configure Gemini\n",
640
+ "genai.configure(api_key=os.getenv(\"GEMINI_API_KEY\"))\n",
641
+ "gemini_model = genai.GenerativeModel(generation_model)\n",
642
+ "\n",
643
  "logging.basicConfig(level=logging.INFO)\n",
644
  "logger = logging.getLogger(__name__)\n",
645
  "\n",
 
649
  " with open(file_path, \"rb\") as f:\n",
650
  " return hashlib.md5(f.read()).hexdigest()\n",
651
  "\n",
652
+ "# --- Custom Embedding Handler ---\n",
653
  "class MistralEmbeddings(Embeddings):\n",
654
+ " \"\"\"E5-Mistral-7B embedding adapter\"\"\"\n",
655
  " def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
656
  " embeddings = []\n",
657
  " try:\n",
 
658
  " for i in tqdm(range(0, len(texts), EMBEDDING_BATCH_SIZE), desc=\"Embedding Progress\"):\n",
659
  " batch = texts[i:i + EMBEDDING_BATCH_SIZE]\n",
660
  " response = client.embeddings.create(\n",
 
671
  " def embed_query(self, text: str) -> List[float]:\n",
672
  " return self.embed_documents([text])[0]\n",
673
  "\n",
674
+ "# --- Data Processing ---\n",
675
  "def load_and_chunk_data(file_path: str) -> List[Document]:\n",
676
  " \"\"\"Enhanced chunking with metadata preservation\"\"\"\n",
677
  " current_hash = get_data_hash(file_path)\n",
 
772
  " @lru_cache(maxsize=500)\n",
773
  " def _hyde_expansion(self, query: str) -> str:\n",
774
  " try:\n",
775
+ " response = gemini_model.generate_content(\n",
776
+ " f\"Generate a technical draft about biomimicry for: {query}\\nInclude domain-specific terms.\"\n",
 
777
  " )\n",
778
  " return response.text\n",
779
  " except Exception as e:\n",
 
807
  "\n",
808
  "# --- Generation System ---\n",
809
  "SYSTEM_PROMPT = \"\"\"**Biomimicry Expert Guidelines**\n",
810
+ "1. Firstly Base answers strictly on context and if there is not context answer by your own.\n",
811
  "2. **Bold** technical terms\n",
812
+ "3. Must Include reference links at the end of the response\n",
813
  "\n",
814
  "Context: {context}\"\"\"\n",
815
  "\n",
816
  "@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=20))\n",
817
  "def get_ai_response(query: str, context: str) -> str:\n",
818
  " try:\n",
819
+ " response = gemini_model.generate_content(\n",
820
+ " f\"{SYSTEM_PROMPT.format(context=context)}\\nQuestion: {query}\\nProvide a detailed technical answer:\"\n",
 
821
  " )\n",
822
+ " logger.info(f\"Raw Response: {response.text}\")\n",
823
  " return _postprocess_response(response.text)\n",
824
  " except Exception as e:\n",
825
  " logger.error(f\"Generation Error: {str(e)}\")\n",
 
830
  " response = re.sub(r\"\\*\\*([\\w-]+)\\*\\*\", r\"**\\1**\", response)\n",
831
  " return response\n",
832
  "\n",
833
+ "# --- Pipeline ---\n",
834
  "documents = load_and_chunk_data(data_file_name)\n",
835
  "retriever = EnhancedRetriever(documents)\n",
836
  "\n",
 
856
  " label=\"Inquiry\", scale=4)\n",
857
  " clear_btn = gr.Button(\"Clear History\", variant=\"secondary\")\n",
858
  " \n",
859
+ " gr.Markdown(\"\"\"<div style=\"text-align: center; color: #4a7c59;\">\n",
860
+ " <small>Powered by AskNature's Database | \n",
861
+ " Explore nature's blueprints at <a href=\"https://asknature.org\">asknature.org</a></small></div>\"\"\")\n",
 
 
862
  " question.submit(chat_interface, [question, chatbot], [question, chatbot])\n",
863
  " clear_btn.click(lambda: [], None, chatbot)\n",
864
  "\n",
 
877
  "cell_type": "code",
878
  "execution_count": null,
879
  "metadata": {},
880
+ "outputs": [
881
+ {
882
+ "name": "stderr",
883
+ "output_type": "stream",
884
+ "text": [
885
+ "INFO:__main__:Loading cached documents\n",
886
+ "INFO:__main__:Loading cached BM25 index\n",
887
+ "INFO:__main__:Loading cached FAISS index\n",
888
+ "INFO:faiss.loader:Loading faiss with AVX2 support.\n",
889
+ "INFO:faiss.loader:Successfully loaded faiss with AVX2 support.\n",
890
+ "c:\\Users\\Mohamed Elsafty\\.conda\\envs\\rag\\Lib\\site-packages\\gradio\\components\\chatbot.py:273: UserWarning: You have not specified a value for the `type` parameter. Defaulting to the 'tuples' format for chatbot messages, but this is deprecated and will be removed in a future version of Gradio. Please set type='messages' instead, which uses openai-style dictionaries with 'role' and 'content' keys.\n",
891
+ " warnings.warn(\n"
892
+ ]
893
+ },
894
+ {
895
+ "name": "stdout",
896
+ "output_type": "stream",
897
+ "text": [
898
+ "* Running on local URL: http://127.0.0.1:7860\n"
899
+ ]
900
+ },
901
+ {
902
+ "name": "stderr",
903
+ "output_type": "stream",
904
+ "text": [
905
+ "INFO:httpx:HTTP Request: GET https://api.gradio.app/pkg-version \"HTTP/1.1 200 OK\"\n",
906
+ "INFO:httpx:HTTP Request: GET http://127.0.0.1:7860/gradio_api/startup-events \"HTTP/1.1 200 OK\"\n",
907
+ "INFO:httpx:HTTP Request: HEAD http://127.0.0.1:7860/ \"HTTP/1.1 200 OK\"\n"
908
+ ]
909
+ },
910
+ {
911
+ "name": "stdout",
912
+ "output_type": "stream",
913
+ "text": [
914
+ "\n",
915
+ "To create a public link, set `share=True` in `launch()`.\n"
916
+ ]
917
+ },
918
+ {
919
+ "data": {
920
+ "text/html": [
921
+ "<div><iframe src=\"http://127.0.0.1:7860/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
922
+ ],
923
+ "text/plain": [
924
+ "<IPython.core.display.HTML object>"
925
+ ]
926
+ },
927
+ "metadata": {},
928
+ "output_type": "display_data"
929
+ },
930
+ {
931
+ "name": "stderr",
932
+ "output_type": "stream",
933
+ "text": [
934
+ "INFO:httpx:HTTP Request: POST https://chat-ai.academiccloud.de/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
935
+ "Embedding Progress: 0%| | 0/1 [00:00<?, ?it/s]INFO:httpx:HTTP Request: POST https://chat-ai.academiccloud.de/v1/embeddings \"HTTP/1.1 200 OK\"\n",
936
+ "Embedding Progress: 100%|██████████| 1/1 [00:00<00:00, 4.64it/s]\n",
937
+ "INFO:httpx:HTTP Request: POST https://chat-ai.academiccloud.de/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
938
+ ]
939
+ }
940
+ ],
941
  "source": [
942
+ "# Combined Llama 3 and Gemini Flash Chatbot\n",
943
  "import json\n",
944
  "import logging\n",
945
  "import re\n",
 
947
  "import pickle\n",
948
  "from typing import List, Tuple, Optional\n",
949
  "import gradio as gr\n",
950
+ "from openai import OpenAI\n",
951
+ "import google.generativeai as genai\n",
952
  "from functools import lru_cache\n",
953
  "from tenacity import retry, stop_after_attempt, wait_exponential\n",
954
  "from langchain_community.retrievers import BM25Retriever\n",
 
957
  "from langchain_core.documents import Document\n",
958
  "from collections import defaultdict\n",
959
  "import hashlib\n",
960
+ "from tqdm import tqdm\n",
 
 
 
961
  "from dotenv import load_dotenv\n",
962
+ "\n",
963
  "load_dotenv()\n",
964
  "\n",
965
  "# --- Configuration ---\n",
966
  "FAISS_INDEX_PATH = \"faiss_index\"\n",
967
  "BM25_INDEX_PATH = \"bm25_index.pkl\"\n",
968
+ "CACHE_VERSION = \"v1\"\n",
969
+ "embedding_model = \"e5-mistral-7b-instruct\"\n",
 
970
  "data_file_name = \"AskNatureNet_data_enhanced.json\"\n",
971
+ "CHUNK_SIZE = 800\n",
972
+ "OVERLAP = 200\n",
973
+ "EMBEDDING_BATCH_SIZE = 32\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
974
  "\n",
975
  "# Initialize clients\n",
976
  "OPENAI_API_CONFIG = {\n",
 
978
  " \"base_url\": \"https://chat-ai.academiccloud.de/v1\"\n",
979
  "}\n",
980
  "client = OpenAI(**OPENAI_API_CONFIG)\n",
981
+ "genai.configure(api_key=os.getenv(\"GEMINI_API_KEY\"))\n",
982
+ "\n",
983
  "logging.basicConfig(level=logging.INFO)\n",
984
  "logger = logging.getLogger(__name__)\n",
985
  "\n",
 
989
  " with open(file_path, \"rb\") as f:\n",
990
  " return hashlib.md5(f.read()).hexdigest()\n",
991
  "\n",
992
+ "# --- Custom Embedding Handler ---\n",
993
  "class MistralEmbeddings(Embeddings):\n",
994
+ " \"\"\"E5-Mistral-7B embedding adapter\"\"\"\n",
995
  " def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
996
  " embeddings = []\n",
997
  " try:\n",
 
998
  " for i in tqdm(range(0, len(texts), EMBEDDING_BATCH_SIZE), desc=\"Embedding Progress\"):\n",
999
  " batch = texts[i:i + EMBEDDING_BATCH_SIZE]\n",
1000
  " response = client.embeddings.create(\n",
 
1011
  " def embed_query(self, text: str) -> List[float]:\n",
1012
  " return self.embed_documents([text])[0]\n",
1013
  "\n",
1014
+ "# --- Data Processing ---\n",
1015
  "def load_and_chunk_data(file_path: str) -> List[Document]:\n",
1016
  " \"\"\"Enhanced chunking with metadata preservation\"\"\"\n",
1017
  " current_hash = get_data_hash(file_path)\n",
 
1112
  " @lru_cache(maxsize=500)\n",
1113
  " def _hyde_expansion(self, query: str) -> str:\n",
1114
  " try:\n",
1115
+ " response = client.chat.completions.create(\n",
1116
+ " model=\"meta-llama-3-70b-instruct\",\n",
1117
+ " messages=[{\n",
1118
+ " \"role\": \"user\",\n",
1119
+ " \"content\": f\"Generate a technical draft about biomimicry for: {query}\\nInclude domain-specific terms.\"\n",
1120
+ " }],\n",
1121
+ " temperature=0.5,\n",
1122
+ " max_tokens=200\n",
1123
  " )\n",
1124
+ " return response.choices[0].message.content\n",
1125
  " except Exception as e:\n",
1126
  " logger.error(f\"HyDE Error: {str(e)}\")\n",
1127
  " return query\n",
 
1154
  "# --- Generation System ---\n",
1155
  "SYSTEM_PROMPT = \"\"\"**Biomimicry Expert Guidelines**\n",
1156
  "1. Base answers strictly on context\n",
1157
+ "2. Cite sources as [Source]\n",
1158
+ "3. **Bold** technical terms\n",
1159
+ "4. Include reference links\n",
1160
  "\n",
1161
  "Context: {context}\"\"\"\n",
1162
  "\n",
1163
  "@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=20))\n",
1164
+ "def get_ai_response(query: str, context: str, model: str) -> str:\n",
 
1165
  " try:\n",
1166
+ " if model == \"gemini-2.0-flash\":\n",
1167
+ " gemini_model = genai.GenerativeModel(model)\n",
1168
+ " response = gemini_model.generate_content(\n",
1169
+ " f\"{SYSTEM_PROMPT.format(context=context)}\\nQuestion: {query}\\nProvide a detailed technical answer:\"\n",
1170
+ " )\n",
1171
+ " return _postprocess_response(response.text)\n",
1172
+ " elif model == \"meta-llama-3-70b-instruct\":\n",
1173
+ " response = client.chat.completions.create(\n",
1174
+ " model=model,\n",
1175
+ " messages=[\n",
1176
+ " {\"role\": \"system\", \"content\": SYSTEM_PROMPT.format(context=context)},\n",
1177
+ " {\"role\": \"user\", \"content\": f\"Question: {query}\\nProvide a detailed technical answer:\"}\n",
1178
+ " ],\n",
1179
+ " temperature=0.4,\n",
1180
+ " max_tokens=2000\n",
1181
+ " )\n",
1182
+ " return _postprocess_response(response.choices[0].message.content)\n",
1183
  " except Exception as e:\n",
1184
  " logger.error(f\"Generation Error: {str(e)}\")\n",
 
1185
  " return \"I'm unable to generate a response right now. Please try again later.\"\n",
1186
  "\n",
1187
  "def _postprocess_response(response: str) -> str:\n",
 
1189
  " response = re.sub(r\"\\*\\*([\\w-]+)\\*\\*\", r\"**\\1**\", response)\n",
1190
  " return response\n",
1191
  "\n",
1192
+ "# --- Pipeline ---\n",
1193
  "documents = load_and_chunk_data(data_file_name)\n",
1194
  "retriever = EnhancedRetriever(documents)\n",
1195
  "\n",
1196
+ "def generate_response(question: str, model: str) -> str:\n",
1197
  " try:\n",
1198
  " context = retriever.retrieve(question)\n",
1199
+ " return get_ai_response(question, context, model) if context else \"No relevant information found.\"\n",
1200
  " except Exception as e:\n",
1201
  " logger.error(f\"Pipeline Error: {str(e)}\")\n",
1202
  " return \"An error occurred processing your request.\"\n",
1203
  "\n",
1204
  "# --- Gradio Interface ---\n",
1205
+ "def chat_interface(question: str, history: List[Tuple[str, str]], model: str):\n",
1206
+ " response = generate_response(question, model)\n",
1207
  " return \"\", history + [(question, response)]\n",
1208
  "\n",
1209
  "with gr.Blocks(title=\"AskNature BioRAG Expert\", theme=gr.themes.Soft()) as demo:\n",
 
1213
  " with gr.Row():\n",
1214
  " question = gr.Textbox(placeholder=\"Ask about biomimicry (e.g. 'How does Werewool use coral proteins to make fibers?')\",\n",
1215
  " label=\"Inquiry\", scale=4)\n",
1216
+ " model_selector = gr.Dropdown(choices=[\"gemini-2.0-flash\", \"meta-llama-3-70b-instruct\"], label=\"Generation Model\", value=\"gemini-2.0-flash\")\n",
1217
  " clear_btn = gr.Button(\"Clear History\", variant=\"secondary\")\n",
1218
  " \n",
1219
  " gr.Markdown(\"\"\"\n",
 
1221
  " <small>Powered by AskNature's Database | \n",
1222
  " Explore nature's blueprints at <a href=\"https://asknature.org\">asknature.org</a></small>\n",
1223
  " </div>\"\"\")\n",
1224
+ " question.submit(chat_interface, [question, chatbot, model_selector], [question, chatbot])\n",
1225
  " clear_btn.click(lambda: [], None, chatbot)\n",
1226
  "\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1227
  "if __name__ == \"__main__\":\n",
1228
+ " demo.launch(show_error=True)"
 
 
 
1229
  ]
1230
  },
1231
+ {
1232
+ "cell_type": "code",
1233
+ "execution_count": null,
1234
+ "metadata": {},
1235
+ "outputs": [],
1236
+ "source": []
1237
+ },
1238
+ {
1239
+ "cell_type": "code",
1240
+ "execution_count": null,
1241
+ "metadata": {},
1242
+ "outputs": [],
1243
+ "source": []
1244
+ },
1245
+ {
1246
+ "cell_type": "code",
1247
+ "execution_count": null,
1248
+ "metadata": {},
1249
+ "outputs": [],
1250
+ "source": []
1251
+ },
1252
+ {
1253
+ "cell_type": "code",
1254
+ "execution_count": null,
1255
+ "metadata": {},
1256
+ "outputs": [],
1257
+ "source": []
1258
+ },
1259
+ {
1260
+ "cell_type": "code",
1261
+ "execution_count": null,
1262
+ "metadata": {},
1263
+ "outputs": [],
1264
+ "source": []
1265
+ },
1266
  {
1267
  "cell_type": "code",
1268
  "execution_count": null,