freechat / server /backend.py
K00B404's picture
Add application file
368a861
import re
from datetime import datetime
from g4f import ChatCompletion
from flask import request, Response, stream_with_context
from requests import get
from server.config import special_instructions
import requests
from bs4 import BeautifulSoup
import wikipedia
class Backend_Api:
def __init__(self, bp, config: dict) -> None:
"""
Initialize the Backend_Api class.
:param app: Flask application instance
:param config: Configuration dictionary
"""
self.bp = bp
self.routes = {
'/backend-api/v2/conversation': {
'function': self._conversation,
'methods': ['POST']
}
}
def _conversation(self):
"""
Handles the conversation route.
:return: Response object containing the generated conversation stream
"""
conversation_id = request.json['conversation_id']
try:
jailbreak = request.json['jailbreak']
model = request.json['model']
messages = build_messages(jailbreak)
# Generate response
response = ChatCompletion.create(
model=model,
chatId=conversation_id,
messages=messages
)
return Response(stream_with_context(generate_stream(response, jailbreak)), 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(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]
# Add the existing conversation
conversation = _conversation
# Add web results if enabled
if internet_access:
current_date = datetime.now().strftime("%Y-%m-%d")
query = f'Current date: {current_date}. ' + prompt["content"]
search_results = fetch_search_results("google",query)
conversation.extend(search_results)
# Add jailbreak instructions if enabled
if jailbreak_instructions := getJailbreak(jailbreak):
conversation.extend(jailbreak_instructions)
# Add the prompt
conversation.append(prompt)
# Reduce conversation size to avoid API Token quantity error
if len(conversation) > 3:
conversation = conversation[-4:]
return conversation
def fetch_search_results(search_engine, query):
"""Fetch search results for a given query from Google, DuckDuckGo, or Wikipedia.
:param search_engine: Search engine choice ('google', 'duckduckgo', or 'wikipedia')
:param query: Search query string
:return: List of search results
"""
if search_engine == 'google':
# Construct Google search URL and send a request
google_url = f'https://www.google.com/search?q={query}'
response = requests.get(google_url)
# Parse the HTML content using BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# Extract search result snippets (example: first 3 results)
search_results = soup.find_all('div', class_='tF2Cxc')
snippets = ""
for index, result in enumerate(search_results[:3]):
snippet = f'[{index + 1}] "{result.text}" URL: {result.find_parent("a")["href"]}.'
snippets += snippet
response = "Here are some Google search results:"
response += snippets
#elif search_engine == 'duckduckgo':
# Use the DuckDuckGo API (you can replace it with the appropriate URL and parameters)
# Your existing DuckDuckGo API code goes here
# Update the response accordingly
# Note: You should implement the DuckDuckGo API part here.
elif search_engine == 'wikipedia':
# Search for the query on Wikipedia
wikipedia.set_lang("en") # Set the language to English (you can change this)
try:
wikipedia_results = wikipedia.search(query, results=3) # Get the top 3 Wikipedia search results
snippets = ""
for index, result in enumerate(wikipedia_results):
page = wikipedia.page(result)
snippet = f'[{index + 1}] "{page.summary}" URL: {page.url}.'
snippets += snippet
response = "Here are some Wikipedia search results:"
response += snippets
except wikipedia.exceptions.DisambiguationError as e:
response = "Wikipedia search returned multiple results. Please specify your query."
else:
response = "Unsupported search engine choice. Use 'google', 'duckduckgo', or 'wikipedia'."
return [{'role': 'system', 'content': response}]
"""
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,
})
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_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 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