Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 40 additions & 59 deletions chatbot.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,50 @@
import scratchattach as sa
import requests
import time
"""
Pollinations AI chatbot integration (currently disabled).
"""

import logging
from urllib.parse import quote

import requests

index = 0
logger = logging.getLogger(__name__)

# function to encode into url format
def encode(text: str):
"""
Function to encode special character into wen url format.
SYSTEM_PROMPT = (
"You are a helpful scratch.mit.edu user and bot called ScratchOn. "
"You cannot swear or do anything inappropriate. Never say anything bad "
"about someone or something. Your language must be appropriate for 7-12 "
"year olds. Always refer to yourself as ScratchOn, or _Scratch-On_ as "
"your scratch username. Either refer to the user by their username, or "
"don't refer to them at all. Keep your answers short and concise, up to "
"500 characters. Do not use regular emojis, only use Scratch-style emojis "
"like :), _:D_, or XD. Speak like a scratch.mit.edu user would, using "
"simple words and phrases a 12 years old would use in a chat, for example "
"'Hey!', 'That's cool!', 'Thanks!', 'No problem!', 'I guess you're "
"right lol'. Answer the following user with their question/message."
)

@parameter:

- text: the text to be encoded.
"""
encoded = quote(text, safe="?-_.!~*'()")

return encoded

# Function to simplify AI calling
def answer(query: str, username: str):
"""
Function to simplify AI calling
def _encode(text: str) -> str:
"""URL-encode *text*, preserving Scratch-safe characters."""
return quote(text, safe="?-_.!~*'()")

@parameters:

- query: a sample prompt
- username: By what name the AI will call the user
def answer(query: str, username: str) -> dict | None:
"""
global index
print("Answering...")
prompt = { "content": "You are a helpful scratch.mit.edu user and bot called ScratchOn. You cannot swear or do anything inappropriate. Never say anything bad about someone or something. Your language must be appropriate for 7-12 year olds. Always refer to yourself as ScratchOn, or _Scratch-On_ as your scratch username. Either refer to the user by their username, or don't refer to them at all. Keep your answers short and concise, up to 500 characters. Do not use regular emojis, only use Scratch-style emojis like :), _:D_, or XD. Speak like a scratch.mit.edu user would, using simple words and phrases a 12 years old would use in a chat, for example 'Hey!', 'That's cool!', 'Thanks!', 'No problem!', 'I guess you're right lol'. Answer the following user with their question/message." }

res = requests.get(f"https://text.pollinations.ai/{encode(prompt.content + ' : ' + username + ' : ' + query)}")
result = res.json()
print("Answered!")
return result

Send a prompt to the Pollinations AI and return the JSON response.

# Setup scratch connection (temporarily ignored to avoid bugs with Scratch API)
# with open("private/password.txt") as f:
# session = sa.login(username="_Scratch-On_", password=f.readlines()[0])

# profile = session.connect_linked_user()
# events = session.connect_message_events()
# print("Logged in")

# Main part : message replyer
# @events.event
# def on_message(message):
# print("Message detected")

# time.sleep(60) # Wait 1 minute before replying to prevent comment glitches

# comment = profile.comments(page=1, limit=1)[0]

# comment.reply(
# content=answer(query=message.comment_fragment, username=message.actor_username)
# )
# """
# session.connect_user() gets the ScratchOn profile,
# comment_by_id finds the message based on infos provided by the event handler,
# reply() sends a reply by sending the message to the AI setted up earlier.
# """


# events.start(thread=True, ignore_exceptions=True)
:param query: The user's message.
:param username: The Scratch username of the user being addressed.
:return: Parsed JSON response, or ``None`` on failure.
"""
prompt_text = f"{SYSTEM_PROMPT} : {username} : {query}"
try:
response = requests.get(
f"https://text.pollinations.ai/{_encode(prompt_text)}",
timeout=30,
)
response.raise_for_status()
return response.json()
except requests.RequestException:
logger.exception("Pollinations request failed")
return None
2 changes: 1 addition & 1 deletion commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
bot.load_extension("commands.<module_name>")
"""

__all__ = [
__all__: list[str] = [
"user_commands",
"project_commands",
"studio_forum_commands",
Expand Down
28 changes: 14 additions & 14 deletions commands/currency_commands.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
"""
Scratch cloud Discord bridge commands.
Scratch cloud to Discord bridge commands.

Handles communication with a BlockBit server using cloud variables.
"""

import asyncio
import logging

import interactions

from config import scratch_orange
from services import request_search, get_latest_response

logger = logging.getLogger(__name__)


class CurrencyCommands(interactions.Extension):
"""Currency / BlockBit commands."""
Expand All @@ -25,24 +28,21 @@ class CurrencyCommands(interactions.Extension):
opt_type=interactions.OptionType.STRING,
required=True,
)
async def blockbit_search(self, ctx: interactions.SlashContext, username: str):
"""Communicates with the Scratch cloud project to retrieve a balance."""
async def blockbit_search(
self, ctx: interactions.SlashContext, username: str
) -> None:
"""Communicate with the Scratch cloud project to retrieve a balance."""
await ctx.defer()

try:
# Send request to Scratch
request_search(username)

# Wait briefly to allow Scratch to process the request
await asyncio.sleep(1.2)

# Fetch the response
response = get_latest_response()

if response is None:
await ctx.send(
embed=interactions.Embed(
title="No response",
title="No response",
description="Scratch did not respond in time. Try again.",
color=0xFF0000,
)
Expand All @@ -51,23 +51,23 @@ async def blockbit_search(self, ctx: interactions.SlashContext, username: str):

await ctx.send(
embed=interactions.Embed(
title="Scratch Response",
description=f"```{username}``` has ```{response}``` Bits",
title="Scratch Response",
description=f"**{username}** has **{response}** Bits",
color=scratch_orange,
)
)

except Exception as error:
logger.exception("Error in blockbit_search command")
await ctx.send(
embed=interactions.Embed(
title="⚠️ Error",
title="Error",
description=str(type(error).__name__),
color=0xFF0000,
),
ephemeral=True,
)
print(f"Error in blockbit_search command: {error}")


def setup(bot: interactions.Client):
def setup(bot: interactions.Client) -> None:
CurrencyCommands(bot)
Loading
Loading