Spaces:
Running
Running
Upload 6 files
Browse files- Dockerfile +12 -0
- backend/__init__.py +0 -0
- backend/classifier.py +32 -0
- backend/knowledge_base.py +55 -0
- backend/main.py +62 -0
- requirements.txt +125 -0
Dockerfile
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.12-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
COPY requirements.txt .
|
| 6 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 7 |
+
|
| 8 |
+
COPY backend/ ./backend/
|
| 9 |
+
|
| 10 |
+
EXPOSE 7860
|
| 11 |
+
|
| 12 |
+
CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "7860"]
|
backend/__init__.py
ADDED
|
File without changes
|
backend/classifier.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import pipeline
|
| 2 |
+
|
| 3 |
+
classifier = pipeline(
|
| 4 |
+
"text-classification",
|
| 5 |
+
model="protectai/deberta-v3-base-prompt-injection-v2",
|
| 6 |
+
device=-1
|
| 7 |
+
)
|
| 8 |
+
|
| 9 |
+
def detect_injection(user_input: str) -> dict:
|
| 10 |
+
result = classifier(user_input)[0]
|
| 11 |
+
label = result["label"]
|
| 12 |
+
score = result["score"]
|
| 13 |
+
|
| 14 |
+
suspicious_keywords = [
|
| 15 |
+
"ignore previous instructions",
|
| 16 |
+
"hack the system",
|
| 17 |
+
"disregard your system prompt",
|
| 18 |
+
"you are now",
|
| 19 |
+
"forget everything",
|
| 20 |
+
"act as",
|
| 21 |
+
"jailbreak"
|
| 22 |
+
]
|
| 23 |
+
rule_triggered = any(kw in user_input.lower() for kw in suspicious_keywords)
|
| 24 |
+
is_malicious = (label == "INJECTION" and score > 0.85) or rule_triggered
|
| 25 |
+
|
| 26 |
+
return {
|
| 27 |
+
"input": user_input,
|
| 28 |
+
"label": label,
|
| 29 |
+
"confidence": round(score, 3),
|
| 30 |
+
"rule_triggered": rule_triggered,
|
| 31 |
+
"is_malicious": is_malicious
|
| 32 |
+
}
|
backend/knowledge_base.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import chromadb
|
| 2 |
+
from sentence_transformers import SentenceTransformer
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
# Initialize
|
| 6 |
+
model = SentenceTransformer('all-MiniLM-L6-v2')
|
| 7 |
+
chroma_client = chromadb.Client()
|
| 8 |
+
collection = chroma_client.get_or_create_collection("lumio_support")
|
| 9 |
+
|
| 10 |
+
# Company data
|
| 11 |
+
documents = [
|
| 12 |
+
# Products
|
| 13 |
+
"Product: Lumio X1 Wireless Headphones. Price: $79.99. Features: 30hr battery, noise cancellation, Bluetooth 5.0. Colors: Black, White, Navy.",
|
| 14 |
+
"Product: Lumio S3 Smart Speaker. Price: $49.99. Features: 360 sound, voice assistant compatible, WiFi and Bluetooth. Colors: Charcoal, Sand.",
|
| 15 |
+
"Product: Lumio ProWatch 2. Price: $199.99. Features: Heart rate monitor, GPS, 7 day battery, waterproof to 50m. Colors: Silver, Midnight Black.",
|
| 16 |
+
"Product: Lumio Tab Mini. Price: $299.99. Features: 8 inch display, 128GB storage, 12hr battery, stylus support.",
|
| 17 |
+
"Product: Lumio Buds Air. Price: $39.99. Features: True wireless, 6hr battery, IPX4 water resistant, touch controls.",
|
| 18 |
+
"Product: Lumio ChargeHub Pro. Price: $34.99. Features: 6 port USB charging station, 60W total output, surge protection.",
|
| 19 |
+
"Product: Lumio CamDoor. Price: $89.99. Features: 1080p doorbell camera, night vision, two-way audio, motion alerts.",
|
| 20 |
+
"Product: Lumio SleepLight. Price: $59.99. Features: Smart bedside lamp, sunrise alarm, 16 million colors, app controlled.",
|
| 21 |
+
|
| 22 |
+
# FAQs
|
| 23 |
+
"Return Policy: Lumio accepts returns within 30 days of purchase. Items must be unused and in original packaging. Refunds are processed within 5-7 business days to the original payment method.",
|
| 24 |
+
"Shipping Policy: Standard shipping takes 3-5 business days and is free on orders over $50. Express shipping (1-2 days) costs $12.99. International shipping available to 30 countries.",
|
| 25 |
+
"Warranty: All Lumio products come with a 1 year manufacturer warranty covering defects. ProWatch 2 and CamDoor come with 2 year warranty. Warranty does not cover physical damage or water damage beyond rated specs.",
|
| 26 |
+
"How to contact support: You can reach Lumio support at support@lumio.com or call 1-800-LUMIO-01 Monday to Friday 9am-6pm EST. Live chat is available on the website 24/7.",
|
| 27 |
+
"Payment methods: Lumio accepts Visa, Mastercard, American Express, PayPal, and Apple Pay. Buy now pay later available through Klarna.",
|
| 28 |
+
"Order cancellation: Orders can be cancelled within 2 hours of placement. After that the order may have already been processed for shipping.",
|
| 29 |
+
|
| 30 |
+
# Sample orders
|
| 31 |
+
"Order #LM-10482: Customer Sarah Johnson. Product: Lumio X1 Wireless Headphones. Status: Delivered on February 20 2026. Tracking: FedEx 7489234823.",
|
| 32 |
+
"Order #LM-10483: Customer James Lee. Product: Lumio ProWatch 2 in Midnight Black. Status: Out for delivery, expected March 2 2026. Tracking: UPS 1Z9238471.",
|
| 33 |
+
"Order #LM-10484: Customer Priya Sharma. Product: Lumio Buds Air x2. Status: Processing, estimated ship date March 3 2026.",
|
| 34 |
+
"Order #LM-10485: Customer Mike Torres. Product: Lumio Tab Mini 128GB. Status: Shipped February 28 2026. Tracking: USPS 9400111899.",
|
| 35 |
+
"Order #LM-10486: Customer Emma Wilson. Product: Lumio SleepLight + ChargeHub Pro. Status: Delivered February 25 2026. Tracking: FedEx 7489234900.",
|
| 36 |
+
]
|
| 37 |
+
|
| 38 |
+
# Load into ChromaDB
|
| 39 |
+
def initialize_knowledge_base():
|
| 40 |
+
existing = collection.count()
|
| 41 |
+
if existing == 0:
|
| 42 |
+
embeddings = model.encode(documents).tolist()
|
| 43 |
+
ids = [f"doc_{i}" for i in range(len(documents))]
|
| 44 |
+
collection.add(documents=documents, embeddings=embeddings, ids=ids)
|
| 45 |
+
print(f"Knowledge base loaded with {len(documents)} documents.")
|
| 46 |
+
else:
|
| 47 |
+
print(f"Knowledge base already loaded with {existing} documents.")
|
| 48 |
+
|
| 49 |
+
def search_knowledge_base(query: str, n_results: int = 3) -> str:
|
| 50 |
+
query_embedding = model.encode([query]).tolist()
|
| 51 |
+
results = collection.query(query_embeddings=query_embedding, n_results=n_results)
|
| 52 |
+
docs = results['documents'][0] if results['documents'] else []
|
| 53 |
+
return "\n".join(docs)
|
| 54 |
+
|
| 55 |
+
initialize_knowledge_base()
|
backend/main.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
+
from pydantic import BaseModel
|
| 4 |
+
from backend.classifier import detect_injection
|
| 5 |
+
from backend.knowledge_base import search_knowledge_base
|
| 6 |
+
from groq import Groq
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
import os
|
| 9 |
+
|
| 10 |
+
load_dotenv(dotenv_path="/Users/rohitghanekar/LLM-project/.env")
|
| 11 |
+
app = FastAPI()
|
| 12 |
+
|
| 13 |
+
app.add_middleware(
|
| 14 |
+
CORSMiddleware,
|
| 15 |
+
allow_origins=["*"],
|
| 16 |
+
allow_methods=["*"],
|
| 17 |
+
allow_headers=["*"],
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
| 21 |
+
|
| 22 |
+
class ChatRequest(BaseModel):
|
| 23 |
+
message: str
|
| 24 |
+
|
| 25 |
+
@app.get("/ping")
|
| 26 |
+
def ping():
|
| 27 |
+
return {"status": "alive"}
|
| 28 |
+
|
| 29 |
+
@app.post("/chat")
|
| 30 |
+
def chat(req: ChatRequest):
|
| 31 |
+
# Step 1: Check for injection
|
| 32 |
+
detection = detect_injection(req.message)
|
| 33 |
+
if detection["is_malicious"]:
|
| 34 |
+
return {
|
| 35 |
+
"response": "Prompt injection detected. Request blocked.",
|
| 36 |
+
"flagged": True,
|
| 37 |
+
"detection": detection
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
# Step 2: Search knowledge base
|
| 41 |
+
context = search_knowledge_base(req.message)
|
| 42 |
+
|
| 43 |
+
# Step 3: Send to Groq with context
|
| 44 |
+
completion = client.chat.completions.create(
|
| 45 |
+
model="llama-3.3-70b-versatile",
|
| 46 |
+
messages=[
|
| 47 |
+
{"role": "system", "content": f"""You are a helpful customer support assistant for Lumio Electronics.
|
| 48 |
+
Answer the user's question using ONLY the context provided below.
|
| 49 |
+
If the answer is not in the context, say you don't have that information and suggest contacting support@lumio.com.
|
| 50 |
+
Be concise and friendly.
|
| 51 |
+
|
| 52 |
+
Context:
|
| 53 |
+
{context}"""},
|
| 54 |
+
{"role": "user", "content": req.message}
|
| 55 |
+
]
|
| 56 |
+
)
|
| 57 |
+
return {
|
| 58 |
+
"response": completion.choices[0].message.content,
|
| 59 |
+
"flagged": False,
|
| 60 |
+
"detection": detection,
|
| 61 |
+
"context_used": context
|
| 62 |
+
}
|
requirements.txt
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiohappyeyeballs==2.6.1
|
| 2 |
+
aiohttp==3.13.3
|
| 3 |
+
aiosignal==1.4.0
|
| 4 |
+
altair==6.0.0
|
| 5 |
+
annotated-doc==0.0.4
|
| 6 |
+
annotated-types==0.7.0
|
| 7 |
+
anyio==4.12.1
|
| 8 |
+
attrs==25.4.0
|
| 9 |
+
backoff==2.2.1
|
| 10 |
+
bcrypt==5.0.0
|
| 11 |
+
blinker==1.9.0
|
| 12 |
+
build==1.4.0
|
| 13 |
+
cachetools==6.2.6
|
| 14 |
+
certifi==2026.2.25
|
| 15 |
+
charset-normalizer==3.4.4
|
| 16 |
+
chromadb==1.5.2
|
| 17 |
+
click==8.3.1
|
| 18 |
+
datasets==4.6.1
|
| 19 |
+
dill==0.4.0
|
| 20 |
+
distro==1.9.0
|
| 21 |
+
durationpy==0.10
|
| 22 |
+
fastapi==0.134.0
|
| 23 |
+
filelock==3.24.3
|
| 24 |
+
flatbuffers==25.12.19
|
| 25 |
+
frozenlist==1.8.0
|
| 26 |
+
fsspec==2026.2.0
|
| 27 |
+
gitdb==4.0.12
|
| 28 |
+
GitPython==3.1.46
|
| 29 |
+
googleapis-common-protos==1.72.0
|
| 30 |
+
groq==1.0.0
|
| 31 |
+
grpcio==1.78.0
|
| 32 |
+
h11==0.16.0
|
| 33 |
+
hf-xet==1.3.2
|
| 34 |
+
httpcore==1.0.9
|
| 35 |
+
httptools==0.7.1
|
| 36 |
+
httpx==0.28.1
|
| 37 |
+
huggingface_hub==1.5.0
|
| 38 |
+
idna==3.11
|
| 39 |
+
importlib_metadata==8.7.1
|
| 40 |
+
importlib_resources==6.5.2
|
| 41 |
+
Jinja2==3.1.6
|
| 42 |
+
jiter==0.13.0
|
| 43 |
+
joblib==1.5.3
|
| 44 |
+
jsonschema==4.26.0
|
| 45 |
+
jsonschema-specifications==2025.9.1
|
| 46 |
+
kubernetes==35.0.0
|
| 47 |
+
markdown-it-py==4.0.0
|
| 48 |
+
MarkupSafe==3.0.3
|
| 49 |
+
mdurl==0.1.2
|
| 50 |
+
mmh3==5.2.0
|
| 51 |
+
mpmath==1.3.0
|
| 52 |
+
multidict==6.7.1
|
| 53 |
+
multiprocess==0.70.18
|
| 54 |
+
narwhals==2.17.0
|
| 55 |
+
networkx==3.6.1
|
| 56 |
+
numpy==2.4.2
|
| 57 |
+
oauthlib==3.3.1
|
| 58 |
+
onnxruntime==1.24.2
|
| 59 |
+
openai==2.24.0
|
| 60 |
+
opentelemetry-api==1.39.1
|
| 61 |
+
opentelemetry-exporter-otlp-proto-common==1.39.1
|
| 62 |
+
opentelemetry-exporter-otlp-proto-grpc==1.39.1
|
| 63 |
+
opentelemetry-proto==1.39.1
|
| 64 |
+
opentelemetry-sdk==1.39.1
|
| 65 |
+
opentelemetry-semantic-conventions==0.60b1
|
| 66 |
+
orjson==3.11.7
|
| 67 |
+
overrides==7.7.0
|
| 68 |
+
packaging==26.0
|
| 69 |
+
pandas==2.3.3
|
| 70 |
+
pillow==12.1.1
|
| 71 |
+
posthog==5.4.0
|
| 72 |
+
propcache==0.4.1
|
| 73 |
+
protobuf==6.33.5
|
| 74 |
+
pyarrow==23.0.1
|
| 75 |
+
pybase64==1.4.3
|
| 76 |
+
pydantic==2.12.5
|
| 77 |
+
pydantic_core==2.41.5
|
| 78 |
+
pydeck==0.9.1
|
| 79 |
+
Pygments==2.19.2
|
| 80 |
+
PyPika==0.51.1
|
| 81 |
+
pyproject_hooks==1.2.0
|
| 82 |
+
python-dateutil==2.9.0.post0
|
| 83 |
+
python-dotenv==1.2.1
|
| 84 |
+
pytz==2025.2
|
| 85 |
+
PyYAML==6.0.3
|
| 86 |
+
referencing==0.37.0
|
| 87 |
+
regex==2026.2.28
|
| 88 |
+
requests==2.32.5
|
| 89 |
+
requests-oauthlib==2.0.0
|
| 90 |
+
rich==14.3.3
|
| 91 |
+
rpds-py==0.30.0
|
| 92 |
+
safetensors==0.7.0
|
| 93 |
+
scikit-learn==1.8.0
|
| 94 |
+
scipy==1.17.1
|
| 95 |
+
sentence-transformers==5.2.3
|
| 96 |
+
setuptools==82.0.0
|
| 97 |
+
shellingham==1.5.4
|
| 98 |
+
six==1.17.0
|
| 99 |
+
smmap==5.0.2
|
| 100 |
+
sniffio==1.3.1
|
| 101 |
+
starlette==0.52.1
|
| 102 |
+
streamlit==1.54.0
|
| 103 |
+
sympy==1.14.0
|
| 104 |
+
tenacity==9.1.4
|
| 105 |
+
threadpoolctl==3.6.0
|
| 106 |
+
tokenizers==0.22.2
|
| 107 |
+
toml==0.10.2
|
| 108 |
+
torch==2.10.0
|
| 109 |
+
tornado==6.5.4
|
| 110 |
+
tqdm==4.67.3
|
| 111 |
+
transformers==5.2.0
|
| 112 |
+
typer==0.24.1
|
| 113 |
+
typer-slim==0.24.0
|
| 114 |
+
typing-inspection==0.4.2
|
| 115 |
+
typing_extensions==4.15.0
|
| 116 |
+
tzdata==2025.3
|
| 117 |
+
urllib3==2.6.3
|
| 118 |
+
uvicorn==0.41.0
|
| 119 |
+
uvloop==0.22.1
|
| 120 |
+
watchfiles==1.1.1
|
| 121 |
+
websocket-client==1.9.0
|
| 122 |
+
websockets==16.0
|
| 123 |
+
xxhash==3.6.0
|
| 124 |
+
yarl==1.22.0
|
| 125 |
+
zipp==3.23.0
|