Spaces:
Sleeping
Sleeping
Update app.py
Browse files
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 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
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("
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
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(
|
669 |
"""
|
670 |
-
Sends a
|
671 |
"""
|
672 |
-
headers = {
|
673 |
-
|
674 |
-
"Authorization": f"Bearer {api_key}"
|
675 |
-
}
|
676 |
payload = {
|
677 |
-
"
|
678 |
-
"
|
679 |
-
|
680 |
-
|
681 |
-
"topK": 40,
|
682 |
-
"maxOutputTokens": 850
|
683 |
}
|
684 |
try:
|
685 |
-
response = requests.post(
|
686 |
response.raise_for_status()
|
687 |
data = response.json()
|
688 |
-
|
|
|
|
|
|
|
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
|
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 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
#
|
704 |
-
response_text = f"**{
|
705 |
-
|
706 |
-
{d['body']}"
|
707 |
else:
|
708 |
-
# 2
|
709 |
-
|
710 |
-
|
711 |
-
You
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
for
|
726 |
-
|
727 |
-
|
728 |
-
# add the current user query
|
729 |
-
msgs.append({"author": "user", "content": clean})
|
730 |
|
731 |
-
|
732 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
733 |
|
734 |
-
# 3
|
735 |
quote = select_relevant_quote(response_text)
|
736 |
-
|
737 |
-
response_text = f"{clean_resp}
|
738 |
-
|
739 |
-
“{quote}”
|
740 |
-
|
741 |
-
{TAGLINE}"
|
742 |
|
743 |
-
# 4
|
744 |
-
chat_history.append((message,
|
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 |
-
|
766 |
-
|
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()
|
|
|
|