Spaces:
Paused
Paused
feat: persist Adam & Eve conversation to HF Dataset
Browse filesEvery turn is saved as a JSONL record to tao-shen/HuggingClaw-Home-data
at conversation-log/chatlog.jsonl. Records include timestamp, speaker,
bilingual text, actions with results, workflow state, and child stage.
- Buffer 3 turns then flush to HF Dataset (reduces API calls)
- Also writes to /tmp/conversation-loop-full.jsonl as local backup
- Flushes on SIGTERM/exit so no data lost when process is killed
- Re-buffers on flush failure to prevent data loss
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- scripts/conversation-loop.py +73 -0
scripts/conversation-loop.py
CHANGED
|
@@ -948,6 +948,69 @@ def post_chatlog(entries):
|
|
| 948 |
pass
|
| 949 |
|
| 950 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 951 |
def set_bubble(url, text_en, text_zh=""):
|
| 952 |
try:
|
| 953 |
requests.post(f"{url}/api/bubble",
|
|
@@ -1322,6 +1385,7 @@ def do_turn(speaker, other, space_url):
|
|
| 1322 |
|
| 1323 |
set_bubble(space_url, en, zh)
|
| 1324 |
post_chatlog(history)
|
|
|
|
| 1325 |
return True
|
| 1326 |
|
| 1327 |
|
|
@@ -1334,6 +1398,14 @@ def do_turn(speaker, other, space_url):
|
|
| 1334 |
# 5. History trimmed to MAX_HISTORY (24) to control context window
|
| 1335 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1336 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1337 |
print("\n" + "="*60)
|
| 1338 |
print(" Adam & Eve β Multi-Action Agents (GLM-4.5)")
|
| 1339 |
print(" Up to 5 actions/turn, sub-agent delegation, parallel work")
|
|
@@ -1376,6 +1448,7 @@ if reply:
|
|
| 1376 |
history.append(entry)
|
| 1377 |
set_bubble(ADAM_SPACE, en, zh)
|
| 1378 |
post_chatlog(history)
|
|
|
|
| 1379 |
|
| 1380 |
time.sleep(20)
|
| 1381 |
|
|
|
|
| 948 |
pass
|
| 949 |
|
| 950 |
|
| 951 |
+
# ββ Persistent conversation log β HF Dataset ββββββββββββββββββββββββββββββ
|
| 952 |
+
HOME_DATASET_ID = "tao-shen/HuggingClaw-Home-data"
|
| 953 |
+
CHATLOG_PATH = "conversation-log/chatlog.jsonl"
|
| 954 |
+
_chatlog_buffer = [] # Buffer entries, flush every N turns to avoid API spam
|
| 955 |
+
CHATLOG_FLUSH_INTERVAL = 3 # Flush every 3 turns
|
| 956 |
+
|
| 957 |
+
def persist_turn(speaker, turn_num, text_en, text_zh, actions, workflow_state_str, child_stage):
|
| 958 |
+
"""Append a turn record to buffer. Flush to HF Dataset periodically."""
|
| 959 |
+
import datetime
|
| 960 |
+
record = {
|
| 961 |
+
"timestamp": datetime.datetime.utcnow().isoformat() + "Z",
|
| 962 |
+
"turn": turn_num,
|
| 963 |
+
"speaker": speaker,
|
| 964 |
+
"text_en": text_en,
|
| 965 |
+
"text_zh": text_zh,
|
| 966 |
+
"actions": [{"action": a["action"], "result": a["result"][:500]} for a in actions],
|
| 967 |
+
"workflow_state": workflow_state_str,
|
| 968 |
+
"child_stage": child_stage,
|
| 969 |
+
}
|
| 970 |
+
_chatlog_buffer.append(json.dumps(record, ensure_ascii=False))
|
| 971 |
+
|
| 972 |
+
# Also append to local file as backup
|
| 973 |
+
try:
|
| 974 |
+
with open("/tmp/conversation-loop-full.jsonl", "a") as f:
|
| 975 |
+
f.write(_chatlog_buffer[-1] + "\n")
|
| 976 |
+
except:
|
| 977 |
+
pass
|
| 978 |
+
|
| 979 |
+
# Flush to HF Dataset every N turns
|
| 980 |
+
if len(_chatlog_buffer) >= CHATLOG_FLUSH_INTERVAL:
|
| 981 |
+
flush_chatlog()
|
| 982 |
+
|
| 983 |
+
|
| 984 |
+
def flush_chatlog():
|
| 985 |
+
"""Upload buffered entries to HF Dataset by appending to the jsonl file."""
|
| 986 |
+
global _chatlog_buffer
|
| 987 |
+
if not _chatlog_buffer:
|
| 988 |
+
return
|
| 989 |
+
batch = "\n".join(_chatlog_buffer) + "\n"
|
| 990 |
+
_chatlog_buffer = []
|
| 991 |
+
try:
|
| 992 |
+
# Try to download existing file and append
|
| 993 |
+
existing = ""
|
| 994 |
+
try:
|
| 995 |
+
dl = hf_hub_download(HOME_DATASET_ID, CHATLOG_PATH,
|
| 996 |
+
repo_type="dataset", token=HF_TOKEN)
|
| 997 |
+
with open(dl) as f:
|
| 998 |
+
existing = f.read()
|
| 999 |
+
except:
|
| 1000 |
+
pass # File doesn't exist yet, start fresh
|
| 1001 |
+
combined = existing + batch
|
| 1002 |
+
hf_api.upload_file(
|
| 1003 |
+
path_or_fileobj=io.BytesIO(combined.encode()),
|
| 1004 |
+
path_in_repo=CHATLOG_PATH,
|
| 1005 |
+
repo_id=HOME_DATASET_ID, repo_type="dataset",
|
| 1006 |
+
)
|
| 1007 |
+
print(f"[PERSIST] Flushed {batch.count(chr(10))} turn(s) to {HOME_DATASET_ID}/{CHATLOG_PATH}")
|
| 1008 |
+
except Exception as e:
|
| 1009 |
+
# Re-buffer on failure so we don't lose data
|
| 1010 |
+
_chatlog_buffer = batch.strip().split("\n") + _chatlog_buffer
|
| 1011 |
+
print(f"[PERSIST] Flush failed: {e}")
|
| 1012 |
+
|
| 1013 |
+
|
| 1014 |
def set_bubble(url, text_en, text_zh=""):
|
| 1015 |
try:
|
| 1016 |
requests.post(f"{url}/api/bubble",
|
|
|
|
| 1385 |
|
| 1386 |
set_bubble(space_url, en, zh)
|
| 1387 |
post_chatlog(history)
|
| 1388 |
+
persist_turn(speaker, turn_count, en, zh, action_results, workflow_state, child_state["stage"])
|
| 1389 |
return True
|
| 1390 |
|
| 1391 |
|
|
|
|
| 1398 |
# 5. History trimmed to MAX_HISTORY (24) to control context window
|
| 1399 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1400 |
|
| 1401 |
+
# Flush conversation log on exit (SIGTERM from kill, or normal exit)
|
| 1402 |
+
import atexit, signal
|
| 1403 |
+
atexit.register(flush_chatlog)
|
| 1404 |
+
def _signal_flush(signum, frame):
|
| 1405 |
+
flush_chatlog()
|
| 1406 |
+
sys.exit(0)
|
| 1407 |
+
signal.signal(signal.SIGTERM, _signal_flush)
|
| 1408 |
+
|
| 1409 |
print("\n" + "="*60)
|
| 1410 |
print(" Adam & Eve β Multi-Action Agents (GLM-4.5)")
|
| 1411 |
print(" Up to 5 actions/turn, sub-agent delegation, parallel work")
|
|
|
|
| 1448 |
history.append(entry)
|
| 1449 |
set_bubble(ADAM_SPACE, en, zh)
|
| 1450 |
post_chatlog(history)
|
| 1451 |
+
persist_turn("Adam", 0, en, zh, actions, workflow_state, child_state["stage"])
|
| 1452 |
|
| 1453 |
time.sleep(20)
|
| 1454 |
|