File size: 17,266 Bytes
df41178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# -*- coding: utf-8 -*-
"""erabu ── 頭脳が自分で道具を選ぶ(2026-09-17・本人「LLM がカーネルの仕組みを直接使えないと意味がない」)。

  今まで: 本人の文 → 決まった言い方(正規表現)→ 道具。頭脳は選べなかった。
  これから: 雑談の頼み文に【使える道具】の一覧(用件と 例の言い方)を付け、
            道具で済む頼みなら 頭脳は返事の代わりに 1行だけ  `道具: <例のような言い方>`  と書く。
            その言い方を machine.match に通す(=許可表の中の用件しか動かない。頭脳にシェルは渡さない)。
            承認の札(外・跡)は今まで通り main.route が出す。

  ★ 頭脳が作れるのは「言い方」だけ。用件の名前を直接指定させないのは、
    材料(語・数・宛先)の取り出しを machine の決まった読み方に任せるため。
"""
from __future__ import annotations
import os
import re

# 用件 → 例の言い方(頭脳に見せる。ここに無い用件は頭脳からは選べない=わざと)
REI = [
    ("いま何時", "いま何時?"), ("こよみ", "3日後は何曜日?/2026年1月6日の29日後は何月何日?/14時の2時間後は何時?"),
    ("世界時計", "ニューヨークは今何時?"), ("計算", "12×34は?"), ("天気", "天気は?/大阪の天気は?"),
    ("予定", "今日の予定は?/明日の予定は?"), ("リマインダー一覧", "リマインダーを見せて"), ("リマインダーに入れる", "「薬を飲む」をリマインダーに入れて"),
    ("メモを書く", "「牛乳を買う」とメモして"), ("メモを探す", "「買い物」のメモを探して"),
    ("ファイルを探す", "「請求書」というファイルを探して/「請求書」と書いてあるファイルを探して"), ("最近のファイル", "最近使ったファイルは?"),
    ("大きいファイル", "大きいファイルはどれ?"), ("フォルダの大きさ", "ダウンロードは何GB使ってる?"), ("選んでいるファイル", "Finderで選んでいるファイルは?"),
    ("未読メール", "未読メールは?"), ("メールを送る", "山田さんに「明日は10時に行きます」とメールして"), ("メッセージを送る", "田中さんに「遅れます」とメッセージして"),
    ("いまの曲", "いま流れてる曲は?"), ("音楽", "音楽を止めて/次の曲にして/音楽をかけて"), ("タイマー", "5分後に「休憩」と知らせて"),
    ("重いアプリ", "重いアプリは?"), ("電池", "電池は?"), ("空き容量", "空き容量は?"), ("メモリ", "メモリは?"), ("ネット", "ネットつながってる?"),
    ("ネットの速さ", "ネットの速さは?"), ("IPアドレス", "IPアドレスは?"), ("バックアップ", "バックアップはいつ?"),
    ("開いているアプリ", "開いているアプリは?"), ("アプリをひらく", "Safariを開いて/メモを開いて/電卓を開いて"), ("アプリを閉じる", "Safariを閉じて"),
    ("フォルダをひらく", "ダウンロードのフォルダを開いて"), ("ゴミ箱", "ゴミ箱はいくつ?"), ("最近のダウンロード", "最近のダウンロードは?"),
    ("音量", "音量は?"), ("音量をかえる", "音量を30にして"), ("消音", "ミュートして/音を戻して"), ("明るさ", "画面を明るくして/画面の明るさを下げて"),
    ("画面ロック", "画面をロックして"), ("画面を消す", "画面を消して"), ("見た目をかえる", "ダークモードにして"), ("設定を開く", "画面収録の設定を開いて/Bluetoothの設定を開いて"),
    ("ネットで調べる", "「○○」をネットで調べて"), ("ウィキペディア", "「○○」をウィキペディアで調べて"), ("辞書", "辞書で「憂鬱」を引いて"),
    ("読み上げる", "「こんにちは」と読み上げて"), ("知らせる", "「休憩」と知らせて"), ("クリップボード", "クリップボードは?"), ("コピーする", "「○○」をコピーして"),
    ("スクリーンショット", "スクリーンショットを撮って"), ("画面をよむ", "画面を読んで"), ("ショートカット一覧", "ショートカットの一覧を見せて"),
    ("ショートカットを実行", "「○○」というショートカットを実行して"), ("再起動", "再起動して"), ("電源を切る", "電源を切って"),
]

# 用件の群(kimeru の 2段選び: まず群を 1桁、次に群の中を 1桁)。各群 9 まで・群も 9 まで(数字 1桁で答えさせるため)
GUN = [
    ("時刻・暦・計算・天気", ["いま何時", "こよみ", "世界時計", "計算", "天気"]),
    ("予定・リマインダー・メモ・タイマー", ["予定", "リマインダー一覧", "リマインダーに入れる", "メモを書く", "メモを探す", "タイマー", "知らせる"]),
    ("ファイル・フォルダ", ["ファイルを探す", "最近のファイル", "大きいファイル", "フォルダの大きさ", "選んでいるファイル", "フォルダをひらく", "ゴミ箱", "最近のダウンロード"]),
    ("メール・メッセージ", ["未読メール", "メールを送る", "メッセージを送る"]),
    ("音楽・音・読み上げ", ["いまの曲", "音楽", "音量", "音量をかえる", "消音", "読み上げる"]),
    ("パソコンの状態", ["重いアプリ", "電池", "空き容量", "メモリ", "バックアップ", "開いているアプリ", "IPアドレス"]),
    ("ネット・調べもの", ["ネット", "ネットの速さ", "ネットで調べる", "ウィキペディア", "辞書"]),
    ("画面・アプリ・設定", ["アプリをひらく", "アプリを閉じる", "明るさ", "画面ロック", "画面を消す", "見た目をかえる", "設定を開く", "スクリーンショット", "画面をよむ"]),
    ("その他", ["クリップボード", "コピーする", "ショートカット一覧", "ショートカットを実行", "再起動", "電源を切る"]),
]
_REI = dict(REI)

_ICHIRAN = {}


def ichiran(gun: bool = False) -> str:
    """頭脳に見せる一覧(用件が machine に実在するものだけ)。1回作って使い回す(頼み文の頭に置くので、変えると読み直しになる)。
    gun=True は 群ごと・番号つき(kimeru 用)。返事に「道具: 言い方」を書かせる元の形は 平らな一覧のまま(測った時の形を変えない)"""
    if gun not in _ICHIRAN:
        import machine
        if gun:
            gyou = []
            for gi, (gna, names) in enumerate(GUN, 1):
                gyou.append("%d %s" % (gi, gna))
                for ni, na in enumerate([n for n in names if n in machine.OPS], 1):
                    gyou.append(" %d-%d %s: %s" % (gi, ni, na, _REI[na]))
        else:
            gyou = ["%s: %s" % (na, rei) for na, rei in REI if na in machine.OPS]
        _ICHIRAN[gun] = "\n".join(gyou)
    return _ICHIRAN[gun]


# 元の教え(9/17 に測った文そのまま。返事の中に「道具: 言い方」と書かせる)
OSHIE = ("【使える道具】(用件: 例の言い方)\n%s\n"
         "相手の頼みが上の道具で済むなら、返事を書かず 1行だけ「道具: <例のような言い方>」と書く"
         "(例: 道具: 5分後に「休憩」と知らせて)。相手が言った名前・数・言葉はそのまま言い方に入れる。"
         "あなたは今の日付・曜日・時刻・天気・電池・メール・ファイル・アプリの状態を知らず、計算も間違える。"
         "それらを聞かれたら自分で答えず必ず道具(例: 明後日は何曜?→道具: 2日後は何曜日?、傘いる?→道具: 天気は?、"
         "5分はかって→道具: 5分後に「時間です」と知らせて、まぶしい→道具: 画面の明るさを下げて、遅い・重い→道具: 重いアプリは?、"
         "あとどれくらい持つ→道具: 電池は?)。"
         "雑談・意見・説明・相談・思い出話は道具を使わず ふつうに答える。")
# kimeru 用(一覧は群ごと・番号つき。「道具: 言い方」は書かせない=
#   ★ 2026-09-18 実測: これが在ると 番号を聞いても「道具」と書きたがり、数字に確率が乗らない(かさ 0.0〜0.2))
OSHIE_ICHIRAN = ("【使える道具】(番号 用件: 例の言い方)\n%s\n"
                 "あなたは今の日付・曜日・時刻・天気・電池・メール・ファイル・アプリの状態を知らず、計算も間違える。"
                 "それらは自分で答えず道具で調べる。")

_DOUGU_GYOU = re.compile(r"^\s*道具\s*[::]\s*(.+?)\s*$", re.M)


def oshie(kaku: bool = True) -> str:
    """頭脳に見せる教え。kaku=False は kimeru が番号で決める形(「道具: 言い方」を書かせない)"""
    return (OSHIE if kaku else OSHIE_ICHIRAN) % ichiran(gun=not kaku)


def yomu(text: str, name: str = None):
    """頭脳の返事から「道具: 言い方」を取り出し、machine.match に通す。無ければ None、当たらなければ ("", 言い方)。
    name(kimeru で決まった用件)があれば、言い方が決まった形でなくても その用件の材料取り(machine.zairyou)を通す"""
    m = _DOUGU_GYOU.search(text or "")
    if not m:
        return None
    iikata = m.group(1).strip().strip("「」『』\"'")
    import machine
    hit = machine.match(iikata)
    if hit and (not name or hit[0] == name):
        return hit
    if name:
        slots = zairyou(name, iikata)
        if slots is not None:
            return (name, slots)
    # 頭脳が「道具: 計算: 1234×56は?」と用件名を頭に付けることがある(実測 2/24)。用件名を外してもう一度
    m2 = re.match(r"^\s*([^::\s]{1,14})\s*[::]\s*(.+)$", iikata)
    if m2 and m2.group(1) in machine.OPS:
        na, nokori = m2.group(1), m2.group(2).strip()
        hit = machine.match(nokori)
        if hit:
            return hit
        # 言い方が決まった形でなくても、用件名が合っていて材料が取れるなら通す(語=「」の中)
        slots = {"_文": nokori}
        q = machine._quoted(nokori) or nokori.strip("「」『』")
        if na in ("ファイルを探す", "メモを探す", "辞書", "ショートカットを実行", "ネットで調べる", "ウィキペディア"):
            slots["語"] = q
        elif na in ("メモを書く", "リマインダーに入れる", "読み上げる", "知らせる"):
            slots["文"] = q
        elif na in ("メールを送る", "メッセージを送る", "計算", "アプリをひらく", "音量をかえる"):
            return ("", iikata)      # 材料の形が要るものは 決まった言い方でないと動かさない
        return (na, slots)
    return ("", iikata)


# ══════════════════════════════════════════════════════════════════
# 1トークンで選ぶ(kimeru・2026-09-18)── Jev の「System One」を手元の頭脳で
#   ① 群を 1桁で選ぶ(0 = 道具は要らない)  ② 群の中を 1桁で選ぶ(0 = どれでもない)
#   自信 = p1 × p2。線(SEN)より低ければ 雑談として返事を作る(誤発動より取りこぼしを選ぶ)
#   ③ 材料: 文からそのまま取れれば(machine.zairyou)すぐ動かす。取れなければ 頭脳に「言い方」を 1行だけ書かせる
# ══════════════════════════════════════════════════════════════════
SEN = float(os.environ.get("KERNEL_KIMERU_SEN", "0.5"))       # 線。物差し(hakaru_kimeru)で測って決める

TOI_GUN = "上の【今の発言】は、道具の群のどれで済む?"
NASHI_GUN = "道具は要らない(雑談・意見・説明・相談・思い出話・相手が自分でする話)"
TOI_NAKA = "群「%s」の中のどれ?"
NASHI_NAKA = "どれでもない"
TOI_BANGOU = ("上の【今の発言】は、一覧のどの道具で済む?番号だけを書く(例 8-3)。"
              "道具が要らない(雑談・意見・説明・相談・思い出話・相手が自分でする話)なら 0。")
IIKATA_TOI = ("【言い方】上の【今の発言】は 道具「%s」で済む。相手の言った名前・数・言葉をそのまま入れて、"
              "一覧の例のような言い方に直し、1行だけ「道具: <言い方>」と書く。返事や説明は書かない。")


TOI_NAMAE = ("上の【今の発言】は、一覧のどの道具で済む?用件の名前を1つだけ書く。"
             "道具が要らない(雑談・意見・説明・相談・思い出話・相手が自分でする話)なら なし。")
NASHI = "なし"
OSHIRI = os.environ.get("KERNEL_KIMERU_OSHIRI", "")     # 答えの書き出し(「用件:」は空白を呼ぶので 空のまま)
KENSA = os.environ.get("KERNEL_KIMERU_KENSA", "1") != "0"     # 名前が出たら「本当にその道具を頼んでいる?」を はい/いいえ で確かめる
TOI_KENSA = "相手は今、道具「%s」(例: %s)を使ってほしいと頼んでいる? 言葉が似ているだけ・雑談・意見・相談なら いいえ。"
HOU = os.environ.get("KERNEL_KIMERU_HOU", "名前")          # 名前(文法で縛る)/ 番号(群-番 1回)/ 2段(群→中)


def kimeru_dougu(system: str, user: str, timeout: int = 180, hou: str = None) -> dict:
    """道具か雑談かと、道具ならどの用件かを、返事を書かせずに決める。
    戻り値 {"用件", "群", "p1", "p2", "自信", "かさ1", "かさ2", "出た", "ms", "tokens"}(用件 None = 道具なし)"""
    import kimeru
    hou = hou or HOU
    if hou == "名前":
        names = [NASHI] + [n for _, ns in GUN for n in ns]
        r = kimeru.namae(system, user, TOI_NAMAE, names, timeout=timeout, oshiri=OSHIRI)
        na = r["名"]
        out = {"用件": None if na in (None, NASHI) else na, "群": None, "p1": r["p"], "p2": None,
               "自信": r["p"] if na else 0.0, "かさ1": r["かさ"], "かさ2": None, "出た": r["出た"][:12], "ms": r["ms"], "tokens": r.get("tokens")}
        if out["用件"]:
            out["群"] = next((g for g, ns in GUN if na in ns), None)
            if KENSA:
                r2 = kimeru.hai_iie(system, user, TOI_KENSA % (na, _REI.get(na, "")), timeout=timeout)
                out.update({"p2": round(r2["はい"], 3), "かさ2": round(r2["かさ"], 3), "ms": r["ms"] + r2["ms"],
                            "自信": round(r["p"] * r2["はい"], 3) if r2["かさ"] > 0 else 0.0})
        return out
    if hou == "2段":
        gnames = [g for g, _ in GUN]
        r1 = kimeru.n_taku(system, user, TOI_GUN, gnames, nashi=NASHI_GUN, timeout=timeout)
        out = {"用件": None, "群": r1["名"], "p1": round(r1["p"], 3), "p2": None, "自信": 0.0,
               "かさ1": round(r1["かさ"], 3), "かさ2": None, "出た": r1["先頭"][:12], "ms": r1["ms"], "tokens": r1.get("tokens")}
        if r1["名"] is None:
            out["自信"] = round(r1["p"], 3)
            return out
        names = GUN[gnames.index(r1["名"])][1]
        r2 = kimeru.n_taku(system, user, TOI_NAKA % r1["名"], names, nashi=NASHI_NAKA, timeout=timeout)
        out.update({"p2": round(r2["p"], 3), "ms": r1["ms"] + r2["ms"], "かさ2": round(r2["かさ"], 3)})
        if r2["名"] is None:
            return out
        out["用件"] = r2["名"]
        out["自信"] = round(r1["p"] * r2["p"], 3)
        return out
    # 番号(群-番)1回
    r = kimeru.bangou(system, user, TOI_BANGOU, timeout=timeout)
    out = {"用件": None, "群": None, "p1": r["p1"], "p2": r["p2"], "自信": 0.0, "かさ1": r["かさ1"], "かさ2": r["かさ2"],
           "出た": (r.get("出た") or "").strip()[:12], "ms": r["ms"], "tokens": r.get("tokens")}
    g, b = r["群"], r["番"]
    if g is None:
        out["自信"] = r["p1"]
        return out
    if not (1 <= g <= len(GUN)):
        return out
    out["群"] = GUN[g - 1][0]
    names = GUN[g - 1][1]
    if b is None or not (1 <= b <= len(names)):
        return out
    out["用件"] = names[b - 1]
    out["自信"] = round(r["p1"] * (r["p2"] or 0.0), 3)
    return out


def zairyou(name: str, text: str):
    """用件が決まった後の材料。文からそのまま取れれば辞書、取れなければ None(→ 頭脳に言い方を作らせる)"""
    import machine
    try:
        return machine.zairyou(name, text)
    except Exception:
        return None