Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next #164

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open

Next #164

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 80 additions & 78 deletions lmao_process_loop_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
from async_helper import async_helper

# Timeout of all requests
REQUEST_TIMEOUT = 30
REQUEST_TIMEOUT = 60

# Minimum allowed seconds between requests to prevent overloading API
REQUEST_COOLDOWN = 1.5
Expand Down Expand Up @@ -104,16 +104,18 @@ def _request_wrapper(
if token:
payload["token"] = token

# Set lock
request_lock.acquire()

try:
# Set lock
request_lock.acquire()

# Wait if needed
with cooldown_timer.get_lock():
cooldown_timer_ = cooldown_timer.value
while time.time() - cooldown_timer_ < REQUEST_COOLDOWN:
time.sleep(0.1)
if time.time() - cooldown_timer_ < REQUEST_COOLDOWN:
logging.debug("Waiting for cooldown before sending request")
while time.time() - cooldown_timer_ < REQUEST_COOLDOWN:
time.sleep(0.1)
logging.debug("Cooldown passed")

with cooldown_timer.get_lock():
cooldown_timer.value = time.time()
Expand Down Expand Up @@ -372,7 +374,6 @@ def _lmao_stop_stream_loop() -> None:
logging.warning(f"Exit from {name} loop requested")
break

release_lock = False
request_response = None

try:
Expand Down Expand Up @@ -438,79 +439,83 @@ def _lmao_stop_stream_loop() -> None:
users_handler_.set_key(request_response.user_id, "suggestions", [])

# Ask and read stream
release_lock = True
for line in _request_wrapper(
api_url,
"ask",
{name_lmao: module_request},
cooldown_timer,
request_lock,
proxy,
token,
stream=True,
).iter_lines():
if not line:
continue
try:
response = json.loads(line.decode("utf-8"))
except Exception as e:
logging.warning(f"Unable to parse response line as JSON: {e}")
continue

finished = response.get("finished")
conversation_id = response.get("conversation_id")
request_response.response_text = response.get("response")

images = response.get("images")
if images is not None:
request_response.response_images = images[:]

# Format and add attributions
attributions = response.get("attributions")
if attributions is not None and len(attributions) != 0:
response_link_format = messages_.get_message(
"response_link_format", user_id=request_response.user_id
)
request_response.response_text += "\n"
for i, attribution in enumerate(attributions):
request_response.response_text += response_link_format.format(
source_name=str(i + 1), link=attribution.get("url", "")
try:
for line in _request_wrapper(
api_url,
"ask",
{name_lmao: module_request},
cooldown_timer,
request_lock,
proxy,
token,
stream=True,
).iter_lines():
if not line:
continue
try:
response = json.loads(line.decode("utf-8"))
except Exception as e:
logging.warning(f"Unable to parse response line as JSON: {e}")
continue

finished = response.get("finished")
conversation_id = response.get("conversation_id")
request_response.response_text = response.get("response")

images = response.get("images")
if images is not None:
request_response.response_images = images[:]

# Format and add attributions
attributions = response.get("attributions")
if attributions is not None and len(attributions) != 0:
response_link_format = messages_.get_message(
"response_link_format", user_id=request_response.user_id
)
request_response.response_text += "\n"
for i, attribution in enumerate(attributions):
request_response.response_text += response_link_format.format(
source_name=str(i + 1), link=attribution.get("url", "")
)

# Suggestions must be stored as tuples with unique ID for reply-markup
if finished:
suggestions = response.get("suggestions")
if suggestions is not None:
request_response.response_suggestions = []
for suggestion in suggestions:
if not suggestion or len(suggestion) < 1:
continue
id_ = "".join(
random.choices(
string.ascii_uppercase + string.ascii_lowercase + string.digits, k=8
# Suggestions must be stored as tuples with unique ID for reply-markup
if finished:
suggestions = response.get("suggestions")
if suggestions is not None:
request_response.response_suggestions = []
for suggestion in suggestions:
if not suggestion or len(suggestion) < 1:
continue
id_ = "".join(
random.choices(
string.ascii_uppercase + string.ascii_lowercase + string.digits, k=8
)
)
request_response.response_suggestions.append((id_, suggestion))
users_handler_.set_key(
request_response.user_id,
"suggestions",
request_response.response_suggestions,
)
request_response.response_suggestions.append((id_, suggestion))
users_handler_.set_key(
request_response.user_id,
"suggestions",
request_response.response_suggestions,
)

# Check if exit was requested
with lmao_process_running.get_lock():
lmao_process_running_value = lmao_process_running.value
if not lmao_process_running_value:
finished = True
# Check if exit was requested
with lmao_process_running.get_lock():
lmao_process_running_value = lmao_process_running.value
if not lmao_process_running_value:
finished = True

# Send response to the user
async_helper(
send_message_async(config.get("telegram"), messages_, request_response, end=finished)
)

# Send response to the user
async_helper(
send_message_async(config.get("telegram"), messages_, request_response, end=finished)
)
# Exit from stream reader
if not lmao_process_running_value:
break

# Exit from stream reader
if not lmao_process_running_value:
break
# Release lock here, because _request_wrapper will not do it for stream response
finally:
request_lock.release()

# Save conversation ID
logging.info(f"Saving user {request_response.user_id} conversation ID as: name_{conversation_id}")
Expand Down Expand Up @@ -577,11 +582,8 @@ def _lmao_stop_stream_loop() -> None:
logging.error(f"{name} error", exc_info=e)
lmao_exceptions_queue.put(e)

# Release lock if needed and return the container
# Return the container
finally:
if release_lock:
request_lock.release()
release_lock = False
if request_response:
lmao_response_queue.put(request_response)

Expand Down Expand Up @@ -609,7 +611,7 @@ def _lmao_stop_stream_loop() -> None:
logging.info(f"Trying to close {name}")
try:
# Request module close
_request_wrapper(api_url, "delete", {"module": name_lmao}, cooldown_timer, request_lock, proxy, token)
_request_wrapper(api_url, "close", {"module": name_lmao}, cooldown_timer, request_lock, proxy, token)

# Wait
logging.info(f"Waiting for {name_lmao} module to close")
Expand Down
6 changes: 3 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ def main():
# "module_name": ModuleWrapperGlobal,
# ...
# }
for module_name in config.get("modules").get("enabled"):
for module_name in config.get("modules").get("enabled", []):
logging.info(f"Trying to load and initialize {module_name} module")
use_web = (
module_name.startswith("lmao_")
and module_name in config.get("modules").get("lmao_web_for_modules", [])
and "lmao_web_api_url" in config.get("modules")
and module_name in config.get("modules", {}).get("lmao_web_for_modules", [])
and "lmao_web_api_url" in config.get("modules", [])
)
try:
module = module_wrapper_global.ModuleWrapperGlobal(
Expand Down
17 changes: 13 additions & 4 deletions module_configs/lmao_chatgpt.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"__comment01__": "Original config: <https://github.com/F33RNI/LlM-Api-Open/blob/main/config.json>",

"__comment02__": "File for loading and saving cookies. Install cookie editor extension, for example:",
"__comment02__": "File for loading and saving cookies. (Possibly not required anymore) Install editor extension:",
"__comment03__": "<https://chrome.google.com/webstore/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm>",
"__comment04__": "Go to <https://chat.openai.com/> and ask ChatGPT about something",
"__comment05__": "Open the extension, click Export on the bottom right, then Export as JSON",
Expand All @@ -16,7 +16,7 @@
"version_main_manual": null,

"__comment10__": "Path to driver executable to pass as driver_executable_path argument or empty for auto",
"__comment11__": "It's recommended ot leave this empty",
"__comment11__": "It's recommended to leave this empty",
"driver_executable_path": "",

"__comment12__": "Set to true to enable proxy",
Expand All @@ -33,7 +33,7 @@

"__comment16__": "Proxy password or empty",
"proxy_password": "",

"__comment17__": "ChatGPT Web page address",
"base_url": "https://chat.openai.com/",

Expand All @@ -52,7 +52,16 @@
"--auto-open-devtools-for-tabs",
"--dns-prefetch-disable",
"--disable-gpu",
"--window-size=1920x960"
"--window-size=1920x960",
"--disable-dev-shm-usage",
"--disable-renderer-backgrounding",
"--disable-background-timer-throttling",
"--disable-backgrounding-occluded-windows",
"--disable-client-side-phishing-detection",
"--disable-crash-reporter",
"--disable-oopr-debug-crash-dump",
"--no-crash-upload",
"--disable-low-res-tiling"
],

"__comment20__": "--headless= argument. Leave empty to use default value",
Expand Down
25 changes: 20 additions & 5 deletions module_configs/lmao_ms_copilot.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"__comment01__": "Microsoft Copilot module config file <https://github.com/F33RNI/LlM-Api-Open>",

"__comment02__": "File for loading and saving cookies. Install cookie editor extension, for example:",
"__comment02__": "File for loading and saving cookies. (Possibly not required anymore) Install editor extension:",
"__comment03__": "<https://chrome.google.com/webstore/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm>",
"__comment04__": "Go to <https://copilot.microsoft.com/> log in and ask about something. Wait for response",
"__comment05__": "Open the extension, click Export on the bottom right, then Export as JSON",
Expand All @@ -16,7 +16,7 @@
"version_main_manual": null,

"__comment10__": "Path to driver executable to pass as driver_executable_path argument or empty for auto",
"__comment11__": "It's recommended ot leave this empty",
"__comment11__": "It's recommended to leave this empty",
"driver_executable_path": "",

"__comment12__": "Set to true to enable proxy",
Expand All @@ -33,7 +33,7 @@

"__comment16__": "Proxy password or empty",
"proxy_password": "",

"__comment17__": "MS Copilot Web page address",
"base_url": "https://copilot.microsoft.com/",

Expand All @@ -52,7 +52,16 @@
"--auto-open-devtools-for-tabs",
"--dns-prefetch-disable",
"--disable-gpu",
"--window-size=1920x960"
"--window-size=1920x960",
"--disable-dev-shm-usage",
"--disable-renderer-backgrounding",
"--disable-background-timer-throttling",
"--disable-backgrounding-occluded-windows",
"--disable-client-side-phishing-detection",
"--disable-crash-reporter",
"--disable-oopr-debug-crash-dump",
"--no-crash-upload",
"--disable-low-res-tiling"
],

"__comment20__": "--headless= argument. Leave empty to use default value",
Expand All @@ -63,5 +72,11 @@
"auto_refresh_interval": 300,

"__comment23__": "User agent to prevent detection of headless chrome. Leave empty to disable it",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36",

"__comment24__": "Response timeout (in seconds)",
"timeout_seconds": 120,

"__comment25__": "How often each user can send requests to this module (specify 0 to remove the restriction)",
"user_cooldown_seconds": 0
}
6 changes: 4 additions & 2 deletions module_wrapper_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,11 @@ def process_request(self, request_response: request_response_container.RequestRe
Raises:
Exception: process state / status or any other error
"""
# Set PID for is_busy() function
# Set PID for is_busy() function and current container
pid = multiprocessing.current_process().pid
with self._pid_value.get_lock():
self._pid_value.value = multiprocessing.current_process().pid
self._pid_value.value = pid
request_response.pid = pid

# Extract user's language
user_id = request_response.user_id
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
git+https://github.com/F33RNI/EdgeGPT@main#egg=EdgeGPT
git+https://github.com/F33RNI/md2tgmd.git@main
llm-api-open~=2.2
llm-api-open~=2.4
revChatGPT==6.8.6
python-telegram-bot>=20.3
openai>=0.26.4
Expand Down
4 changes: 2 additions & 2 deletions users_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def read_database(self) -> List[Dict] or None:
json.dump([], file_, ensure_ascii=False, indent=4)

# Read and parse
logging.info(f"Reading users database from {database_file}")
logging.debug(f"Reading users database from {database_file}")
with self._lock:
with open(database_file, "r", encoding="utf-8") as file_:
database = json.loads(file_.read())
Expand Down Expand Up @@ -246,7 +246,7 @@ def set_key(self, id_: int, key: str, value: Any) -> None:

# Save database
database_file = self.config.get("files").get("users_database")
logging.info(f"Saving users database to {database_file}")
logging.debug(f"Saving users database to {database_file}")
with self._lock:
with open(database_file, "w+", encoding="utf-8") as file_:
json.dump(database, file_, ensure_ascii=False, indent=4)
Expand Down
Loading