diff --git a/requirements.txt b/requirements.txt index 0dc625c..735687e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ slack-bolt slack-sdk openai +requests diff --git a/slackAskBot.py b/slackAskBot.py index 95b8253..ed7764d 100644 --- a/slackAskBot.py +++ b/slackAskBot.py @@ -1,6 +1,7 @@ import os import re import json +import requests from slack_bolt import App from slack_bolt.adapter.socket_mode import SocketModeHandler @@ -47,7 +48,6 @@ def ask_chatgpt(text, user_id, channel_id, thread_ts=None, ts=None): messages = [] if thread_ts: messages = fetch_conversation_history(channel_id, thread_ts) - #print(f"DEBUG: Messages fetched from thread: {messages}") # Determine channel or user name for settings channel_name = determine_channel_or_user_name(channel_id, user_id) @@ -55,7 +55,6 @@ def ask_chatgpt(text, user_id, channel_id, thread_ts=None, ts=None): # Load channel-specific settings system_prompt, please_wait_message = load_channel_settings(channel_name) - #print(f"Using system_prompt: '{system_prompt}'") print(f"Using please_wait_message: '{please_wait_message}' for channel/user name: {channel_name}") # Get the bot's user ID @@ -63,37 +62,12 @@ def ask_chatgpt(text, user_id, channel_id, thread_ts=None, ts=None): # Construct the conversation history conversation_history = construct_conversation_history(messages, bot_user_id, user_id, text, thread_ts, ts) - #print(f"DEBUG: Constructed conversation history: {conversation_history}") # Send a message to indicate that GPT-4 is working on the request and capture the timestamp status_message_ts = post_message_to_slack(channel_id, please_wait_message, thread_ts) def worker(): - initial_header_ts = None - initial_response_ts = None - initial_footer_ts = None - initial_status_ts = None - - # Generate initial response with GPT-3.5-turbo - #print(conversation_history) - try: - initial_response, initial_status_ts = gpt(conversation_history, system_prompt, model="gpt-3.5-turbo-16k", max_tokens=1000, channel_id=channel_id, thread_ts=thread_ts) - # Modify the markdown to strip out the language specifier after the triple backticks - initial_response = re.sub(r'```[a-zA-Z]+', '```', initial_response) - print(initial_response) - # Post the GPT-3.5-turbo response and save its timestamp - initial_header_ts = post_message_to_slack(channel_id, "Initial GPT-3.5-Turbo response:", thread_ts) - initial_response_ts = post_message_to_slack(channel_id, f"{initial_response}", thread_ts) - initial_footer_ts = post_message_to_slack(channel_id, "Checking that with GPT-4...", thread_ts) - # Append the initial GPT-3.5-turbo response to the conversation history - conversation_history.append({"role": "assistant", "content": f"GPT-3.5 response: {initial_response}"}) - - # Synthetic review process - synthetic_review = "Let’s review the GPT-3.5 response and determine whether any corrections, clarifications, or elaborations are required. If no changes are needed, reply with 'GOOD AS-IS' in all caps. If the GPT-3.5 response needs to be completely replaced, don't refer to it: just respond with a new message, and the old one be deleted and not visible. DO NOT make reference to 'a misunderstanding in my previous response', 'My mistake', or similar: just write a new and better response. If the GPT-3.5 response only needs clarification or elaboration, not correction, instead reply with 'ADDITIONAL RESPONSE: ' in all caps, followed by a follow-up message with any clarifications or elaborations we want to append to the last reply. If you can't tell for sure without a tool call whether the response is correct or not, go ahead and make the tool call." - conversation_history.append({"role": "assistant", "content": synthetic_review}) - except Exception as e: - print(f"Error from GPT-3.5: {e}") - #print(conversation_history) + initial_header_ts, initial_response_ts, initial_footer_ts, initial_status_ts = generate_initial_response(conversation_history, system_prompt, channel_id, thread_ts) # Enhance response with GPT-4-Turbo enhanced_response, enhanced_response_ts = gpt(conversation_history, system_prompt, model="gpt-4-turbo-preview", channel_id=channel_id, thread_ts=thread_ts) @@ -134,10 +108,30 @@ def worker(): thread = threading.Thread(target=worker) thread.start() +def generate_initial_response(conversation_history, system_prompt, channel_id, thread_ts): + initial_header_ts = None + initial_response_ts = None + initial_footer_ts = None + initial_status_ts = None + + try: + initial_response, initial_status_ts = gpt(conversation_history, system_prompt, model="gpt-3.5-turbo-16k", max_tokens=1000, channel_id=channel_id, thread_ts=thread_ts) + initial_response = re.sub(r'```[a-zA-Z]+', '```', initial_response) + print(initial_response) + initial_header_ts = post_message_to_slack(channel_id, "Initial GPT-3.5-Turbo response:", thread_ts) + initial_response_ts = post_message_to_slack(channel_id, f"{initial_response}", thread_ts) + initial_footer_ts = post_message_to_slack(channel_id, "Checking that with GPT-4...", thread_ts) + conversation_history.append({"role": "assistant", "content": f"GPT-3.5 response: {initial_response}"}) + synthetic_review = "Let's review the GPT-3.5 response and determine whether any corrections, clarifications, or elaborations are required. If no changes are needed, reply with 'GOOD AS-IS' in all caps. If the GPT-3.5 response needs to be completely replaced, don't refer to it: just respond with a new message, and the old one be deleted and not visible. DO NOT make reference to 'a misunderstanding in my previous response', 'My mistake', or similar: just write a new and better response. If the GPT-3.5 response only needs clarification or elaboration, not correction, instead reply with 'ADDITIONAL RESPONSE: ' in all caps, followed by a follow-up message with any clarifications or elaborations we want to append to the last reply. If you can't tell for sure without a tool call whether the response is correct or not, go ahead and make the tool call." + conversation_history.append({"role": "assistant", "content": synthetic_review}) + except Exception as e: + print(f"Error from GPT-3.5: {e}") + + return initial_header_ts, initial_response_ts, initial_footer_ts, initial_status_ts + def fetch_conversation_history(channel_id, thread_ts): try: history = app.client.conversations_replies(channel=channel_id, ts=thread_ts) - #print(f"DEBUG: Fetched conversation history for channel {channel_id} and thread {thread_ts}. Messages count: {len(history['messages'])}") return history['messages'] except SlackApiError as e: print(f"Failed to fetch conversation history: {e}") @@ -197,6 +191,21 @@ def construct_conversation_history(messages, bot_user_id, user_id, current_text, content = msg.get("text") if content: conversation_history.append({"role": role, "content": content}) + if 'files' in msg: + for file in msg['files']: + if file['filetype'] in ['text', 'python', 'javascript', 'html', 'diff']: # Add other file types as needed + url = file['url_private'] + headers = {"Authorization": f"Bearer {os.environ['SLACK_BOT_TOKEN']}"} + response = requests.get(url, headers=headers) + if response.status_code == 200: + print(f"Successfully retrieved file content from URL: {url}") + #print(f"Response: {response.text}") + conversation_history.append({"role": role, "content": response.text}) + else: + print(f"Failed to retrieve file content from URL: {url}") + print(f"Response status code: {response.status_code}") + else: + print(f"Not adding file type {file['filetype']}") # Add the current message to the conversation history if it's not already included if not thread_ts or thread_ts == ts: @@ -338,7 +347,23 @@ def gpt(conversation_history, system_prompt, channel_id, thread_ts=None, model=" if tools_parameter: request_payload["tools"] = tools_parameter - response = client.chat.completions.create(**request_payload) + # Serialize the request payload to JSON for size check + serialized_payload = json.dumps(request_payload) + if len(serialized_payload.encode('utf-8')) > 128 * 1024: # Check if the payload exceeds 128 KB + print("Payload exceeds 128 KB limit.") + return "This thread is too long. Please start another shorter thread.", None + + try: + response = client.chat.completions.create(**request_payload) + except Exception as e: + error_message = str(e) + print(f"Error from GPT: {error_message}") + if "context length" in error_message or "Request too large" in error_message: + if model == "gpt-3.5-turbo-16k": + post_message_to_slack(channel_id, "This thread is too long for GPT-3.5. Please wait for GPT-4.", thread_ts) + elif model == "gpt-4-turbo-preview": + post_message_to_slack(channel_id, "This thread is too long for GPT-4. Please start another shorter thread.", thread_ts) + return None, "error" # Debugging: Print the entire GPT response print("GPT Response:", response)