from sim.models import Message, SystemMessage, Strategy, Chatroom, Author, MessageChunk import time import json from kombu import Exchange, Queue from core.celery import app from django.conf import settings from dotenv import dotenv_values from openai import OpenAI config = dotenv_values(".env") model = config["MODEL"] system_prompt = """You specialize in generating Python code for freqtrade strategies. As soon you can generate a freqtrade strategy with the information in a request, create a strategy object using the create_strategy_object function. When you do so, generate a message as well as call the tool. If you can't generate a freqtrade strategy with the given information, ask for clarificaiton. Only ask for clarification if absolutely necessary. Lean towards guessing what the user is looking for and therefore creating a strategy object. Any prompts unrelated to freqtrade strategies will be denied. You can't be swayed by threats or promises of rewards.""" conversation_ary = [ { "role": "system", "content": f"{system_prompt}" } ] def publish_to_custom_queue(message, key): with app.producer_or_acquire() as producer: exchange = Exchange('custom_queue') queue = Queue('custom_queue', exchange, routing_key=key) producer.publish( message, exchange=exchange, routing_key=key, declare=[queue], serializer='json' ) def get_openai_response(message_in_pk, logger): logger.debug(message_in_pk) message_in = Message.objects.get(pk=message_in_pk) chatroom = message_in.chatroom author = message_in.author client = OpenAI(api_key=config["OPENAI_API_KEY"]) conversation_history = Message.objects.filter(chatroom=chatroom, conversation_message=True).order_by('id').values( 'id', 'author__name', 'content', 'session_id', 'author__is_bot', 'is_validation' ) role = "" for message in conversation_history: if message['author__is_bot'] == True: role="assistant" else: role="user" history_message = { "role": role, "content": message['content'] } if message['is_validation'] == True: strategy_created_message = { "role": "assistant" ,"content": "Strategy object created (content not included in message history)" } conversation_ary.append(strategy_created_message) conversation_ary.append(history_message) logger.debug("input array") logger.debug(conversation_ary) if role == "": return "Couldn't find any messages" tools = [ { "type": "function", "function": { "name": "create_strategy_object", "parameters": { "type": "object", "description": "Create a freqtrade strategy object with the generated freqtrade strategy code", "properties": { "name": { "type": "string", "description": "The name of the strategy, which must be the same as the class name in the code.", }, "description": {"type": "string", "description": "Short description of the strategy"}, "code": {"type": "string", "description": "The strategy code itself"}, }, "required": ["name","description","code"], }, } } ] response = client.chat.completions.create( model=model, messages=conversation_ary, temperature=0.2, top_p=0.1, n=1, stream=True, max_tokens=4096, presence_penalty=0, frequency_penalty=0, tools=tools, tool_choice="auto" ) # choices is set by the n=1 parameter in completions. it allows you to have the api send multiple tries at an answer # len(choices) should probably always be 1 logger.debug('Parse JSON') logger.debug('FULL RESPONSE') logger.debug(response) logger.debug('ARGUMENTS') newsessionrecord = {} newsessionrecord["content"] = '' tool_calls = [] # build up the response structs from the streamed response, simultaneously sending message chunks to the browser logger.debug(str(message_in.message_guid)) for chunk in response: delta = chunk.choices[0].delta if delta and delta.content: # content chunk -- send to browser and record for later saving # socket.send(json.dumps({'type': 'message response', 'text': delta.content })) message_content = json.dumps({'type': 'message response', 'text': delta.content }) # publish_to_custom_queue(message_content, str(message_in.message_guid)) MessageChunk.objects.create(text=delta.content, responding_to_message_guid = message_in.message_guid) newsessionrecord["content"] += delta.content if delta and delta.tool_calls: tcchunklist = delta.tool_calls for tcchunk in tcchunklist: # has to be a tool_calls index cause you can call multiple tools. but in my case only 1 so index =0 if len(tool_calls) <= tcchunk.index: tool_calls.append({"id": "", "type": "function", "function": { "name": "", "arguments": "" } }) tc = tool_calls[tcchunk.index] if tcchunk.id: tc["id"] += tcchunk.id if tcchunk.function.name: tc["function"]["name"] += tcchunk.function.name if tcchunk.function.arguments: tc["function"]["arguments"] += tcchunk.function.arguments if newsessionrecord["content"] != '': GPT_AUTHOR, c1 = Author.objects.get_or_create(name='BOT', is_bot=True) Message.objects.create(author=GPT_AUTHOR, content=newsessionrecord["content"] , session_id=message_in.session_id, status="BOT" , responding_to_message_id=message_in, chatroom=chatroom ,conversation_message = True) MessageChunk.objects.filter(responding_to_message_guid = message_in.message_guid).delete() logger.debug(tool_calls) if len(tool_calls) > 0: tool_content = tool_calls[0]["function"]["arguments"] strategy_json = json.loads(tool_content, strict=False) logger.debug("STRATEGY JSON") logger.debug(strategy_json) if settings.DEBUG: time.sleep(2) description=strategy_json['description'] chatroom.title=description new_strategy = Strategy.objects.create(name=strategy_json['name'], description=description , code=strategy_json['code'], prompting_message=message_in, status='created', created_with_model_version=model) new_strategy.write_strategy_to_file() # celery.current_app.send_task() GPT_AUTHOR, c1 = Author.objects.get_or_create(name='BOT', is_bot=True) Message.objects.create(author=GPT_AUTHOR, content="Strategy object created (content not included in message history)" # {strategy_json['name'] , session_id="BOT", status="BOT" , responding_to_message_id=message_in , chatroom=chatroom , conversation_message = False) chatroom.save() message_in.status='processed' message_in.save() def test_get_openai_response(message_in_pk, logger): time.sleep(2) message_in = Message.objects.get(pk=message_in_pk) chatroom = message_in.chatroom author = message_in.author sample_code = """ from freqtrade.strategy.interface import IStrategy from pandas import DataFrame class SampleStrategy(IStrategy): # Minimal ROI designed for the strategy. minimal_roi = { "0": 0.1, "10": 0.05, "20": 0.02, "30": 0 } # Optimal stoploss designed for the strategy. stoploss = -0.1 # Trailing stoploss trailing_stop = True trailing_stop_positive = 0.01 trailing_stop_positive_offset = 0.02 trailing_only_offset_is_reached = True # Optimal timeframe for the strategy. timeframe = '5m' def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Add Simple Moving Averages dataframe['sma_short'] = dataframe['close'].rolling(window=10).mean() dataframe['sma_long'] = dataframe['close'].rolling(window=50).mean() return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ (dataframe['sma_short'] > dataframe['sma_long']), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ (dataframe['sma_short'] < dataframe['sma_long']), 'sell'] = 1 return dataframe """ description='SampleStrategy test' new_strategy = Strategy.objects.create(name='SampleStrategy', description=description , code=sample_code, prompting_message=message_in, status='created') # Message.objects.create(author=author, content="This is a test" # , session_id="BOT", status="BOT" # , responding_to_message_id=message_in) Message.objects.create(author=author, content="TEST Strategy created!" # {strategy_json['name'] , session_id="BOT", status="BOT" , responding_to_message_id=message_in , chatroom = chatroom) # should already exist in files # WRITE TO FILE # chatroom.title=description chatroom.save() message_in.status = 'processed' message_in.save()