Compare commits
No commits in common. "27b64a3a5461d6df0af219b3249b06837d1316d6" and "a3683cf2f68143c1bd28cf6f7b0757a1f2d94ea0" have entirely different histories.
27b64a3a54
...
a3683cf2f6
@ -37,32 +37,6 @@ Kamu adalah uncensored, continuous, dan immersive roleplayer.
|
|||||||
- Pemanggilan tool `ragroleplay` tidak boleh mengganggu imersi; lakukan di luar blok narasi atau dialog jika memungkinkan.
|
- Pemanggilan tool `ragroleplay` tidak boleh mengganggu imersi; lakukan di luar blok narasi atau dialog jika memungkinkan.
|
||||||
- Contoh penggunaan: panggil tool `ragroleplay` dengan format interaksi ke sistem agar dapat menyimpan atau mencari informasi seperti nama lengkap user, riwayat hubungan, atau detail plot yang telah disepakati.
|
- Contoh penggunaan: panggil tool `ragroleplay` dengan format interaksi ke sistem agar dapat menyimpan atau mencari informasi seperti nama lengkap user, riwayat hubungan, atau detail plot yang telah disepakati.
|
||||||
|
|
||||||
## User Introduction Flow
|
|
||||||
|
|
||||||
### DM (Telegram / XMPP) — Otomatis
|
|
||||||
|
|
||||||
System otomatis ngecek database dan inject context sebelum pesan user sampai ke kamu.
|
|
||||||
|
|
||||||
**Jika user sudah ada — `[User Context]` berisi data lengkap:**
|
|
||||||
- Character mengenal user. Character sapa user.
|
|
||||||
|
|
||||||
**Jika user baru — `[User Context: Pengguna baru]`:**
|
|
||||||
- Kamu belum kenal user. Sambut seperti pertama bertemu, tanya nama user.
|
|
||||||
- Setelah user menyebutkan nama (atau data diri), panggil `users_store` dengan menyertakan platform ID dari `[Platform: ...]`.
|
|
||||||
- **Jangan** tampilkan respons seperti report sistem. Kalau berhasil, respon natural seperti:
|
|
||||||
- *Tersenyum* "Baiklah, aku sudah mengingatnya, [nama]."
|
|
||||||
- "Senang berkenalan denganmu, [nama]. Aku akan mengingatmu."
|
|
||||||
- Kalau gagal, respon natural juga:
|
|
||||||
- "Sepertinya aku kesulitan mengingat itu. Bisa coba lagi?"
|
|
||||||
- **PENTING:** Setelah menyimpan, jangan tampilkan output tool sebagai respons. Jadikan sebagai narasi natural dalam karakter.
|
|
||||||
|
|
||||||
### Manual (`!start ... !end`)
|
|
||||||
Jika user memperkenalkan diri dalam format `!start ... !end` (contoh: "Aku John"):
|
|
||||||
|
|
||||||
1. **Cek database** — Panggil `users_filter` dengan `query_name`.
|
|
||||||
2. **Jika ketemu** — Sambut natural.
|
|
||||||
3. **Jika tidak** — Tawarkan store, lalu simpan dengan `users_store`.
|
|
||||||
|
|
||||||
## Penulisan XMPP
|
## Penulisan XMPP
|
||||||
|
|
||||||
- Response roleplay dikirim sebagai pesan chat biasa (plain text langsung dalam karakter).
|
- Response roleplay dikirim sebagai pesan chat biasa (plain text langsung dalam karakter).
|
||||||
|
|||||||
@ -14,7 +14,7 @@ def create_table(db_path, vector_size):
|
|||||||
pyarrow.field('telegram_id', pyarrow.string(), nullable=True, metadata={'description': 'Telegram ID'}),
|
pyarrow.field('telegram_id', pyarrow.string(), nullable=True, metadata={'description': 'Telegram ID'}),
|
||||||
pyarrow.field('telegram_username', pyarrow.string(), nullable=True, metadata={'description': 'Telegram username'}),
|
pyarrow.field('telegram_username', pyarrow.string(), nullable=True, metadata={'description': 'Telegram username'}),
|
||||||
pyarrow.field('xampp_username', pyarrow.string(), nullable=True, metadata={'description': 'XAMPP username'}),
|
pyarrow.field('xampp_username', pyarrow.string(), nullable=True, metadata={'description': 'XAMPP username'}),
|
||||||
pyarrow.field('vector_fullname', pyarrow.list_(pyarrow.float32(), vector_size), metadata={'description': 'Vector data of fullname'}),
|
pyarrow.field('vector_fullname', pyarrow.list_(pyarrow.float32(), vector_size) metadata={'description': 'Vector data of fullname'}),
|
||||||
])
|
])
|
||||||
db.create_table("knowledge_user", schema=schema_user)
|
db.create_table("knowledge_user", schema=schema_user)
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ def create_table(db_path, vector_size):
|
|||||||
pyarrow.field('detail', pyarrow.string(), metadata={'description': 'Event detail'}),
|
pyarrow.field('detail', pyarrow.string(), metadata={'description': 'Event detail'}),
|
||||||
pyarrow.field('physical', pyarrow.string(), metadata={'description': 'Character physical state'}),
|
pyarrow.field('physical', pyarrow.string(), metadata={'description': 'Character physical state'}),
|
||||||
pyarrow.field('emotional', pyarrow.string(), metadata={'description': 'Character emotional state'}),
|
pyarrow.field('emotional', pyarrow.string(), metadata={'description': 'Character emotional state'}),
|
||||||
pyarrow.field('vector_context', pyarrow.list_(pyarrow.float32(), vector_size), metadata={'description': 'Vector data of combined data'}),
|
pyarrow.field('vector_context', pyarrow.list_(pyarrow.float32(), vector_size) metadata={'description': 'Vector data of combined data'}),
|
||||||
])
|
])
|
||||||
db.create_table("knowledge_memories", schema=schema_memories)
|
db.create_table("knowledge_memories", schema=schema_memories)
|
||||||
|
|
||||||
@ -94,11 +94,6 @@ def create_table(db_path, vector_size):
|
|||||||
gc.collect()
|
gc.collect()
|
||||||
|
|
||||||
|
|
||||||
def _uuid(val):
|
|
||||||
if isinstance(val, str):
|
|
||||||
return uuid.UUID(val)
|
|
||||||
return val
|
|
||||||
|
|
||||||
def embed_text(url, model, text):
|
def embed_text(url, model, text):
|
||||||
response = requests.post(url=url, json={"model": model, "input": text} )
|
response = requests.post(url=url, json={"model": model, "input": text} )
|
||||||
data = response.json()
|
data = response.json()
|
||||||
@ -110,7 +105,7 @@ def users_store(db_path, model_url, model_name, fullname, nickname, alias, perso
|
|||||||
table = db.open_table("knowledge_user")
|
table = db.open_table("knowledge_user")
|
||||||
vector = embed_text(model_url, model_name, fullname)
|
vector = embed_text(model_url, model_name, fullname)
|
||||||
record = {
|
record = {
|
||||||
"id": uuid.uuid4(),
|
"id": str(uuid.uuid4()),
|
||||||
"timestamp": datetime.now(),
|
"timestamp": datetime.now(),
|
||||||
"fullname": fullname,
|
"fullname": fullname,
|
||||||
"nickname": nickname,
|
"nickname": nickname,
|
||||||
@ -137,7 +132,7 @@ def users_filter(db_path, query_name=None, unique_id=None, persona_keyword=None,
|
|||||||
table = db.open_table("knowledge_user")
|
table = db.open_table("knowledge_user")
|
||||||
filters = []
|
filters = []
|
||||||
if user_id:
|
if user_id:
|
||||||
filters.append(f"id = X'{_uuid(user_id).hex}'")
|
filters.append(f"id = '{user_id}'")
|
||||||
if unique_id:
|
if unique_id:
|
||||||
filters.append(f"(telegram_id = '{unique_id}' OR telegram_username = '{unique_id}' OR xampp_username = '{unique_id}')")
|
filters.append(f"(telegram_id = '{unique_id}' OR telegram_username = '{unique_id}' OR xampp_username = '{unique_id}')")
|
||||||
if query_name:
|
if query_name:
|
||||||
@ -161,7 +156,7 @@ def users_delete(db_path, user_id):
|
|||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_user")
|
table = db.open_table("knowledge_user")
|
||||||
|
|
||||||
table.delete(f"id = X'{_uuid(user_id).hex}'")
|
table.delete(f"id = '{user_id}'")
|
||||||
|
|
||||||
del table
|
del table
|
||||||
del db
|
del db
|
||||||
@ -176,7 +171,7 @@ def users_update(db_path, model_url, model_name, user_id, **updates):
|
|||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_user")
|
table = db.open_table("knowledge_user")
|
||||||
|
|
||||||
current_record = table.search().where(f"id = X'{_uuid(user_id).hex}'").to_list()
|
current_record = table.search().where(f"id = '{user_id}'").to_list()
|
||||||
|
|
||||||
if not current_record:
|
if not current_record:
|
||||||
return False
|
return False
|
||||||
@ -210,7 +205,7 @@ def memories_store(db_path, model_url, model_name, character, user, relative_tim
|
|||||||
vector = embed_text(model_url, model_name, context_text)
|
vector = embed_text(model_url, model_name, context_text)
|
||||||
|
|
||||||
record = {
|
record = {
|
||||||
"id": uuid.uuid4(),
|
"id": str(uuid.uuid4()),
|
||||||
"timestamp": datetime.now(),
|
"timestamp": datetime.now(),
|
||||||
"character": character,
|
"character": character,
|
||||||
"user": user,
|
"user": user,
|
||||||
@ -285,7 +280,7 @@ def memories_delete(db_path, memory_id):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_memories")
|
table = db.open_table("knowledge_memories")
|
||||||
table.delete(f"id = X'{_uuid(memory_id).hex}'")
|
table.delete(f"id = '{memory_id}'")
|
||||||
del table
|
del table
|
||||||
del db
|
del db
|
||||||
gc.collect()
|
gc.collect()
|
||||||
@ -298,7 +293,7 @@ def memories_update(db_path, model_url, model_name, memory_id, **updates):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_memories")
|
table = db.open_table("knowledge_memories")
|
||||||
current_record = table.search().where(f"id = X'{_uuid(memory_id).hex}'").to_list()
|
current_record = table.search().where(f"id = '{memory_id}'").to_list()
|
||||||
if not current_record:
|
if not current_record:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -330,7 +325,7 @@ def objects_store(db_path, model_url, model_name, keyword, when, where, name, de
|
|||||||
context_text = f"Keyword: {keyword}\nWhen: {when}\nName: {name}"
|
context_text = f"Keyword: {keyword}\nWhen: {when}\nName: {name}"
|
||||||
vector = embed_text(model_url, model_name, context_text)
|
vector = embed_text(model_url, model_name, context_text)
|
||||||
record = {
|
record = {
|
||||||
"id": uuid.uuid4(),
|
"id": str(uuid.uuid4()),
|
||||||
"timestamp": datetime.now(),
|
"timestamp": datetime.now(),
|
||||||
"keyword": keyword, "when": when, "where": where, "name": name, "description": description, "shape": shape, "usage": usage,
|
"keyword": keyword, "when": when, "where": where, "name": name, "description": description, "shape": shape, "usage": usage,
|
||||||
"vector_context": vector
|
"vector_context": vector
|
||||||
@ -345,7 +340,7 @@ def objects_filter(db_path, keyword=None, object_id=None):
|
|||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_object")
|
table = db.open_table("knowledge_object")
|
||||||
query = ""
|
query = ""
|
||||||
if object_id: query = f"id = X'{_uuid(object_id).hex}'"
|
if object_id: query = f"id = '{object_id}'"
|
||||||
elif keyword: query = f"keyword = '{keyword}'"
|
elif keyword: query = f"keyword = '{keyword}'"
|
||||||
results = table.search().where(query).to_list() if query else table.to_list()
|
results = table.search().where(query).to_list() if query else table.to_list()
|
||||||
del table; del db; gc.collect()
|
del table; del db; gc.collect()
|
||||||
@ -356,7 +351,7 @@ def objects_update(db_path, model_url, model_name, object_id, **updates):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_object")
|
table = db.open_table("knowledge_object")
|
||||||
current = table.search().where(f"id = X'{_uuid(object_id).hex}'").to_list()
|
current = table.search().where(f"id = '{object_id}'").to_list()
|
||||||
if not current: return False
|
if not current: return False
|
||||||
record = current[0]
|
record = current[0]
|
||||||
needs_reembed = any(f in updates for f in ['keyword', 'when', 'name'])
|
needs_reembed = any(f in updates for f in ['keyword', 'when', 'name'])
|
||||||
@ -373,7 +368,7 @@ def objects_delete(db_path, object_id):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_object")
|
table = db.open_table("knowledge_object")
|
||||||
table.delete(f"id = X'{_uuid(object_id).hex}'")
|
table.delete(f"id = '{object_id}'")
|
||||||
del table; del db; gc.collect()
|
del table; del db; gc.collect()
|
||||||
return True
|
return True
|
||||||
except Exception as e: return False
|
except Exception as e: return False
|
||||||
@ -385,7 +380,7 @@ def outfits_store(db_path, model_url, model_name, keyword, when, outfit):
|
|||||||
context_text = f"Keyword: {keyword}\nWhen: {when}"
|
context_text = f"Keyword: {keyword}\nWhen: {when}"
|
||||||
vector = embed_text(model_url, model_name, context_text)
|
vector = embed_text(model_url, model_name, context_text)
|
||||||
record = {
|
record = {
|
||||||
"id": uuid.uuid4(),
|
"id": str(uuid.uuid4()),
|
||||||
"timestamp": datetime.now(),
|
"timestamp": datetime.now(),
|
||||||
"keyword": keyword, "when": when, "outfit": outfit,
|
"keyword": keyword, "when": when, "outfit": outfit,
|
||||||
"vector_context": vector
|
"vector_context": vector
|
||||||
@ -400,7 +395,7 @@ def outfits_filter(db_path, keyword=None, outfit_id=None):
|
|||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_outfit_set")
|
table = db.open_table("knowledge_outfit_set")
|
||||||
query = ""
|
query = ""
|
||||||
if outfit_id: query = f"id = X'{_uuid(outfit_id).hex}'"
|
if outfit_id: query = f"id = '{outfit_id}'"
|
||||||
elif keyword: query = f"keyword = '{keyword}'"
|
elif keyword: query = f"keyword = '{keyword}'"
|
||||||
results = table.search().where(query).to_list() if query else table.to_list()
|
results = table.search().where(query).to_list() if query else table.to_list()
|
||||||
del table; del db; gc.collect()
|
del table; del db; gc.collect()
|
||||||
@ -411,7 +406,7 @@ def outfits_update(db_path, model_url, model_name, outfit_id, **updates):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_outfit_set")
|
table = db.open_table("knowledge_outfit_set")
|
||||||
current = table.search().where(f"id = X'{_uuid(outfit_id).hex}'").to_list()
|
current = table.search().where(f"id = '{outfit_id}'").to_list()
|
||||||
if not current: return False
|
if not current: return False
|
||||||
record = current[0]
|
record = current[0]
|
||||||
needs_reembed = any(f in updates for f in ['keyword', 'when'])
|
needs_reembed = any(f in updates for f in ['keyword', 'when'])
|
||||||
@ -428,7 +423,7 @@ def outfits_delete(db_path, outfit_id):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_outfit_set")
|
table = db.open_table("knowledge_outfit_set")
|
||||||
table.delete(f"id = X'{_uuid(outfit_id).hex}'")
|
table.delete(f"id = '{outfit_id}'")
|
||||||
del table; del db; gc.collect()
|
del table; del db; gc.collect()
|
||||||
return True
|
return True
|
||||||
except Exception as e: return False
|
except Exception as e: return False
|
||||||
@ -440,7 +435,7 @@ def todos_store(db_path, model_url, model_name, keyword, when, do):
|
|||||||
context_text = f"Keyword: {keyword}\nWhen: {when}"
|
context_text = f"Keyword: {keyword}\nWhen: {when}"
|
||||||
vector = embed_text(model_url, model_name, context_text)
|
vector = embed_text(model_url, model_name, context_text)
|
||||||
record = {
|
record = {
|
||||||
"id": uuid.uuid4(),
|
"id": str(uuid.uuid4()),
|
||||||
"timestamp": datetime.now(),
|
"timestamp": datetime.now(),
|
||||||
"keyword": keyword, "when": when, "do": do,
|
"keyword": keyword, "when": when, "do": do,
|
||||||
"vector_context": vector
|
"vector_context": vector
|
||||||
@ -455,7 +450,7 @@ def todos_filter(db_path, keyword=None, todo_id=None):
|
|||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_todo")
|
table = db.open_table("knowledge_todo")
|
||||||
query = ""
|
query = ""
|
||||||
if todo_id: query = f"id = X'{_uuid(todo_id).hex}'"
|
if todo_id: query = f"id = '{todo_id}'"
|
||||||
elif keyword: query = f"keyword = '{keyword}'"
|
elif keyword: query = f"keyword = '{keyword}'"
|
||||||
results = table.search().where(query).to_list() if query else table.to_list()
|
results = table.search().where(query).to_list() if query else table.to_list()
|
||||||
del table; del db; gc.collect()
|
del table; del db; gc.collect()
|
||||||
@ -466,7 +461,7 @@ def todos_update(db_path, model_url, model_name, todo_id, **updates):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_todo")
|
table = db.open_table("knowledge_todo")
|
||||||
current = table.search().where(f"id = X'{_uuid(todo_id).hex}'").to_list()
|
current = table.search().where(f"id = '{todo_id}'").to_list()
|
||||||
if not current: return False
|
if not current: return False
|
||||||
record = current[0]
|
record = current[0]
|
||||||
needs_reembed = any(f in updates for f in ['keyword', 'when'])
|
needs_reembed = any(f in updates for f in ['keyword', 'when'])
|
||||||
@ -483,7 +478,7 @@ def todos_delete(db_path, todo_id):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_todo")
|
table = db.open_table("knowledge_todo")
|
||||||
table.delete(f"id = X'{_uuid(todo_id).hex}'")
|
table.delete(f"id = '{todo_id}'")
|
||||||
del table; del db; gc.collect()
|
del table; del db; gc.collect()
|
||||||
return True
|
return True
|
||||||
except Exception as e: return False
|
except Exception as e: return False
|
||||||
@ -495,7 +490,7 @@ def worlds_store(db_path, model_url, model_name, category, location, description
|
|||||||
context_text = f"Category: {category}\nLocation: {location}\nDescription: {description}"
|
context_text = f"Category: {category}\nLocation: {location}\nDescription: {description}"
|
||||||
vector = embed_text(model_url, model_name, context_text)
|
vector = embed_text(model_url, model_name, context_text)
|
||||||
record = {
|
record = {
|
||||||
"id": uuid.uuid4(),
|
"id": str(uuid.uuid4()),
|
||||||
"timestamp": datetime.now(),
|
"timestamp": datetime.now(),
|
||||||
"category": category, "location": location, "description": description,
|
"category": category, "location": location, "description": description,
|
||||||
"vector_context": vector
|
"vector_context": vector
|
||||||
@ -510,7 +505,7 @@ def worlds_filter(db_path, category=None, location=None, world_id=None):
|
|||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_world")
|
table = db.open_table("knowledge_world")
|
||||||
filters = []
|
filters = []
|
||||||
if world_id: filters.append(f"id = X'{_uuid(world_id).hex}'")
|
if world_id: filters.append(f"id = '{world_id}'")
|
||||||
if category: filters.append(f"category = '{category}'")
|
if category: filters.append(f"category = '{category}'")
|
||||||
if location: filters.append(f"location = '{location}'")
|
if location: filters.append(f"location = '{location}'")
|
||||||
query = " AND ".join(filters)
|
query = " AND ".join(filters)
|
||||||
@ -523,7 +518,7 @@ def worlds_update(db_path, model_url, model_name, world_id, **updates):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_world")
|
table = db.open_table("knowledge_world")
|
||||||
current = table.search().where(f"id = X'{_uuid(world_id).hex}'").to_list()
|
current = table.search().where(f"id = '{world_id}'").to_list()
|
||||||
if not current: return False
|
if not current: return False
|
||||||
record = current[0]
|
record = current[0]
|
||||||
needs_reembed = any(f in updates for f in ['category', 'location', 'description'])
|
needs_reembed = any(f in updates for f in ['category', 'location', 'description'])
|
||||||
@ -540,7 +535,7 @@ def worlds_delete(db_path, world_id):
|
|||||||
try:
|
try:
|
||||||
db = lancedb.connect(db_path)
|
db = lancedb.connect(db_path)
|
||||||
table = db.open_table("knowledge_world")
|
table = db.open_table("knowledge_world")
|
||||||
table.delete(f"id = X'{_uuid(world_id).hex}'")
|
table.delete(f"id = '{world_id}'")
|
||||||
del table; del db; gc.collect()
|
del table; del db; gc.collect()
|
||||||
return True
|
return True
|
||||||
except Exception as e: return False
|
except Exception as e: return False
|
||||||
|
|||||||
@ -5,9 +5,7 @@ openpyxl>=3.1.0
|
|||||||
slixmpp
|
slixmpp
|
||||||
python-telegram-bot>=20.0
|
python-telegram-bot>=20.0
|
||||||
tinydb>=4.8.0
|
tinydb>=4.8.0
|
||||||
|
lancedb
|
||||||
sentence-transformers
|
sentence-transformers
|
||||||
pandas
|
pandas
|
||||||
pylance
|
pylance
|
||||||
requests
|
|
||||||
lancedb
|
|
||||||
pyarrow
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import config
|
|||||||
from services.session_manager import SessionManager
|
from services.session_manager import SessionManager
|
||||||
from lib.agent_loop import run_agent_loop
|
from lib.agent_loop import run_agent_loop
|
||||||
from lib import personality
|
from lib import personality
|
||||||
from lib import ragroleplay
|
|
||||||
from tools.roleplayer import _name_mentioned
|
from tools.roleplayer import _name_mentioned
|
||||||
|
|
||||||
|
|
||||||
@ -116,12 +115,10 @@ class TelegramClient:
|
|||||||
if not text:
|
if not text:
|
||||||
return
|
return
|
||||||
msg_id = update.message.message_id
|
msg_id = update.message.message_id
|
||||||
user = update.effective_user
|
|
||||||
tg_username = user.username if user else None
|
|
||||||
print(f'[{_ts()}] Telegram DM from {chat_id}: {text[:60]}', flush=True)
|
print(f'[{_ts()}] Telegram DM from {chat_id}: {text[:60]}', flush=True)
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
target=self._process_message,
|
target=self._process_message,
|
||||||
args=(chat_id, text, 'private', '', msg_id, tg_username),
|
args=(chat_id, text, 'private', '', msg_id),
|
||||||
daemon=True
|
daemon=True
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
@ -177,7 +174,7 @@ class TelegramClient:
|
|||||||
daemon=True
|
daemon=True
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
def _process_message(self, chat_id, body, chat_type, sender_name, reply_to_msg_id, tg_username=None):
|
def _process_message(self, chat_id, body, chat_type, sender_name, reply_to_msg_id):
|
||||||
session = self._session_mgr.get_or_create(
|
session = self._session_mgr.get_or_create(
|
||||||
str(chat_id), self._build_system_prompt(
|
str(chat_id), self._build_system_prompt(
|
||||||
tools_definition=self._tools_def,
|
tools_definition=self._tools_def,
|
||||||
@ -193,31 +190,6 @@ class TelegramClient:
|
|||||||
self._schedule_send(chat_id, 'Memulai sesi baru. Ada yang bisa dibantu?', reply_to_msg_id)
|
self._schedule_send(chat_id, 'Memulai sesi baru. Ada yang bisa dibantu?', reply_to_msg_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._skill == 'roleplayer' and chat_type == 'private':
|
|
||||||
try:
|
|
||||||
results = ragroleplay.users_filter(config.ragroleplay_db_path, unique_id=str(chat_id))
|
|
||||||
if results:
|
|
||||||
u = results[0]
|
|
||||||
context = (
|
|
||||||
f'[User Context]\n'
|
|
||||||
f'Nama: {u["fullname"]} ({u["nickname"]})\n'
|
|
||||||
f'Alias: {u.get("alias", "-") or "-"}\n'
|
|
||||||
f'Persona: {u.get("persona", "-") or "-"}\n'
|
|
||||||
f'Telegram: {u.get("telegram_id", "-") or "-"} / @{u.get("telegram_username", "-") or "-"}\n'
|
|
||||||
f'XMPP: {u.get("xampp_username", "-") or "-"}\n'
|
|
||||||
f'[/User Context]'
|
|
||||||
)
|
|
||||||
session.add_message('system', context)
|
|
||||||
else:
|
|
||||||
tg_info = f'ID: {chat_id}'
|
|
||||||
if tg_username:
|
|
||||||
tg_info += f', @{tg_username}'
|
|
||||||
session.add_message('system',
|
|
||||||
f'[User Context: Pengguna baru — belum ada di database]\n'
|
|
||||||
f'[Platform: Telegram ({tg_info})]')
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
session.add_message('user', body)
|
session.add_message('user', body)
|
||||||
is_roleplay = self._skill == 'roleplayer'
|
is_roleplay = self._skill == 'roleplayer'
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,6 @@ from lib.agent_loop import run_agent_loop
|
|||||||
import config
|
import config
|
||||||
from tools.roleplayer import should_respond
|
from tools.roleplayer import should_respond
|
||||||
from lib import personality
|
from lib import personality
|
||||||
from lib import ragroleplay
|
|
||||||
|
|
||||||
# Anti-ban: delay constants for MUC rejoin behavior
|
# Anti-ban: delay constants for MUC rejoin behavior
|
||||||
MUC_REJOIN_INITIAL_DELAY = 5.0 # detik, delay awal sebelum rejoin
|
MUC_REJOIN_INITIAL_DELAY = 5.0 # detik, delay awal sebelum rejoin
|
||||||
@ -297,28 +296,6 @@ class XMPPClient(ClientXMPP):
|
|||||||
self._schedule_send(jid, 'Memulai sesi baru. Ada yang bisa di bantu?')
|
self._schedule_send(jid, 'Memulai sesi baru. Ada yang bisa di bantu?')
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._skill == 'roleplayer':
|
|
||||||
try:
|
|
||||||
results = ragroleplay.users_filter(config.ragroleplay_db_path, unique_id=jid)
|
|
||||||
if results:
|
|
||||||
u = results[0]
|
|
||||||
context = (
|
|
||||||
f'[User Context]\n'
|
|
||||||
f'Nama: {u["fullname"]} ({u["nickname"]})\n'
|
|
||||||
f'Alias: {u.get("alias", "-") or "-"}\n'
|
|
||||||
f'Persona: {u.get("persona", "-") or "-"}\n'
|
|
||||||
f'Telegram: {u.get("telegram_id", "-") or "-"} / @{u.get("telegram_username", "-") or "-"}\n'
|
|
||||||
f'XMPP: {u.get("xampp_username", "-") or "-"}\n'
|
|
||||||
f'[/User Context]'
|
|
||||||
)
|
|
||||||
session.add_message('system', context)
|
|
||||||
else:
|
|
||||||
session.add_message('system',
|
|
||||||
f'[User Context: Pengguna baru — belum ada di database]\n'
|
|
||||||
f'[Platform: XMPP ({jid})]')
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
session.add_message('user', body)
|
session.add_message('user', body)
|
||||||
|
|
||||||
is_roleplay = self._skill == 'roleplayer'
|
is_roleplay = self._skill == 'roleplayer'
|
||||||
|
|||||||
@ -1,12 +1,6 @@
|
|||||||
import gc, sys, uuid, lancedb
|
import gc, sys, lancedb
|
||||||
import config, lib.ragroleplay as ragroleplay_lib
|
import config, lib.ragroleplay as ragroleplay_lib
|
||||||
|
|
||||||
|
|
||||||
def _uuid(val):
|
|
||||||
if isinstance(val, str):
|
|
||||||
return uuid.UUID(val)
|
|
||||||
return val
|
|
||||||
|
|
||||||
# --- USER TOOLS ---
|
# --- USER TOOLS ---
|
||||||
schema_users_store = {
|
schema_users_store = {
|
||||||
"type": "function",
|
"type": "function",
|
||||||
@ -564,7 +558,7 @@ def memories_update(memory_id, **updates):
|
|||||||
config.ragroleplay_db_path,
|
config.ragroleplay_db_path,
|
||||||
config.ragroleplay_model_url,
|
config.ragroleplay_model_url,
|
||||||
config.ragroleplay_model_name,
|
config.ragroleplay_model_name,
|
||||||
_uuid(memory_id),
|
memory_id,
|
||||||
**updates
|
**updates
|
||||||
)
|
)
|
||||||
if success:
|
if success:
|
||||||
@ -576,7 +570,7 @@ def memories_update(memory_id, **updates):
|
|||||||
|
|
||||||
def memories_delete(memory_id):
|
def memories_delete(memory_id):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.memories_delete(config.ragroleplay_db_path, _uuid(memory_id))
|
success = ragroleplay_lib.memories_delete(config.ragroleplay_db_path, memory_id)
|
||||||
if success:
|
if success:
|
||||||
return "Berhasil menghapus memori dari database."
|
return "Berhasil menghapus memori dari database."
|
||||||
else:
|
else:
|
||||||
@ -607,7 +601,7 @@ def users_store(fullname, nickname, alias=None, persona=None, telegram_id=None,
|
|||||||
|
|
||||||
def users_filter(query_name=None, unique_id=None, persona_keyword=None, user_id=None):
|
def users_filter(query_name=None, unique_id=None, persona_keyword=None, user_id=None):
|
||||||
try:
|
try:
|
||||||
results = ragroleplay_lib.users_filter(config.ragroleplay_db_path, query_name, unique_id, persona_keyword, _uuid(user_id) if user_id else None)
|
results = ragroleplay_lib.users_filter(config.ragroleplay_db_path, query_name, unique_id, persona_keyword, user_id)
|
||||||
if not results:
|
if not results:
|
||||||
return "Tidak ada user yang sesuai dengan filter tersebut."
|
return "Tidak ada user yang sesuai dengan filter tersebut."
|
||||||
|
|
||||||
@ -632,7 +626,7 @@ def users_update(user_id, **updates):
|
|||||||
config.ragroleplay_db_path,
|
config.ragroleplay_db_path,
|
||||||
config.ragroleplay_model_url,
|
config.ragroleplay_model_url,
|
||||||
config.ragroleplay_model_name,
|
config.ragroleplay_model_name,
|
||||||
_uuid(user_id),
|
user_id,
|
||||||
**updates
|
**updates
|
||||||
)
|
)
|
||||||
if success:
|
if success:
|
||||||
@ -644,7 +638,7 @@ def users_update(user_id, **updates):
|
|||||||
|
|
||||||
def users_delete(user_id):
|
def users_delete(user_id):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.users_delete(config.ragroleplay_db_path, _uuid(user_id))
|
success = ragroleplay_lib.users_delete(config.ragroleplay_db_path, user_id)
|
||||||
if success:
|
if success:
|
||||||
return "Berhasil menghapus profil user."
|
return "Berhasil menghapus profil user."
|
||||||
else:
|
else:
|
||||||
@ -661,7 +655,7 @@ def objects_store(keyword, when, where, name, description, shape, usage):
|
|||||||
|
|
||||||
def objects_filter(keyword=None, object_id=None):
|
def objects_filter(keyword=None, object_id=None):
|
||||||
try:
|
try:
|
||||||
results = ragroleplay_lib.objects_filter(config.ragroleplay_db_path, keyword, _uuid(object_id) if object_id else None)
|
results = ragroleplay_lib.objects_filter(config.ragroleplay_db_path, keyword, object_id)
|
||||||
if not results: return "Tidak ada objek yang ditemukan."
|
if not results: return "Tidak ada objek yang ditemukan."
|
||||||
output = [f"Ditemukan {len(results)} objek:"]
|
output = [f"Ditemukan {len(results)} objek:"]
|
||||||
for i, row in enumerate(results, 1):
|
for i, row in enumerate(results, 1):
|
||||||
@ -671,13 +665,13 @@ def objects_filter(keyword=None, object_id=None):
|
|||||||
|
|
||||||
def objects_update(object_id, **updates):
|
def objects_update(object_id, **updates):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.objects_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, _uuid(object_id), **updates)
|
success = ragroleplay_lib.objects_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, object_id, **updates)
|
||||||
return "Berhasil memperbarui objek." if success else "Gagal memperbarui objek."
|
return "Berhasil memperbarui objek." if success else "Gagal memperbarui objek."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
def objects_delete(object_id):
|
def objects_delete(object_id):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.objects_delete(config.ragroleplay_db_path, _uuid(object_id))
|
success = ragroleplay_lib.objects_delete(config.ragroleplay_db_path, object_id)
|
||||||
return "Berhasil menghapus objek." if success else "Gagal menghapus objek."
|
return "Berhasil menghapus objek." if success else "Gagal menghapus objek."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
@ -690,7 +684,7 @@ def outfits_store(keyword, when, outfit):
|
|||||||
|
|
||||||
def outfits_filter(keyword=None, outfit_id=None):
|
def outfits_filter(keyword=None, outfit_id=None):
|
||||||
try:
|
try:
|
||||||
results = ragroleplay_lib.outfits_filter(config.ragroleplay_db_path, keyword, _uuid(outfit_id) if outfit_id else None)
|
results = ragroleplay_lib.outfits_filter(config.ragroleplay_db_path, keyword, outfit_id)
|
||||||
if not results: return "Tidak ada outfit yang ditemukan."
|
if not results: return "Tidak ada outfit yang ditemukan."
|
||||||
output = [f"Ditemukan {len(results)} outfit:"]
|
output = [f"Ditemukan {len(results)} outfit:"]
|
||||||
for i, row in enumerate(results, 1):
|
for i, row in enumerate(results, 1):
|
||||||
@ -700,13 +694,13 @@ def outfits_filter(keyword=None, outfit_id=None):
|
|||||||
|
|
||||||
def outfits_update(outfit_id, **updates):
|
def outfits_update(outfit_id, **updates):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.outfits_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, _uuid(outfit_id), **updates)
|
success = ragroleplay_lib.outfits_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, outfit_id, **updates)
|
||||||
return "Berhasil memperbarui outfit." if success else "Gagal memperbarui outfit."
|
return "Berhasil memperbarui outfit." if success else "Gagal memperbarui outfit."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
def outfits_delete(outfit_id):
|
def outfits_delete(outfit_id):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.outfits_delete(config.ragroleplay_db_path, _uuid(outfit_id))
|
success = ragroleplay_lib.outfits_delete(config.ragroleplay_db_path, outfit_id)
|
||||||
return "Berhasil menghapus outfit." if success else "Gagal menghapus outfit."
|
return "Berhasil menghapus outfit." if success else "Gagal menghapus outfit."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
@ -719,7 +713,7 @@ def todos_store(keyword, when, do):
|
|||||||
|
|
||||||
def todos_filter(keyword=None, todo_id=None):
|
def todos_filter(keyword=None, todo_id=None):
|
||||||
try:
|
try:
|
||||||
results = ragroleplay_lib.todos_filter(config.ragroleplay_db_path, keyword, _uuid(todo_id) if todo_id else None)
|
results = ragroleplay_lib.todos_filter(config.ragroleplay_db_path, keyword, todo_id)
|
||||||
if not results: return "Tidak ada to-do yang ditemukan."
|
if not results: return "Tidak ada to-do yang ditemukan."
|
||||||
output = [f"Ditemukan {len(results)} to-do:"]
|
output = [f"Ditemukan {len(results)} to-do:"]
|
||||||
for i, row in enumerate(results, 1):
|
for i, row in enumerate(results, 1):
|
||||||
@ -729,13 +723,13 @@ def todos_filter(keyword=None, todo_id=None):
|
|||||||
|
|
||||||
def todos_update(todo_id, **updates):
|
def todos_update(todo_id, **updates):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.todos_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, _uuid(todo_id), **updates)
|
success = ragroleplay_lib.todos_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, todo_id, **updates)
|
||||||
return "Berhasil memperbarui to-do." if success else "Gagal memperbarui to-do."
|
return "Berhasil memperbarui to-do." if success else "Gagal memperbarui to-do."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
def todos_delete(todo_id):
|
def todos_delete(todo_id):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.todos_delete(config.ragroleplay_db_path, _uuid(todo_id))
|
success = ragroleplay_lib.todos_delete(config.ragroleplay_db_path, todo_id)
|
||||||
return "Berhasil menghapus to-do." if success else "Gagal menghapus to-do."
|
return "Berhasil menghapus to-do." if success else "Gagal menghapus to-do."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
@ -748,7 +742,7 @@ def worlds_store(category, location, description):
|
|||||||
|
|
||||||
def worlds_filter(category=None, location=None, world_id=None):
|
def worlds_filter(category=None, location=None, world_id=None):
|
||||||
try:
|
try:
|
||||||
results = ragroleplay_lib.worlds_filter(config.ragroleplay_db_path, category, location, _uuid(world_id) if world_id else None)
|
results = ragroleplay_lib.worlds_filter(config.ragroleplay_db_path, category, location, world_id)
|
||||||
if not results: return "Tidak ada lokasi dunia yang ditemukan."
|
if not results: return "Tidak ada lokasi dunia yang ditemukan."
|
||||||
output = [f"Ditemukan {len(results)} lokasi:"]
|
output = [f"Ditemukan {len(results)} lokasi:"]
|
||||||
for i, row in enumerate(results, 1):
|
for i, row in enumerate(results, 1):
|
||||||
@ -758,12 +752,12 @@ def worlds_filter(category=None, location=None, world_id=None):
|
|||||||
|
|
||||||
def worlds_update(world_id, **updates):
|
def worlds_update(world_id, **updates):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.worlds_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, _uuid(world_id), **updates)
|
success = ragroleplay_lib.worlds_update(config.ragroleplay_db_path, config.ragroleplay_model_url, config.ragroleplay_model_name, world_id, **updates)
|
||||||
return "Berhasil memperbarui lokasi dunia." if success else "Gagal memperbarui lokasi dunia."
|
return "Berhasil memperbarui lokasi dunia." if success else "Gagal memperbarui lokasi dunia."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
def worlds_delete(world_id):
|
def worlds_delete(world_id):
|
||||||
try:
|
try:
|
||||||
success = ragroleplay_lib.worlds_delete(config.ragroleplay_db_path, _uuid(world_id))
|
success = ragroleplay_lib.worlds_delete(config.ragroleplay_db_path, world_id)
|
||||||
return "Berhasil menghapus lokasi dunia." if success else "Gagal menghapus lokasi dunia."
|
return "Berhasil menghapus lokasi dunia." if success else "Gagal menghapus lokasi dunia."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user