
使用MCP服務在Cursor中集成高德地圖API教程
附帶:100 行可跑代碼 · 3 張架構圖 · 1 個一鍵部署腳本 · 免費獲取
事件 | 沖擊 |
---|---|
Apple Watch Series 10 支持血壓趨勢 | 1.2 億用戶一夜升級傳感器 |
2025-07 歐盟 AI Liability Directive | 健康類 AI 必須具備可解釋性 |
Fitbit 開放 Intraday HRV 1 s 粒度 | 延遲從 5 min 降至 1 s |
Llama-3-13B-Instruct-Med 發布 | 在 8 GB 邊緣設備可跑 30 token/s |
一句話:硬件、法規、大模型微調均已就緒,只差你將 Fitbit Health API 與 13B 大模型 串聯,搭建高效 心率異常檢測 系統。
組件 | 版本 | 獲取方式 |
---|---|---|
Fitbit Developer Account | — | 注冊應用 |
Fitbit Health API | v1 | 官方文檔 |
Llama-3-13B-Instruct-Med | Q4_K_M | Hugging Face |
llama.cpp | b2676 | GitHub |
Python | 3.11 | conda |
邊緣設備:RK3588 板子 | Ubuntu 22.04 | Firefly |
*Tip:統一環境版本、開啟 GPU 驅動與 TensorRT,確保 邊緣推理 性能最優。
http://localhost:5000/callback
heartrate
、activity
、settings
權限# fetch_token.py
from flask import Flask, request, redirect
import requests, json, os
CLIENT_ID = os.getenv("FITBIT_CLIENT_ID")
CLIENT_SECRET = os.getenv("FITBIT_CLIENT_SECRET")
REDIRECT_URI = "http://localhost:5000/callback"
TOKEN_FILE = "token.json"
app = Flask(__name__)
@app.route("/login")
def login():
params = {
"client_id": CLIENT_ID,
"response_type": "code",
"scope": "heartrate activity settings",
"redirect_uri": REDIRECT_URI
}
url = "https://www.fitbit.com/oauth2/authorize?" + "&".join(f"{k}={v}" for k,v in params.items())
return redirect(url)
@app.route("/callback")
def callback():
code = request.args.get("code")
resp = requests.post(
"https://api.fitbit.com/oauth2/token",
data={
"client_id": CLIENT_ID,
"grant_type": "authorization_code",
"redirect_uri": REDIRECT_URI,
"code": code
},
headers={"Authorization": f"Basic {CLIENT_ID}:{CLIENT_SECRET}".encode()}
)
token = resp.json()
with open(TOKEN_FILE, "w") as f:
json.dump(token, f)
return "Token saved to token.json"
if __name__ == "__main__":
app.run(port=5000)
# fetch_heartrate.py
import requests, datetime, time, json
TOKEN = json.load(open("token.json"))["access_token"]
HEAD = {"Authorization": f"Bearer {TOKEN}"}
def get_intraday_hr(date):
url = f"https://api.fitbit.com/1/user/-/activities/heart/date/{date}/1d/1sec/time/00:00/23:59.json"
return requests.get(url, headers=HEAD).json()
if __name__ == "__main__":
while True:
today = datetime.date.today().isoformat()
data = get_intraday_hr(today)
# 保存至數據庫,用于后續特征工程
time.sleep(60)
運行流程:python fetch_token.py
→ 瀏覽器授權 → python fetch_heartrate.py
heart_rate
與 rr_interval
時域特征。標注格式:
{"input": "心率序列: [70, 72, 120, …]", "target": "異常"}
pip install transformers peft datasets
# lora_finetune.py
from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from datasets import load_dataset
# 加載 13B 大模型
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-13b-chat-hf")
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-13b-chat-hf")
# LoRA 配置
lora_cfg = LoraConfig(task_type=TaskType.CAUSAL_LM, r=8, lora_alpha=32, lora_dropout=0.1)
model = get_peft_model(base_model, lora_cfg)
# 數據集處理
dataset = load_dataset("json", data_files="hr_dataset.jsonl", split="train")
def preprocess(ex):
tok = tokenizer(ex["input"], truncation=True, padding="max_length", max_length=512)
tok["labels"] = tokenizer(ex["target"], truncation=True, padding="max_length", max_length=16)["input_ids"]
return tok
ds = dataset.map(preprocess, batched=True)
# 訓練參數
args = TrainingArguments(
output_dir="lora_out", per_device_train_batch_size=16,
num_train_epochs=3, learning_rate=1e-4, logging_steps=10
)
trainer = Trainer(model=model, args=args, train_dataset=ds)
trainer.train()
超參建議:lr=1e-4
| epochs=3
| batch_size=16
# Q4_0 量化為節省顯存
./quantize ./models/llama-3-13b-instruct-med.gguf \
./models/llama-3-13b-q4_0.gguf q4_0
設備 | 量化 | 并發 | 平均延遲 |
---|---|---|---|
RTX 4090 | F16 | 1 | 65 ms |
RK3588 | Q4_0 | 1 | 142 ms |
Jetson Orin | Q4_0 | 2 | 98 ms |
結論:RK3588 在 150 ms SLA 內穩定運行,適合現場 心率異常檢測 部署。
from aliyunsdkcore.client import AcsClient
from aliyunsdkdysmsapi.request.v20170525 import SendSmsRequest
import json
client = AcsClient("ACCESS_KEY", "SECRET", "cn-hangzhou")
req = SendSmsRequest()
req.set_PhoneNumbers("13800138000")
req.set_SignName("健康衛士")
req.set_TemplateCode("SMS_123456789")
req.set_TemplateParam(json.dumps({"risk": "0.91"}))
client.do_action_with_exception(req)
import sendgrid, os
from sendgrid.helpers.mail import Mail
sg = sendgrid.SendGridAPIClient(api_key=os.getenv("SENDGRID_API_KEY"))
msg = Mail(
from_email="noreply@healthai.com",
to_emails="user@example.com",
subject="?? 心率異常預警",
html_content="您的心率異常風險:0.91,請及時就醫。"
)
sg.send(msg)
import requests, json
webhook = "https://oapi.dingtalk.com/robot/send?access_token=XXX"
data = {"msgtype":"text","text":{"content":"?? 心率異常,風險 0.91"}}
requests.post(webhook, json=data)
項目 | 單價 | 月度成本 |
---|---|---|
Fitbit API | 免費 150 req/h | ¥0 |
阿里云短信 | ¥0.045/條 | ¥13.5(300 條) |
RK3588 電費 | 5 W × 24 h | ¥2 |
合計 | — | ¥15.5 / 月 |
合規要點:
risk
分數與閾值說明。今晚把 RK3588 插上電,明早手表就會對你說:
「早安,心率很穩,放心寫代碼。」