mirror of
https://git.squeakyrat.moe/faggot-chan/
synced 2026-11-05 02:45:45 +01:00
fixed a couple bugs, moved a couple of this. also made main stateless so i can do funny things
This commit is contained in:
commit
a8fdeb52f0
2 files changed
+523
No files matched your search
@@ -0,0 +1,387 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import traceback
|
||||||
|
import discord
|
||||||
|
import websockets
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def ignore_connection_closed_ok(loop, context): #this doesn't fucking work
|
||||||
|
exc = context.get("exception")
|
||||||
|
if isinstance(exc, websockets.exceptions.ConnectionClosedOK):
|
||||||
|
return
|
||||||
|
loop.default_exception_handler(context)
|
||||||
|
|
||||||
|
system_prompt = "you are a funny discord user that uses discrd"
|
||||||
|
|
||||||
|
system_prompt = "you are a funny discord user that uses discrd"
|
||||||
|
|
||||||
|
FILES_DIR = Path("files")
|
||||||
|
LOG_DIR = FILES_DIR / "log"
|
||||||
|
MEDIA_DIR = FILES_DIR / "media"
|
||||||
|
CONFIG_DIR = FILES_DIR / "config"
|
||||||
|
|
||||||
|
ERROR_FILE = LOG_DIR / "errorlog.txt"
|
||||||
|
MEMORY_FILE = LOG_DIR / "memory.txt"
|
||||||
|
MEDIA_FILE = MEDIA_DIR / "media.txt"
|
||||||
|
THREADS_FILE = CONFIG_DIR / "threads.txt"
|
||||||
|
|
||||||
|
def init_files():
|
||||||
|
for d in (LOG_DIR, MEDIA_DIR, CONFIG_DIR):
|
||||||
|
d.mkdir(parents=True, exist_ok=True)
|
||||||
|
for f in (ERROR_FILE, MEMORY_FILE, MEDIA_FILE):
|
||||||
|
f.touch(exist_ok=True)
|
||||||
|
if not THREADS_FILE.exists():
|
||||||
|
THREADS_FILE.write_text("6\n")
|
||||||
|
|
||||||
|
init_files()
|
||||||
|
|
||||||
|
TOKEN= "your token goes here"
|
||||||
|
|
||||||
|
|
||||||
|
server = "put your serevr id here"
|
||||||
|
|
||||||
|
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
intents.message_content = True
|
||||||
|
intents.members = True
|
||||||
|
client = discord.Client(intents=intents)
|
||||||
|
|
||||||
|
block_id = ["1000000000000003", "1000000000000004"] #fuck these two in particular
|
||||||
|
|
||||||
|
last_server_message = 0.0 # unix timestamp of last message anyone sent in the server
|
||||||
|
dm_sent = False
|
||||||
|
interaction_count = 0
|
||||||
|
|
||||||
|
QUIET_COOLDOWN = 600 # seconds of silence before she's allowed to send a random message (10 mins)
|
||||||
|
|
||||||
|
def timestamp() -> str:
|
||||||
|
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
def log_error(text: str):
|
||||||
|
with ERROR_FILE.open("a", encoding="utf-8") as f:
|
||||||
|
f.write(text + "\n")
|
||||||
|
|
||||||
|
def log_message(text: str):
|
||||||
|
with MEMORY_FILE.open("a", encoding="utf-8") as f:
|
||||||
|
f.write(text + "\n")
|
||||||
|
|
||||||
|
def nots(line: str) -> str:
|
||||||
|
if line.startswith("[") and "]" in line:
|
||||||
|
return line.split("]", 1)[1].lstrip()
|
||||||
|
return line
|
||||||
|
|
||||||
|
def load_shortterm() -> list[str]:
|
||||||
|
try:
|
||||||
|
with MEMORY_FILE.open("r", encoding="utf-8", errors="ignore") as f:
|
||||||
|
lines = f.readlines()[-15:] # reads bottom 15 lines
|
||||||
|
return [line.strip() for line in lines if line.strip()]
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"[{timestamp()}] error reading shortterm: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def load_longterm() -> list[str]:
|
||||||
|
try:
|
||||||
|
with MEMORY_FILE.open("r", encoding="utf-8", errors="ignore") as f:
|
||||||
|
lines = [nots(line.strip()) for line in f if line.strip()]
|
||||||
|
return lines[-515:-15] if len(lines) > 15 else []
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"[{timestamp()}] error reading longterm: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def build_payload(sys_prompt: str, user_input: str, rebuild: bool = False) -> str:
|
||||||
|
return json.dumps({
|
||||||
|
"system_prompt": sys_prompt,
|
||||||
|
"user_input": user_input,
|
||||||
|
"shortterm": load_shortterm(),
|
||||||
|
"longterm": load_longterm(),
|
||||||
|
"rebuild_vectors": rebuild,
|
||||||
|
})
|
||||||
|
|
||||||
|
async def call_main(payload: str) -> tuple[bool, str]:
|
||||||
|
uri = "ws://0.0.0.0:8765"
|
||||||
|
try:
|
||||||
|
async with websockets.connect(uri, open_timeout=None, ping_timeout=None) as websocket:
|
||||||
|
await websocket.send(payload)
|
||||||
|
raw = await websocket.recv()
|
||||||
|
data = json.loads(raw)
|
||||||
|
if "error" in data:
|
||||||
|
return False, data["error"]
|
||||||
|
return True, data["ok"]
|
||||||
|
except websockets.exceptions.ConnectionClosedOK:
|
||||||
|
return False, f"[{timestamp()}] websocket closed cleanly (no reply)"
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"[{timestamp()}] websocket error: {e}"
|
||||||
|
|
||||||
|
async def handle_error(error_msg: str, notify_channel=None, notify_user=None):
|
||||||
|
print(error_msg)
|
||||||
|
log_error(error_msg)
|
||||||
|
notice = "someone tell <@1000000000000001> there is a problem with my ai"
|
||||||
|
try:
|
||||||
|
if notify_channel:
|
||||||
|
await notify_channel.send(notice)
|
||||||
|
elif notify_user:
|
||||||
|
dm = await notify_user.create_dm()
|
||||||
|
await dm.send(notice)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
saved_media_urls = set()
|
||||||
|
|
||||||
|
with MEDIA_FILE.open("r", encoding="utf-8") as f:
|
||||||
|
for line in f:
|
||||||
|
if "saved media:" in line:
|
||||||
|
url = line.split("saved media:", 1)[1].strip()
|
||||||
|
saved_media_urls.add(url)
|
||||||
|
|
||||||
|
def steal_media(text: str):
|
||||||
|
if "saved media:" not in text:
|
||||||
|
return
|
||||||
|
url = text.split("saved media:", 1)[1].strip()
|
||||||
|
if url in saved_media_urls:
|
||||||
|
return
|
||||||
|
saved_media_urls.add(url)
|
||||||
|
with MEDIA_FILE.open("a", encoding="utf-8") as f:
|
||||||
|
f.write(text + "\n")
|
||||||
|
|
||||||
|
def is_member_in_server(member: discord.Member) -> bool:
|
||||||
|
guild = client.get_guild(server)
|
||||||
|
return guild and guild.get_member(member.id) is not None
|
||||||
|
|
||||||
|
async def random_dm():
|
||||||
|
global dm_sent
|
||||||
|
await client.wait_until_ready()
|
||||||
|
while not client.is_closed():
|
||||||
|
await asyncio.sleep(300) #every 5 minutes
|
||||||
|
for guild in client.guilds:
|
||||||
|
if random.random() < 0.01: #should be 1%
|
||||||
|
members = [m for m in guild.members if not m.bot]
|
||||||
|
if dm_sent:
|
||||||
|
dm_sent = False
|
||||||
|
continue
|
||||||
|
if not members:
|
||||||
|
continue
|
||||||
|
victim = random.choice(members)
|
||||||
|
payload = build_payload(
|
||||||
|
system_prompt,
|
||||||
|
f"System: you are sending a dm to {victim}, write a long, playful story or an over-the-top pun monologue about anything. "
|
||||||
|
"It should sound like something faggot-chan would post when she's bored — chaotic, funny, and full of personality (at least 20 words)."
|
||||||
|
"keep in mind this is a dm so make it a bit personal"
|
||||||
|
)
|
||||||
|
ok, result = await call_main(payload)
|
||||||
|
if not ok:
|
||||||
|
await handle_error(result, notify_user=victim)
|
||||||
|
continue
|
||||||
|
try: #sends the dm
|
||||||
|
dm = await victim.create_dm()
|
||||||
|
async with dm.typing():
|
||||||
|
await dm.send(result)
|
||||||
|
dm_sent = True
|
||||||
|
log_message(f"[{timestamp()}]Faggot-chan sent a random dm to {victim}: {result}")
|
||||||
|
print(f"[{timestamp()}] random dm to {victim}: {result}")
|
||||||
|
except Exception as e:
|
||||||
|
await handle_error(f"[{timestamp()}] failed to send dm to {victim}: {e}", notify_user=victim)
|
||||||
|
|
||||||
|
async def random_message():
|
||||||
|
await client.wait_until_ready()
|
||||||
|
while not client.is_closed():
|
||||||
|
await asyncio.sleep(240) #every 4 minutes
|
||||||
|
if time.time() - last_server_message < QUIET_COOLDOWN: #only send if server has been quiet for 10 mins
|
||||||
|
continue
|
||||||
|
if random.random() < 0.01: #1%
|
||||||
|
for guild in client.guilds:
|
||||||
|
channel = discord.utils.get(guild.text_channels, name="general")
|
||||||
|
if channel:
|
||||||
|
payload = build_payload(
|
||||||
|
system_prompt,
|
||||||
|
"System: write a long, playful story or an over-the-top pun monologue about cheese. or anything random"
|
||||||
|
"it should sound like something faggot-chan would post when she's bored."
|
||||||
|
"chaotic, funny, and full of personality (at least 15 words and no more than 20)"
|
||||||
|
)
|
||||||
|
ok, result = await call_main(payload)
|
||||||
|
if not ok:
|
||||||
|
await handle_error(result, notify_channel=channel)
|
||||||
|
continue
|
||||||
|
async with channel.typing():
|
||||||
|
await channel.send(result)
|
||||||
|
log_message(f"[{timestamp()}] random message: {result}")
|
||||||
|
print(f"[{timestamp()}] random message: {result}")
|
||||||
|
|
||||||
|
@client.event
|
||||||
|
async def on_ready():
|
||||||
|
client.loop.create_task(random_message())
|
||||||
|
client.loop.create_task(random_dm())
|
||||||
|
print(f"faggot-chan is active as {client.user}")
|
||||||
|
|
||||||
|
|
||||||
|
@client.event
|
||||||
|
async def on_random(message):
|
||||||
|
|
||||||
|
RNG = random.randint(1,3)
|
||||||
|
|
||||||
|
if message.author == client.user:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if not is_member_in_server(message.author):
|
||||||
|
return
|
||||||
|
|
||||||
|
if str(message.author.id) in block_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not message.guild or message.guild.id != server:
|
||||||
|
return
|
||||||
|
|
||||||
|
if message.channel.name not in ["general", "announcements"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
mentioned = client.user.mentioned_in(message)
|
||||||
|
|
||||||
|
#steal images and gifs and stuff (always do this regardless of what else fires)
|
||||||
|
media_urls = [
|
||||||
|
a.url for a in message.attachments
|
||||||
|
if a.content_type and a.content_type.startswith(("image/", "video/"))
|
||||||
|
]
|
||||||
|
|
||||||
|
for embed in message.embeds:
|
||||||
|
if embed.image and embed.image.url:
|
||||||
|
media_urls.append(embed.image.url)
|
||||||
|
if embed.video and embed.video.url:
|
||||||
|
media_urls.append(embed.video.url)
|
||||||
|
|
||||||
|
for url in media_urls:
|
||||||
|
steal_media(f"[{timestamp()}] saved media: {url}")
|
||||||
|
|
||||||
|
#stickers - early exit, skip ai generation
|
||||||
|
stickers = list(message.guild.stickers)
|
||||||
|
if stickers and not mentioned and random.random() < 0.15: #15% chance of sending a sticker
|
||||||
|
chosen = random.choice(stickers)
|
||||||
|
try:
|
||||||
|
await message.channel.send(stickers=[chosen])
|
||||||
|
log_message(f"[{timestamp()}] Faggot-chan sent sticker: {chosen.name}")
|
||||||
|
print(f"[{timestamp()}] Faggot-chan sent sticker: {chosen.name}")
|
||||||
|
except websockets.exceptions.ConnectionClosedOK:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"[{timestamp()}] error: {e}")
|
||||||
|
await message.reply("someone tell <@1000000000000001> there is a problem with my ai")
|
||||||
|
print(f"Sticker send failed: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
emojis = [str(e) for e in message.guild.emojis]
|
||||||
|
if emojis and not mentioned and random.random() < 0.2: #20% of reacting - early exit
|
||||||
|
try:
|
||||||
|
await message.add_reaction(random.choice(emojis))
|
||||||
|
except websockets.exceptions.ConnectionClosedOK:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"[{timestamp()}] error: {e}")
|
||||||
|
await message.reply("someone tell <@1000000000000001> there is a problem with my ai")
|
||||||
|
print(f"Emoji reaction failed: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if random.random() < 0.1 and saved_media_urls: #10% of sending a stolen image - early exit, uses live set
|
||||||
|
chosen = random.choice(list(saved_media_urls))
|
||||||
|
await message.channel.send(chosen)
|
||||||
|
log_message(f"[{timestamp()}] Faggot-chan sent media: {chosen}")
|
||||||
|
print(f"[{timestamp()}] Faggot-chan sent media: {chosen}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@client.event
|
||||||
|
async def on_message(message):
|
||||||
|
global dm_sent, interaction_count, last_server_message
|
||||||
|
if message.author == client.user:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not is_member_in_server(message.author):
|
||||||
|
return
|
||||||
|
|
||||||
|
# update last activity so random_message knows the server isn't quiet
|
||||||
|
last_server_message = time.time()
|
||||||
|
|
||||||
|
if str(message.author.id) in block_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
# always detect replies
|
||||||
|
replied_message = None
|
||||||
|
replied_to_bot = False
|
||||||
|
if message.reference:
|
||||||
|
try:
|
||||||
|
replied_message = message.reference.resolved or await message.channel.fetch_message(message.reference.message_id)
|
||||||
|
if replied_message:
|
||||||
|
if replied_message.author == client.user:
|
||||||
|
replied_to_bot = True
|
||||||
|
log_message(f'[{timestamp()}] {message.author} replied to {replied_message.author} saying: "{replied_message.content}" with reply: "{message.content}"')
|
||||||
|
else:
|
||||||
|
log_message(f'[{timestamp()}] {message.author} said: {message.content}')
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"[{timestamp()}] failed to resolve reply: {e}")
|
||||||
|
log_message(f'[{timestamp()}] {message.author} said: {message.content}')
|
||||||
|
else:
|
||||||
|
log_message(f'[{timestamp()}] {message.author} said: {message.content}')
|
||||||
|
|
||||||
|
interaction_count += 1
|
||||||
|
rebuild = (interaction_count % 150 == 0)
|
||||||
|
|
||||||
|
if message.guild is None: #dms now should work
|
||||||
|
if str(message.author.id) in block_id:
|
||||||
|
return
|
||||||
|
dm_sent = False
|
||||||
|
if replied_message:
|
||||||
|
user_input = f'{message.author} replied to {replied_message.author} saying: "{replied_message.content}" with reply: "{message.content}"'
|
||||||
|
else:
|
||||||
|
user_input = f"{message.author} said in DM: {message.content}"
|
||||||
|
payload = build_payload(system_prompt, user_input, rebuild)
|
||||||
|
ok, result = await call_main(payload)
|
||||||
|
if not ok:
|
||||||
|
await handle_error(result, notify_user=message.author)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
async with message.channel.typing():
|
||||||
|
await message.reply(result)
|
||||||
|
print(f"[{timestamp()}] DM from {message.author}: {message.content} Bot replied in DM: {result}")
|
||||||
|
log_message(f"[{timestamp()}] DM from {message.author}: {message.content}")
|
||||||
|
log_message(f"[{timestamp()}] Faggot-chan replied in DM: {result}")
|
||||||
|
except Exception as e:
|
||||||
|
await handle_error(f"[{timestamp()}] failed to send DM reply: {e}", notify_user=message.author)
|
||||||
|
return
|
||||||
|
|
||||||
|
if message.channel.name not in ["general", "announcements"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
mentioned = client.user.mentioned_in(message)
|
||||||
|
|
||||||
|
# if it replied to bot, treat it as a mention automatically
|
||||||
|
if replied_to_bot:
|
||||||
|
mentioned = True
|
||||||
|
|
||||||
|
if not mentioned and random.random() > 0.05: #5% chance of replying if not mentiond
|
||||||
|
return
|
||||||
|
|
||||||
|
if replied_message:
|
||||||
|
user_input = f'{message.author} replied to {replied_message.author} saying: "{replied_message.content}" with reply: "{message.content}"'
|
||||||
|
else:
|
||||||
|
user_input = f"{message.author} said: {message.content}"
|
||||||
|
|
||||||
|
payload = build_payload(system_prompt, user_input, rebuild)
|
||||||
|
ok, result = await call_main(payload)
|
||||||
|
if not ok:
|
||||||
|
await handle_error(result, notify_channel=message.channel)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
async with message.channel.typing():
|
||||||
|
await message.reply(result)
|
||||||
|
print(f"[{timestamp()}] {message.author} said: {message.content}\n[{timestamp()}] Faggot-chan said: {result}")
|
||||||
|
log_message(f"[{timestamp()}] {message.author} said: {message.content}\n[{timestamp()}] Faggot-chan said: {result}")
|
||||||
|
except Exception as e:
|
||||||
|
await handle_error(f"[{timestamp()}] failed to send reply: {e}", notify_channel=message.channel)
|
||||||
|
|
||||||
|
await on_random(message)
|
||||||
|
|
||||||
|
client.run(TOKEN)
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import ollama
|
||||||
|
import websockets
|
||||||
|
from websockets.server import serve
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
#chatmodel = "hf.co/Orenguteng/Llama-3.1-8B-Lexi-Uncensored-V2-GGUF:Llama-3.1-8B-Lexi-Uncensored_V2_Q4.gguf"
|
||||||
|
embedmodel = 'hf.co/CompendiumLabs/bge-base-en-v1.5-gguf'
|
||||||
|
|
||||||
|
# these are test models just ignore
|
||||||
|
chatmodel = "hf.co/tvall43/Qwen3.5-4B-heretic-gguf:Q4_K_M"
|
||||||
|
#chatmodel = 'hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF'
|
||||||
|
#chatmodel = 'hf.co/VibeStudio/Nidum-Llama-3.2-3B-Uncensored-GGUF'
|
||||||
|
#chatmodel = "faggotchan"
|
||||||
|
#chatmodel = "deepseek-r1:1.5b"
|
||||||
|
|
||||||
|
NUM_THREADS = 6 # hardcoded since threads.txt is gone, change if needed
|
||||||
|
|
||||||
|
def times() -> str:
|
||||||
|
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
def nots(line: str) -> str:
|
||||||
|
if line.startswith("[") and "]" in line:
|
||||||
|
return line.split("]", 1)[1].lstrip()
|
||||||
|
return line
|
||||||
|
|
||||||
|
|
||||||
|
# THANK YOU GUY FROM HUGGING FACE THAT MADE ALL THIS SO THAT I DON'T HAVE TO THINK I LOVE YOU
|
||||||
|
|
||||||
|
# Each element in the VECTOR_DB will be a tuple (chunk, embedding)
|
||||||
|
# The embedding is a list of floats, for example: [0.1, 0.04, -0.34, 0.21, ...]
|
||||||
|
VECTOR_DB = []
|
||||||
|
|
||||||
|
def add_chunk_to_database(chunk):
|
||||||
|
embedding = ollama.embed(model=embedmodel, input=chunk)['embeddings'][0]
|
||||||
|
VECTOR_DB.append((chunk, embedding))
|
||||||
|
|
||||||
|
def cosine_similarity(a, b):
|
||||||
|
dot_product = sum([x * y for x, y in zip(a, b)])
|
||||||
|
norm_a = sum([x ** 2 for x in a]) ** 0.5
|
||||||
|
norm_b = sum([x ** 2 for x in b]) ** 0.5
|
||||||
|
return dot_product / (norm_a * norm_b)
|
||||||
|
|
||||||
|
def retrieve(query, top_n=5):
|
||||||
|
query_embedding = ollama.embed(model=embedmodel, input=query)['embeddings'][0]
|
||||||
|
similarities = []
|
||||||
|
for chunk, embedding in VECTOR_DB:
|
||||||
|
similarity = cosine_similarity(query_embedding, embedding)
|
||||||
|
similarities.append((chunk, similarity))
|
||||||
|
similarities.sort(key=lambda x: x[1], reverse=True)
|
||||||
|
return similarities[:top_n]
|
||||||
|
|
||||||
|
def rebuild_vector_db(longterm_lines: list[str]):
|
||||||
|
VECTOR_DB.clear()
|
||||||
|
for i, chunk in enumerate(longterm_lines):
|
||||||
|
add_chunk_to_database(chunk)
|
||||||
|
print(f"[{times()}] Added chunk {i+1}/{len(longterm_lines)} to the database")
|
||||||
|
|
||||||
|
interaction_count = 0
|
||||||
|
|
||||||
|
|
||||||
|
async def ollamachat(websocket):
|
||||||
|
global interaction_count
|
||||||
|
try:
|
||||||
|
# bot sends one json payload with everything main needs
|
||||||
|
raw = await websocket.recv()
|
||||||
|
payload = json.loads(raw)
|
||||||
|
|
||||||
|
system_prompt = payload["system_prompt"]
|
||||||
|
user_input = payload["user_input"]
|
||||||
|
shortterm = payload.get("shortterm", []) # list of strings
|
||||||
|
longterm = payload.get("longterm", []) # list of strings
|
||||||
|
|
||||||
|
interaction_count += 1
|
||||||
|
|
||||||
|
# rebuild vector db if bot signals it (every 150 interactions bot sends full longterm)
|
||||||
|
if payload.get("rebuild_vectors"):
|
||||||
|
rebuild_vector_db(longterm)
|
||||||
|
print(f"[{times()}] Vector DB rebuilt with {len(longterm)} chunks")
|
||||||
|
|
||||||
|
user_query = nots(user_input)
|
||||||
|
retrieved_knowledge = retrieve(user_query) if VECTOR_DB else []
|
||||||
|
|
||||||
|
context_message = (
|
||||||
|
"These are memory notes to help you continue naturally. "
|
||||||
|
"Do NOT imitate tone, style, structure, or wording.\n\n"
|
||||||
|
"Short-term memory, these are the most 15 recent chats sent by various people:\n"
|
||||||
|
+ "\n".join(f"- {line}" for line in shortterm)
|
||||||
|
+ "\n\nLong-term memory, these are retrieved older messages using cosine similarity:\n"
|
||||||
|
+ "\n".join(f"- {chunk}" for chunk, _ in retrieved_knowledge)
|
||||||
|
)
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": system_prompt + "\n\n" + context_message},
|
||||||
|
{"role": "user", "content": user_input},
|
||||||
|
]
|
||||||
|
|
||||||
|
response = ollama.chat(
|
||||||
|
model=chatmodel,
|
||||||
|
messages=messages,
|
||||||
|
options={
|
||||||
|
"temperature": 0.8,
|
||||||
|
"top_p": 0.9,
|
||||||
|
"top_k": 40,
|
||||||
|
"repeat_penalty": 1.1,
|
||||||
|
"num_predict": 4096,
|
||||||
|
"num_thread": NUM_THREADS,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
bot_reply = response["message"]["content"].strip()
|
||||||
|
|
||||||
|
print(messages)
|
||||||
|
print(f"[{times()}] reply: {bot_reply}\n")
|
||||||
|
|
||||||
|
await websocket.send(json.dumps({"ok": bot_reply}))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"[{times()}] error in ollamachat: {e}"
|
||||||
|
print(error_msg)
|
||||||
|
try:
|
||||||
|
await websocket.send(json.dumps({"error": error_msg}))
|
||||||
|
except Exception:
|
||||||
|
pass # if we can't even send the error, nothing we can do
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
print(f"[{times()}] hosting on ws://0.0.0.0:8765")
|
||||||
|
async with serve(ollamachat, "0.0.0.0", 8765, ping_interval=None, ping_timeout=None):
|
||||||
|
await asyncio.Future()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
Reference in new issue
Block a user