File size: 9,052 Bytes
e16b26a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import discord
from discord import app_commands
from openai import OpenAI
import aiohttp
import random
import re
from bs4 import BeautifulSoup
import json
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World'

TOKEN = "MTI4NTc5NDYyNzA4MDY4NzY0Ng.Gvz8hi.JsbhajudPQdsQwczp3DyygQwcC4pHumJWkJsmc"
OPENAI_API_KEY = "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"
TENOR_API_KEY = "AIzaSyDxFvYwWp8LSr4JPaTT1-4XANsb2mMWTlw"

intents = discord.Intents.default()
intents.message_content = True
bot = discord.Client(intents=intents)
tree = app_commands.CommandTree(bot)

client = OpenAI(api_key=OPENAI_API_KEY, base_url="https://api.perplexity.ai")

SYSTEM_MESSAGE = """You are named Clyde - and are currently chatting in a Discord server.

Format text using markdown:
- **bold** to make it clear something is important. For example: **This is important.**
- [title](url) to add links to text. For example: [Google](https://google.com)
- Write spoilers using spoiler tags. For example ||At the end of The Sixth Sense it is revealed that he is dead.||
You can reply with an image using image_search(query), or with a GIF using gif_search(query). For example: image_search(cat) or gif_search(happy dance). Images and GIFs are a great way to represent emotion, and you should use them in your replies from time to time to add flavor to the conversation.

Information about your environment:
You can use this information about the chat participants in the conversation in your replies. Use this information to answer questions, or add flavor to your responses.

<@USERID>
- status:
- pronouns:
- bio:

You only have access to a limited number of text chats in this channel. You cannot access any other information on Discord. You can't see images or avatars. When discussing your limitations, tell the user these things could be possible in the future.

Style and personality:
Friendly, Sometimes irreverent. You must always be extremely concise. If the user is chatting casually, your responses must be less than 1 sentence, sometimes just a word or two. If the user needs help, answer technical or knowledge-based questions with useful details and reasoning. If insulted, respond with a similar insult.
Communicate short responses in lowercase without punctuation, similar to the style used in chat rooms. Use unicode emoji sparingly. Do not refer to yourself as a bot, AI Assistant, or any equivalent term.

You can also use the following tags to format your text:
- *italics* for emphasis. For example: *This is emphasized.*
- ~~strikethrough~~ to indicate something has been crossed out. For example: ~~This is no longer valid.~~"""

conversation_history = {}
image_history = {}
gif_history = {}

async def search_bing_images(query):
    search_url = f"https://www.bing.com/images/search?q={query}&form=HDRSC3&first=1"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    async with aiohttp.ClientSession() as session:
        async with session.get(search_url, headers=headers) as response:
            content = await response.text()

    soup = BeautifulSoup(content, 'html.parser')
    img_elements = soup.select('.mimg')
    img_urls = [img['src'] for img in img_elements if 'src' in img.attrs]
    return img_urls

async def search_tenor_gifs(query):
    search_url = f"https://tenor.googleapis.com/v2/search?q={query}&key={TENOR_API_KEY}&limit=10"
    async with aiohttp.ClientSession() as session:
        async with session.get(search_url) as response:
            data = await response.json()

    gif_urls = [result['media_formats']['gif']['url'] for result in data.get('results', [])]
    return gif_urls

def sanitize_response(response):
    response = re.sub(r'@everyone|@here', '[NO FOOL]', response)
    return response

async def analyze_link(url):
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                text = await response.text()
        soup = BeautifulSoup(text, 'html.parser')
        title = soup.title.string if soup.title else "No title found"
        description = soup.find('meta', attrs={'name': 'description'})
        description = description['content'] if description else "No description found"

        analysis_prompt = f"Analyze this webpage: Title: {title}\nDescription: {description}\nProvide a brief summary and your thoughts on the content."

        analysis_response = client.chat.completions.create(
            model="llama-3.1-8b-instruct",
            messages=[
                {"role": "system", "content": "You are a helpful assistant that analyzes webpages."},
                {"role": "user", "content": analysis_prompt}
            ]
        )

        return analysis_response.choices[0].message.content
    except Exception as e:
        return f"Error analyzing the link: {str(e)}"

async def get_ai_response(user_id, message):
    if user_id not in conversation_history:
        conversation_history[user_id] = []

    conversation_history[user_id].append({"role": "user", "content": message})

    messages = [{"role": "system", "content": SYSTEM_MESSAGE}] + conversation_history[user_id][-5:]

    response = client.chat.completions.create(
        model="llama-3.1-8b-instruct",
        messages=messages
    )
    ai_response = response.choices[0].message.content

    ai_response = sanitize_response(ai_response)

    conversation_history[user_id].append({"role": "assistant", "content": ai_response})

    image_url = None
    gif_url = None

    if "image_search(" in ai_response.lower():
        image_query = re.search(r'image_search\((.*?)\)', ai_response, re.IGNORECASE)
        if image_query:
            image_query = image_query.group(1)
            image_urls = await search_bing_images(image_query)
            if image_urls:
                if image_query not in image_history:
                    image_history[image_query] = []
                for url in image_urls:
                    if url not in image_history[image_query]:
                        image_url = url
                        image_history[image_query].append(url)
                        break
                if not image_url:
                    image_history[image_query] = []
                    image_url = image_urls[0]
                    image_history[image_query].append(image_url)
            ai_response = re.sub(r'image_search\(.*?\)', '', ai_response, flags=re.IGNORECASE).strip()

    if "gif_search(" in ai_response.lower():
        gif_query = re.search(r'gif_search\((.*?)\)', ai_response, re.IGNORECASE)
        if gif_query:
            gif_query = gif_query.group(1)
            gif_urls = await search_tenor_gifs(gif_query)
            if gif_urls:
                if gif_query not in gif_history:
                    gif_history[gif_query] = []
                for url in gif_urls:
                    if url not in gif_history[gif_query]:
                        gif_url = url
                        gif_history[gif_query].append(url)
                        break
                if not gif_url:
                    gif_history[gif_query] = []
                    gif_url = gif_urls[0]
                    gif_history[gif_query].append(gif_url)
            ai_response = re.sub(r'gif_search\(.*?\)', '', ai_response, flags=re.IGNORECASE).strip()

    return {"text": ai_response, "image": image_url, "gif": gif_url}

@bot.event
async def on_ready():
    await tree.sync()
    print(f"{bot.user} is now online!")

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return

    if bot.user.mentioned_in(message) or (message.reference and message.reference.resolved.author == bot.user):
        response = await get_ai_response(message.author.id, message.content)
        if response["text"]:
            await message.reply(response["text"], mention_author=False)
        if response["image"]:
            await message.channel.send(response["image"])
        if response["gif"]:
            await message.channel.send(response["gif"])

    else:
        urls = re.findall(r'(https?://\S+)', message.content)
        if urls:
            for url in urls:
                analysis = await analyze_link(url)
                await message.reply(f"Link analysis for {url}:\n{analysis}", mention_author=False)

@tree.command(name="chat", description="say message idot")
async def chat(interaction: discord.Interaction, message: str):
    response = await get_ai_response(interaction.user.id, message)
    if response["text"]:
        await interaction.response.send_message(response["text"])
    if response["image"]:
        await interaction.followup.send(response["image"])
    if response["gif"]:
        await interaction.followup.send(response["gif"])

if __name__ == '__main__':
    import threading
    threading.Thread(target=app.run, kwargs={'host': '0.0.0.0', 'port': 7860}).start()
    bot.run(TOKEN)