Discord-bot / app.py
StrawberryJelly's picture
Update app.py
0c4b27c verified
Raw
History Blame Contribute Delete
8.98 kB
import discord, requests, os, aiosqlite, time, hmac, json
from discord.ext import commands
from discord import app_commands
from aiohttp import web
CEREBRAS_KEY = os.environ.get("CEREBRAS_KEY")
DISCORD_TOKEN = os.environ.get("DISCORD_TOKEN")
WEBHOOK_SECRET = os.environ.get("WEBHOOK_SECRET")
DAILY_FREE_TOKENS = 1000
MAX_TOKENS_PER_REQ = 250
CHAT_MAX_TOKENS = 200
TOKEN_PACK_AMOUNT = 1000 # ile daje 1x "Token AI Pack" z UB
intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)
# === BAZA DANYCH ===
async def init_db():
async with aiosqlite.connect("data.db") as db:
await db.execute('''CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
tokens INTEGER DEFAULT 0,
last_reset INTEGER DEFAULT 0
)''')
await db.execute('''CREATE TABLE IF NOT EXISTS chat_sessions (
user_id INTEGER PRIMARY KEY,
channel_id INTEGER,
history TEXT DEFAULT '[]'
)''')
await db.execute('''CREATE TABLE IF NOT EXISTS used_webhooks (
inventory_id TEXT PRIMARY KEY
)''')
await db.commit()
async def get_user_tokens(user_id: int):
async with aiosqlite.connect("data.db") as db:
async with db.execute("SELECT tokens, last_reset FROM users WHERE user_id =?", (user_id,)) as cur:
row = await cur.fetchone()
now = int(time.time())
if not row or now - row[1] > 86400:
await db.execute("INSERT OR REPLACE INTO users VALUES (?,?,?)",
(user_id, DAILY_FREE_TOKENS, now))
await db.commit()
return DAILY_FREE_TOKENS
return row[0]
async def use_tokens(user_id: int, amount: int):
async with aiosqlite.connect("data.db") as db:
await db.execute("UPDATE users SET tokens = tokens -? WHERE user_id =?", (amount, user_id))
await db.commit()
async def add_tokens(user_id: int, amount: int):
async with aiosqlite.connect("data.db") as db:
await db.execute("INSERT INTO users (user_id, tokens, last_reset) VALUES (?,?,?) ON CONFLICT(user_id) DO UPDATE SET tokens = tokens +?",
(user_id, amount, int(time.time()), amount))
await db.commit()
# === KOMENDY ===
@bot.event
async def on_ready():
await init_db()
bot.loop.create_task(start_webserver())
await bot.tree.sync()
print(f'Bot online: {bot.user}')
@bot.tree.command(name="ask", description="Zapytaj AI. Limit: 1000 tokenów/dzień")
@app_commands.checks.cooldown(1, 20, key=lambda i: i.user.id)
@app_commands.describe(prompt="Twoje pytanie do AI")
async def ask(interaction: discord.Interaction, prompt: str):
await interaction.response.defer()
user_id = interaction.user.id
tokens_left = await get_user_tokens(user_id)
if tokens_left < 50:
await interaction.followup.send(f"Masz tylko {tokens_left} tokenów. Doładuj w sklepie lub wróć jutro.")
return
try:
r = requests.post("https://api.cerebras.ai/v1/chat/completions",
headers={"Authorization": f"Bearer {CEREBRAS_KEY}"},
json={
"model":"llama3.1-70b",
"messages":[{"role":"user","content":prompt}],
"max_tokens": min(MAX_TOKENS_PER_REQ, tokens_left)
}, timeout=30)
r.raise_for_status()
reply = r.json()['choices'][0]['message']['content']
used = r.json()['usage']['completion_tokens']
await use_tokens(user_id, used)
embed = discord.Embed(description=reply[:4000], color=0x2b2d31)
embed.set_footer(text=f"Zużyto {used} tokenów | Zostało: {tokens_left - used}/1000")
await interaction.followup.send(embed=embed)
except Exception as e:
await interaction.followup.send(f"Błąd: {e}")
@ask.error
async def ask_error(interaction, error):
if isinstance(error, commands.CommandOnCooldown):
await interaction.response.send_message(f"Zwolnij. Spróbuj za {error.retry_after:.0f}s", ephemeral=True)
@bot.tree.command(name="balance", description="Sprawdź ile masz tokenów AI")
async def balance(interaction: discord.Interaction):
tokens = await get_user_tokens(interaction.user.id)
await interaction.response.send_message(f"Masz **{tokens}/1000** tokenów AI na dziś.", ephemeral=True)
# === TRYB CZATU ===
chat_group = app_commands.Group(name="chat", description="Tryb swobodnej rozmowy z AI")
@chat_group.command(name="start", description="Włącz tryb czatu w tym kanale")
async def chat_start(interaction: discord.Interaction):
user_id = interaction.user.id
if await get_user_tokens(user_id) < 50:
await interaction.response.send_message("Masz za mało tokenów żeby zacząć czat. Minimum 50.", ephemeral=True)
return
async with aiosqlite.connect("data.db") as db:
await db.execute("INSERT OR REPLACE INTO chat_sessions VALUES (?,?,'[]')",
(user_id, interaction.channel_id))
await db.commit()
await interaction.response.send_message("Tryb czatu ON ✅ Pisz normalnie. `/chat stop` żeby zakończyć.", ephemeral=True)
@chat_group.command(name="stop", description="Wyłącz tryb czatu")
async def chat_stop(interaction: discord.Interaction):
async with aiosqlite.connect("data.db") as db:
await db.execute("DELETE FROM chat_sessions WHERE user_id =?", (interaction.user.id,))
await db.commit()
await interaction.response.send_message("Tryb czatu OFF.", ephemeral=True)
bot.tree.add_command(chat_group)
@bot.event
async def on_message(message: discord.Message):
if message.author.bot: return
async with aiosqlite.connect("data.db") as db:
async with db.execute("SELECT channel_id, history FROM chat_sessions WHERE user_id =?",
(message.author.id,)) as cur:
row = await cur.fetchone()
if not row or row[0]!= message.channel.id:
await bot.process_commands(message)
return
user_id = message.author.id
tokens_left = await get_user_tokens(user_id)
if tokens_left < 30:
await message.reply("Skończyły Ci się tokeny. `/chat stop` i doładuj w sklepie.")
return
history = json.loads(row[1])
history.append({"role": "user", "content": message.content})
history = history[-6:] # pamięć 3 wymian
async with message.channel.typing():
try:
r = requests.post("https://api.cerebras.ai/v1/chat/completions",
headers={"Authorization": f"Bearer {CEREBRAS_KEY}"},
json={
"model":"llama3.1-70b",
"messages": [{"role":"system","content":"Jesteś luzackim botem Discord. Odpowiadaj krótko, na temat, bez lania wody."}] + history,
"max_tokens": min(CHAT_MAX_TOKENS, tokens_left)
}, timeout=30)
r.raise_for_status()
reply = r.json()['choices'][0]['message']['content']
used = r.json()['usage']['completion_tokens']
await use_tokens(user_id, used)
history.append({"role": "assistant", "content": reply})
async with aiosqlite.connect("data.db") as db:
await db.execute("UPDATE chat_sessions SET history =? WHERE user_id =?",
(json.dumps(history), user_id))
await db.commit()
await message.reply(reply[:2000])
except Exception as e:
await message.reply(f"AI padło: {e}")
# === WEBHOOK UNBELIEVABOAT ===
async def ub_webhook(request):
secret = request.rel_url.query.get('key')
if not WEBHOOK_SECRET or not hmac.compare_digest(secret, WEBHOOK_SECRET):
return web.Response(text="Unauthorized", status=401)
try:
data = await request.json()
except:
return web.Response(text="Bad JSON", status=400)
user_id = int(data.get('user_id', 0))
item_name = data.get('item_name', '')
quantity = int(data.get('quantity', 1))
inventory_id = data.get('id')
if not user_id or "Token AI" not in item_name:
return web.Response(text="Ignored", status=200)
async with aiosqlite.connect("data.db") as db:
async with db.execute("SELECT 1 FROM used_webhooks WHERE inventory_id =?", (inventory_id,)) as cur:
if await cur.fetchone():
return web.Response(text="Already processed", status=200)
await db.execute("INSERT INTO used_webhooks VALUES (?)", (inventory_id,))
await db.commit()
tokens_to_add = TOKEN_PACK_AMOUNT * quantity
await add_tokens(user_id, tokens_to_add)
return web.Response(text=f"Added {tokens_to_add} tokens")
async def start_webserver():
app = web.Application()
app.router.add_post('/ub-webhook', ub_webhook)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, '0.0.0.0', 7860)
await site.start()
bot.run(DISCORD_TOKEN)