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

Fix: Start a flask server on Windows instead of gunicorn server. Fix RequestOrm column type define. #3

Merged
merged 3 commits into from
Apr 26, 2024
Merged
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
11 changes: 6 additions & 5 deletions agentuniverse/agent_serve/web/dal/request_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import datetime
import json

from sqlalchemy import JSON, Integer, String, DateTime, Column, create_engine
from sqlalchemy import JSON, Integer, String, DateTime, Text, Column
from sqlalchemy import create_engine
from sqlalchemy import select
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Expand All @@ -27,10 +28,10 @@ class RequestORM(Base):
"""SQLAlchemy ORM Model for RequestDO."""
__tablename__ = REQUEST_TABLE_NAME
id = Column(Integer, primary_key=True, autoincrement=True)
request_id = Column(String, nullable=False)
query = Column(String)
session_id = Column(String)
state = Column(String)
request_id = Column(String(20), nullable=False)
query = Column(Text)
session_id = Column(String(50))
state = Column(String(20))
result = Column(JSON)
steps = Column(JSON)
additional_args = Column(JSON)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from ..service_instance import ServiceInstance, ServiceNotFoundError
from .request_task import RequestTask
from .web_util import request_param, service_run_queue, make_standard_response
from agentuniverse.base.util.logging.logging_util import LOGGER
from ...base.util.logging.logging_util import LOGGER


app = Flask(__name__)
Expand Down
77 changes: 77 additions & 0 deletions agentuniverse/agent_serve/web/gunicorn_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# !/usr/bin/env python3
# -*- coding:utf-8 -*-

# @Time : 2024/4/23 18:10
# @Author : fanen.lhy
# @Email : [email protected]
# @FileName: gunicorn_server.py

import tomli
from gunicorn.app.base import BaseApplication

from .flask_server import app
from ...base.annotation.singleton import singleton


DEFAULT_GUNICORN_CONFIG = {
'bind': '127.0.0.1:8888',
'workers': 5,
'backlog': 2048,
'worker_class': 'gthread',
'threads': 4,
'timeout': 60,
'keepalive': 10
}


@singleton
class GunicornApplication(BaseApplication):
"""Use gunicorn to wrap the flask web server."""
def __init__(self, config_path: str = None):
self.options = {}
if config_path:
self.__load_config_from_file(config_path)
else:
self.default_config = None
self.application = app
super().__init__()

def load_config(self):
"""Check the config file first, use default config while config file
not exist, then overwrite parts which in options."""
if not self.default_config:
config = DEFAULT_GUNICORN_CONFIG
else:
config = self.default_config
for key, value in config.items():
if key in self.cfg.settings and value is not None:
self.cfg.set(key.lower(), value)

# The priority of the passed arguments supersedes that of config file.
for key, value in self.options.items():
if key in self.cfg.settings and value is not None:
self.cfg.set(key.lower(), value)

def update_config(self, options: dict):
self.options = options
self.load_config()

def load(self):
return self.application

def __load_config_from_file(self, config_path: str):
"""Load gunicorn config file."""
try:
with open(config_path, 'rb') as f:
config = tomli.load(f)["GUNICORN_CONFIG"]
except (FileNotFoundError, TypeError):
print("can't find gunicorn config file, use default config")
return
except (tomli.TOMLDecodeError, KeyError):
print("gunicorn config file isn't a valid toml, "
"use default config.")
return

self.default_config = {
key: value for key, value in config.items()
}
89 changes: 16 additions & 73 deletions agentuniverse/agent_serve/web/web_booster.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,79 +6,22 @@
# @Email : [email protected]
# @FileName: web_booster.py

import tomli
from gunicorn.app.base import BaseApplication

from .web_server import app
from agentuniverse.base.annotation.singleton import singleton


DEFAULT_GUNICORN_CONFIG = {
'bind': '127.0.0.1:8000',
'workers': 5,
'backlog': 2048,
'worker_class': 'gthread',
'threads': 4,
'timeout': 60,
'keepalive': 10
}


@singleton
class GunicornApplication(BaseApplication):
"""Use gunicorn to wrap the flask web server."""
def __init__(self, config_path: str = None):
self.options = {}
if config_path:
self.__load_config_from_file(config_path)
else:
self.default_config = None
self.application = app
super().__init__()

def load_config(self):
"""Check the config file first, use default config while config file
not exist, then overwrite parts which in options."""
if not self.default_config:
config = DEFAULT_GUNICORN_CONFIG
else:
config = self.default_config
for key, value in config.items():
if key in self.cfg.settings and value is not None:
self.cfg.set(key.lower(), value)

# The priority of the passed arguments supersedes that of config file.
for key, value in self.options.items():
if key in self.cfg.settings and value is not None:
self.cfg.set(key.lower(), value)

def update_config(self, options: dict):
self.options = options
self.load_config()

def load(self):
return self.application

def __load_config_from_file(self, config_path: str):
"""Load gunicorn config file."""
try:
with open(config_path, 'rb') as f:
config = tomli.load(f)["GUNICORN_CONFIG"]
except (FileNotFoundError, TypeError):
print("can't find gunicorn config file, use default config")
return
except (tomli.TOMLDecodeError, KeyError):
print("gunicorn config file isn't a valid toml, "
"use default config.")
return

self.default_config = {
key: value for key, value in config.items()
}
import sys


def start_web_server(**kwargs):
"""Start func of flask server. Accept input arguments to overwrite default
gunicorn config."""
GunicornApplication().update_config(kwargs)
GunicornApplication().run()
"""Start func of flask server(on windows platform) or gunicorn server(on
others). Accept input arguments to overwrite default gunicorn config."""
if sys.platform.startswith('win'):
from .flask_server import app
if 'bind' in kwargs:
host, port = kwargs['bind'].split(':')
port = int(port)
else:
port = 8888
host = '0.0.0.0'
app.run(port=port, host=host, debug=False)
else:
from .gunicorn_server import GunicornApplication
GunicornApplication().update_config(kwargs)
GunicornApplication().run()
2 changes: 1 addition & 1 deletion agentuniverse/agent_serve/web/web_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def wrapper(*args, **kwargs):
if "saved" in req_data:
kwargs['saved'] = req_data['saved']
else:
kwargs['saved'] = sig.parameters['saved']
kwargs['saved'] = sig.parameters['saved'].default
continue
if name == "session_id":
kwargs[name] = request.headers.get("X-Session-Id")
Expand Down
17 changes: 9 additions & 8 deletions agentuniverse/base/agentuniverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@
from agentuniverse.base.config.application_configer.application_config_manager import ApplicationConfigManager
from agentuniverse.base.config.component_configer.component_configer import ComponentConfiger
from agentuniverse.base.component.component_configer_util import ComponentConfigerUtil
from agentuniverse.base.config.component_configer.configers.prompt_configer import PromptConfiger
from agentuniverse.base.config.config_type_enum import ConfigTypeEnum
from agentuniverse.base.config.configer import Configer
from agentuniverse.base.config.custom_configer.custom_key_configer import CustomKeyConfiger
from agentuniverse.base.component.component_enum import ComponentEnum
from agentuniverse.base.util.system_util import get_project_root_path
from agentuniverse.base.util.logging.logging_util import init_loggers
from agentuniverse.agent_serve.web.request_task import RequestLibrary
from agentuniverse.agent_serve.web.web_booster import GunicornApplication
from agentuniverse.prompt.prompt_manager import PromptManager


@singleton
Expand Down Expand Up @@ -70,11 +67,15 @@ def start(self, config_path: str = None):
# init web request task database
RequestLibrary(configer=configer)

# init gunicorn web server
gunicorn_config_path = self.__parse_sub_config_path(
configer.value.get('SUB_CONFIG_PATH', {})
.get('gunicorn_config_path'), config_path)
GunicornApplication(config_path=gunicorn_config_path)
# init gunicorn web server on mac or unix platform
if not sys.platform.lower().startswith("win"):
gunicorn_config_path = self.__parse_sub_config_path(
configer.value.get('SUB_CONFIG_PATH', {})
.get('gunicorn_config_path'), config_path
)
from ..agent_serve.web.gunicorn_server import \
GunicornApplication
GunicornApplication(config_path=gunicorn_config_path)

# init all extension module
ext_classes = configer.value.get('EXTENSION_MODULES', {}).get('class_list')
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ gunicorn = "21.2.0"
chromadb = "0.4.24"
sphinx = "^7.2.6"
sphinx-rtd-theme = "^2.0.0"
aliyun-log-python-sdk = "0.8.8"
aliyun-log-python-sdk = { version = "0.8.8", optional = true}
googleapis-common-protos = "^1.63.0"
myst-parser = "^2.0.0"

[tool.poetry.extras]
log_ext = ["aliyun-log-python-sdk"]

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
pytest-cov = "^4.0.0"
Expand Down
8 changes: 3 additions & 5 deletions tests/test_agentuniverse/unit/agent_serve/test_web_booster.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import os
import pytest

from agentuniverse.agent_serve.web import web_booster
from agentuniverse.base.agentuniverse import AgentUniverse


def test_service():
os.environ['OPENAI_API_KEY'] = 'you openai api key'
# os.environ['OPENAI_API_KEY'] = 'you openai api key'
AgentUniverse().start(config_path='../agent/config.toml')
web_booster.start_web_server(bind="127.0.0.1:8002")


if __name__ == "__main__":
# os.environ['OPENAI_API_KEY'] = 'you openai api key'
AgentUniverse().start(config_path='../agent/config.toml')
web_booster.start_web_server(bind="0.0.0.0:8002")
pytest.main([__file__, "-s"])