From 07c23253a124d8ddff39a88c716a6ecb7cd92a10 Mon Sep 17 00:00:00 2001 From: barrierye Date: Thu, 7 Mar 2024 17:31:25 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0AgentRuntime=E7=9A=84?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=AD=97=E6=AE=B5extra?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbuilder/core/agent.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appbuilder/core/agent.py b/appbuilder/core/agent.py index c0f7fb28..542a7b0e 100644 --- a/appbuilder/core/agent.py +++ b/appbuilder/core/agent.py @@ -279,8 +279,8 @@ def gen_sse_resp(stream_message): iterator = iter(stream_message.content) prev_result = { "content": next(iterator), - "extra": stream_message.extra if hasattr(stream_message, "extra") else {}, - "token_usage": stream_message.token_usage if hasattr(stream_message, "token_usage") else {}, + "extra": getattr(stream_message, "extra", None), + "token_usage": getattr(stream_message, "token_usage", {}), } for sub_content in iterator: logging.info(f"[request_id={request_id}, session_id={session_id}] streaming_result={prev_result}") @@ -294,8 +294,8 @@ def gen_sse_resp(stream_message): }, ensure_ascii=False) + "\n\n" prev_result = { "content": sub_content, - "extra": stream_message.extra if hasattr(stream_message, "extra") else {}, - "token_usage": stream_message.token_usage if hasattr(stream_message, "token_usage") else {}, + "extra": getattr(stream_message, "extra", None), + "token_usage": getattr(stream_message, "token_usage", {}), } logging.info(f"[request_id={request_id}, session_id={session_id}] streaming_result={prev_result}") yield "data: " + json.dumps({ From b01f0341d53374570b0a80ee7c81a82f392a1d30 Mon Sep 17 00:00:00 2001 From: barrierye Date: Fri, 8 Mar 2024 19:51:57 +0800 Subject: [PATCH 2/6] =?UTF-8?q?AgentRuntime=E6=94=AF=E6=8C=81=E9=A2=9D?= =?UTF-8?q?=E5=A4=96=E7=9A=84=E8=87=AA=E5=AE=9A=E4=B9=89=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbuilder/core/agent.py | 26 +++++++++++-------------- appbuilder/core/components/llms/base.py | 12 ++++++++++++ appbuilder/core/message.py | 4 ++-- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/appbuilder/core/agent.py b/appbuilder/core/agent.py index 542a7b0e..7728c18e 100644 --- a/appbuilder/core/agent.py +++ b/appbuilder/core/agent.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import sys +import copy import os import logging import uuid @@ -276,34 +277,29 @@ def warp(): def gen_sse_resp(stream_message): with app.app_context(): try: - iterator = iter(stream_message.content) - prev_result = { - "content": next(iterator), - "extra": getattr(stream_message, "extra", None), - "token_usage": getattr(stream_message, "token_usage", {}), - } - for sub_content in iterator: + content_iterator = iter(stream_message.content) + prev_content = next(content_iterator) + prev_result = copy.deepcopy(stream_message) + prev_result.content = prev_content + for sub_content in content_iterator: logging.info(f"[request_id={request_id}, session_id={session_id}] streaming_result={prev_result}") yield "data: " + json.dumps({ "code": 0, "message": "", "result": { "session_id": session_id, "is_completion": False, - "answer_message": prev_result + "answer_message": json.loads(prev_result.json(exclude_none=True)) } }, ensure_ascii=False) + "\n\n" - prev_result = { - "content": sub_content, - "extra": getattr(stream_message, "extra", None), - "token_usage": getattr(stream_message, "token_usage", {}), - } + prev_result = copy.deepcopy(stream_message) + prev_result.content = sub_content logging.info(f"[request_id={request_id}, session_id={session_id}] streaming_result={prev_result}") yield "data: " + json.dumps({ "code": 0, "message": "", "result": { "session_id": session_id, "is_completion": True, - "answer_message": prev_result + "answer_message": json.loads(prev_result.json(exclude_none=True)) } }, ensure_ascii=False) + "\n\n" self.user_session._post_append() @@ -317,7 +313,7 @@ def gen_sse_resp(stream_message): {'Content-Type': 'text/event-stream; charset=utf-8'}, ) else: - blocking_result = json.loads(answer.json(exclude_none=True)) + blocking_result = json.loads(copy.deepcopy(answer).json(exclude_none=True)) logging.info(f"[request_id={request_id}, session_id={session_id}] blocking_result={blocking_result}") self.user_session._post_append() return { diff --git a/appbuilder/core/components/llms/base.py b/appbuilder/core/components/llms/base.py index 29d789e7..9570b44e 100644 --- a/appbuilder/core/components/llms/base.py +++ b/appbuilder/core/components/llms/base.py @@ -17,6 +17,8 @@ from enum import Enum import logging import requests +import copy +import collections.abc from appbuilder.core.constants import GATEWAY_URL, GATEWAY_INNER_URL from pydantic import BaseModel, Field, ValidationError, HttpUrl, validator from pydantic.types import confloat @@ -40,6 +42,16 @@ class LLMMessage(Message): def __str__(self): return f"Message(name={self.name}, content={self.content}, " \ f"mtype={self.mtype}, extra={self.extra}, token_usage={self.token_usage})" + + def __deepcopy__(self, memo): + new_instance = self.__class__() + memo[id(self)] = new_instance + for k, v in self.__dict__.items(): + if k == "content" and isinstance(v, collections.abc.Iterator): + pass + else: + setattr(new_instance, k, copy.deepcopy(v, memo)) + return new_instance class CompletionRequest(object): diff --git a/appbuilder/core/message.py b/appbuilder/core/message.py index ed9d073d..022bf70e 100644 --- a/appbuilder/core/message.py +++ b/appbuilder/core/message.py @@ -16,14 +16,14 @@ import uuid -from pydantic import BaseModel +from pydantic import BaseModel, Extra from typing import Optional, TypeVar, Generic _T = TypeVar("_T") -class Message(BaseModel, Generic[_T]): +class Message(BaseModel, Generic[_T], extra=Extra.allow): content: Optional[_T] = {} name: Optional[str] = "msg" mtype: Optional[str] = "dict" From 697de00b75135909f5507a93b7a25aaec7388d14 Mon Sep 17 00:00:00 2001 From: barrierye Date: Wed, 13 Mar 2024 11:47:51 +0800 Subject: [PATCH 3/6] =?UTF-8?q?component=20lzay=E9=89=B4=E6=9D=83=E4=B8=8E?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=8B=89=E5=8F=96=E6=B7=BB=E5=8A=A0=E5=86=85?= =?UTF-8?q?=E5=AD=98cache=20&=20=E4=BC=98=E5=8C=96AgentRuntime=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbuilder/core/agent.py | 4 ++++ appbuilder/core/component.py | 7 ++++--- .../core/components/excel2figure/component.py | 4 +++- appbuilder/core/components/llms/base.py | 4 +++- appbuilder/core/utils.py | 16 ++++++++++++++++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/appbuilder/core/agent.py b/appbuilder/core/agent.py index e3df4e23..c6828e61 100644 --- a/appbuilder/core/agent.py +++ b/appbuilder/core/agent.py @@ -247,7 +247,11 @@ def warp(): app_builder_token = request.headers["X-Appbuilder-Token"] self.component.set_secret_key_and_gateway(secret_key=app_builder_token) except appbuilder.core._exception.BaseRPCException as e: + logging.error(f"failed to verify. err={e}", exc_info=True) raise BadRequest("X-Appbuilder-Token invalid") + except Exception as e: + logging.error(f"failed to verify. err={e}", exc_info=True) + raise e else: pass diff --git a/appbuilder/core/component.py b/appbuilder/core/component.py index 7aba7783..aefb7498 100644 --- a/appbuilder/core/component.py +++ b/appbuilder/core/component.py @@ -19,7 +19,7 @@ from pydantic import BaseModel from typing import Dict, List, Optional, Any - +from appbuilder.core.utils import ttl_lru_cache from appbuilder.core._client import HTTPClient from appbuilder.core.message import Message @@ -81,8 +81,9 @@ def __init__( self.lazy_certification = lazy_certification if not self.lazy_certification: self.set_secret_key_and_gateway(self.secret_key, self.gateway) - - def set_secret_key_and_gateway(self, secret_key: Optional[str] = None, gateway: str = ""): + + @ttl_lru_cache(seconds_to_live=1 * 60 * 60) # 1h + def appbuilder/core/component.py(self, secret_key: Optional[str] = None, gateway: str = ""): self.secret_key = secret_key self.gateway = gateway self._http_client = HTTPClient(self.secret_key, self.gateway) diff --git a/appbuilder/core/components/excel2figure/component.py b/appbuilder/core/components/excel2figure/component.py index 5b72c8e3..d37a059b 100644 --- a/appbuilder/core/components/excel2figure/component.py +++ b/appbuilder/core/components/excel2figure/component.py @@ -25,7 +25,7 @@ from appbuilder.core._exception import AppBuilderServerException, ModelNotSupportedException from appbuilder.core.component import Component, ComponentArguments from appbuilder.core.message import Message -from appbuilder.core.utils import ModelInfo +from appbuilder.core.utils import ModelInfo, ttl_lru_cache class Excel2FigureArgs(ComponentArguments): @@ -74,11 +74,13 @@ def __init__( self._check_model_and_get_model_url(self.model, self.model_type) self.server_sub_path = "/v1/ai_engine/copilot_engine/v1/api/agent/excel2figure" + @ttl_lru_cache(seconds_to_live=1 * 60 * 60) # 1h def set_secret_key_and_gateway(self, secret_key: Optional[str] = None, gateway: str = ""): super(Excel2Figure, self).set_secret_key_and_gateway( secret_key=secret_key, gateway=gateway) self.__class__.model_info = ModelInfo(client=self.http_client) + @ttl_lru_cache(seconds_to_live=1 * 60 * 60) # 1h def _check_model_and_get_model_url(self, model, model_type): if model and model in self.excluded_models: raise ModelNotSupportedException(f"Model {model} not supported") diff --git a/appbuilder/core/components/llms/base.py b/appbuilder/core/components/llms/base.py index 9570b44e..11b4c124 100644 --- a/appbuilder/core/components/llms/base.py +++ b/appbuilder/core/components/llms/base.py @@ -29,7 +29,7 @@ from typing import Dict, List, Optional, Any from appbuilder.core.component import ComponentArguments -from appbuilder.core.utils import ModelInfo +from appbuilder.core.utils import ModelInfo, ttl_lru_cache from appbuilder.utils.sse_util import SSEClient from appbuilder.core._exception import AppBuilderServerException, ModelNotSupportedException @@ -282,11 +282,13 @@ def __init__( if not lazy_certification: self._check_model_and_get_model_url(self.model_name, self.model_type) + @ttl_lru_cache(seconds_to_live=1 * 60 * 60) # 1h def set_secret_key_and_gateway(self, secret_key: Optional[str] = None, gateway: str = ""): super(CompletionBaseComponent, self).set_secret_key_and_gateway( secret_key=secret_key, gateway=gateway) self.__class__.model_info = ModelInfo(client=self.http_client) + @ttl_lru_cache(seconds_to_live=1 * 60 * 60) # 1h def _check_model_and_get_model_url(self, model, model_type): if model and model in self.excluded_models: raise ModelNotSupportedException(f"Model {model} not supported") diff --git a/appbuilder/core/utils.py b/appbuilder/core/utils.py index fa6af8f3..47d7445b 100644 --- a/appbuilder/core/utils.py +++ b/appbuilder/core/utils.py @@ -11,12 +11,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import time import itertools from typing import List from urllib.parse import urlparse from appbuilder.core._client import HTTPClient from appbuilder.core._exception import TypeNotSupportedException, ModelNotSupportedException from appbuilder.utils.model_util import GetModelListRequest, Models, RemoteModelCollector +from functools import lru_cache def utils_get_user_agent(): @@ -75,6 +77,20 @@ def is_url(string): return all([result.scheme, result.netloc]) +def ttl_lru_cache(seconds_to_live: int, maxsize: int = 128): + """ + Time aware lru caching + """ + def wrapper(func): + @lru_cache(maxsize) + def inner(__ttl, *args, **kwargs): + # Note that __ttl is not passed down to func, + # as it's only used to trigger cache miss after some time + return func(*args, **kwargs) + return lambda *args, **kwargs: inner(time.time() // seconds_to_live, *args, **kwargs) + return wrapper + + class ModelInfo: """ 模型信息类 """ From f876e53407dfb0001f5b1ad883aa7ba71655fd70 Mon Sep 17 00:00:00 2001 From: barrierye Date: Wed, 13 Mar 2024 16:11:38 +0800 Subject: [PATCH 4/6] bug fix --- appbuilder/core/component.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appbuilder/core/component.py b/appbuilder/core/component.py index aefb7498..31256c92 100644 --- a/appbuilder/core/component.py +++ b/appbuilder/core/component.py @@ -83,7 +83,7 @@ def __init__( self.set_secret_key_and_gateway(self.secret_key, self.gateway) @ttl_lru_cache(seconds_to_live=1 * 60 * 60) # 1h - def appbuilder/core/component.py(self, secret_key: Optional[str] = None, gateway: str = ""): + def set_secret_key_and_gateway(self, secret_key: Optional[str] = None, gateway: str = ""): self.secret_key = secret_key self.gateway = gateway self._http_client = HTTPClient(self.secret_key, self.gateway) From 337cd30a01adcb35205166b32f1e06cd23749332 Mon Sep 17 00:00:00 2001 From: barrierye Date: Wed, 13 Mar 2024 21:12:07 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E8=B0=83=E6=95=B4exception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbuilder/core/_exception.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/appbuilder/core/_exception.py b/appbuilder/core/_exception.py index bf34809b..e272cd64 100644 --- a/appbuilder/core/_exception.py +++ b/appbuilder/core/_exception.py @@ -74,15 +74,16 @@ class TypeNotSupportedException(BaseRPCException): class AppBuilderServerException(BaseRPCException): r"""AppBuilderServerException represent backend server failed response. """ + description: str = "Interal Server Error" + code: int = 500 def __init__(self, request_id="", code="", message="", service_err_code="", service_err_message=""): - r"""__init__ a AppBuilderServerException instance. - :param request_id: str, request unique id. - :param code: str, backend . - :rtype: - """ - super().__init__("request_id={}, code={}, message={}, service_err_code={}, service_err_message={} ".format( - request_id, code, message, service_err_code, service_err_message)) + self.description = "request_id={}, code={}, message={}, service_err_code={}, service_err_message={} ".format( + request_id, code, message, service_err_code, service_err_message) + self.code = code if code else self.code + + def __str__(self): + return self.description class InvalidRequestArgumentError(BaseRPCException): From 070677ce2a4868118ba18bce75950b368b476c0a Mon Sep 17 00:00:00 2001 From: barrierye Date: Wed, 13 Mar 2024 23:27:00 +0800 Subject: [PATCH 6/6] =?UTF-8?q?excel2figure=20=E4=BD=9C=E4=B8=BAtool?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E5=A4=B1=E8=B4=A5=E6=97=B6=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E6=8A=9B=E5=87=BA=E5=BC=82=E5=B8=B8=E3=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appbuilder/core/components/excel2figure/component.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appbuilder/core/components/excel2figure/component.py b/appbuilder/core/components/excel2figure/component.py index d37a059b..e74befde 100644 --- a/appbuilder/core/components/excel2figure/component.py +++ b/appbuilder/core/components/excel2figure/component.py @@ -223,8 +223,8 @@ def tool_eval( 'text': [result_msg.content], } except Exception as e: - result = f'绘制图表时发生错误:{e}' - logging.error(result, exc_info=True) + raise RuntimeError(f'绘制图表时发生错误:{e}') + if streaming: yield result else: