diff --git a/README.md b/README.md
index cb3d628..b04bd7d 100644
--- a/README.md
+++ b/README.md
@@ -5,17 +5,18 @@
## Что можно?
Смут.
-14к токенов (лично у меня 32к не схавал).
+По слованом анона 16-20к токенов.
Кодинг с рабочим стримом (плюс в сравнении со скалой).
Подтягивать данные из интернета.
![image](https://github.com/Barbariskaa/Biba/assets/129290831/b5176621-4a1f-4b57-9c7f-865861825c30)
-Подтягивать подсказки из бинга.
+Подтягивать подсказки из бинга (через /suggestion после указанного в URL режима).
![image](https://user-images.githubusercontent.com/129290831/236729981-42f4cbf8-abbd-4deb-9a70-1a1cb5917119.png)
## Что по куму?
Ответы с сервера фильтруются посреди стрима, прямо как в чае. В среднем обрубает на 100 токенах и до нескольких сотен. Зависит от выбранного режима.
Возможно это ограничение можно обойти, если повозиться с промптами.
-Также банят. Могут забанить за один день, в отличии от Слаки. Решается перерегом.
+Также банят. Могут забанить за один день, в отличии от Слаки. Решается перерегом.
+С 29.05.2023г. на территории РФ работает только через VPN.
## Как поставить?
Нужны куки чата с Бингом.
@@ -24,8 +25,8 @@
Если установлен не Windows с Эджем, то придется повозиться с юзерагентом. Можно поставить следующий ЮА: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51`
Также, санкционным анонам придется повозиться с доступом к Бингу. Рекомендую использовать впн и чистить куки, затем искать в самом бинге Bing AI. Если нет кнопки перехода в чат, значит нужно либо чистить куки еще раз, либо пробовать другой айпи впна.
-![image](https://user-images.githubusercontent.com/129290831/236732426-91d87aa3-32e2-4f87-9758-ac5c4b222a71.png)
-
+![image](https://user-images.githubusercontent.com/129290831/236732426-91d87aa3-32e2-4f87-9758-ac5c4b222a71.png)
+Ссылка на чат по которой доступен Бинг в случае успешной настройки: https://www.bing.com/search?q=Bing+AI&showconv=1&wlsso=0
После успешного захода и открытия чата, нужно экспортировать сами куки. Для этого нужен следующий плагин:
* Хром/Эдж: https://chrome.google.com/webstore/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm
diff --git a/main.py b/main.py
index a2d7443..c441204 100644
--- a/main.py
+++ b/main.py
@@ -12,11 +12,11 @@ from urllib.parse import urlparse
PORT = 8081
HOST = "127.0.0.1"
-CONCATENATE_NSFW_RESPONSES = True
-DESIRED_TOKENS = 500
-ASK_TO_CONTINUE_AS_A_ROLE = "user" #user/system/assistant
+CONCATENATE_RESPONSES = True
+CONCATENATE_RESPONSES_STRING = "\n\n"
+DESIRED_TOKENS = 200
CONTINUATION_QUERY = "(continue roleplay from the sentence where you have left)"
-ASTERISK_FIX = True
+MARKUP_FIX = True
USER_MESSAGE_WORKAROUND = True
USER_MESSAGE = "Respond to the text above."
@@ -44,12 +44,16 @@ class LinkPlaceholderReplacer:
return ""
elif self.i == 1 and not re.search(self.regex, self.stash):
self.i = 0
- return self.stash
+ result = self.stash
+ self.stash = ""
+ return result
elif self.i == 2:
result = re.sub(r'\[\^(\d+)\^\]', lambda match: transform_into_hyperlink(match, urls), self.stash)
self.i = 0
self.stash = ""
return result
+
+ self.stash = ""
class OpenaiResponse:
@@ -157,8 +161,31 @@ class SSEHandler(web.View):
return web.json_response(data)
async def post(self):
- id = "chatcmpl-" + ''.join(random.choices(string.ascii_letters + string.digits, k=29))
- created = str(int(time.time()))
+
+ self.id = "chatcmpl-" + ''.join(random.choices(string.ascii_letters + string.digits, k=29))
+ self.created = str(int(time.time()))
+ self.responseWasFiltered = False
+ self.responseWasFilteredInLoop = False
+ self.response_text = ""
+ self.full_response = ""
+
+ async def streamCallback(self, data):
+ self.full_response += data
+ if stream:
+ await self.response.write(b"data: " + json.dumps({
+ "id": self.id,
+ "object": "chat.completion.chunk",
+ "created": self.created,
+ "model": "gpt-4",
+ "choices": [
+ {
+ "delta": { "content": data },
+ "index": 0,
+ "finish_reason": "null"
+ }
+ ]
+ }).encode() + b"\n\n")
+
request_data = await self.request.json()
messages = request_data.get('messages', [])
@@ -169,22 +196,14 @@ class SSEHandler(web.View):
prompt = messages[-1]['content']
context = process_messages(messages[:-1])
stream = request_data.get('stream', [])
- if stream:
- self.response = web.StreamResponse(
- status=200,
- headers={
- 'Content-Type': 'application/json',
- }
- )
- await self.response.prepare(self.request)
- else:
- self.response = web.StreamResponse(
- status=200,
- headers={
- 'Content-Type': 'application/json',
- }
- )
- await self.response.prepare(self.request)
+ self.response = web.StreamResponse(
+ status=200,
+ headers={
+ 'Content-Type': 'application/json',
+ }
+ )
+ await self.response.prepare(self.request)
+
conversation_style = self.request.path.split('/')[1]
if conversation_style not in ["creative", "balanced", "precise"]:
@@ -193,20 +212,21 @@ class SSEHandler(web.View):
suggestion = self.request.path.split('/')[2]
if suggestion != "suggestion":
suggestion = None
- try:
- chatbot = await Chatbot.create(cookie_path="cookies.json")
- except Exception as e:
- if str(e) == "[Errno 11001] getaddrinfo failed":
- print("Нет интернет соединения.")
+
+ async def output(self, streamCallback, nsfwMode=False):
+ self.response_text = ""
+
+ try:
+ chatbot = await Chatbot.create(cookie_path="cookies.json")
+ except Exception as e:
+ if str(e) == "[Errno 11001] getaddrinfo failed":
+ print("Нет интернет-соединения.")
+ return
+ print("Ошибка запуска чатбота.", str(e))
return
- print("Ошибка запуска чатбота.", str(e))
- return
-
- async def output():
+
print("\nФормируется запрос...")
-
link_placeholder_replacer = LinkPlaceholderReplacer()
- response_text = ""
wrote = 0
async for final, response in chatbot.ask_stream(
@@ -240,20 +260,22 @@ class SSEHandler(web.View):
print("\nОтвет от сервера:\n")
if message.get("contentOrigin") == "Apology":
if stream and wrote == 0:
- await self.response.write(prepare_response(id, created, filter=True))
+ await streamCallback(self, "Отфильтровано.")
+ if nsfwMode:
+ self.responseWasFilteredInLoop = True
+ break
- if stream:
- if ASTERISK_FIX and (response_text.count("*") % 2 == 1):
- asterisk = "*"
- else:
- asterisk = ""
- await self.response.write(prepare_response(id, created, content=asterisk, end=True, done=True))
- else:
- if ASTERISK_FIX and len(response_text.split("*")) % 2 == 0:
- response_text += "*"
- oai_response = prepare_response(id, created, content=response_text, stream=False)
- await self.response.write(oai_response)
- print("\nСообщение отозвано.")
+ if MARKUP_FIX:
+ if self.response_text.count("*") % 2 == 1 or self.response_text.count("*") == 1:
+ await streamCallback(self, "*")
+ self.response_text += "*"
+ if self.response_text.count("\"") % 2 == 1 or self.response_text.count("\"") == 1:
+ await streamCallback(self, "\"")
+ self.response_text += "\""
+
+ self.responseWasFiltered = True
+
+ print("\nОтвет отозван во время стрима.")
break
else:
streaming_content_chunk = message['text'][wrote:]
@@ -264,10 +286,9 @@ class SSEHandler(web.View):
if urls:
streaming_content_chunk = link_placeholder_replacer.process(streaming_content_chunk, urls)
- response_text += streaming_content_chunk
+ self.response_text += streaming_content_chunk
- if stream:
- await self.response.write(prepare_response(id, created, content=streaming_content_chunk))
+ await streamCallback(self, streaming_content_chunk)
print(message["text"][wrote:], end="")
sys.stdout.flush()
@@ -276,30 +297,97 @@ class SSEHandler(web.View):
if "suggestedResponses" in message:
suggested_responses = '\n'.join(x["text"] for x in message["suggestedResponses"])
suggested_responses = "\n```" + suggested_responses + "```"
- if stream:
- if suggestion:
- await self.response.write(prepare_response(id, created, content=streaming_content_chunk, end=True, done=True))
- else:
- await self.response.write(prepare_response(id, created, end=True, done=True))
- else:
- if suggestion:
- response_text = response_text + suggested_responses
- oai_response = prepare_response(id, created, content=response_text, stream=False)
- await self.response.write(oai_response)
+ if suggestion and not nsfwMode:
+ await streamCallback(self, suggested_responses)
break
if final and not response["item"]["messages"][-1].get("text"):
- if stream:
- await self.response.write(prepare_response(id, created, filter=True, end=True))
print("Сработал фильтр.")
+ if nsfwMode:
+ print("Выходим из цикла.\n")
+ self.responseWasFilteredInLoop = True
- if response_text:
- encoding = tiktoken.get_encoding("cl100k_base")
- tokens = len(encoding.encode(response_text))
- print(f"\nВсего токенов в ответе: \033[1;32m{tokens}\033[0m")
-
- try:
- await output()
await chatbot.close()
+
+
+
+ try:
+ if stream:
+ await self.response.write(b"data: " + json.dumps({
+ "id": self.id,
+ "object": "chat.completion.chunk",
+ "created": self.created,
+ "model": "gpt-4",
+ "choices": [
+ {
+ "delta": { "role": 'assistant' },
+ "index": 0,
+ "finish_reason": "null"
+ }
+ ]
+ }).encode() + b"\n\n")
+ await output(self, streamCallback)
+ encoding = tiktoken.get_encoding("cl100k_base")
+ if self.responseWasFiltered and CONCATENATE_RESPONSES:
+ tokens_total = len(encoding.encode(self.full_response))
+ if USER_MESSAGE_WORKAROUND:
+ prompt = CONTINUATION_QUERY
+ context += f"[assistant](#message)\n{self.response_text}\n"
+ else:
+ context+=f"[{messages[-1]['role']}](#message)\n{prompt}\n\n[assistant](#message)\n{self.response_text}\n"
+ prompt=CONTINUATION_QUERY
+ self.full_response += CONCATENATE_RESPONSES_STRING
+ print("Токенов в ответе:",tokens_total)
+ while tokens_total < DESIRED_TOKENS and not self.responseWasFilteredInLoop:
+ if stream:
+ await self.response.write(b"data: " + json.dumps({
+ "id": self.id,
+ "object": "chat.completion.chunk",
+ "created": self.created,
+ "model": "gpt-4",
+ "choices": [
+ {
+ "delta": { "content": CONCATENATE_RESPONSES_STRING },
+ "index": 0,
+ "finish_reason": "null"
+ }
+ ]
+ }).encode() + b"\n\n")
+ await output(self, streamCallback, nsfwMode=True)
+ context+=self.response_text + CONCATENATE_RESPONSES_STRING
+ self.full_response += CONCATENATE_RESPONSES_STRING
+ tokens_response = len(encoding.encode(self.response_text))
+ tokens_total = len(encoding.encode(self.full_response))
+ print(f"Токенов в ответе: {tokens_response}")
+ print(f"Токенов всего: {tokens_total}")
+
+ if stream:
+ await self.response.write(b"data: " + json.dumps({
+ "id": self.id,
+ "created": self.created,
+ "object": 'chat.completion.chunk',
+ "model": "gpt-4",
+ "choices": [{
+ "delta": {},
+ "finish_reason": 'stop',
+ "index": 0,
+ }],
+ }).encode() + b"\n\n")
+ else:
+ await self.response.write(json.dumps({
+ "id": self.id,
+ "created": self.created,
+ "object": "chat.completion",
+ "model": "gpt-4",
+ "choices": [{
+ "message": {
+ "role": 'assistant',
+ "content": self.full_response
+ },
+ 'finish_reason': 'stop',
+ 'index': 0,
+ }]
+ }).encode())
+ return self.response
except Exception as e:
error = f"Ошибка: {str(e)}."
error_text = ""
@@ -324,12 +412,19 @@ class SSEHandler(web.View):
print(error, error_text)
else:
print(error)
- if stream:
- oai_response = prepare_response(id, created, content=error + error_text, end=True, done=True, stream=True)
+ if not self.full_response:
+ if stream:
+ oai_response = prepare_response(self.id, self.created, content=error + error_text, end=True, done=True, stream=True)
+ else:
+ oai_response = prepare_response(self.id, self.created, content=error + error_text, stream=False)
else:
- oai_response = prepare_response(id, created, content=error + error_text, stream=False)
+ if stream:
+ oai_response = prepare_response(self.id, self.created, end=True, done=True, stream=True)
+ else:
+ oai_response = prepare_response(self.id, self.created, content=self.full_response, stream=False)
await self.response.write(oai_response)
- return self.response
+ return self.response
+
app = web.Application()
@@ -344,4 +439,4 @@ if __name__ == '__main__':
f"Режим precise: http://{HOST}:{PORT}/precise\n"
f"Режим balanced: http://{HOST}:{PORT}/balanced\n"
f"Также есть режим подсказок от Бинга. Чтобы его включить, нужно добавить /suggestion к концу URL, после режима.")
- web.run_app(app, host=HOST, port=PORT, print=None)
+ web.run_app(app, host=HOST, port=PORT, print=None)
\ No newline at end of file