AI 工具

Character.AI 会话时长记录:本地休息提醒

沉浸式角色聊天容易超时。这篇本地账本记录 start/end,超过软限制(默认 45 分钟)给出休息提示。不联网、不读取 App。

BINBHO · 图文教程

沉浸式角色聊天容易超时。这篇本地账本记录 start/end,超过软限制(默认 45 分钟)给出休息提示。不联网、不读取 App。

先看清成品

  • start→end 写出分钟数;summary 汇总。
  • 2 项 pytest 通过。

合规提醒:Character.AI 角色均为虚构内容,不代表真实人物,不能当作医疗/法律/金融等专业建议。平台有年龄限制与未成年人安全措施,请遵守官方规定。长时间聊天注意休息。官方 Help Center 表明目前没有面向开发者的公开 API;勿使用非官方逆向客户端(可能违反条款且不稳定)。本文不编造价格与会员权益。

运行说明:无 Character.AI API(官方亦无公开开发者 API)。三篇均为本地助手:角色定义校验、会话时长账本、导出/提示词虚构免责扫描。未登录 character.ai。2026-10-23(Asia/Shanghai)pytest 通过。

做完之后你会得到什么?

成果 说明
session_timer.py 时长账本
test_106b.py 测试

需要准备哪些环境?

项目 说明
Python 3.10+

关键事实

事实 来源
产品建议注意休息与数字健康 常见安全提示
本工具与 Character.AI 服务器无关 重要
软限制可按个人调整 --limit-min 实践

文件结构

106-character-ai-B-src/
├── session_timer.py
└── test_106b.py

第 1 步:计时脚本

#!/usr/bin/env python3
"""Local wellbeing timer for long Character.AI chat sessions (offline; no API)."""
from __future__ import annotations

import argparse
import json
from datetime import datetime, timezone
from pathlib import Path

DEFAULT_LIMIT = 45


def load(path: Path) -> dict:
    if path.exists():
        return json.loads(path.read_text(encoding="utf-8"))
    return {"sessions": []}


def start(ledger: dict, label: str) -> dict:
    now = datetime.now(timezone.utc).isoformat()
    ledger.setdefault("sessions", []).append({"label": label, "started": now, "ended": None})
    return {"action": "start", "label": label, "started": now}


def end(ledger: dict, limit_min: int) -> dict:
    open_s = [s for s in ledger.get("sessions") or [] if not s.get("ended")]
    if not open_s:
        return {"action": "end", "error": "无进行中的会话"}
    s = open_s[-1]
    now = datetime.now(timezone.utc)
    s["ended"] = now.isoformat()
    started = datetime.fromisoformat(s["started"])
    minutes = (now - started).total_seconds() / 60.0
    warn = minutes >= limit_min
    return {
        "action": "end",
        "label": s.get("label"),
        "minutes": round(minutes, 1),
        "over_soft_limit": warn,
        "message": "建议休息一下眼睛与手腕" if warn else "时长在建议范围内",
    }


def summary(ledger: dict) -> dict:
    total = 0.0
    n = 0
    for s in ledger.get("sessions") or []:
        if s.get("started") and s.get("ended"):
            total += (
                datetime.fromisoformat(s["ended"]) - datetime.fromisoformat(s["started"])
            ).total_seconds() / 60.0
            n += 1
    return {"closed_sessions": n, "total_minutes": round(total, 1)}


def main(argv=None) -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--ledger", default="cai_sessions.json")
    sub = ap.add_subparsers(dest="cmd", required=True)
    s = sub.add_parser("start")
    s.add_argument("label", nargs="?", default="chat")
    e = sub.add_parser("end")
    e.add_argument("--limit-min", type=int, default=DEFAULT_LIMIT)
    sub.add_parser("summary")
    args = ap.parse_args(argv)
    path = Path(args.ledger)
    ledger = load(path)
    if args.cmd == "start":
        out = start(ledger, args.label)
    elif args.cmd == "end":
        out = end(ledger, args.limit_min)
    else:
        out = summary(ledger)
    path.write_text(json.dumps(ledger, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    print(json.dumps(out, ensure_ascii=False, indent=2))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

第 2 步:测试

from pathlib import Path
import json, subprocess, sys, time
from session_timer import start, end, load
HERE = Path(__file__).resolve().parent

def test_flow(tmp_path):
    led = {"sessions": []}
    start(led, "demo")
    time.sleep(0.05)
    info = end(led, limit_min=999)
    assert info["minutes"] >= 0 and info["over_soft_limit"] is False

def test_cli(tmp_path):
    led = tmp_path / "l.json"
    subprocess.run([sys.executable, str(HERE/"session_timer.py"), "--ledger", str(led), "start", "x"], check=True)
    r = subprocess.run([sys.executable, str(HERE/"session_timer.py"), "--ledger", str(led), "end", "--limit-min", "999"], capture_output=True, text=True, check=True)
    assert "minutes" in r.stdout

第 3 步:运行

$ session_timer
{
  "action": "start",
  "label": "demo",
  "started": "2026-10-23T04:57:54.430674+00:00"
}
{
  "action": "end",
  "label": "demo",
  "minutes": 0.0,
  "over_soft_limit": false,
  "message": "时长在建议范围内"
}
{
  "closed_sessions": 1,
  "total_minutes": 0.0
}

$ pytest -q
..                                                                       [100%]
2 passed in 0.11s

怎么检查结果?

  • end 含 minutes 与 message。
  • summary 统计 closed_sessions。

调试示例

忘了 end。 summary 不会计入未关闭会话。养成结束聊天就跑 end 的习惯,或用系统番茄钟双保险。

常见问题

现象 原因 处理
多角色并行 多次 start 分别 end
改 45 分钟 end --limit-min 按需
要云同步 自行备份 ledger 勿含隐私对话全文

模板规则

  • 超时就休息。
  • 账本勿提交含敏感对话的仓库。
  • 遵守平台安全提示。

项目资源

用途 地址
About(官方) https://character.ai/about
Blog(官方) https://blog.character.ai/

角色可以陪聊,身体不能透支。