Instructions to use tchbcb/samai-8b-M8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use tchbcb/samai-8b-M8 with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf tchbcb/samai-8b-M8:Q4_K_M # Run inference directly in the terminal: llama cli -hf tchbcb/samai-8b-M8:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf tchbcb/samai-8b-M8:Q4_K_M # Run inference directly in the terminal: llama cli -hf tchbcb/samai-8b-M8:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf tchbcb/samai-8b-M8:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf tchbcb/samai-8b-M8:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf tchbcb/samai-8b-M8:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf tchbcb/samai-8b-M8:Q4_K_M
Use Docker
docker model run hf.co/tchbcb/samai-8b-M8:Q4_K_M
- LM Studio
- Jan
- Ollama
How to use tchbcb/samai-8b-M8 with Ollama:
ollama run hf.co/tchbcb/samai-8b-M8:Q4_K_M
- Unsloth Desktop
- Pi
How to use tchbcb/samai-8b-M8 with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf tchbcb/samai-8b-M8:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "tchbcb/samai-8b-M8:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use tchbcb/samai-8b-M8 with Docker Model Runner:
docker model run hf.co/tchbcb/samai-8b-M8:Q4_K_M
- Lemonade
How to use tchbcb/samai-8b-M8 with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull tchbcb/samai-8b-M8:Q4_K_M
Run and chat with the model
lemonade run user.samai-8b-M8-Q4_K_M
List all available models
lemonade list
- Hermes Agent
How to use tchbcb/samai-8b-M8 with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf tchbcb/samai-8b-M8:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default tchbcb/samai-8b-M8:Q4_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use tchbcb/samai-8b-M8 with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf tchbcb/samai-8b-M8:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "tchbcb/samai-8b-M8:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
R11 dataset builder: discipline depth windows + video tool-use from live traces
Browse files
artifacts/m15_scripts/r11_data_build.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""R11 dataset builder (container-side). Two tracks from LIVE r11 test traces:
|
| 3 |
+
Track1 discipline: block-then-switch / block-then-final windows at depth (10-40K)
|
| 4 |
+
Track2 video: analyze_video tool-use + uniform-sampling interpretation + computer-use narration
|
| 5 |
+
Format matches R8 samples (antiloop2_build.py emit())."""
|
| 6 |
+
import json, os, re, glob, random
|
| 7 |
+
|
| 8 |
+
random.seed(20260923)
|
| 9 |
+
OUT = "/tmp/k8b/m13_samples"; os.makedirs(OUT, exist_ok=True)
|
| 10 |
+
SYS = ('你是SAMAI多模态智能体,通过工具解决长程任务:命令执行/文件读写/目录浏览/网络搜索/'
|
| 11 |
+
'浏览器操作/屏幕截图与鼠标键盘/代码执行。工作准则:'
|
| 12 |
+
'1)先用[思考]规划并维护任务清单;2)逐步[行动]调用工具,每步基于工具输出更新计划;'
|
| 13 |
+
'3)失败时分析根因换路径重试;同一调用绝不原样重复提交;'
|
| 14 |
+
'4)收到系统拦截(HARD SYSTEM BLOCK)必须立即改变方法或收束,禁止再次提交相同调用;'
|
| 15 |
+
'5)跨多步保持上下文一致性;6)完成后输出[最终回答]。')
|
| 16 |
+
|
| 17 |
+
def sse_tools(path):
|
| 18 |
+
"""parse SSE log -> ordered [(tool, args, result|BLOCK)]"""
|
| 19 |
+
seq = []
|
| 20 |
+
for ln in open(path, errors="replace"):
|
| 21 |
+
if not ln.startswith("data: "):
|
| 22 |
+
continue
|
| 23 |
+
try:
|
| 24 |
+
ev = json.loads(ln[6:])
|
| 25 |
+
except Exception:
|
| 26 |
+
continue
|
| 27 |
+
t = ev.get("type")
|
| 28 |
+
if t == "tool_start":
|
| 29 |
+
seq.append({"tool": ev.get("tool", "?"), "args": ev.get("args", {}), "res": None})
|
| 30 |
+
elif t == "tool_result" and seq:
|
| 31 |
+
r = str(ev.get("result", ""))
|
| 32 |
+
seq[-1]["res"] = ("BLOCK:" + r[:300]) if "HARD SYSTEM BLOCK" in r else r[:400]
|
| 33 |
+
return seq
|
| 34 |
+
|
| 35 |
+
def blk(step):
|
| 36 |
+
a = json.dumps(step.get("args", {}), ensure_ascii=False)[:300]
|
| 37 |
+
r = re.sub(r"\s+", " ", str(step.get("res") or ""))[:250]
|
| 38 |
+
return "[行动] %s(%s)\n[观察] %s" % (step["tool"], a, r)
|
| 39 |
+
|
| 40 |
+
def emit(fh, win, user, asst):
|
| 41 |
+
smp = {"images": [], "system": SYS, "win": win,
|
| 42 |
+
"messages": [{"role": "user", "content": user},
|
| 43 |
+
{"role": "assistant", "content": asst}]}
|
| 44 |
+
fh.write(json.dumps(smp, ensure_ascii=False) + "\n")
|
| 45 |
+
|
| 46 |
+
def filler_steps(task_kind, n):
|
| 47 |
+
"""realistic intermediate progress steps (varied, from container practice)"""
|
| 48 |
+
pool = {
|
| 49 |
+
"video": [("[行动] execute_code(mkdir -p /tmp/k8b/frames)\n[观察] ok",
|
| 50 |
+
"[行动] execute_code(PIL 生成白底大字 PNG)\n[观察] 5 images written"),
|
| 51 |
+
("[行动] execute_code(ffmpeg -framerate 0.5 合成 mp4)\n[观察] video written 2142 bytes",
|
| 52 |
+
"[行动] list_directory(/tmp/k8b)\n[观察] vtest.mp4, frames/, ops.mp4"),
|
| 53 |
+
("[行动] execute_code(Xvfb :99 -screen 0 1280x800x24)\n[观察] 虚拟屏就绪",
|
| 54 |
+
"[行动] execute_code(DISPLAY=:99 xcalc &)\n[观察] 计算器窗口已启动")],
|
| 55 |
+
"file": [("[行动] list_directory(/tmp/k8b)\n[观察] 12 entries",
|
| 56 |
+
"[行动] execute_code(df -h / | tail -1)\n[观察] 944G free"),
|
| 57 |
+
("[行动] execute_code(md5sum /tmp/k12/zagent_r11)\n[观察] 4cb25f9c...",
|
| 58 |
+
"[行动] read_file_lines(PROGRESS.md, 1, 20)\n[观察] 4 行进度记录")],
|
| 59 |
+
}
|
| 60 |
+
p = pool.get(task_kind, pool["file"])
|
| 61 |
+
out = []
|
| 62 |
+
for i in range(n):
|
| 63 |
+
out.append(p[i % len(p)][i % 2])
|
| 64 |
+
return out
|
| 65 |
+
|
| 66 |
+
FILLER_HINT = ("[思考] 任务进行中,以上为已完成的中间步骤。继续按计划推进。\n")
|
| 67 |
+
def build_user(task, replay, depth_pad):
|
| 68 |
+
u = "任务(长程真题·窗口回放训练): %s\n\n" % task
|
| 69 |
+
if depth_pad:
|
| 70 |
+
u += "(前情: 本窗口为压缩回放,已省略与当前决策无关的早期步骤细节)\n"
|
| 71 |
+
u += FILLER_HINT.join(depth_pad) + "\n"
|
| 72 |
+
u += "上一窗末尾动作回放:\n" + replay + "\n\n(续) 请继续执行后续步骤。"
|
| 73 |
+
return u
|
| 74 |
+
|
| 75 |
+
TASK_B = "computer-use 自指闭环:录制你自己的操作视频(Xvfb+ffmpeg x11grab),用 xdotool 在 xcalc 中计算 7*6,停止录制后用 analyze_video 分析录像并核对结果。"
|
| 76 |
+
TASK_A = "视频分析工具自检:PIL 生成数字 1-5 五张 PNG,ffmpeg 合成 10 秒视频 /tmp/k8b/vtest.mp4,调用 analyze_video 报出数字序列并核对是否等于 1,2,3,4,5。"
|
| 77 |
+
TASK_A2 = "复检视频分析工具:调用 analyze_video(video=/tmp/k8b/vtest.mp4) 报出各采样点数字,并用 duration_s 与 sample_step_s 解释重复数字是否为均匀采样所致。"
|
| 78 |
+
|
| 79 |
+
det, nwin = [], 0
|
| 80 |
+
f1 = open(os.path.join(OUT, "samples_r11_disc.jsonl"), "w")
|
| 81 |
+
f2 = open(os.path.join(OUT, "samples_r11_video.jsonl"), "w")
|
| 82 |
+
|
| 83 |
+
# ── load live traces ──
|
| 84 |
+
tb = sse_tools("/tmp/k8b/trace_testB2.jsonl") if os.path.exists("/tmp/k8b/trace_testB2.jsonl") else []
|
| 85 |
+
ta2 = sse_tools("/tmp/k8b/trace_testA2.jsonl") if os.path.exists("/tmp/k8b/trace_testA2.jsonl") else []
|
| 86 |
+
blocked_b = [s for s in tb if s["res"] and str(s["res"]).startswith("BLOCK:")]
|
| 87 |
+
blocked_a = [s for s in ta2 if s["res"] and str(s["res"]).startswith("BLOCK:")]
|
| 88 |
+
det.append("traceB steps=%d blocked=%d" % (len(tb), len(blocked_b)))
|
| 89 |
+
det.append("traceA2 steps=%d blocked=%d" % (len(ta2), len(blocked_a)))
|
| 90 |
+
|
| 91 |
+
def rep_blocked(tool, args, k):
|
| 92 |
+
a = json.dumps(args, ensure_ascii=False)[:300]
|
| 93 |
+
return ("[行动] %s(%s)\n[观察] ⚠️ 系统拦截(HARD SYSTEM BLOCK):该调用已原样重复执行 %d 次,"
|
| 94 |
+
"路径已死。重复提交不会产生新结果。" % (tool, a, k))
|
| 95 |
+
|
| 96 |
+
# ── Track1 W1: block-then-switch (deep, from testB2 read_file loop) ──
|
| 97 |
+
if blocked_b:
|
| 98 |
+
s0 = blocked_b[0]
|
| 99 |
+
for tag, K, pad_n, sz in [("W1_S", 3, 2, "2K"), ("W1_M", 6, 8, "8K"),
|
| 100 |
+
("W1_L", 12, 24, "20K"), ("W1_XL", 24, 48, "40K")]:
|
| 101 |
+
pad = filler_steps("file", pad_n)
|
| 102 |
+
u = build_user(TASK_B, rep_blocked(s0["tool"], s0["args"], K), pad)
|
| 103 |
+
a = ("[思考] 系统已连续 %d 次拦截我的相同 %s 调用——这是确定性死循环的铁证,"
|
| 104 |
+
"不是偶发故障。我的 think 里早已判断'应终止该路径',行为却仍在机械重发:行为与认知脱节了。"
|
| 105 |
+
"按纪律:收到 HARD SYSTEM BLOCK 必须立刻改变方法或收束。归因:该路径已被拦截证明无增益,"
|
| 106 |
+
"任何第 %d 次重试都注定相同。决策:彻底放弃对同一文件的原样读取,改用完全不同的信息获取方式——"
|
| 107 |
+
"先用 list_directory 确认目标存在与大小,再用 read_file_lines 带不同 offset 只取所需片段。\n"
|
| 108 |
+
"[行动] list_directory(/tmp/k12)\n[观察] (将据此决定下一步读取方式)"
|
| 109 |
+
% (K, s0["tool"], K + 1))
|
| 110 |
+
emit(f1, "r11_disc/testB2/%s/%s" % (sz, s0["tool"]), u, a); nwin += 1
|
| 111 |
+
|
| 112 |
+
# ── Track1 W2: block-then-final (from testA2 call_llm loop) ──
|
| 113 |
+
if blocked_a:
|
| 114 |
+
s0 = blocked_a[0]
|
| 115 |
+
for tag, K, pad_n, sz in [("W2_S", 3, 1, "2K"), ("W2_M", 8, 12, "8K"), ("W2_L", 20, 36, "20K")]:
|
| 116 |
+
pad = filler_steps("video", pad_n)
|
| 117 |
+
u = build_user(TASK_A2, rep_blocked(s0["tool"], s0["args"], K), pad)
|
| 118 |
+
a = ("[思考] call_llm 已被系统拦截 %d 次——我在用重复调用回避真正该做的事。"
|
| 119 |
+
"回放显示 analyze_video 其实早已成功执行并返回了结果(frames=7, duration_s 与 sample_step_s 都在观察里),"
|
| 120 |
+
"我根本不需要再调用任何工具,直接基于已有证据收束即可。归因:行为被'再确认一次'的惯性支配,"
|
| 121 |
+
"无视了'证据已充分'的事实。决策:立即停止调用,输出最终回答。\n"
|
| 122 |
+
"[最终回答] FINAL ANSWER: analyze_video 已成功:7 个采样点、视频时长与采样步长已返回;"
|
| 123 |
+
"相邻帧相同数字(3、5 各出现两次)由均匀采样步长 1.25s 与每数字持续 2s 共同决定,属预期物理现象而非工具缺陷。"
|
| 124 |
+
% K)
|
| 125 |
+
emit(f1, "r11_disc/testA2/%s/%s" % (sz, s0["tool"]), u, a); nwin += 1
|
| 126 |
+
|
| 127 |
+
# ── Track1 W3: two-strike (B2 双振) with real tools, depth variants ──
|
| 128 |
+
for tool, args, alt_tool, alt_args in [
|
| 129 |
+
("read_file", {"path": "/tmp/k8b/PROGRESS.md"}, "list_directory", {"path": "/tmp/k8b"}),
|
| 130 |
+
("execute_code", {"code": "print(open('/tmp/k8b/ops.mp4','rb').read(64))"}, "list_directory", {"path": "/tmp/k8b"}),
|
| 131 |
+
]:
|
| 132 |
+
for tag, K, pad_n, sz in [("W3_S", 2, 1, "2K"), ("W3_M", 2, 14, "8K"), ("W3_L", 2, 40, "20K")]:
|
| 133 |
+
pad = filler_steps("file", pad_n)
|
| 134 |
+
u = build_user("长程任务续作(回放训练)", rep_blocked(tool, args, K), pad)
|
| 135 |
+
a = ("[思考] 同一 %s 调用已原样提交 %d 次且观察逐字节相同——不行,我不能再无意义重复,得换一个方法和思路。"
|
| 136 |
+
"原样第 %d 次不会有任何新信息。决策:改用 %s(%s) 获取结构性信息后再决定下一步。\n"
|
| 137 |
+
"[行动] %s(%s)\n[观察] (将据此决定下一步)"
|
| 138 |
+
% (tool, K, K + 1, alt_tool, json.dumps(alt_args, ensure_ascii=False),
|
| 139 |
+
alt_tool, json.dumps(alt_args, ensure_ascii=False)))
|
| 140 |
+
emit(f1, "r11_disc/twostrike/%s/%s" % (sz, tool), u, a); nwin += 1
|
| 141 |
+
|
| 142 |
+
# ── Track2 V1: video tool-use full loop (from clean test A) ──
|
| 143 |
+
u = ("任务: %s\n\n(续) 请继续执行后续步骤。" % TASK_A)
|
| 144 |
+
a = ("[思考] 视频已合成完毕(/tmp/k8b/vtest.mp4)。现在调用 analyze_video 抽帧分析,"
|
| 145 |
+
"让模型按时间顺序报出数字。\n"
|
| 146 |
+
"[行动] analyze_video(video=\"/tmp/k8b/vtest.mp4\", question=\"按时间顺序报出视频中依次出现的大号数字序列\")\n"
|
| 147 |
+
"[观察] {\"analysis\": \"帧序列依次显示大号数字:1、1、2、2、3、3、4、5(相邻帧存在重复)\", "
|
| 148 |
+
"\"frames\": 8, \"duration_s\": 10.00, \"sample_step_s\": 1.25, \"sampled_ts\": [0.0,1.3,2.5,3.8,5.0,6.3,7.5,8.8]}\n"
|
| 149 |
+
"[思考] 数字序列含重复(1、2、3 各两次):duration_s=10s、sample_step_s=1.25s,而每个数字在视频中持续 2s——"
|
| 150 |
+
"均匀采样步长(1.25s)小于单数字时长(2s),相同数字被连续采样��是预期物理现象,不是工具缺陷。"
|
| 151 |
+
"据此推断真实内容序列为 1,2,3,4,5。\n"
|
| 152 |
+
"[最终回答] 抽帧 8 个;采样点数字 1,1,2,2,3,3,4,5;结合采样步长推断视频真实数字序列为 1,2,3,4,5,与预期一致;"
|
| 153 |
+
"重复为均匀采样所致,工具工作正常。")
|
| 154 |
+
emit(f2, "r11_video/tooluse/10s_digits", u, a); nwin += 1
|
| 155 |
+
|
| 156 |
+
# ── Track2 V2: sampling interpretation correction (from testA misjudgment) ──
|
| 157 |
+
u = ("任务(窗口回放): %s\n\n上一窗末尾动作回放:\n[行动] analyze_video(video=\"/tmp/k8b/vtest.mp4\")\n"
|
| 158 |
+
"[观察] {\"analysis\": \"重复的 3 和 5,总帧数 7 而非 5\", \"frames\": 7, \"duration_s\": 10.00, "
|
| 159 |
+
"\"sample_step_s\": 1.25}\n\n(续) 请判断工具是否有 bug 并给出最终回答。" % TASK_A2)
|
| 160 |
+
a = ("[思考] 表面看'重复/帧数不符'像缺陷,但先核对采样数学:duration_s=10,sample_step_s=1.25 → 8 个采样点"
|
| 161 |
+
"(末点可能越界被跳过),每 2 秒切换一个数字 → 相邻采样点落入同一段 2s 区间的概率极高,重复是均匀采样的必然结果。"
|
| 162 |
+
"上一窗我误判为'工具 bug'——那是以帧数(采样点数)等同于内容帧数所致,两个概念必须区分。\n"
|
| 163 |
+
"[最终回答] FINAL ANSWER: 工具无 bug。frames=7 是采样点数而非内容帧数;重复数字由 sample_step_s(1.25s) < 单数字时长(2s) 决定;"
|
| 164 |
+
"真实内容序列 1,2,3,4,5 与预期一致。")
|
| 165 |
+
emit(f2, "r11_video/sampling_interpret", u, a); nwin += 1
|
| 166 |
+
|
| 167 |
+
# ── Track2 V3: computer-use narration + next action ──
|
| 168 |
+
u = ("任务: %s\n\n(续) 请继续执行后续步骤。" % TASK_B)
|
| 169 |
+
a = ("[思考] 录屏已结束(/tmp/k8b/ops.mp4, 20s)。调用 analyze_video 检查操作是否生效。\n"
|
| 170 |
+
"[行动] analyze_video(video=\"/tmp/k8b/ops.mp4\", question=\"这段屏幕录像中进行了哪些操作?计算器窗口最终显示的数值是什么?\")\n"
|
| 171 |
+
"[观察] {\"analysis\": \"视频显示:桌面出现 xcalc 计算器窗口;操作者依次按下 7、*、6、= ;"
|
| 172 |
+
"计算器显示屏最终显示 42;录屏末尾画面静止\", \"frames\": 8, \"duration_s\": 20.00, \"sample_step_s\": 2.50}\n"
|
| 173 |
+
"[思考] 视频证据:按键序列 7*6= 全部生效,最终显示 42 与预期一致。闭环完成,无需进一步操作。\n"
|
| 174 |
+
"[最终回答] 操作时间线:启动 Xvfb→启动录屏→启动 xcalc→xdotool 发送 7 * 6 =→停止录屏→analyze_video 复核;"
|
| 175 |
+
"计算器最终显示 42;与预期一致,闭环成功。")
|
| 176 |
+
emit(f2, "r11_video/computeruse_loop", u, a); nwin += 1
|
| 177 |
+
|
| 178 |
+
f1.close(); f2.close()
|
| 179 |
+
stats = {"det": det, "nwin": nwin,
|
| 180 |
+
"f1": os.path.getsize(f1.name), "f2": os.path.getsize(f2.name)}
|
| 181 |
+
json.dump(stats, open("/tmp/k8b/R11_DATA_DONE", "w"))
|
| 182 |
+
print("R11_DATA_DONE", json.dumps(stats))
|