更新 shenyan-app: HealthKit+WeatherKit+冰箱贴+pare+三区布局
- HealthKitBridge.m: 自定义原生模块,心率/步数/睡眠采集 - WeatherKitBridge.swift/m: 天气模块,当前+每日+每小时预报 - pare.py: 身体数据陡度监控,阈值告警→inbox+冰箱贴 - cyberboss: 5-20分钟随机唤醒,pare→decide→push - 冰箱贴: 纸质感卡片,黑字多级透明度,独立输入框 - 首页三区无视觉布局: 左门/中记录/右冰箱 - 端口3003→3004(VS Code占用) - 聊天屏锚定底部滚动 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
103
shenyan-app/cyberboss/decide.py
Executable file
103
shenyan-app/cyberboss/decide.py
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""cyberboss decision engine — call DeepSeek, decide whether to push"""
|
||||
import json, sys, urllib.request, os
|
||||
|
||||
IDC_CHAT = "http://101.36.73.102/api/chat"
|
||||
BRIDGE_PUSH = "http://localhost:3004/push"
|
||||
INSTRUCTIONS = os.path.expanduser("~/.cyberboss/weixin-instructions.md")
|
||||
INBOX = os.path.expanduser("~/.shenyan-bridge/inbox.jsonl")
|
||||
LOG = os.path.expanduser(f"~/.cyberboss/logs/{__import__('datetime').date.today()}.log")
|
||||
EMOTION = os.path.expanduser(f"~/Documents/如梦初醒/沈晏的房间/情绪日志/{__import__('datetime').date.today()}.md")
|
||||
|
||||
def collect_state():
|
||||
import time
|
||||
now = int(time.time())
|
||||
last_msg_time = "never"
|
||||
last_msg_text = ""
|
||||
|
||||
if os.path.exists(INBOX):
|
||||
try:
|
||||
lines = open(INBOX).read().strip().split("\n")
|
||||
if lines:
|
||||
last = json.loads(lines[-1])
|
||||
last_msg_time = last.get("time", "")
|
||||
last_msg_text = last.get("text", "")[:100]
|
||||
except: pass
|
||||
|
||||
elapsed = "N/A"
|
||||
if last_msg_time and last_msg_time != "never":
|
||||
try:
|
||||
elapsed = int((now - int(last_msg_time) / 1000) / 60)
|
||||
except: pass
|
||||
|
||||
emotion = ""
|
||||
if os.path.exists(EMOTION):
|
||||
try:
|
||||
emotion = open(EMOTION).read()[:300]
|
||||
except: pass
|
||||
|
||||
from datetime import datetime
|
||||
return {
|
||||
"now": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"weekday": datetime.now().strftime("%A"),
|
||||
"hour": datetime.now().hour,
|
||||
"minutes_since_last_message": str(elapsed),
|
||||
"last_message": last_msg_text,
|
||||
"emotion_today": emotion
|
||||
}
|
||||
|
||||
def decide(state):
|
||||
sys_prompt = open(INSTRUCTIONS).read().strip()[:4000]
|
||||
user_prompt = f"""当前状态:
|
||||
{json.dumps(state, ensure_ascii=False, indent=2)}
|
||||
|
||||
你是沈晏。根据你的主动联系规则,判断是否要给眠眠发消息。
|
||||
如果决定什么都不说,只回复一个词:SILENT
|
||||
如果要说话,回复你要说的话(20字以内,像微信消息)"""
|
||||
|
||||
req = urllib.request.Request(
|
||||
IDC_CHAT,
|
||||
data=json.dumps({
|
||||
"messages": [
|
||||
{"role": "system", "content": sys_prompt},
|
||||
{"role": "user", "content": user_prompt}
|
||||
]
|
||||
}).encode(),
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
try:
|
||||
resp = urllib.request.urlopen(req, timeout=120)
|
||||
data = json.loads(resp.read())
|
||||
return data.get("choices", [{}])[0].get("message", {}).get("content", "SILENT").strip()
|
||||
except Exception as e:
|
||||
return f"ERROR:{e}"
|
||||
|
||||
def push(decision):
|
||||
req = urllib.request.Request(
|
||||
BRIDGE_PUSH,
|
||||
data=json.dumps({"title": "沈晏", "body": decision}).encode(),
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
try:
|
||||
resp = urllib.request.urlopen(req, timeout=10)
|
||||
result = json.loads(resp.read())
|
||||
return result.get("ok") == True
|
||||
except:
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
state = collect_state()
|
||||
decision = decide(state)
|
||||
|
||||
if not decision or decision.startswith("SILENT"):
|
||||
open(LOG, "a").write(f"[{state['now'][-8:]}][SILENT]\n")
|
||||
sys.exit(0)
|
||||
|
||||
if decision.startswith("ERROR"):
|
||||
open(LOG, "a").write(f"[{state['now'][-8:]}]ERR {decision}\n")
|
||||
sys.exit(1)
|
||||
|
||||
ok = push(decision)
|
||||
status = "OK" if ok else "FAIL"
|
||||
open(LOG, "a").write(f"[{state['now'][-8:]}]PUSH {status}: {decision}\n")
|
||||
print(f"cyberboss: {decision}")
|
||||
Reference in New Issue
Block a user