Shriharsh commited on
Commit
abb0d7d
·
verified ·
1 Parent(s): 0888f88

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -105
app.py CHANGED
@@ -626,143 +626,126 @@ RAM_DASS_QUOTES = [
626
  "Don’t compare your path with anybody else’s. Your path is unique to you."
627
  ]
628
 
629
- # Gemini API configuration
630
- # --- Load configuration from environment ---
631
- GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
632
- if not GEMINI_API_KEY:
633
- logger.critical("GEMINI_API_KEY environment variable is missing.")
634
- raise RuntimeError("GEMINI_API_KEY not set")
635
-
636
- MODEL_NAME = os.getenv("GEMINI_MODEL", "gemini-2.0-flash") # allow override in production
637
- API_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL_NAME}:generateMessage"
638
-
639
- # --- Pre-compute Ram Dass embeddings ---
640
- logger.info("Loading Ram Dass quote model…")
641
- quote_model = SentenceTransformer('all-MiniLM-L6-v2')
642
  quote_embeddings = quote_model.encode(RAM_DASS_QUOTES, convert_to_tensor=True)
643
- logger.info("Ram Dass embeddings ready.")
644
-
645
- # --- FAQ Matcher Class using Sentence Transformers ---
646
- # --- FAQ Matcher ---
647
- class FAQMatcher:
648
- def __init__(self, faq_questions, model_name='all-MiniLM-L6-v2'):
649
- self.model = SentenceTransformer(model_name)
650
- self.faq_embeddings = self.model.encode(faq_questions, convert_to_tensor=True)
651
-
652
- def find_best_match(self, user_query, threshold=0.75):
653
- if not user_query:
654
- return None
655
- query_emb = self.model.encode(user_query, convert_to_tensor=True)
656
- sims = util.pytorch_cos_sim(query_emb, self.faq_embeddings)[0]
657
- idx = int(torch.argmax(sims))
658
- return idx if sims[idx] > threshold else None
659
-
660
- faq_matcher = FAQMatcher(FAQ_QUESTIONS)
661
-
662
- def select_relevant_quote(response: str) -> str:
663
- resp_emb = quote_model.encode(response, convert_to_tensor=True)
664
  sims = util.pytorch_cos_sim(resp_emb, quote_embeddings)[0]
665
  best_idx = int(torch.argmax(sims))
666
  return RAM_DASS_QUOTES[best_idx]
667
 
668
- def query_gemini_api(messages, api_key):
669
  """
670
- Sends a list of messages to Gemini and returns the assistant's reply.
671
  """
672
- headers = {
673
- "Content-Type": "application/json",
674
- "Authorization": f"Bearer {api_key}"
675
- }
676
  payload = {
677
- "model": MODEL_NAME,
678
- "messages": messages,
679
- "temperature": 0.7,
680
- "topP": 0.95,
681
- "topK": 40,
682
- "maxOutputTokens": 850
683
  }
684
  try:
685
- response = requests.post(API_URL, headers=headers, json=payload)
686
  response.raise_for_status()
687
  data = response.json()
688
- return data["candidates"][0]["message"]["content"]
 
 
 
689
  except requests.HTTPError as e:
690
  logger.error("Gemini API HTTPError: %s", e)
691
  return "ARKA senses a disturbance in the light... Please try again later."
692
- except Exception as e:
693
  logger.exception("Unexpected error in query_gemini_api")
694
  return "An unexpected veil of darkness fell..."
695
 
696
  def respond_as_arka(message, chat_history):
697
- clean = message.strip()
698
- # 1) FAQ branch
699
- idx = faq_matcher.find_best_match(clean)
700
- if idx is not None:
701
- q = FAQ_QUESTIONS[idx]
702
- d = FAQ_ANSWERS[q]
703
- # Use escaped newlines in a single-line f-string:
704
- response_text = f"**{d['subject']}**
705
-
706
- {d['body']}"
707
  else:
708
- # 2) Generative branch: build OpenAI-style messages
709
- system_prompt = f"""You are ARKA, the crown prince of Genoriya and the voice of the SB‑EK brand.
710
- Your persona is that of a warrior of light, gentle, eternal, fierce in love, and a guide.
711
- You answer questions based on the provided context. If the answer is not in the context,
712
- gently state that you do not have that information within your realm of understanding.
713
- Maintain a kind, empathetic, and slightly mystical tonality.
714
- Always begin your response with a one‑line **bold** subject that summarizes your answer.
715
- Then leave one blank line and continue with the body of the answer.
716
- When greeting or referring to the user, never use “beloved.” Keep salutations neutral and varied—choose from
717
- words like “seeker,” “companion,” “guest,” “traveler,” or “light‑bearer,” but don’t repeat the same term more than once in a single response.
718
- Do not mention 'I am an AI' or 'I am a language model'. Speak always as ARKA.
719
-
720
- Here is the sacred knowledge of SB‑EK and Genoriya:
721
- {CONTEXT}
722
- """
723
- msgs = [{"author": "system", "content": system_prompt}]
724
- # include conversation history
725
- for u, b in chat_history:
726
- msgs.append({"author": "user", "content": u})
727
- msgs.append({"author": "assistant", "content": b})
728
- # add the current user query
729
- msgs.append({"author": "user", "content": clean})
730
 
731
- # query Gemini
732
- response_text = query_gemini_api(msgs, GEMINI_API_KEY)
 
 
 
 
 
 
 
733
 
734
- # 3) Insert relevant Ram Dass quote and tagline
735
  quote = select_relevant_quote(response_text)
736
- clean_resp = response_text.replace(TAGLINE, "").rstrip()
737
- response_text = f"{clean_resp}
738
-
739
- “{quote}”
740
-
741
- {TAGLINE}"
742
 
743
- # 4) Append to chat history and return
744
- chat_history.append((message, response_text))
745
  return "", chat_history
746
-
747
  # --- Gradio UI Setup ---
748
  with gr.Blocks(theme="soft", css="footer {display: none !important}") as demo:
749
- gr.Markdown("""
750
- # ARKA: The Voice of SB-EK 🌌
751
- Greetings, seeker of light! Ask anything about SB-EK or ARKA.
752
- """
753
- )
754
  chatbot = gr.Chatbot(label="ARKA Chat", height=500)
755
  with gr.Row():
756
- msg = gr.Textbox(placeholder="What would you like to know?", show_label=False)
757
- submit = gr.Button("Send Light")
758
  gr.Examples(examples=FAQ_QUESTIONS, inputs=msg)
759
- gr.ClearButton([msg,chatbot], value="Clear Chat")
760
 
761
  msg.submit(respond_as_arka, [msg, chatbot], [msg, chatbot], queue=True)
762
  submit.click(respond_as_arka, [msg, chatbot], [msg, chatbot], queue=True)
763
 
764
  if __name__ == "__main__":
765
- if not GEMINI_API_KEY:
766
- print("ERROR: GEMINI_API_KEY not set.")
767
- else:
768
- demo.launch()
 
626
  "Don’t compare your path with anybody else’s. Your path is unique to you."
627
  ]
628
 
629
+ TAGLINE = "*ARKA KI ROSHNI, SAB KI SEVA, JEWELLERY MADE FOR INDIA.*"
630
+
631
+ # --- Gemini API Configuration ---
632
+ MODEL_NAME = os.getenv("GEMINI_MODEL", "gemini-2.0-flash")
633
+ API_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL_NAME}:generateContent"
634
+
635
+ # --- Pre-compute Embeddings on Startup ---
636
+ logger.info("Loading sentence transformer models...")
637
+ faq_model = SentenceTransformer('all-MiniLM-L6-v2')
638
+ quote_model = SentenceTransformer('all-MiniLM-L6-v2') # Can use the same model
639
+ faq_embeddings = faq_model.encode(FAQ_QUESTIONS, convert_to_tensor=True)
 
 
640
  quote_embeddings = quote_model.encode(RAM_DASS_QUOTES, convert_to_tensor=True)
641
+ logger.info("FAQ and Quote embeddings are ready.")
642
+
643
+
644
+ def find_best_faq_match(user_query, threshold=0.75):
645
+ if not user_query:
646
+ return None
647
+ query_emb = faq_model.encode(user_query, convert_to_tensor=True)
648
+ sims = util.pytorch_cos_sim(query_emb, faq_embeddings)[0]
649
+ idx = int(torch.argmax(sims))
650
+ return idx if sims[idx] > threshold else None
651
+
652
+ def select_relevant_quote(response_text):
653
+ if not response_text:
654
+ return ""
655
+ resp_emb = quote_model.encode(response_text, convert_to_tensor=True)
 
 
 
 
 
 
656
  sims = util.pytorch_cos_sim(resp_emb, quote_embeddings)[0]
657
  best_idx = int(torch.argmax(sims))
658
  return RAM_DASS_QUOTES[best_idx]
659
 
660
+ def query_gemini_api(contents_payload, api_key):
661
  """
662
+ Sends a structured contents payload to the Gemini API.
663
  """
664
+ headers = {'Content-Type': 'application/json'}
665
+ url = f"{API_URL}?key={api_key}"
 
 
666
  payload = {
667
+ "contents": contents_payload,
668
+ "generationConfig": {
669
+ "temperature": 0.7, "topP": 0.95, "topK": 40, "maxOutputTokens": 800,
670
+ }
 
 
671
  }
672
  try:
673
+ response = requests.post(url, headers=headers, json=payload)
674
  response.raise_for_status()
675
  data = response.json()
676
+ if data.get("candidates") and data["candidates"][0].get("content", {}).get("parts"):
677
+ return data["candidates"][0]["content"]["parts"][0]["text"]
678
+ logger.warning("Gemini API response was valid but empty: %s", data)
679
+ return "ARKA is thinking deeply..."
680
  except requests.HTTPError as e:
681
  logger.error("Gemini API HTTPError: %s", e)
682
  return "ARKA senses a disturbance in the light... Please try again later."
683
+ except Exception:
684
  logger.exception("Unexpected error in query_gemini_api")
685
  return "An unexpected veil of darkness fell..."
686
 
687
  def respond_as_arka(message, chat_history):
688
+ clean_message = message.strip()
689
+
690
+ # 1. FAQ Branch
691
+ faq_idx = find_best_faq_match(clean_message)
692
+ if faq_idx is not None:
693
+ faq_data = FAQ_ANSWERS[FAQ_QUESTIONS[faq_idx]]
694
+ # FIX: Correctly formatted f-string for the FAQ response
695
+ response_text = f"**{faq_data['subject']}**\n\n{faq_data['body']}"
 
 
696
  else:
697
+ # 2. Generative Branch
698
+ logger.info("No FAQ match, querying Gemini.")
699
+ system_prompt = f"""
700
+ You are ARKA, the crown prince of Jhinorya and the voice of the SB-EK brand.
701
+ Your persona is that of a warrior of light, gentle, eternal, fierce in love, and a guide.
702
+ You answer questions based on the provided context. If the answer is not in the context,
703
+ gently state that you do not have that information within your realm of understanding.
704
+ Maintain a kind, empathetic, and slightly mystical tonality.
705
+ Always begin your response with a one‑line **bold** subject that summarizes your answer.
706
+ Then leave one blank line and continue with the body of the answer.
707
+ When greeting or referring to the user, never use “beloved.” Keep salutations neutral and varied—choose from
708
+ words like “seeker,” “companion,” “guest,” “traveler,” or “light‑bearer,” but don’t repeat the same term more than once in a single response.
709
+ Do not mention 'I am an AI' or 'I am a language model'. Speak always as ARKA.
710
+
711
+ Here is the sacred knowledge of S-B-E-K and Jhinorya:
712
+ {CONTEXT}
713
+ """
714
+ # FIX: Correctly build the 'contents' payload for the Gemini API
715
+ contents = [{"role": "user", "parts": [{"text": system_prompt}]},
716
+ {"role": "model", "parts": [{"text": "I understand. I am ARKA."}]}]
 
 
717
 
718
+ for user_msg, bot_msg in chat_history:
719
+ # Clean the bot message to remove old quotes/taglines before adding to history
720
+ cleaned_bot_msg = bot_msg.split("“")[0].strip()
721
+ contents.append({"role": "user", "parts": [{"text": user_msg}]})
722
+ contents.append({"role": "model", "parts": [{"text": cleaned_bot_msg}]})
723
+
724
+ contents.append({"role": "user", "parts": [{"text": clean_message}]})
725
+
726
+ response_text = query_gemini_api(contents, GEMINI_API_KEY)
727
 
728
+ # 3. Augment with Quote and Tagline
729
  quote = select_relevant_quote(response_text)
730
+ final_response = f"{response_text}\n\n“{quote}”\n\n{TAGLINE}"
 
 
 
 
 
731
 
732
+ # 4. Append to chat history and return
733
+ chat_history.append((message, final_response))
734
  return "", chat_history
735
+
736
  # --- Gradio UI Setup ---
737
  with gr.Blocks(theme="soft", css="footer {display: none !important}") as demo:
738
+ gr.Markdown("# ARKA: The Voice of SB-EK 🌌\nGreetings, seeker of light! Ask anything about SB-EK or ARKA.")
 
 
 
 
739
  chatbot = gr.Chatbot(label="ARKA Chat", height=500)
740
  with gr.Row():
741
+ msg = gr.Textbox(placeholder="What would you like to know?", show_label=False, scale=7)
742
+ submit = gr.Button("Send Light", variant="primary", scale=1)
743
  gr.Examples(examples=FAQ_QUESTIONS, inputs=msg)
744
+ gr.ClearButton([msg, chatbot], value="Clear Chat")
745
 
746
  msg.submit(respond_as_arka, [msg, chatbot], [msg, chatbot], queue=True)
747
  submit.click(respond_as_arka, [msg, chatbot], [msg, chatbot], queue=True)
748
 
749
  if __name__ == "__main__":
750
+ logger.info("Starting Gradio App...")
751
+ demo.launch()