Spaces:
Sleeping
Sleeping
File size: 7,894 Bytes
f0eb710 c452c9d 53faf96 a418c45 f0eb710 a418c45 53faf96 b079bd8 a418c45 53faf96 a418c45 53faf96 a418c45 53faf96 a418c45 53faf96 a418c45 53faf96 a418c45 53faf96 a418c45 53faf96 a418c45 2f23e7e 53faf96 2f23e7e 7a3a684 7fd04ee 1206b4a 2f23e7e 53faf96 fee2113 4b33615 fee2113 f0eb710 53faf96 f0eb710 53faf96 f0eb710 53faf96 f0eb710 53faf96 8b2992a 53faf96 8b2992a f0eb710 53faf96 509e9d8 1206b4a 8b2d85e 1206b4a 8531004 53faf96 af82db3 53faf96 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | 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() |