mirror of
https://github.com/hanzo-io/team.git
synced 2026-10-30 18:56:23 +00:00
260 lines
6.4 KiB
Python
260 lines
6.4 KiB
Python
import frappe
|
|
|
|
from raven.ai.handler import stream_response
|
|
from raven.ai.openai_client import (
|
|
code_interpreter_file_types,
|
|
file_search_file_types,
|
|
get_open_ai_client,
|
|
)
|
|
|
|
|
|
def handle_bot_dm(message, bot):
|
|
"""
|
|
Function to handle direct messages to the bot.
|
|
|
|
We need to start a new thread with the message and create a new conversation in OpenAI
|
|
"""
|
|
|
|
client = get_open_ai_client()
|
|
|
|
# If the message is a poll, send a message to the user that we don't support polls for AI yet
|
|
|
|
if message.message_type == "Poll":
|
|
bot.send_message(
|
|
channel_id=message.channel_id,
|
|
text="Sorry, I don't support polls yet. Please send a text message or file.",
|
|
)
|
|
return
|
|
|
|
if message.message_type in ["File", "Image"]:
|
|
|
|
if message.message_type == "File" and not check_if_bot_has_file_search(bot, message.channel_id):
|
|
return
|
|
|
|
# If the file has an "fid" query parameter, we need to remove that from the file_url
|
|
if "fid" in message.file:
|
|
file_url = message.file.split("?fid=")[0]
|
|
else:
|
|
file_url = message.file
|
|
|
|
# Upload the file to OpenAI
|
|
file = create_file_in_openai(file_url, message.message_type, client)
|
|
|
|
content, attachments = get_content_attachment_for_file(message.message_type, file.id, file_url)
|
|
|
|
ai_thread = client.beta.threads.create(
|
|
messages=[
|
|
{
|
|
"role": "user",
|
|
"content": content,
|
|
"metadata": {"user": message.owner, "message": message.name},
|
|
"attachments": attachments,
|
|
}
|
|
],
|
|
metadata={
|
|
"bot": bot.name,
|
|
"channel": message.channel_id,
|
|
"user": message.owner,
|
|
"message": message.name,
|
|
},
|
|
)
|
|
|
|
else:
|
|
ai_thread = client.beta.threads.create(
|
|
messages=[
|
|
{
|
|
"role": "user",
|
|
"content": message.content,
|
|
"metadata": {"user": message.owner, "message": message.name},
|
|
}
|
|
],
|
|
metadata={
|
|
"bot": bot.name,
|
|
"channel": message.channel_id,
|
|
"user": message.owner,
|
|
"message": message.name,
|
|
},
|
|
)
|
|
|
|
thread_channel = frappe.get_doc(
|
|
{
|
|
"doctype": "Raven Channel",
|
|
"channel_name": message.name,
|
|
"type": "Private",
|
|
"is_thread": 1,
|
|
"is_ai_thread": 1,
|
|
"is_dm_thread": 1,
|
|
"openai_thread_id": ai_thread.id,
|
|
"thread_bot": bot.name,
|
|
}
|
|
).insert()
|
|
|
|
# Update the message to mark it as a thread
|
|
message.is_thread = 1
|
|
message.save()
|
|
# nosemgrep We need to commit here since the response will be streamed, and hence might take a while
|
|
frappe.db.commit()
|
|
|
|
frappe.publish_realtime(
|
|
"ai_event",
|
|
{
|
|
"text": "Raven AI is thinking...",
|
|
"channel_id": thread_channel.name,
|
|
"bot": bot.name,
|
|
},
|
|
doctype="Raven Channel",
|
|
docname=thread_channel.name,
|
|
after_commit=True,
|
|
)
|
|
|
|
stream_response(ai_thread_id=ai_thread.id, bot=bot, channel_id=thread_channel.name)
|
|
|
|
|
|
def handle_ai_thread_message(message, channel):
|
|
"""
|
|
Function to handle messages in an AI thread
|
|
|
|
When a new message is sent, we need to send it to the OpenAI API and then stream the response
|
|
"""
|
|
|
|
client = get_open_ai_client()
|
|
|
|
bot = frappe.get_doc("Raven Bot", channel.thread_bot)
|
|
|
|
if message.message_type in ["File", "Image"]:
|
|
|
|
file_url = message.file
|
|
if "fid" in file_url:
|
|
file_url = file_url.split("?fid=")[0]
|
|
|
|
if message.message_type == "File" and not check_if_bot_has_file_search(bot, channel.name):
|
|
return
|
|
# Upload the file to OpenAI
|
|
try:
|
|
file = create_file_in_openai(file_url, message.message_type, client)
|
|
except Exception as e:
|
|
frappe.log_error("Raven AI Error", frappe.get_traceback())
|
|
bot.send_message(
|
|
channel_id=channel.name,
|
|
text="Sorry, there was an error in processing your file. Please try again.<br/><br/>Error: "
|
|
+ str(e),
|
|
)
|
|
return
|
|
|
|
content, attachments = get_content_attachment_for_file(message.message_type, file.id, file_url)
|
|
|
|
try:
|
|
client.beta.threads.messages.create(
|
|
thread_id=channel.openai_thread_id,
|
|
role="user",
|
|
content=content,
|
|
metadata={"user": message.owner, "message": message.name},
|
|
attachments=attachments,
|
|
)
|
|
except Exception as e:
|
|
frappe.log_error("Raven AI Error", frappe.get_traceback())
|
|
bot.send_message(
|
|
channel_id=channel.name,
|
|
text="Sorry, there was an error in processing your file. Please try again.<br/><br/>Error: "
|
|
+ str(e),
|
|
)
|
|
return
|
|
|
|
else:
|
|
|
|
client.beta.threads.messages.create(
|
|
thread_id=channel.openai_thread_id,
|
|
role="user",
|
|
content=message.content,
|
|
metadata={"user": message.owner, "message": message.name},
|
|
)
|
|
|
|
frappe.publish_realtime(
|
|
"ai_event",
|
|
{
|
|
"text": "Raven AI is thinking...",
|
|
"channel_id": channel.name,
|
|
"bot": bot.name,
|
|
},
|
|
doctype="Raven Channel",
|
|
docname=channel.name,
|
|
)
|
|
|
|
stream_response(ai_thread_id=channel.openai_thread_id, bot=bot, channel_id=channel.name)
|
|
|
|
|
|
def check_if_bot_has_file_search(bot, channel_id):
|
|
"""
|
|
Checks of bot has file search. If not, send a message to the user. If yes, return True
|
|
"""
|
|
|
|
if not bot.enable_file_search:
|
|
bot.send_message(
|
|
channel_id=channel_id,
|
|
text="Sorry, your bot does not support file search. Please enable it and try again.",
|
|
)
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def create_file_in_openai(file_url: str, message_type: str, client):
|
|
"""
|
|
Function to create a file in OpenAI
|
|
|
|
We need to upload the file to OpenAI and return the file ID
|
|
"""
|
|
|
|
file_doc = frappe.get_doc("File", {"file_url": file_url})
|
|
file_path = file_doc.get_full_path()
|
|
|
|
file = client.files.create(
|
|
file=open(file_path, "rb"), purpose="assistants" if message_type == "File" else "vision"
|
|
)
|
|
|
|
return file
|
|
|
|
|
|
def get_content_attachment_for_file(message_type: str, file_id: str, file_url: str):
|
|
|
|
attachments = None
|
|
|
|
if message_type == "File":
|
|
content = f"Uploaded a file. URL of the file is '{file_url}'. Use this URL to attach the file to any document if requested."
|
|
|
|
file_extension = file_url.split(".")[-1].lower()
|
|
|
|
if file_extension == "pdf":
|
|
content += (
|
|
" The file is a PDF. If it's not machine readable, you can extract the text via images."
|
|
)
|
|
|
|
attachments = []
|
|
|
|
if file_extension in code_interpreter_file_types:
|
|
attachments.append(
|
|
{
|
|
"file_id": file_id,
|
|
"tools": [{"type": "code_interpreter"}],
|
|
}
|
|
)
|
|
|
|
if file_extension in file_search_file_types:
|
|
attachments.append(
|
|
{
|
|
"file_id": file_id,
|
|
"tools": [{"type": "file_search"}],
|
|
}
|
|
)
|
|
|
|
else:
|
|
content = [
|
|
{
|
|
"type": "text",
|
|
"text": f"Uploaded an image. URL of the image is '{file_url}'. Use this URL to attach the image to any document if requested.",
|
|
},
|
|
{"type": "image_file", "image_file": {"file_id": file_id}},
|
|
]
|
|
|
|
return content, attachments
|