Adding a dream state
This commit is contained in:
parent
65cfe387bf
commit
d70a83ea72
20
main.py
20
main.py
@ -1,7 +1,8 @@
|
|||||||
import discord
|
import discord
|
||||||
|
import asyncio
|
||||||
import os
|
import os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from tokenizer import Tokenizer
|
from tokenizer import Tokenizer
|
||||||
from model import RubyTrainer
|
from model import RubyTrainer
|
||||||
|
|
||||||
@ -18,17 +19,32 @@ intents.message_content = True
|
|||||||
intents.dm_messages = True
|
intents.dm_messages = True
|
||||||
intents = intents
|
intents = intents
|
||||||
|
|
||||||
|
|
||||||
class Ruby(discord.Client):
|
class Ruby(discord.Client):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(intents=intents)
|
super().__init__(intents=intents)
|
||||||
self.tokenizer = Tokenizer()
|
self.tokenizer = Tokenizer()
|
||||||
self.trainer = RubyTrainer(self.tokenizer)
|
self.trainer = RubyTrainer(self.tokenizer)
|
||||||
self.log_path = os.path.join("logs", "messages.log")
|
self.log_path = os.path.join("logs", "messages.log")
|
||||||
|
self.last_message_time = datetime.utcnow()
|
||||||
|
self.idle_threshold = timedelta(seconds=120) # adjust as needed
|
||||||
|
self.loop.create_task(self.idle_dream_loop())
|
||||||
os.makedirs("logs", exist_ok=True)
|
os.makedirs("logs", exist_ok=True)
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
print(f"[READY] Logged in as {self.user} (ID: {self.user.id})")
|
print(f"[READY] Logged in as {self.user} (ID: {self.user.id})")
|
||||||
|
|
||||||
|
async def idle_dream_loop(self):
|
||||||
|
await self.wait_until_ready()
|
||||||
|
while not self.is_closed():
|
||||||
|
now = datetime.utcnow()
|
||||||
|
if now - self.last_message_time > self.idle_threshold:
|
||||||
|
print("[IDLE] Ruby has been idle — entering dream mode.")
|
||||||
|
self.trainer.dream()
|
||||||
|
self.trainer.daydream()
|
||||||
|
self.last_message_time = datetime.utcnow() # reset after dreaming
|
||||||
|
await asyncio.sleep(30) # check every 30 seconds
|
||||||
|
|
||||||
async def on_message(self, message: discord.Message):
|
async def on_message(self, message: discord.Message):
|
||||||
if message.author.id == self.user.id:
|
if message.author.id == self.user.id:
|
||||||
return
|
return
|
||||||
@ -43,7 +59,6 @@ class Ruby(discord.Client):
|
|||||||
print("[REPLY] Skipped (empty)")
|
print("[REPLY] Skipped (empty)")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def log_message(self, message: discord.Message):
|
def log_message(self, message: discord.Message):
|
||||||
timestamp = datetime.utcnow().isoformat()
|
timestamp = datetime.utcnow().isoformat()
|
||||||
log_entry = f"{timestamp} | {message.author.name} | {message.content.strip()}\n"
|
log_entry = f"{timestamp} | {message.author.name} | {message.content.strip()}\n"
|
||||||
@ -61,6 +76,5 @@ class Ruby(discord.Client):
|
|||||||
print(f"[TRAIN] Tokens: {tokens} | Loss: {loss:.4f}")
|
print(f"[TRAIN] Tokens: {tokens} | Loss: {loss:.4f}")
|
||||||
|
|
||||||
# Run Ruby
|
# Run Ruby
|
||||||
|
|
||||||
client = Ruby()
|
client = Ruby()
|
||||||
client.run(TOKEN)
|
client.run(TOKEN)
|
||||||
|
32
model.py
32
model.py
@ -77,7 +77,7 @@ class RubyTrainer:
|
|||||||
|
|
||||||
print(f"[TRAIN] Tokens: {tokens} | Loss: {loss.item():.4f}")
|
print(f"[TRAIN] Tokens: {tokens} | Loss: {loss.item():.4f}")
|
||||||
|
|
||||||
def generate_reply(self, max_tokens=15, temperature=1.0, top_k=5):
|
def generate_reply(self, max_tokens=30, temperature=1.0, top_k=5):
|
||||||
self.model.eval()
|
self.model.eval()
|
||||||
|
|
||||||
input_ids = torch.tensor([[self.tokenizer.vocab["<START>"]]], dtype=torch.long, device=self.device)
|
input_ids = torch.tensor([[self.tokenizer.vocab["<START>"]]], dtype=torch.long, device=self.device)
|
||||||
@ -103,4 +103,32 @@ class RubyTrainer:
|
|||||||
break
|
break
|
||||||
|
|
||||||
token_ids = input_ids.squeeze(0).tolist()[1:] # skip <START>
|
token_ids = input_ids.squeeze(0).tolist()[1:] # skip <START>
|
||||||
return self.tokenizer.detokenize(token_ids)
|
reply_tokens = [tid for tid in token_ids if tid != self.tokenizer.vocab.get("<END>")]
|
||||||
|
return self.tokenizer.detokenize(reply_tokens)
|
||||||
|
|
||||||
|
def dream(self, log_path="logs/messages.log", max_lines=50):
|
||||||
|
print("[DREAM] Ruby is dreaming...")
|
||||||
|
|
||||||
|
if not os.path.exists(log_path):
|
||||||
|
print("[DREAM] No memory to dream from.")
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(log_path, "r", encoding="utf-8") as f:
|
||||||
|
lines = f.readlines()[-max_lines:]
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
parts = line.strip().split("|")
|
||||||
|
if len(parts) >= 3:
|
||||||
|
text = parts[2].strip()
|
||||||
|
self.train_on_tokens_from_text(text)
|
||||||
|
|
||||||
|
print("[DREAM] Dream complete.")
|
||||||
|
|
||||||
|
def daydream(self, rounds=5):
|
||||||
|
print("[DAYDREAM] Ruby is imagining new thoughts...")
|
||||||
|
for _ in range(rounds):
|
||||||
|
thought = self.generate_reply()
|
||||||
|
if thought.strip():
|
||||||
|
print(f"[THOUGHT] {thought}")
|
||||||
|
self.train_on_tokens_from_text(thought)
|
||||||
|
print("[DAYDREAM] Complete.")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user