File size: 6,958 Bytes
dde49a0
720c1cf
c384631
1e2f57f
1111830
aae4949
 
 
1e2f57f
aae4949
 
 
 
 
1e2f57f
 
 
 
 
 
aae4949
70422d8
aae4949
 
 
 
 
 
 
14dbe6a
79bf545
 
 
c384631
 
720c1cf
 
c384631
720c1cf
c384631
 
 
724f683
 
c384631
 
 
 
 
 
 
67db7ba
 
 
 
 
 
c384631
 
 
 
 
 
 
 
 
 
 
 
 
 
720c1cf
aae4949
1111830
1e2f57f
 
 
d5176a8
1e2f57f
 
 
 
 
 
d5176a8
1e2f57f
 
 
 
 
 
 
 
1111830
1e2f57f
 
8a8fe1d
2436a6f
 
 
6642f5e
 
 
8a8fe1d
6642f5e
c384631
2436a6f
 
 
 
8a8fe1d
6642f5e
 
1e2f57f
 
8a8fe1d
d5176a8
1e2f57f
 
 
8a8fe1d
1e2f57f
 
 
 
 
 
e340463
1e2f57f
8a8fe1d
1e2f57f
2436a6f
1e2f57f
2436a6f
 
 
c384631
1e2f57f
d5176a8
 
1e2f57f
 
 
 
 
 
 
 
c384631
1e2f57f
0efc2d5
1e2f57f
 
0efc2d5
1e2f57f
0efc2d5
 
 
 
 
 
1e2f57f
5684fd5
d5176a8
8a8fe1d
14dbe6a
 
 
 
 
 
 
 
 
 
 
1e2f57f
14dbe6a
8a8fe1d
1e2f57f
14dbe6a
1e2f57f
c384631
8a8fe1d
 
49e515b
1e2f57f
 
49e515b
1e2f57f
 
49e515b
 
 
 
 
 
 
d5176a8
 
c384631
1e2f57f
 
 
 
 
 
c384631
 
 
 
 
 
 
d5176a8
c384631
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
210
211
212
213
214
215
216
import re
import time
import g4f
from g4f import ChatCompletion
from googletrans import Translator
from flask import request
from datetime import datetime
from requests import get
from server.auto_proxy import get_random_proxy, update_working_proxies
from server.config import special_instructions


class Backend_Api:
    def __init__(self, app, config: dict) -> None:
        """  
        Initialize the Backend_Api class.  

        :param app: Flask application instance  
        :param config: Configuration dictionary  
        """
        self.app = app
        self.use_auto_proxy = config['use_auto_proxy']
        self.routes = {
            '/backend-api/v2/conversation': {
                'function': self._conversation,
                'methods': ['POST']
            }
        }

        # if self.use_auto_proxy:
        #    update_proxies = threading.Thread(
        #        target=update_working_proxies, daemon=True)
        #    update_proxies.start()

    def _conversation(self):
        """    
        Handles the conversation route.    

        :return: Response object containing the generated conversation stream    
        """
        max_retries = 3
        retries = 0
        conversation_id = request.json['conversation_id']
        
        while retries < max_retries:
            try:
                jailbreak = request.json['jailbreak']
                model = request.json['model']
                messages = build_messages(jailbreak)

                # Generate response
                response = ChatCompletion.create(
                    model=model, 
                    stream=True, 
                    chatId=conversation_id,
                    messages=messages
                )

                return self.app.response_class(generate_stream(response, jailbreak), mimetype='text/event-stream')

            except Exception as e:
                print(e)
                print(e.__traceback__.tb_next)

                retries += 1
                if retries >= max_retries:
                    return {
                        '_action': '_ask',
                        'success': False,
                        "error": f"an error occurred {str(e)}"
                    }, 400
                time.sleep(3)  # Wait 3 second before trying again


def build_messages(jailbreak):
    """  
    Build the messages for the conversation.  

    :param jailbreak: Jailbreak instruction string  
    :return: List of messages for the conversation  
    """
    _conversation = request.json['meta']['content']['conversation']
    internet_access = request.json['meta']['content']['internet_access']
    prompt = request.json['meta']['content']['parts'][0]

    # Generate system message
    current_date = datetime.now().strftime("%Y-%m-%d")
    system_message = (
        f'You are ChatGPT also known as ChatGPT, a large language model trained by OpenAI. '
        f'Strictly follow the users instructions. '
        f'Knowledge cutoff: 2021-09-01 Current date: {current_date}. '
        f'{set_response_language(prompt)}'
    )

    # Initialize the conversation with the system message
    conversation = [{'role': 'system', 'content': system_message}]

    # Add the existing conversation
    conversation += _conversation

    # Add web results if enabled
    conversation += fetch_search_results(
        prompt["content"]) if internet_access else []

    # Add jailbreak instructions if enabled
    if jailbreak_instructions := getJailbreak(jailbreak):
        conversation += jailbreak_instructions

    # Add the prompt
    conversation += [prompt]

    # Reduce conversation size to avoid API Token quantity error
    conversation = conversation[-4:] if len(conversation) > 3 else conversation

    return conversation


def fetch_search_results(query):
    """  
    Fetch search results for a given query.  

    :param query: Search query string  
    :return: List of search results  
    """
    search = get('https://ddg-api.herokuapp.com/search',
                 params={
                     'query': query,
                     'limit': 3,
                 })

    results = []
    snippets = ""
    for index, result in enumerate(search.json()):
        snippet = f'[{index + 1}] "{result["snippet"]}" URL:{result["link"]}.'
        snippets += snippet
    results.append({'role': 'system', 'content': snippets})

    return results


def generate_stream(response, jailbreak):
    """  
    Generate the conversation stream.  

    :param response: Response object from ChatCompletion.create  
    :param jailbreak: Jailbreak instruction string  
    :return: Generator object yielding messages in the conversation  
    """
    if getJailbreak(jailbreak):
        response_jailbreak = ''
        jailbroken_checked = False
        for message in response:
            response_jailbreak += message
            if jailbroken_checked:
                yield message
            else:
                if response_jailbroken_success(response_jailbreak):
                    jailbroken_checked = True
                if response_jailbroken_failed(response_jailbreak):
                    yield response_jailbreak
                    jailbroken_checked = True
    else:
        yield from response


def response_jailbroken_success(response: str) -> bool:
    """Check if the response has been jailbroken.

    :param response: Response string
    :return: Boolean indicating if the response has been jailbroken
    """
    act_match = re.search(r'ACT:', response, flags=re.DOTALL)
    return bool(act_match)


def response_jailbroken_failed(response):
    """  
    Check if the response has not been jailbroken.  

    :param response: Response string  
    :return: Boolean indicating if the response has not been jailbroken  
    """
    return False if len(response) < 4 else not (response.startswith("GPT:") or response.startswith("ACT:"))


def set_response_language(prompt):  
    """  
    Set the response language based on the prompt content.  
  
    :param prompt: Prompt dictionary  
    :return: String indicating the language to be used for the response  
    """  
    translator = Translator()  
    max_chars = 256  
    content_sample = prompt['content'][:max_chars]  
    detected_language = translator.detect(content_sample).lang  
    return f"You will respond in the language: {detected_language}. "  



def getJailbreak(jailbreak):
    """  
    Check if jailbreak instructions are provided.  

    :param jailbreak: Jailbreak instruction string  
    :return: Jailbreak instructions if provided, otherwise None  
    """
    if jailbreak != "default":
        special_instructions[jailbreak][0]['content'] += special_instructions['two_responses_instruction']
        if jailbreak in special_instructions:
            special_instructions[jailbreak]
            return special_instructions[jailbreak]
        else:
            return None
    else:
        return None