Skip to content

Commit

Permalink
Merge pull request #3 from alipay/dev_fanen
Browse files Browse the repository at this point in the history
Fix: Start a flask server on Windows instead of gunicorn server. Fix RequestOrm column type define.
  • Loading branch information
LandJerry authored Apr 26, 2024
2 parents 513c243 + c99f171 commit 31e9980
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 94 deletions.
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"])

0 comments on commit 31e9980

Please sign in to comment.