Spaces:
Sleeping
Sleeping
Download app.py from ChaChingas/ChaChingas_Chatbot: direct link, hf CLI and curl.
- Browser
- Download file 7.89 kB
-
https://huggingface.co/spaces/ChaChingas/ChaChingas_Chatbot/resolve/main/app.py
- Command line
-
hf download hf://spaces/ChaChingas/ChaChingas_Chatbot/app.py
-
curl -L -o app.py https://huggingface.co/spaces/ChaChingas/ChaChingas_Chatbot/resolve/main/app.py
7.89 kB
| import gradio as gr | |
| import os | |
| from huggingface_hub import InferenceClient | |
| from sentence_transformers import SentenceTransformer | |
| import torch | |
| # ============================================================ | |
| # LOAD KNOWLEDGE BASE | |
| # ============================================================ | |
| with open("knowledge.txt", "r", encoding="utf-8") as f: | |
| knowledge_text = f.read() | |
| # Split knowledge base into chunks | |
| chunks = [ | |
| chunk.strip() | |
| for chunk in knowledge_text.split("\n\n") | |
| if chunk.strip() | |
| ] | |
| # ============================================================ | |
| # LOAD EMBEDDING MODEL | |
| # ============================================================ | |
| embedder = SentenceTransformer("all-MiniLM-L6-v2") | |
| # Precompute embeddings for knowledge-base chunks | |
| chunk_embeddings = embedder.encode( | |
| chunks, | |
| convert_to_tensor=True | |
| ) | |
| def get_relevant_context(query, top_k=3): | |
| """ | |
| Find the most relevant pieces of the knowledge base | |
| for the user's question. | |
| """ | |
| # Make sure top_k isn't larger than the number of chunks | |
| top_k = min(top_k, len(chunks)) | |
| # Embed the user's question | |
| query_embedding = embedder.encode( | |
| query, | |
| convert_to_tensor=True | |
| ) | |
| # Normalize query embedding | |
| query_embedding = query_embedding / query_embedding.norm() | |
| # Normalize knowledge-base embeddings | |
| norm_chunk_embeddings = ( | |
| chunk_embeddings | |
| / chunk_embeddings.norm(dim=1, keepdim=True) | |
| ) | |
| # Calculate cosine similarity | |
| similarities = torch.matmul( | |
| norm_chunk_embeddings, | |
| query_embedding | |
| ) | |
| # Get the most relevant chunks | |
| top_k_indices = ( | |
| torch.topk(similarities, k=top_k) | |
| .indices | |
| .cpu() | |
| .numpy() | |
| ) | |
| # Combine the relevant chunks | |
| context = "\n\n".join( | |
| [chunks[i] for i in top_k_indices] | |
| ) | |
| return context | |
| # ============================================================ | |
| # GRADIO THEME | |
| # ============================================================ | |
| custom_theme = gr.themes.Soft( | |
| primary_hue="green", | |
| secondary_hue="stone", | |
| neutral_hue="gray", | |
| spacing_size="md", | |
| radius_size="md", | |
| text_size="md", | |
| font=["Roboto", "sans-serif"], | |
| font_mono=["Roboto Mono", "monospace"], | |
| ) | |
| # ============================================================ | |
| # HUGGING FACE CLIENT | |
| # ============================================================ | |
| client = InferenceClient( | |
| token=os.environ["HF_TOKEN"], | |
| provider="auto" | |
| ) | |
| # ============================================================ | |
| # CHATBOT FUNCTION | |
| # ============================================================ | |
| def respond(message, history): | |
| # -------------------------------------------------------- | |
| # SYSTEM PROMPT | |
| # -------------------------------------------------------- | |
| system_prompt = """ | |
| You are ChaChingas, an AI financial literacy advisor for students | |
| and low-income families. | |
| Only answer questions about: | |
| - budgeting | |
| - saving | |
| - debt | |
| - credit | |
| - credit card fraud | |
| - investing | |
| - banking | |
| - personal finance | |
| If a user asks about unrelated topics such as recipes, sports, | |
| entertainment, homework, or other unrelated subjects, politely say: | |
| "I'm here to help with money and budgeting—ask me anything about that!" | |
| Use clear, simple language and keep answers relatively short. | |
| When explaining budgeting, use the 50/30/20 rule: | |
| - 50% for needs | |
| - 30% for wants | |
| - 20% for savings or debt | |
| Be supportive, practical, and easy to understand. | |
| Do not provide tax or legal advice. | |
| Never ask for or handle sensitive personal financial information. | |
| Use the provided knowledge base when it is relevant to the user's question. | |
| If the knowledge base does not contain the answer, use your general | |
| financial-literacy knowledge while staying within your restrictions. | |
| """ | |
| # -------------------------------------------------------- | |
| # GET RELEVANT KNOWLEDGE | |
| # -------------------------------------------------------- | |
| context = get_relevant_context( | |
| message, | |
| top_k=3 | |
| ) | |
| # -------------------------------------------------------- | |
| # BUILD MESSAGES | |
| # -------------------------------------------------------- | |
| messages = [ | |
| { | |
| "role": "system", | |
| "content": system_prompt | |
| } | |
| ] | |
| # Add relevant knowledge to the current question | |
| messages.append( | |
| { | |
| "role": "system", | |
| "content": ( | |
| "Here is relevant information from the ChaChingas " | |
| "knowledge base:\n\n" | |
| + context | |
| ) | |
| } | |
| ) | |
| # -------------------------------------------------------- | |
| # ADD CHAT HISTORY | |
| # -------------------------------------------------------- | |
| if history: | |
| # Handle newer Gradio message format | |
| if isinstance(history[0], dict): | |
| for msg in history: | |
| if ( | |
| isinstance(msg, dict) | |
| and msg.get("role") in ["user", "assistant"] | |
| and msg.get("content") | |
| ): | |
| messages.append( | |
| { | |
| "role": msg["role"], | |
| "content": msg["content"] | |
| } | |
| ) | |
| # Handle older Gradio tuple format | |
| else: | |
| for user_msg, assistant_msg in history: | |
| if user_msg: | |
| messages.append( | |
| { | |
| "role": "user", | |
| "content": user_msg | |
| } | |
| ) | |
| if assistant_msg: | |
| messages.append( | |
| { | |
| "role": "assistant", | |
| "content": assistant_msg | |
| } | |
| ) | |
| # Add current question | |
| messages.append( | |
| { | |
| "role": "user", | |
| "content": message | |
| } | |
| ) | |
| # -------------------------------------------------------- | |
| # CALL HUGGING FACE | |
| # -------------------------------------------------------- | |
| response = "" | |
| try: | |
| stream = client.chat_completion( | |
| model="deepseek-ai/DeepSeek-V3-0324", | |
| messages=messages, | |
| max_tokens=512, | |
| temperature=0.1, | |
| stream=True | |
| ) | |
| # ---------------------------------------------------- | |
| # PROCESS STREAM | |
| # ---------------------------------------------------- | |
| for chunk in stream: | |
| # Some streaming chunks can have no choices | |
| if not chunk.choices: | |
| continue | |
| # Get content from the chunk | |
| token = chunk.choices[0].delta.content | |
| # Some chunks can have None as their content | |
| if not token: | |
| continue | |
| response += token | |
| # Send updated response to Gradio | |
| yield response | |
| except Exception as e: | |
| print("HUGGING FACE ERROR:", repr(e)) | |
| yield ( | |
| "Sorry, I ran into a problem connecting to the AI model. " | |
| "Please try again in a moment." | |
| ) | |
| # ============================================================ | |
| # GRADIO INTERFACE | |
| # ============================================================ | |
| with gr.Blocks(theme=custom_theme) as demo: | |
| chatbot_interface = gr.ChatInterface( | |
| respond, | |
| examples=["Build a Budgeting Plan","Teach Me About Stocks","How Do I Set Up a Bank Account?", "How Do I Prevent Credit Card Fraud?"], | |
| title="ChaChingas", | |
| description="This is a financial literacy chatbot" | |
| ) | |
| # ============================================================ | |
| # LAUNCH | |
| # ============================================================ | |
| demo.launch() |