LifeShield AI provides:
- Risk analysis API (
/analyze) - Memory search (
/memory/search) - Tracker Agent (
/api/tracker/run) – entity enrichment & evidence bundle builder - Verifier Agent (
/api/verifier/run) – claim-level RAG fact verification (Cofacts + 165 + local) - Three input entrypoints (
/line/webhook,/browser/analyze,/web/analyze) - HF training and evaluation pipeline for 6-class risk classification
fake_newsscamphishingjobinvestmentsocial
- Recommended: Python 3.12
- Supported/tested: Python 3.11, 3.12
- Not recommended for this pinned set: Python 3.13+ (for example 3.14 may trigger source builds and fail on Windows)
Rebuild venv (PowerShell, Windows):
cd lifeshield-ai
if (Test-Path .venv) { Remove-Item -Recurse -Force .venv }
py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip setuptools wheel
pip install -r requirements.txtcd lifeshield-ai
py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000Health check:
curl.exe http://127.0.0.1:8000/healthThe project includes a Level-2 demo dashboard with the same analysis pipeline as API/LINE.
Features:
- Input: text, URL, image upload (OCR)
- Output: risk level/label, confidence raw/calibrated, evidence/actions, signals breakdown
- Traceability: event_id, fact-check reference links, memory hit/similarity
- Observability: recent audit log and memory store tables (redacted view only)
- Scam radar: local trends dataset (
data/scam_trends.json) with trusted-source links
Run:
python -m pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
streamlit run dashboard/dashboard_app.pyOptional extras (install only when needed):
# Chroma memory backend (optional)
pip install -r requirements.memory-chroma.txt
# Paddle OCR engine (optional)
pip install -r requirements.ocr-paddle.txtDashboard mode options:
DASHBOARD_MODE=direct(default): import and callanalyze_payloaddirectlyDASHBOARD_MODE=api: callPOST /analyzeby HTTP (configureDASHBOARD_API_URL)
UI modes (new):
長輩小助理:- Simplified action-first view (
安全/注意/可能是詐騙,請小心) - Shows only top reasons and next steps
- Includes a template refusal sentence button
- Simplified action-first view (
一般模式:- Standard analysis + audit + memory tabs
年輕雷達:- Shows TOP5 scam trends and top-3 similar套路 matches
- Includes matched keywords and trusted source links
專業鑑識:- Standard tabs + redacted full result JSON for demo forensics view
API demo resilience:
- Sidebar includes API timeout seconds (default 60)
- If API timeout/request fails, dashboard shows clear guidance and one-click fallback to
direct
Windows helper:
./scripts/run_dashboard.ps1 -Mode direct
./scripts/run_dashboard.ps1 -Mode api -ApiUrl http://127.0.0.1:8000/analyzeMVP demo note:
- Memory uses persistent local store (
data/memory/memory.jsonl) and supportschroma|tfidf|keywordbackends. FEATURE_MEMORY=falseby default, so memory matching is skipped unless explicitly enabled.- If optional deps (for example
chromadb/sentence-transformers/sklearn) are unavailable, memory falls back without crashing. - Fact-check uses local data (
data/fact_check/cofacts_sample.json) with score threshold gating; below threshold means no fact-check evidence.
.env uses:
APP_NAME=LifeShield AI
CHROMA_PATH=
CHROMA_COLLECTION=
CHROMA_PERSIST_DIR=
CHROMA_COLLECTION_CASES=lifeshield_cases
CHROMA_COLLECTION_USERS=lifeshield_users
CHROMA_COLLECTION_EVIDENCE=lifeshield_evidence
EMBEDDING_MODEL=
EMBEDDING_PROVIDER=sentence_transformers
RISK_MODEL_DIR=
LINE_CHANNEL_SECRET=
LINE_CHANNEL_ACCESS_TOKEN=
GOOGLE_SAFE_BROWSING_API_KEY=
FEATURE_URL_SCAN=true
FEATURE_URL_HEURISTIC=true
FEATURE_IMAGE_SIGNAL=true
FEATURE_FACT_CHECK=true
FACT_CHECK_THRESHOLD=0.40
FEATURE_NER=true
FEATURE_WIKI_LOOKUP=true
FEATURE_COMPANY_REGISTRY=true
FEATURE_DOMAIN_INTEL=true
FEATURE_MEMORY=false
FEATURE_MEMORY_AUTOSAVE=false
FEATURE_CALIBRATION=true
CALIBRATION_MODE=sigmoid
CALIBRATION_TEMPERATURE=1.5
FEATURE_AUDIT_LOG=true
AUDIT_LOG_PATH=data/audit/audit.jsonl
MEMORY_SIM_THRESHOLD=0.80
W_MEMORY=0.08
MEMORY_STORE_PATH=data/memory/memory.jsonl
MEMORY_BACKEND=chroma
MEMORY_TOP_K=5
MEMORY_TTL_DAYS=0
MEMORY_NEAR_DUP_THRESHOLD=0.93
MEMORY_DECAY_PER_DAY=0.0
TESSERACT_PATH=C:/Program Files/Tesseract-OCR/tesseract.exe
TESSERACT_CMD=
TESSDATA_PREFIX=
OCR_ENGINE=tesseract
OCR_LANG=chi_tra+eng
MAX_REPLY_TEXT_CHARS=900
# Tracker Agent
FEATURE_TRACKER=true
SERPAPI_KEY=
BING_KEY=
SPACY_MODEL=zh_core_web_sm
MOEA_MODE=stub
TRACKER_WEB_RESULTS=5
# Verifier Agent
COFACTS_APP_SECRET=
NPA165_CACHE_PATH=data/165_rumor.csv
RETRIEVER_MODE=keywordpython -m spacy download zh_core_web_sm # Chinese
python -m spacy download en_core_web_sm # English fallbackIf neither model is installed the tracker falls back to regex-based NER automatically.
Security:
- Keep
.env.examplesecret-free (no real token values). - Do not commit
.envto version control. - Dashboard does not expose webhook raw payload or token/secret values.
- Dashboard text display uses redacted previews (
[PHONE],[ACCOUNT],[LINE_ID],[URL]).
Request:
{
"text": "string",
"url": "https://optional.url",
"source": "text|image (optional, default=text)"
}Response fields:
risk_labelconfidencerisk_levelevidenceactionssignals
Entity enrichment and evidence gathering.
Request:
{
"text": "請匯款至帳號 123-456,聯絡 LINE: abc123",
"locale": "zh-TW"
}Response fields:
entities– NER results (type, text, confidence)wiki_matches– Wikipedia hits per entitywikidata_matches– Wikidata hits per entityweb_results– web search evidence with credibility scorescompany_records– MOEA GCIS company registry matchesoverall_score– weighted credibility score (0–100)reasons– human-readable summary listdecision_log– 6-step structured trace (NER → Wikipedia → Wikidata → WebSearch → CompanyRegistry → CredibilityScoring)
Quick test:
curl -s -X POST http://127.0.0.1:8000/api/tracker/run \
-H "Content-Type: application/json" \
-d '{"text":"台積電 股票投資保證獲利","locale":"zh-TW"}' | python -m json.toolClaim-level fact verification with evidence chain and decision log.
Request:
{
"text": "老師帶單保證獲利,請先轉帳保證金",
"locale": "zh-TW"
}Response fields:
claimsevidence_chain(supporting / contradicting / unknown per claim)verdict(safe|suspicious|scam|unknown)reasonsreasoning_stepsdecision_lograw_sources_summary
Quick test:
curl -s -X POST http://127.0.0.1:8000/api/verifier/run \
-H "Content-Type: application/json" \
-d '{"text":"請點連結驗證並匯款到指定帳號","locale":"zh-TW"}' | python -m json.toolReturns top-5 similar memory cases:
idsimilaritysummary
Add/update one memory item:
{
"text": "老師帶單保證獲利,請先匯款",
"type": "scam_case",
"user_id": "u123",
"session_id": "s456",
"metadata": {
"source": "verifier",
"domain": "example.com",
"risk_label": "scam",
"score": 92.5,
"entities": {"tax_id": "12345678"},
"tags": ["investment", "transfer"]
}
}Search similar memory by text + filters:
{
"text": "保證獲利 匯款",
"k": 5,
"filters": {
"type": ["scam_case", "evidence"],
"domain": "example.com",
"user_id": "u123",
"entities": {"tax_id": "12345678"}
}
}Behavior:
- Verifies
X-Line-SignaturewithLINE_CHANNEL_SECRET - Processes
messageevents for bothmessage.type=textandmessage.type=image - Runs analysis by internal function call (
analyze_payload) without extra HTTP hop - Replies via LINE Reply API (
/v2/bot/message/reply) - Does not store user IDs
- Image handling is in-memory only (no image file written to disk)
Image OCR flow:
- Download image bytes from
https://api-data.line.me/v2/bot/message/{messageId}/content - OCR via
app/services/ocr_pipeline.py - Default: improved Tesseract pipeline (chat-area crop + multi-pass OCR candidate selection)
- Engine switch: set
OCR_ENGINE=tesseractorOCR_ENGINE=paddle(unset defaults totesseract) - Text and image both go through the same
analyze_payloadpipeline - If OCR text is too short/empty or Chinese ratio is too low, reply:
我看不到足夠清晰的文字,請改傳原圖或先裁切對話區再上傳。
app/services/agent_router.py coordinates multiple signals:
- Always run HF classifier (
RiskClassifier) - URL heuristic (
app/agents/url_heuristic.py) whenFEATURE_URL_HEURISTIC=true - URL scan (
app/agents/url_scan.py) when URL exists andFEATURE_URL_SCAN=true - Image signal (
app/agents/image_signal.py) for OCR/image text whenFEATURE_IMAGE_SIGNAL=true - Fact-check (
app/agents/fact_check.py) whenFEATURE_FACT_CHECK=true - Entity extraction (
app/agents/ner.py) whenFEATURE_NER=true - Wikipedia lookup (
app/agents/wiki_lookup.py) whenFEATURE_WIKI_LOOKUP=true - Company registry stub (
app/agents/company_registry.py) whenFEATURE_COMPANY_REGISTRY=true - Domain intel (
app/agents/domain_intel.py) whenFEATURE_DOMAIN_INTEL=true - Optional memory (
FEATURE_MEMORY=true) with graceful degradation
Feature flags:
FEATURE_URL_SCAN=true
FEATURE_URL_HEURISTIC=true
FEATURE_IMAGE_SIGNAL=true
FEATURE_FACT_CHECK=true
FACT_CHECK_THRESHOLD=0.40
FEATURE_NER=true
FEATURE_WIKI_LOOKUP=true
FEATURE_COMPANY_REGISTRY=true
FEATURE_DOMAIN_INTEL=true
FEATURE_MEMORY=false
FEATURE_MEMORY_AUTOSAVE=false
FEATURE_CALIBRATION=true
CALIBRATION_MODE=sigmoid
CALIBRATION_TEMPERATURE=1.5
FEATURE_AUDIT_LOG=true
AUDIT_LOG_PATH=data/audit/audit.jsonl
MEMORY_SIM_THRESHOLD=0.80
W_MEMORY=0.08
MEMORY_STORE_PATH=data/memory/memory.jsonl
GOOGLE_SAFE_BROWSING_API_KEY=Fact-check behavior (Week2 Agent3):
- Input text is matched against local fact-check records (
data/fact_check/cofacts_sample.json) with lightweight TF-IDF retrieval. top_k=3; ifbest_score < FACT_CHECK_THRESHOLDthen no related claim is emitted (has_related_claim=false, empty evidence, emptyreference_links).- Recommended
FACT_CHECK_THRESHOLDrange:0.35-0.45(default0.40). - Only trusted source domains are allowed in
reference_links; unmatched/unsafe records are dropped from index. - When matched, output includes score,
best_match_title, clipped summary, and traceablereference_links(max 2).
Memory behavior (Agent5):
- Memory engine is in
app/agents/memory_engine/with persistent JSONL + optional Chroma index. - Backend selection:
MEMORY_BACKEND=chroma|tfidf|keyword. - Embedding providers:
EMBEDDING_PROVIDER=sentence_transformers|openai|none. - If you need Chroma backend, install:
pip install -r requirements.memory-chroma.txt - Chroma collections are split by context:
lifeshield_caseslifeshield_userslifeshield_evidence
- If Chroma/embedding deps are unavailable, service falls back to
tfidf, thenkeyword, without crashing. - Memory schema includes
id,case_id,version,type,text,metadata,user_id/session_id. - Upsert policy includes dedup + near-duplicate version bump.
- Search supports filters by
domain,user_id,session_id,type,entities,tags. - Verifier/Profiler write incremental memory entries when risk/evidence policy is met.
Confidence calibration behavior (Week3-1):
- Router computes
confidence_rawfrom multi-signal fusion, then calibrates toconfidence_calibrated. FEATURE_CALIBRATION=trueenables calibration (default on).CALIBRATION_MODE=sigmoiduses1/(1+exp(-k*(raw-b)))with defaultsk=5,b=0.5.CALIBRATION_MODE=temperatureusessigmoid(raw / T)withCALIBRATION_TEMPERATURE(default1.5).- Risk-level routing uses calibrated confidence; if calibration is disabled/failed, raw confidence is used.
Audit trail behavior (Week3-5):
- Each analysis generates
event_idand writes an audit event todata/audit/audit.jsonl. - Audit stores only redacted preview and hash (
redacted_text_preview,text_hash), never raw user text/webhook body. key_signals_summarygives compact traceability for external reporting (for exampleurl_suspect=1, sb_hit=0, fc_hit=0).FEATURE_AUDIT_LOG=truecontrols logging; disable it to skip audit writes safely.
Safe degradation behavior:
- If
FEATURE_MEMORY=false, memory module is fully skipped and app startup is unaffected. - If memory optional dependencies are missing, memory matching degrades to fallback algorithm without crashing.
- If Safe Browsing key is missing, URL scan is skipped and app still returns classifier result.
- If
FEATURE_FACT_CHECK=false, fact-check is fully skipped (no lookup, no evidence, no dependency impact). - If
FEATURE_AUDIT_LOG=false, audit writes are skipped and analysis still works. - URL heuristic / image signal / NER / wiki / company stub / domain intel failures are isolated per agent.
- Missing optional dependencies (for example external API timeout) do not crash router or webhook.
- LINE webhook always returns 200 and masks phone/account/LINE ID in logs.
LINE reply format (text/image):
- Risk level + category + confidence (
0-100; higher means more likely this scam type) - Maximum length
<= 900characters (MAX_REPLY_TEXT_CHARS, hard-capped at 900) - Evidence 2-4 points
- Recommended actions 3 points
Week2 demo script:
python scripts/demo_week2.pyMemory rebuild (dev):
python scripts/rebuild_memory_db.py --clear
python scripts/rebuild_memory_db.py --seed-demoAudit query examples:
python scripts/audit_query.py --limit 20
python scripts/audit_query.py --event-id <event_id>
python scripts/audit_query.py --date-from 2026-02-20T00:00:00+00:00 --date-to 2026-02-20T23:59:59+00:00LINE channel setup (product):
- Get long-lived Channel access token:
- LINE Developers Console -> Messaging API -> Channel access token -> issue long-lived token
- Set webhook URL via ngrok:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
ngrok http 8000- Set webhook URL to:
https://<your-ngrok-domain>/line/webhook- Enable
Use webhook - Disable
Auto-reply messagesin LINE Official Account Manager (avoid duplicate replies)
Local signature test (PowerShell):
cd lifeshield-ai
$body = '{"events":[{"type":"message","replyToken":"REPLY_TOKEN","message":{"type":"text","text":"老師帶單保證獲利,現在加入VIP群"}}]}'
$secret = "YOUR_LINE_CHANNEL_SECRET"
$sig = [Convert]::ToBase64String(
[System.Security.Cryptography.HMACSHA256]::new([Text.Encoding]::UTF8.GetBytes($secret)).
ComputeHash([Text.Encoding]::UTF8.GetBytes($body))
)
curl.exe -X POST "http://127.0.0.1:8000/line/webhook" `
-H "Content-Type: application/json" `
-H "X-Line-Signature: $sig" `
-d $bodyWindows 使用者需安裝 Tesseract 並設定路徑。
- Install Tesseract OCR:
- Installer: https://github.com/UB-Mannheim/tesseract/wiki
- Ensure Traditional Chinese language data (
chi_tra.traineddata) is installed undertessdata
- Make sure
tesseract.exeis available:
- Add install path to
PATH, or set.env:
TESSERACT_PATH=C:/Program Files/Tesseract-OCR/tesseract.exe- Reinstall/update Python deps:
pip install -r requirements.txt- OCR env:
TESSERACT_PATH=C:/Program Files/Tesseract-OCR/tesseract.exe
TESSERACT_CMD=C:\\Program Files\\Tesseract-OCR\\tesseract.exe
TESSDATA_PREFIX=C:\\Program Files\\Tesseract-OCR\\tessdata
OCR_ENGINE=tesseract
OCR_LANG=chi_tra+eng
MAX_REPLY_TEXT_CHARS=900- 安裝 PaddleOCR:
pip install -r requirements.ocr-paddle.txt- 啟用
.env:
OCR_ENGINE=paddle- 首次啟用 PaddleOCR 會下載模型,請確保網路可用並預留較長啟動時間。
- 若
OCR_ENGINE未設定或值不合法,系統會回到tesseract。
python scripts/ocr_debug.py path\\to\\chat_screenshot.png --engine tesseract
python scripts/ocr_debug.py path\\to\\chat_screenshot.png --engine paddleOutputs:
<name>_<engine>_text.txt<name>_<engine>_debug.json
Test flow:
- Text test: send a suspicious text message to your LINE bot.
- Screenshot test: send original chat screenshot (avoid screenshot-of-screenshot to keep OCR quality).
- Webhook verify: in LINE Developers Console click
Verifyafter setting ngrok URL.
curl.exe -X POST "http://127.0.0.1:8000/browser/analyze" `
-H "Content-Type: application/json" `
-d "{\"url\":\"https://example.com/promo\",\"page_text\":\"立即加入投資群,保證翻倍,私訊領取名額\"}"curl.exe -X POST "http://127.0.0.1:8000/web/analyze" `
-H "Content-Type: application/json" `
--data "@examples/job_high_salary.json"Investment scam:
curl.exe -X POST "http://127.0.0.1:8000/analyze" `
-H "Content-Type: application/json" `
--data "@examples/investment_group.json"Job scam:
curl.exe -X POST "http://127.0.0.1:8000/analyze" `
-H "Content-Type: application/json" `
--data "@examples/job_high_salary.json"Only public content is collected. Scripts are designed to avoid storing user IDs and to de-identify sensitive info.
python scripts/collect_public_cases.py --source cofacts --limit 50
python scripts/sanitize_cases.py
python scripts/auto_label_cases.py
python scripts/build_real_testset.py --per_class 20Notes:
collect_public_cases.pysupports--source cofacts|gov_anti_fraud_pages|ptt_public_postssanitize_cases.pymasks phone/account/ID/email and converts full URLs to domain formauto_label_cases.pyaddspredicted_label,confidence,needs_review(confidence < 0.6)build_real_testset.pyreports missing counts if class coverage is insufficient
Training data files:
data/train.jsonldata/dev.jsonldata/test.jsonl
JSONL format per line:
{"text":"...", "label":"fake_news|scam|phishing|job|investment|social"}Generate larger balanced dataset (auto backup old files to .bak):
python scripts/generate_dataset.py --per_class 120Supported args:
--per_class N--seed 42--train_ratio 0.8 --dev_ratio 0.1 --test_ratio 0.1
Install training dependencies:
pip install -r requirements-train.txtRun fine-tuning:
python training/train_classifier.pyOptional env overrides:
BASE_MODEL(default:bert-base-chinese)OUT_DIR(default:artifacts/risk_classifier)TRAIN_FILE,DEV_FILE,TEST_FILE
Training output:
- model + tokenizer in
artifacts/risk_classifier - console metrics:
Accuracy,Macro-F1,classification_report
Run evaluation:
python training/eval_report.pyGenerated files in artifacts/risk_classifier:
metrics.jsonconfusion_matrix.pnglatency_ms.txtbaseline_metrics.jsonbaseline_confusion_matrix.pngbaseline_latency_ms.txt
Baseline uses legacy rule-based classifier on the same data/test.jsonl.
app/core/risk_classifier_hf.pyloads model fromartifacts/risk_classifier/analyzealways runs HF prediction first to producerisk_labelandconfidenceapp/services/agent_router.pycombines classifier + Agent1 + Agent2 signals by feature flags- Final schema is unified as:
risk_label,confidence,risk_level,evidence,actions,signals - If model files are missing, classifier falls back to legacy rule-based logic