|
import re |
|
from datetime import datetime |
|
from flask import request, Response, stream_with_context |
|
from requests import get |
|
from server.config import special_instructions |
|
from server.utils import generate_with_references, inject_references_to_messages, check_model, make_prompt |
|
from config import MODEL_REFERENCE_1, MODEL_REFERENCE_2, MODEL_REFERENCE_3 |
|
|
|
class Backend_Api: |
|
def __init__(self, bp, config: dict) -> None: |
|
self.bp = bp |
|
self.routes = { |
|
'/backend-api/v2/conversation': { |
|
'function': self._conversation, |
|
'methods': ['POST'] |
|
} |
|
} |
|
|
|
def _conversation(self): |
|
conversation_id = request.json['conversation_id'] |
|
try: |
|
api_key = request.json['api_key'] |
|
jailbreak = request.json['jailbreak'] |
|
model = request.json['model'] |
|
check_model(model) |
|
messages = self.build_messages(jailbreak) |
|
|
|
|
|
response = self.generate_response(model, messages, jailbreak) |
|
return Response(stream_with_context(response), mimetype='text/event-stream') |
|
|
|
except Exception as e: |
|
print(e) |
|
print(e.__traceback__.tb_next) |
|
return { |
|
'_action': '_ask', |
|
'success': False, |
|
"error": f"an error occurred {str(e)}" |
|
}, 400 |
|
|
|
def build_messages(self, jailbreak): |
|
_conversation = request.json['meta']['content']['conversation'] |
|
internet_access = request.json['meta']['content']['internet_access'] |
|
prompt = request.json['meta']['content']['parts'][0] |
|
|
|
|
|
conversation = _conversation |
|
|
|
|
|
if internet_access: |
|
current_date = datetime.now().strftime("%Y-%m-%d") |
|
query = f'Current date: {current_date}. ' + prompt["content"] |
|
search_results = self.fetch_search_results(query) |
|
conversation.extend(search_results) |
|
|
|
|
|
if jailbreak_instructions := self.getJailbreak(jailbreak): |
|
conversation.extend(jailbreak_instructions) |
|
|
|
|
|
conversation.append(prompt) |
|
|
|
|
|
if len(conversation) > 3: |
|
conversation = conversation[-4:] |
|
|
|
return conversation |
|
|
|
def fetch_search_results(self, query): |
|
search = get('https://ddg-api.herokuapp.com/search', |
|
params={ |
|
'query': query, |
|
'limit': 3, |
|
}) |
|
snippets = "" |
|
for index, result in enumerate(search.json()): |
|
snippet = f'[{index + 1}] "{result["snippet"]}" URL:{result["link"]}.' |
|
snippets += snippet |
|
|
|
response = "Here are some updated web searches. Use this to improve user response:" |
|
response += snippets |
|
|
|
return [{'role': 'system', 'content': response}] |
|
|
|
def generate_response(self, model, messages, jailbreak): |
|
reference_models = [MODEL_REFERENCE_1, MODEL_REFERENCE_2, MODEL_REFERENCE_3] |
|
data = { |
|
"instruction": [[] for _ in range(len(reference_models))], |
|
"references": [""] * len(reference_models), |
|
"model": [m for m in reference_models], |
|
} |
|
|
|
num_proc = len(reference_models) |
|
rounds = 1 |
|
|
|
for i in range(len(reference_models)): |
|
data["instruction"][i].append({"role": "user", "content": messages[-1]['content']}) |
|
|
|
for i_round in range(rounds): |
|
for i in range(num_proc): |
|
reference_model = data["model"][i] |
|
prompt = make_prompt(data["instruction"][i][-1]['content'], data["instruction"][i], reference_model) |
|
data["references"][i] = generate_with_references(reference_model, prompt) |
|
|
|
output = generate_with_references( |
|
model=model, |
|
messages=data["instruction"][0], |
|
references=data["references"], |
|
) |
|
|
|
all_output = "" |
|
for chunk in output: |
|
all_output += chunk |
|
|
|
if jailbreak: |
|
response_jailbreak = '' |
|
jailbroken_checked = False |
|
for message in all_output: |
|
response_jailbreak += message |
|
if jailbroken_checked: |
|
yield message |
|
else: |
|
if self.response_jailbroken_success(response_jailbreak): |
|
jailbroken_checked = True |
|
if self.response_jailbroken_failed(response_jailbreak): |
|
yield response_jailbreak |
|
jailbroken_checked = True |
|
else: |
|
yield all_output |
|
|
|
def response_jailbroken_success(self, response: str) -> bool: |
|
act_match = re.search(r'ACT:', response, flags=re.DOTALL) |
|
return bool(act_match) |
|
|
|
def response_jailbroken_failed(self, response): |
|
return False if len(response) < 4 else not (response.startswith("GPT:") or response.startswith("ACT:")) |
|
|
|
def getJailbreak(self, jailbreak): |
|
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 |