autogen
This commit is contained in:
parent
8e375b0ed2
commit
804599bbc3
@ -539,18 +539,18 @@ def get_crazy_functions():
|
|||||||
except:
|
except:
|
||||||
print('Load function plugin failed')
|
print('Load function plugin failed')
|
||||||
|
|
||||||
# try:
|
try:
|
||||||
# from crazy_functions.多智能体 import 多智能体终端
|
from crazy_functions.多智能体 import 多智能体终端
|
||||||
# function_plugins.update({
|
function_plugins.update({
|
||||||
# "多智能体终端(微软AutoGen)": {
|
"多智能体终端(微软AutoGen)": {
|
||||||
# "Group": "智能体",
|
"Group": "智能体",
|
||||||
# "Color": "stop",
|
"Color": "stop",
|
||||||
# "AsButton": True,
|
"AsButton": True,
|
||||||
# "Function": HotReload(多智能体终端)
|
"Function": HotReload(多智能体终端)
|
||||||
# }
|
}
|
||||||
# })
|
})
|
||||||
# except:
|
except:
|
||||||
# print('Load function plugin failed')
|
print('Load function plugin failed')
|
||||||
|
|
||||||
# try:
|
# try:
|
||||||
# from crazy_functions.chatglm微调工具 import 微调数据集生成
|
# from crazy_functions.chatglm微调工具 import 微调数据集生成
|
||||||
|
@ -3,6 +3,8 @@ from toolbox import report_execption, get_log_folder, update_ui_lastest_msg, Sin
|
|||||||
from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom
|
from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom
|
||||||
from crazy_functions.agent_fns.general import AutoGenGeneral
|
from crazy_functions.agent_fns.general import AutoGenGeneral
|
||||||
import time
|
import time
|
||||||
|
from autogen import AssistantAgent, UserProxyAgent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AutoGenMath(AutoGenGeneral):
|
class AutoGenMath(AutoGenGeneral):
|
||||||
|
584
crazy_functions/agent_fns/bridge_autogen.py
Normal file
584
crazy_functions/agent_fns/bridge_autogen.py
Normal file
@ -0,0 +1,584 @@
|
|||||||
|
from time import sleep
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from typing import List, Optional, Dict, Callable, Union
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import numpy as np
|
||||||
|
from flaml import tune, BlendSearch
|
||||||
|
from flaml.tune.space import is_constant
|
||||||
|
from flaml.automl.logger import logger_formatter
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
try:
|
||||||
|
import openai
|
||||||
|
from openai.error import (
|
||||||
|
ServiceUnavailableError,
|
||||||
|
RateLimitError,
|
||||||
|
APIError,
|
||||||
|
InvalidRequestError,
|
||||||
|
APIConnectionError,
|
||||||
|
Timeout,
|
||||||
|
AuthenticationError,
|
||||||
|
)
|
||||||
|
from openai import Completion as openai_Completion
|
||||||
|
import diskcache
|
||||||
|
|
||||||
|
ERROR = None
|
||||||
|
except ImportError:
|
||||||
|
ERROR = ImportError("please install openai and diskcache to use the autogen.oai subpackage.")
|
||||||
|
openai_Completion = object
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
if not logger.handlers:
|
||||||
|
# Add the console handler.
|
||||||
|
_ch = logging.StreamHandler(stream=sys.stdout)
|
||||||
|
_ch.setFormatter(logger_formatter)
|
||||||
|
logger.addHandler(_ch)
|
||||||
|
|
||||||
|
|
||||||
|
class Completion(openai_Completion):
|
||||||
|
"""A class for OpenAI completion API.
|
||||||
|
|
||||||
|
It also supports: ChatCompletion, Azure OpenAI API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# set of models that support chat completion
|
||||||
|
chat_models = {
|
||||||
|
"gpt-3.5-turbo",
|
||||||
|
"gpt-3.5-turbo-0301", # deprecate in Sep
|
||||||
|
"gpt-3.5-turbo-0613",
|
||||||
|
"gpt-3.5-turbo-16k",
|
||||||
|
"gpt-3.5-turbo-16k-0613",
|
||||||
|
"gpt-35-turbo",
|
||||||
|
"gpt-35-turbo-16k",
|
||||||
|
"gpt-4",
|
||||||
|
"gpt-4-32k",
|
||||||
|
"gpt-4-32k-0314", # deprecate in Sep
|
||||||
|
"gpt-4-0314", # deprecate in Sep
|
||||||
|
"gpt-4-0613",
|
||||||
|
"gpt-4-32k-0613",
|
||||||
|
}
|
||||||
|
|
||||||
|
# price per 1k tokens
|
||||||
|
price1K = {
|
||||||
|
"text-ada-001": 0.0004,
|
||||||
|
"text-babbage-001": 0.0005,
|
||||||
|
"text-curie-001": 0.002,
|
||||||
|
"code-cushman-001": 0.024,
|
||||||
|
"code-davinci-002": 0.1,
|
||||||
|
"text-davinci-002": 0.02,
|
||||||
|
"text-davinci-003": 0.02,
|
||||||
|
"gpt-3.5-turbo": (0.0015, 0.002),
|
||||||
|
"gpt-3.5-turbo-instruct": (0.0015, 0.002),
|
||||||
|
"gpt-3.5-turbo-0301": (0.0015, 0.002), # deprecate in Sep
|
||||||
|
"gpt-3.5-turbo-0613": (0.0015, 0.002),
|
||||||
|
"gpt-3.5-turbo-16k": (0.003, 0.004),
|
||||||
|
"gpt-3.5-turbo-16k-0613": (0.003, 0.004),
|
||||||
|
"gpt-35-turbo": (0.0015, 0.002),
|
||||||
|
"gpt-35-turbo-16k": (0.003, 0.004),
|
||||||
|
"gpt-35-turbo-instruct": (0.0015, 0.002),
|
||||||
|
"gpt-4": (0.03, 0.06),
|
||||||
|
"gpt-4-32k": (0.06, 0.12),
|
||||||
|
"gpt-4-0314": (0.03, 0.06), # deprecate in Sep
|
||||||
|
"gpt-4-32k-0314": (0.06, 0.12), # deprecate in Sep
|
||||||
|
"gpt-4-0613": (0.03, 0.06),
|
||||||
|
"gpt-4-32k-0613": (0.06, 0.12),
|
||||||
|
}
|
||||||
|
|
||||||
|
default_search_space = {
|
||||||
|
"model": tune.choice(
|
||||||
|
[
|
||||||
|
"text-ada-001",
|
||||||
|
"text-babbage-001",
|
||||||
|
"text-davinci-003",
|
||||||
|
"gpt-3.5-turbo",
|
||||||
|
"gpt-4",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"temperature_or_top_p": tune.choice(
|
||||||
|
[
|
||||||
|
{"temperature": tune.uniform(0, 2)},
|
||||||
|
{"top_p": tune.uniform(0, 1)},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"max_tokens": tune.lograndint(50, 1000),
|
||||||
|
"n": tune.randint(1, 100),
|
||||||
|
"prompt": "{prompt}",
|
||||||
|
}
|
||||||
|
|
||||||
|
seed = 41
|
||||||
|
cache_path = f".cache/{seed}"
|
||||||
|
# retry after this many seconds
|
||||||
|
retry_wait_time = 10
|
||||||
|
# fail a request after hitting RateLimitError for this many seconds
|
||||||
|
max_retry_period = 120
|
||||||
|
# time out for request to openai server
|
||||||
|
request_timeout = 60
|
||||||
|
|
||||||
|
openai_completion_class = not ERROR and openai.Completion
|
||||||
|
_total_cost = 0
|
||||||
|
optimization_budget = None
|
||||||
|
|
||||||
|
_history_dict = _count_create = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_cache(cls, seed: Optional[int] = 41, cache_path_root: Optional[str] = ".cache"):
|
||||||
|
"""Set cache path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
seed (int, Optional): The integer identifier for the pseudo seed.
|
||||||
|
Results corresponding to different seeds will be cached in different places.
|
||||||
|
cache_path (str, Optional): The root path for the cache.
|
||||||
|
The complete cache path will be {cache_path}/{seed}.
|
||||||
|
"""
|
||||||
|
cls.seed = seed
|
||||||
|
cls.cache_path = f"{cache_path_root}/{seed}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_cache(cls, seed: Optional[int] = None, cache_path_root: Optional[str] = ".cache"):
|
||||||
|
"""Clear cache.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
seed (int, Optional): The integer identifier for the pseudo seed.
|
||||||
|
If omitted, all caches under cache_path_root will be cleared.
|
||||||
|
cache_path (str, Optional): The root path for the cache.
|
||||||
|
The complete cache path will be {cache_path}/{seed}.
|
||||||
|
"""
|
||||||
|
if seed is None:
|
||||||
|
shutil.rmtree(cache_path_root, ignore_errors=True)
|
||||||
|
return
|
||||||
|
with diskcache.Cache(f"{cache_path_root}/{seed}") as cache:
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _book_keeping(cls, config: Dict, response):
|
||||||
|
"""Book keeping for the created completions."""
|
||||||
|
if response != -1 and "cost" not in response:
|
||||||
|
response["cost"] = cls.cost(response)
|
||||||
|
if cls._history_dict is None:
|
||||||
|
return
|
||||||
|
if cls._history_compact:
|
||||||
|
value = {
|
||||||
|
"created_at": [],
|
||||||
|
"cost": [],
|
||||||
|
"token_count": [],
|
||||||
|
}
|
||||||
|
if "messages" in config:
|
||||||
|
messages = config["messages"]
|
||||||
|
if len(messages) > 1 and messages[-1]["role"] != "assistant":
|
||||||
|
existing_key = get_key(messages[:-1])
|
||||||
|
value = cls._history_dict.pop(existing_key, value)
|
||||||
|
key = get_key(messages + [choice["message"] for choice in response["choices"]])
|
||||||
|
else:
|
||||||
|
key = get_key([config["prompt"]] + [choice.get("text") for choice in response["choices"]])
|
||||||
|
value["created_at"].append(cls._count_create)
|
||||||
|
value["cost"].append(response["cost"])
|
||||||
|
value["token_count"].append(
|
||||||
|
{
|
||||||
|
"model": response["model"],
|
||||||
|
"prompt_tokens": response["usage"]["prompt_tokens"],
|
||||||
|
"completion_tokens": response["usage"].get("completion_tokens", 0),
|
||||||
|
"total_tokens": response["usage"]["total_tokens"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
cls._history_dict[key] = value
|
||||||
|
cls._count_create += 1
|
||||||
|
return
|
||||||
|
cls._history_dict[cls._count_create] = {
|
||||||
|
"request": config,
|
||||||
|
"response": response.to_dict_recursive(),
|
||||||
|
}
|
||||||
|
cls._count_create += 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_response(cls, config: Dict, raise_on_ratelimit_or_timeout=False, use_cache=True):
|
||||||
|
"""Get the response from the openai api call.
|
||||||
|
|
||||||
|
Try cache first. If not found, call the openai api. If the api call fails, retry after retry_wait_time.
|
||||||
|
"""
|
||||||
|
config = config.copy()
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_max_valid_n(cls, key, max_tokens):
|
||||||
|
# find the max value in max_valid_n_per_max_tokens
|
||||||
|
# whose key is equal or larger than max_tokens
|
||||||
|
return max(
|
||||||
|
(value for k, value in cls._max_valid_n_per_max_tokens.get(key, {}).items() if k >= max_tokens),
|
||||||
|
default=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_min_invalid_n(cls, key, max_tokens):
|
||||||
|
# find the min value in min_invalid_n_per_max_tokens
|
||||||
|
# whose key is equal or smaller than max_tokens
|
||||||
|
return min(
|
||||||
|
(value for k, value in cls._min_invalid_n_per_max_tokens.get(key, {}).items() if k <= max_tokens),
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_region_key(cls, config):
|
||||||
|
# get a key for the valid/invalid region corresponding to the given config
|
||||||
|
config = cls._pop_subspace(config, always_copy=False)
|
||||||
|
return (
|
||||||
|
config["model"],
|
||||||
|
config.get("prompt", config.get("messages")),
|
||||||
|
config.get("stop"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _update_invalid_n(cls, prune, region_key, max_tokens, num_completions):
|
||||||
|
if prune:
|
||||||
|
# update invalid n and prune this config
|
||||||
|
cls._min_invalid_n_per_max_tokens[region_key] = invalid_n = cls._min_invalid_n_per_max_tokens.get(
|
||||||
|
region_key, {}
|
||||||
|
)
|
||||||
|
invalid_n[max_tokens] = min(num_completions, invalid_n.get(max_tokens, np.inf))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _pop_subspace(cls, config, always_copy=True):
|
||||||
|
if "subspace" in config:
|
||||||
|
config = config.copy()
|
||||||
|
config.update(config.pop("subspace"))
|
||||||
|
return config.copy() if always_copy else config
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_params_for_create(cls, config: Dict) -> Dict:
|
||||||
|
"""Get the params for the openai api call from a config in the search space."""
|
||||||
|
params = cls._pop_subspace(config)
|
||||||
|
if cls._prompts:
|
||||||
|
params["prompt"] = cls._prompts[config["prompt"]]
|
||||||
|
else:
|
||||||
|
params["messages"] = cls._messages[config["messages"]]
|
||||||
|
if "stop" in params:
|
||||||
|
params["stop"] = cls._stops and cls._stops[params["stop"]]
|
||||||
|
temperature_or_top_p = params.pop("temperature_or_top_p", None)
|
||||||
|
if temperature_or_top_p:
|
||||||
|
params.update(temperature_or_top_p)
|
||||||
|
if cls._config_list and "config_list" not in params:
|
||||||
|
params["config_list"] = cls._config_list
|
||||||
|
return params
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(
|
||||||
|
cls,
|
||||||
|
context: Optional[Dict] = None,
|
||||||
|
use_cache: Optional[bool] = True,
|
||||||
|
config_list: Optional[List[Dict]] = None,
|
||||||
|
filter_func: Optional[Callable[[Dict, Dict, Dict], bool]] = None,
|
||||||
|
raise_on_ratelimit_or_timeout: Optional[bool] = True,
|
||||||
|
allow_format_str_template: Optional[bool] = False,
|
||||||
|
**config,
|
||||||
|
):
|
||||||
|
"""Make a completion for a given context.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context (Dict, Optional): The context to instantiate the prompt.
|
||||||
|
It needs to contain keys that are used by the prompt template or the filter function.
|
||||||
|
E.g., `prompt="Complete the following sentence: {prefix}, context={"prefix": "Today I feel"}`.
|
||||||
|
The actual prompt will be:
|
||||||
|
"Complete the following sentence: Today I feel".
|
||||||
|
More examples can be found at [templating](https://microsoft.github.io/autogen/docs/Use-Cases/enhanced_inference#templating).
|
||||||
|
use_cache (bool, Optional): Whether to use cached responses.
|
||||||
|
config_list (List, Optional): List of configurations for the completion to try.
|
||||||
|
The first one that does not raise an error will be used.
|
||||||
|
Only the differences from the default config need to be provided.
|
||||||
|
E.g.,
|
||||||
|
|
||||||
|
```python
|
||||||
|
response = oai.Completion.create(
|
||||||
|
config_list=[
|
||||||
|
{
|
||||||
|
"model": "gpt-4",
|
||||||
|
"api_key": os.environ.get("AZURE_OPENAI_API_KEY"),
|
||||||
|
"api_type": "azure",
|
||||||
|
"api_base": os.environ.get("AZURE_OPENAI_API_BASE"),
|
||||||
|
"api_version": "2023-03-15-preview",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gpt-3.5-turbo",
|
||||||
|
"api_key": os.environ.get("OPENAI_API_KEY"),
|
||||||
|
"api_type": "open_ai",
|
||||||
|
"api_base": "https://api.openai.com/v1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "llama-7B",
|
||||||
|
"api_base": "http://127.0.0.1:8080",
|
||||||
|
"api_type": "open_ai",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
prompt="Hi",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
filter_func (Callable, Optional): A function that takes in the context, the config and the response and returns a boolean to indicate whether the response is valid. E.g.,
|
||||||
|
|
||||||
|
```python
|
||||||
|
def yes_or_no_filter(context, config, response):
|
||||||
|
return context.get("yes_or_no_choice", False) is False or any(
|
||||||
|
text in ["Yes.", "No."] for text in oai.Completion.extract_text(response)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
raise_on_ratelimit_or_timeout (bool, Optional): Whether to raise RateLimitError or Timeout when all configs fail.
|
||||||
|
When set to False, -1 will be returned when all configs fail.
|
||||||
|
allow_format_str_template (bool, Optional): Whether to allow format string template in the config.
|
||||||
|
**config: Configuration for the openai API call. This is used as parameters for calling openai API.
|
||||||
|
The "prompt" or "messages" parameter can contain a template (str or Callable) which will be instantiated with the context.
|
||||||
|
Besides the parameters for the openai API call, it can also contain:
|
||||||
|
- `max_retry_period` (int): the total time (in seconds) allowed for retrying failed requests.
|
||||||
|
- `retry_wait_time` (int): the time interval to wait (in seconds) before retrying a failed request.
|
||||||
|
- `seed` (int) for the cache. This is useful when implementing "controlled randomness" for the completion.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Responses from OpenAI API, with additional fields.
|
||||||
|
- `cost`: the total cost.
|
||||||
|
When `config_list` is provided, the response will contain a few more fields:
|
||||||
|
- `config_id`: the index of the config in the config_list that is used to generate the response.
|
||||||
|
- `pass_filter`: whether the response passes the filter function. None if no filter is provided.
|
||||||
|
"""
|
||||||
|
if ERROR:
|
||||||
|
raise ERROR
|
||||||
|
config_list = [
|
||||||
|
{
|
||||||
|
"model": "llama-7B",
|
||||||
|
"api_base": "http://127.0.0.1:8080",
|
||||||
|
"api_type": "open_ai",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
last = len(config_list) - 1
|
||||||
|
cost = 0
|
||||||
|
for i, each_config in enumerate(config_list):
|
||||||
|
base_config = config.copy()
|
||||||
|
base_config["allow_format_str_template"] = allow_format_str_template
|
||||||
|
base_config.update(each_config)
|
||||||
|
if i < last and filter_func is None and "max_retry_period" not in base_config:
|
||||||
|
# max_retry_period = 0 to avoid retrying when no filter is given
|
||||||
|
base_config["max_retry_period"] = 0
|
||||||
|
try:
|
||||||
|
response = cls.create(
|
||||||
|
context,
|
||||||
|
use_cache,
|
||||||
|
raise_on_ratelimit_or_timeout=i < last or raise_on_ratelimit_or_timeout,
|
||||||
|
**base_config,
|
||||||
|
)
|
||||||
|
if response == -1:
|
||||||
|
return response
|
||||||
|
pass_filter = filter_func is None or filter_func(
|
||||||
|
context=context, base_config=config, response=response
|
||||||
|
)
|
||||||
|
if pass_filter or i == last:
|
||||||
|
response["cost"] = cost + response["cost"]
|
||||||
|
response["config_id"] = i
|
||||||
|
response["pass_filter"] = pass_filter
|
||||||
|
return response
|
||||||
|
cost += response["cost"]
|
||||||
|
except (AuthenticationError, RateLimitError, Timeout, InvalidRequestError):
|
||||||
|
logger.debug(f"failed with config {i}", exc_info=1)
|
||||||
|
if i == last:
|
||||||
|
raise
|
||||||
|
|
||||||
|
params = cls._construct_params(context, config, allow_format_str_template=allow_format_str_template)
|
||||||
|
if not use_cache:
|
||||||
|
return cls._get_response(
|
||||||
|
params, raise_on_ratelimit_or_timeout=raise_on_ratelimit_or_timeout, use_cache=False
|
||||||
|
)
|
||||||
|
seed = cls.seed
|
||||||
|
if "seed" in params:
|
||||||
|
cls.set_cache(params.pop("seed"))
|
||||||
|
with diskcache.Cache(cls.cache_path) as cls._cache:
|
||||||
|
cls.set_cache(seed)
|
||||||
|
return cls._get_response(params, raise_on_ratelimit_or_timeout=raise_on_ratelimit_or_timeout)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def instantiate(
|
||||||
|
cls,
|
||||||
|
template: Union[str, None],
|
||||||
|
context: Optional[Dict] = None,
|
||||||
|
allow_format_str_template: Optional[bool] = False,
|
||||||
|
):
|
||||||
|
if not context or template is None:
|
||||||
|
return template
|
||||||
|
if isinstance(template, str):
|
||||||
|
return template.format(**context) if allow_format_str_template else template
|
||||||
|
return template(context)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _construct_params(cls, context, config, prompt=None, messages=None, allow_format_str_template=False):
|
||||||
|
params = config.copy()
|
||||||
|
model = config["model"]
|
||||||
|
prompt = config.get("prompt") if prompt is None else prompt
|
||||||
|
messages = config.get("messages") if messages is None else messages
|
||||||
|
# either "prompt" should be in config (for being compatible with non-chat models)
|
||||||
|
# or "messages" should be in config (for tuning chat models only)
|
||||||
|
if prompt is None and (model in cls.chat_models or issubclass(cls, ChatCompletion)):
|
||||||
|
if messages is None:
|
||||||
|
raise ValueError("Either prompt or messages should be in config for chat models.")
|
||||||
|
if prompt is None:
|
||||||
|
params["messages"] = (
|
||||||
|
[
|
||||||
|
{
|
||||||
|
**m,
|
||||||
|
"content": cls.instantiate(m["content"], context, allow_format_str_template),
|
||||||
|
}
|
||||||
|
if m.get("content")
|
||||||
|
else m
|
||||||
|
for m in messages
|
||||||
|
]
|
||||||
|
if context
|
||||||
|
else messages
|
||||||
|
)
|
||||||
|
elif model in cls.chat_models or issubclass(cls, ChatCompletion):
|
||||||
|
# convert prompt to messages
|
||||||
|
params["messages"] = [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": cls.instantiate(prompt, context, allow_format_str_template),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
params.pop("prompt", None)
|
||||||
|
else:
|
||||||
|
params["prompt"] = cls.instantiate(prompt, context, allow_format_str_template)
|
||||||
|
return params
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def extract_text(cls, response: dict) -> List[str]:
|
||||||
|
"""Extract the text from a completion or chat response.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
response (dict): The response from OpenAI API.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of text in the responses.
|
||||||
|
"""
|
||||||
|
choices = response["choices"]
|
||||||
|
if "text" in choices[0]:
|
||||||
|
return [choice["text"] for choice in choices]
|
||||||
|
return [choice["message"].get("content", "") for choice in choices]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def extract_text_or_function_call(cls, response: dict) -> List[str]:
|
||||||
|
"""Extract the text or function calls from a completion or chat response.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
response (dict): The response from OpenAI API.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of text or function calls in the responses.
|
||||||
|
"""
|
||||||
|
choices = response["choices"]
|
||||||
|
if "text" in choices[0]:
|
||||||
|
return [choice["text"] for choice in choices]
|
||||||
|
return [
|
||||||
|
choice["message"] if "function_call" in choice["message"] else choice["message"].get("content", "")
|
||||||
|
for choice in choices
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@property
|
||||||
|
def logged_history(cls) -> Dict:
|
||||||
|
"""Return the book keeping dictionary."""
|
||||||
|
return cls._history_dict
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def print_usage_summary(cls) -> Dict:
|
||||||
|
"""Return the usage summary."""
|
||||||
|
if cls._history_dict is None:
|
||||||
|
print("No usage summary available.", flush=True)
|
||||||
|
|
||||||
|
token_count_summary = defaultdict(lambda: {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0})
|
||||||
|
|
||||||
|
if not cls._history_compact:
|
||||||
|
source = cls._history_dict.values()
|
||||||
|
total_cost = sum(msg_pair["response"]["cost"] for msg_pair in source)
|
||||||
|
else:
|
||||||
|
# source = cls._history_dict["token_count"]
|
||||||
|
# total_cost = sum(cls._history_dict['cost'])
|
||||||
|
total_cost = sum(sum(value_list["cost"]) for value_list in cls._history_dict.values())
|
||||||
|
source = (
|
||||||
|
token_data for value_list in cls._history_dict.values() for token_data in value_list["token_count"]
|
||||||
|
)
|
||||||
|
|
||||||
|
for entry in source:
|
||||||
|
if not cls._history_compact:
|
||||||
|
model = entry["response"]["model"]
|
||||||
|
token_data = entry["response"]["usage"]
|
||||||
|
else:
|
||||||
|
model = entry["model"]
|
||||||
|
token_data = entry
|
||||||
|
|
||||||
|
token_count_summary[model]["prompt_tokens"] += token_data["prompt_tokens"]
|
||||||
|
token_count_summary[model]["completion_tokens"] += token_data["completion_tokens"]
|
||||||
|
token_count_summary[model]["total_tokens"] += token_data["total_tokens"]
|
||||||
|
|
||||||
|
print(f"Total cost: {total_cost}", flush=True)
|
||||||
|
for model, counts in token_count_summary.items():
|
||||||
|
print(
|
||||||
|
f"Token count summary for model {model}: prompt_tokens: {counts['prompt_tokens']}, completion_tokens: {counts['completion_tokens']}, total_tokens: {counts['total_tokens']}",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def start_logging(
|
||||||
|
cls, history_dict: Optional[Dict] = None, compact: Optional[bool] = True, reset_counter: Optional[bool] = True
|
||||||
|
):
|
||||||
|
"""Start book keeping.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
history_dict (Dict): A dictionary for book keeping.
|
||||||
|
If no provided, a new one will be created.
|
||||||
|
compact (bool): Whether to keep the history dictionary compact.
|
||||||
|
Compact history contains one key per conversation, and the value is a dictionary
|
||||||
|
like:
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"create_at": [0, 1],
|
||||||
|
"cost": [0.1, 0.2],
|
||||||
|
}
|
||||||
|
```
|
||||||
|
where "created_at" is the index of API calls indicating the order of all the calls,
|
||||||
|
and "cost" is the cost of each call. This example shows that the conversation is based
|
||||||
|
on two API calls. The compact format is useful for condensing the history of a conversation.
|
||||||
|
If compact is False, the history dictionary will contain all the API calls: the key
|
||||||
|
is the index of the API call, and the value is a dictionary like:
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"request": request_dict,
|
||||||
|
"response": response_dict,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
where request_dict is the request sent to OpenAI API, and response_dict is the response.
|
||||||
|
For a conversation containing two API calls, the non-compact history dictionary will be like:
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
0: {
|
||||||
|
"request": request_dict_0,
|
||||||
|
"response": response_dict_0,
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
"request": request_dict_1,
|
||||||
|
"response": response_dict_1,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
The first request's messages plus the response is equal to the second request's messages.
|
||||||
|
For a conversation with many turns, the non-compact history dictionary has a quadratic size
|
||||||
|
while the compact history dict has a linear size.
|
||||||
|
reset_counter (bool): whether to reset the counter of the number of API calls.
|
||||||
|
"""
|
||||||
|
cls._history_dict = {} if history_dict is None else history_dict
|
||||||
|
cls._history_compact = compact
|
||||||
|
cls._count_create = 0 if reset_counter or cls._count_create is None else cls._count_create
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def stop_logging(cls):
|
||||||
|
"""End book keeping."""
|
||||||
|
cls._history_dict = cls._count_create = None
|
||||||
|
|
||||||
|
|
||||||
|
class ChatCompletion(Completion):
|
||||||
|
"""A class for OpenAI API ChatCompletion. Share the same API as Completion."""
|
||||||
|
|
||||||
|
default_search_space = Completion.default_search_space.copy()
|
||||||
|
default_search_space["model"] = tune.choice(["gpt-3.5-turbo", "gpt-4"])
|
||||||
|
openai_completion_class = not ERROR and openai.ChatCompletion
|
@ -1,23 +1,39 @@
|
|||||||
from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, ProxyNetworkActivate
|
from toolbox import trimmed_format_exc, get_conf, ProxyNetworkActivate
|
||||||
from toolbox import report_execption, get_log_folder, update_ui_lastest_msg, Singleton
|
|
||||||
from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom
|
from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom
|
||||||
|
from request_llms.bridge_all import predict_no_ui_long_connection
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
def gpt_academic_generate_oai_reply(
|
||||||
|
self,
|
||||||
|
messages,
|
||||||
|
sender,
|
||||||
|
config,
|
||||||
|
):
|
||||||
|
from .bridge_autogen import Completion
|
||||||
|
llm_config = self.llm_config if config is None else config
|
||||||
|
if llm_config is False:
|
||||||
|
return False, None
|
||||||
|
if messages is None:
|
||||||
|
messages = self._oai_messages[sender]
|
||||||
|
|
||||||
|
response = Completion.create(
|
||||||
|
context=messages[-1].pop("context", None), messages=self._oai_system_message + messages, **llm_config
|
||||||
|
)
|
||||||
|
return True, Completion.extract_text_or_function_call(response)[0]
|
||||||
|
|
||||||
class AutoGenGeneral(PluginMultiprocessManager):
|
class AutoGenGeneral(PluginMultiprocessManager):
|
||||||
|
|
||||||
def gpt_academic_print_override(self, user_proxy, message, sender):
|
def gpt_academic_print_override(self, user_proxy, message, sender):
|
||||||
# ⭐⭐ 子进程执行
|
# ⭐⭐ run in subprocess
|
||||||
self.child_conn.send(PipeCom("show", sender.name + '\n\n---\n\n' + message['content']))
|
self.child_conn.send(PipeCom("show", sender.name + "\n\n---\n\n" + message["content"]))
|
||||||
|
|
||||||
def gpt_academic_get_human_input(self, user_proxy, message):
|
def gpt_academic_get_human_input(self, user_proxy, message):
|
||||||
# ⭐⭐ 子进程执行
|
# ⭐⭐ run in subprocess
|
||||||
patience = 300
|
patience = 300
|
||||||
begin_waiting_time = time.time()
|
begin_waiting_time = time.time()
|
||||||
self.child_conn.send(PipeCom("interact", message))
|
self.child_conn.send(PipeCom("interact", message))
|
||||||
while True:
|
while True:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
if self.child_conn.poll():
|
if self.child_conn.poll():
|
||||||
wait_success = True
|
wait_success = True
|
||||||
break
|
break
|
||||||
if time.time() - begin_waiting_time > patience:
|
if time.time() - begin_waiting_time > patience:
|
||||||
@ -29,29 +45,55 @@ class AutoGenGeneral(PluginMultiprocessManager):
|
|||||||
else:
|
else:
|
||||||
raise TimeoutError("等待用户输入超时")
|
raise TimeoutError("等待用户输入超时")
|
||||||
|
|
||||||
|
# def gpt_academic_generate_oai_reply(self, agent, messages, sender, config):
|
||||||
|
# from .bridge_autogen import Completion
|
||||||
|
# if messages is None:
|
||||||
|
# messages = agent._oai_messages[sender]
|
||||||
|
|
||||||
|
# def instantiate(
|
||||||
|
# cls,
|
||||||
|
# template: Union[str, None],
|
||||||
|
# context: Optional[Dict] = None,
|
||||||
|
# allow_format_str_template: Optional[bool] = False,
|
||||||
|
# ):
|
||||||
|
# if not context or template is None:
|
||||||
|
# return template
|
||||||
|
# if isinstance(template, str):
|
||||||
|
# return template.format(**context) if allow_format_str_template else template
|
||||||
|
# return template(context)
|
||||||
|
|
||||||
|
# res = predict_no_ui_long_connection(
|
||||||
|
# messages[-1].pop("context", None),
|
||||||
|
# llm_kwargs=self.llm_kwargs,
|
||||||
|
# history=messages,
|
||||||
|
# sys_prompt=agent._oai_system_message,
|
||||||
|
# observe_window=None,
|
||||||
|
# console_slience=False)
|
||||||
|
# return True, res
|
||||||
|
|
||||||
def define_agents(self):
|
def define_agents(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def do_audogen(self, input):
|
def exe_autogen(self, input):
|
||||||
# ⭐⭐ 子进程执行
|
# ⭐⭐ run in subprocess
|
||||||
input = input.content
|
input = input.content
|
||||||
with ProxyNetworkActivate("AutoGen"):
|
with ProxyNetworkActivate("AutoGen"):
|
||||||
config_list = self.get_config_list()
|
code_execution_config = {"work_dir": self.autogen_work_dir, "use_docker": self.use_docker}
|
||||||
code_execution_config={"work_dir": self.autogen_work_dir, "use_docker":self.use_docker}
|
|
||||||
agents = self.define_agents()
|
agents = self.define_agents()
|
||||||
user_proxy = None
|
user_proxy = None
|
||||||
assistant = None
|
assistant = None
|
||||||
for agent_kwargs in agents:
|
for agent_kwargs in agents:
|
||||||
agent_cls = agent_kwargs.pop('cls')
|
agent_cls = agent_kwargs.pop('cls')
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'llm_config':{
|
'llm_config':{},
|
||||||
"config_list": config_list,
|
|
||||||
},
|
|
||||||
'code_execution_config':code_execution_config
|
'code_execution_config':code_execution_config
|
||||||
}
|
}
|
||||||
kwargs.update(agent_kwargs)
|
kwargs.update(agent_kwargs)
|
||||||
agent_handle = agent_cls(**kwargs)
|
agent_handle = agent_cls(**kwargs)
|
||||||
agent_handle._print_received_message = lambda a,b: self.gpt_academic_print_override(agent_kwargs, a, b)
|
agent_handle._print_received_message = lambda a,b: self.gpt_academic_print_override(agent_kwargs, a, b)
|
||||||
|
for d in agent_handle._reply_func_list:
|
||||||
|
if hasattr(d['reply_func'],'__name__') and d['reply_func'].__name__ == 'generate_oai_reply':
|
||||||
|
d['reply_func'] = gpt_academic_generate_oai_reply
|
||||||
if agent_kwargs['name'] == 'user_proxy':
|
if agent_kwargs['name'] == 'user_proxy':
|
||||||
agent_handle.get_human_input = lambda a: self.gpt_academic_get_human_input(user_proxy, a)
|
agent_handle.get_human_input = lambda a: self.gpt_academic_get_human_input(user_proxy, a)
|
||||||
user_proxy = agent_handle
|
user_proxy = agent_handle
|
||||||
@ -63,23 +105,45 @@ class AutoGenGeneral(PluginMultiprocessManager):
|
|||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
self.child_conn.send(PipeCom("done", "AutoGen 执行失败: \n\n" + tb_str))
|
self.child_conn.send(PipeCom("done", "AutoGen 执行失败: \n\n" + tb_str))
|
||||||
|
|
||||||
def get_config_list(self):
|
|
||||||
model = self.llm_kwargs['llm_model']
|
|
||||||
api_base = None
|
|
||||||
if self.llm_kwargs['llm_model'].startswith('api2d-'):
|
|
||||||
model = self.llm_kwargs['llm_model'][len('api2d-'):]
|
|
||||||
api_base = "https://openai.api2d.net/v1"
|
|
||||||
config_list = [{
|
|
||||||
'model': model,
|
|
||||||
'api_key': self.llm_kwargs['api_key'],
|
|
||||||
},]
|
|
||||||
if api_base is not None:
|
|
||||||
config_list[0]['api_base'] = api_base
|
|
||||||
return config_list
|
|
||||||
|
|
||||||
def subprocess_worker(self, child_conn):
|
def subprocess_worker(self, child_conn):
|
||||||
# ⭐⭐ 子进程执行
|
# ⭐⭐ run in subprocess
|
||||||
self.child_conn = child_conn
|
self.child_conn = child_conn
|
||||||
while True:
|
while True:
|
||||||
msg = self.child_conn.recv() # PipeCom
|
msg = self.child_conn.recv() # PipeCom
|
||||||
self.do_audogen(msg)
|
self.exe_autogen(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class AutoGenGroupChat(AutoGenGeneral):
|
||||||
|
def exe_autogen(self, input):
|
||||||
|
# ⭐⭐ run in subprocess
|
||||||
|
import autogen
|
||||||
|
|
||||||
|
input = input.content
|
||||||
|
with ProxyNetworkActivate("AutoGen"):
|
||||||
|
code_execution_config = {"work_dir": self.autogen_work_dir, "use_docker": self.use_docker}
|
||||||
|
agents = self.define_agents()
|
||||||
|
agents_instances = []
|
||||||
|
for agent_kwargs in agents:
|
||||||
|
agent_cls = agent_kwargs.pop("cls")
|
||||||
|
kwargs = {"code_execution_config": code_execution_config}
|
||||||
|
kwargs.update(agent_kwargs)
|
||||||
|
agent_handle = agent_cls(**kwargs)
|
||||||
|
agent_handle._print_received_message = lambda a, b: self.gpt_academic_print_override(agent_kwargs, a, b)
|
||||||
|
agents_instances.append(agent_handle)
|
||||||
|
if agent_kwargs["name"] == "user_proxy":
|
||||||
|
user_proxy = agent_handle
|
||||||
|
user_proxy.get_human_input = lambda a: self.gpt_academic_get_human_input(user_proxy, a)
|
||||||
|
try:
|
||||||
|
groupchat = autogen.GroupChat(agents=agents_instances, messages=[], max_round=50)
|
||||||
|
manager = autogen.GroupChatManager(groupchat=groupchat, **self.define_group_chat_manager_config())
|
||||||
|
manager._print_received_message = lambda a, b: self.gpt_academic_print_override(agent_kwargs, a, b)
|
||||||
|
manager.get_human_input = lambda a: self.gpt_academic_get_human_input(manager, a)
|
||||||
|
if user_proxy is None:
|
||||||
|
raise Exception("user_proxy is not defined")
|
||||||
|
user_proxy.initiate_chat(manager, message=input)
|
||||||
|
except Exception:
|
||||||
|
tb_str = "```\n" + trimmed_format_exc() + "```"
|
||||||
|
self.child_conn.send(PipeCom("done", "AutoGen exe failed: \n\n" + tb_str))
|
||||||
|
|
||||||
|
def define_group_chat_manager_config(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
@ -2,28 +2,28 @@ from toolbox import get_log_folder, update_ui, gen_time_str, get_conf, promote_f
|
|||||||
from crazy_functions.agent_fns.watchdog import WatchDog
|
from crazy_functions.agent_fns.watchdog import WatchDog
|
||||||
import time, os
|
import time, os
|
||||||
|
|
||||||
class PipeCom():
|
class PipeCom:
|
||||||
def __init__(self, cmd, content) -> None:
|
def __init__(self, cmd, content) -> None:
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
self.content = content
|
self.content = content
|
||||||
|
|
||||||
|
|
||||||
class PluginMultiprocessManager():
|
class PluginMultiprocessManager:
|
||||||
def __init__(self, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def __init__(self, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
# ⭐ 主进程
|
# ⭐ run in main process
|
||||||
self.autogen_work_dir = os.path.join(get_log_folder('autogen'), gen_time_str())
|
self.autogen_work_dir = os.path.join(get_log_folder("autogen"), gen_time_str())
|
||||||
self.previous_work_dir_files = {}
|
self.previous_work_dir_files = {}
|
||||||
self.llm_kwargs = llm_kwargs
|
self.llm_kwargs = llm_kwargs
|
||||||
self.plugin_kwargs = plugin_kwargs
|
self.plugin_kwargs = plugin_kwargs
|
||||||
self.chatbot = chatbot
|
self.chatbot = chatbot
|
||||||
self.history = history
|
self.history = history
|
||||||
self.system_prompt = system_prompt
|
self.system_prompt = system_prompt
|
||||||
self.web_port = web_port
|
# self.web_port = web_port
|
||||||
self.alive = True
|
self.alive = True
|
||||||
self.use_docker = get_conf('AUTOGEN_USE_DOCKER')
|
self.use_docker = get_conf("AUTOGEN_USE_DOCKER")
|
||||||
|
|
||||||
# create a thread to monitor self.heartbeat, terminate the instance if no heartbeat for a long time
|
# create a thread to monitor self.heartbeat, terminate the instance if no heartbeat for a long time
|
||||||
timeout_seconds = 5*60
|
timeout_seconds = 5 * 60
|
||||||
self.heartbeat_watchdog = WatchDog(timeout=timeout_seconds, bark_fn=self.terminate, interval=5)
|
self.heartbeat_watchdog = WatchDog(timeout=timeout_seconds, bark_fn=self.terminate, interval=5)
|
||||||
self.heartbeat_watchdog.begin_watch()
|
self.heartbeat_watchdog.begin_watch()
|
||||||
|
|
||||||
@ -35,8 +35,9 @@ class PluginMultiprocessManager():
|
|||||||
return self.alive
|
return self.alive
|
||||||
|
|
||||||
def launch_subprocess_with_pipe(self):
|
def launch_subprocess_with_pipe(self):
|
||||||
# ⭐ 主进程
|
# ⭐ run in main process
|
||||||
from multiprocessing import Process, Pipe
|
from multiprocessing import Process, Pipe
|
||||||
|
|
||||||
parent_conn, child_conn = Pipe()
|
parent_conn, child_conn = Pipe()
|
||||||
self.p = Process(target=self.subprocess_worker, args=(child_conn,))
|
self.p = Process(target=self.subprocess_worker, args=(child_conn,))
|
||||||
self.p.daemon = True
|
self.p.daemon = True
|
||||||
@ -46,14 +47,14 @@ class PluginMultiprocessManager():
|
|||||||
def terminate(self):
|
def terminate(self):
|
||||||
self.p.terminate()
|
self.p.terminate()
|
||||||
self.alive = False
|
self.alive = False
|
||||||
print('[debug] instance terminated')
|
print("[debug] instance terminated")
|
||||||
|
|
||||||
def subprocess_worker(self, child_conn):
|
def subprocess_worker(self, child_conn):
|
||||||
# ⭐⭐ 子进程
|
# ⭐⭐ run in subprocess
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def send_command(self, cmd):
|
def send_command(self, cmd):
|
||||||
# ⭐ 主进程
|
# ⭐ run in main process
|
||||||
self.parent_conn.send(PipeCom("user_input", cmd))
|
self.parent_conn.send(PipeCom("user_input", cmd))
|
||||||
|
|
||||||
def immediate_showoff_when_possible(self, fp):
|
def immediate_showoff_when_possible(self, fp):
|
||||||
@ -63,7 +64,10 @@ class PluginMultiprocessManager():
|
|||||||
# 如果是文本文件, 则直接显示文本内容
|
# 如果是文本文件, 则直接显示文本内容
|
||||||
if file_type.lower() in ['png', 'jpg']:
|
if file_type.lower() in ['png', 'jpg']:
|
||||||
image_path = os.path.abspath(fp)
|
image_path = os.path.abspath(fp)
|
||||||
self.chatbot.append(['检测到新生图像:', f'本地文件预览: <br/><div align="center"><img src="file={image_path}"></div>'])
|
self.chatbot.append([
|
||||||
|
'检测到新生图像:',
|
||||||
|
f'本地文件预览: <br/><div align="center"><img src="file={image_path}"></div>'
|
||||||
|
])
|
||||||
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
|
|
||||||
def overwatch_workdir_file_change(self):
|
def overwatch_workdir_file_change(self):
|
||||||
@ -78,7 +82,7 @@ class PluginMultiprocessManager():
|
|||||||
file_path = os.path.join(root, file)
|
file_path = os.path.join(root, file)
|
||||||
if file_path not in self.previous_work_dir_files.keys():
|
if file_path not in self.previous_work_dir_files.keys():
|
||||||
last_modified_time = os.stat(file_path).st_mtime
|
last_modified_time = os.stat(file_path).st_mtime
|
||||||
self.previous_work_dir_files.update({file_path:last_modified_time})
|
self.previous_work_dir_files.update({file_path: last_modified_time})
|
||||||
change_list.append(file_path)
|
change_list.append(file_path)
|
||||||
else:
|
else:
|
||||||
last_modified_time = os.stat(file_path).st_mtime
|
last_modified_time = os.stat(file_path).st_mtime
|
||||||
@ -86,8 +90,8 @@ class PluginMultiprocessManager():
|
|||||||
self.previous_work_dir_files[file_path] = last_modified_time
|
self.previous_work_dir_files[file_path] = last_modified_time
|
||||||
change_list.append(file_path)
|
change_list.append(file_path)
|
||||||
if len(change_list) > 0:
|
if len(change_list) > 0:
|
||||||
file_links = ''
|
file_links = ""
|
||||||
for f in change_list:
|
for f in change_list:
|
||||||
res = promote_file_to_downloadzone(f)
|
res = promote_file_to_downloadzone(f)
|
||||||
file_links += f'<br/><a href="file={res}" target="_blank">{res}</a>'
|
file_links += f'<br/><a href="file={res}" target="_blank">{res}</a>'
|
||||||
yield from self.immediate_showoff_when_possible(f)
|
yield from self.immediate_showoff_when_possible(f)
|
||||||
@ -117,19 +121,25 @@ class PluginMultiprocessManager():
|
|||||||
# the heartbeat watchdog might have it killed
|
# the heartbeat watchdog might have it killed
|
||||||
self.terminate()
|
self.terminate()
|
||||||
return "terminate"
|
return "terminate"
|
||||||
|
|
||||||
if self.parent_conn.poll():
|
if self.parent_conn.poll():
|
||||||
self.feed_heartbeat_watchdog()
|
self.feed_heartbeat_watchdog()
|
||||||
|
if "[GPT-Academic] 等待中" in self.chatbot[-1][-1]:
|
||||||
|
self.chatbot.pop(-1) # remove the last line
|
||||||
|
if "等待您的进一步指令" in self.chatbot[-1][-1]:
|
||||||
|
self.chatbot.pop(-1) # remove the last line
|
||||||
if '[GPT-Academic] 等待中' in self.chatbot[-1][-1]:
|
if '[GPT-Academic] 等待中' in self.chatbot[-1][-1]:
|
||||||
self.chatbot.pop(-1) # remove the last line
|
self.chatbot.pop(-1) # remove the last line
|
||||||
msg = self.parent_conn.recv() # PipeCom
|
msg = self.parent_conn.recv() # PipeCom
|
||||||
if msg.cmd == "done":
|
if msg.cmd == "done":
|
||||||
self.chatbot.append([f"结束", msg.content]); self.cnt += 1
|
self.chatbot.append([f"结束", msg.content])
|
||||||
|
self.cnt += 1
|
||||||
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
self.terminate(); break
|
self.terminate()
|
||||||
|
break
|
||||||
if msg.cmd == "show":
|
if msg.cmd == "show":
|
||||||
yield from self.overwatch_workdir_file_change()
|
yield from self.overwatch_workdir_file_change()
|
||||||
self.chatbot.append([f"运行阶段-{self.cnt}", msg.content]); self.cnt += 1
|
self.chatbot.append([f"运行阶段-{self.cnt}", msg.content])
|
||||||
|
self.cnt += 1
|
||||||
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
if msg.cmd == "interact":
|
if msg.cmd == "interact":
|
||||||
yield from self.overwatch_workdir_file_change()
|
yield from self.overwatch_workdir_file_change()
|
||||||
@ -159,13 +169,13 @@ class PluginMultiprocessManager():
|
|||||||
return "terminate"
|
return "terminate"
|
||||||
|
|
||||||
def subprocess_worker_wait_user_feedback(self, wait_msg="wait user feedback"):
|
def subprocess_worker_wait_user_feedback(self, wait_msg="wait user feedback"):
|
||||||
# ⭐⭐ 子进程
|
# ⭐⭐ run in subprocess
|
||||||
patience = 5 * 60
|
patience = 5 * 60
|
||||||
begin_waiting_time = time.time()
|
begin_waiting_time = time.time()
|
||||||
self.child_conn.send(PipeCom("interact", wait_msg))
|
self.child_conn.send(PipeCom("interact", wait_msg))
|
||||||
while True:
|
while True:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
if self.child_conn.poll():
|
if self.child_conn.poll():
|
||||||
wait_success = True
|
wait_success = True
|
||||||
break
|
break
|
||||||
if time.time() - begin_waiting_time > patience:
|
if time.time() - begin_waiting_time > patience:
|
||||||
@ -173,4 +183,3 @@ class PluginMultiprocessManager():
|
|||||||
wait_success = False
|
wait_success = False
|
||||||
break
|
break
|
||||||
return wait_success
|
return wait_success
|
||||||
|
|
||||||
|
@ -32,8 +32,15 @@ def 多智能体终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
web_port 当前软件运行的端口号
|
web_port 当前软件运行的端口号
|
||||||
"""
|
"""
|
||||||
# 检查当前的模型是否符合要求
|
# 检查当前的模型是否符合要求
|
||||||
supported_llms = ['gpt-3.5-turbo-16k', 'gpt-4', 'gpt-4-32k',
|
supported_llms = [
|
||||||
'api2d-gpt-3.5-turbo-16k', 'api2d-gpt-4']
|
"gpt-3.5-turbo-16k",
|
||||||
|
"gpt-4",
|
||||||
|
"gpt-4-32k",
|
||||||
|
"azure-gpt-3.5-turbo-16k",
|
||||||
|
"azure-gpt-3.5-16k",
|
||||||
|
"azure-gpt-4",
|
||||||
|
"azure-gpt-4-32k",
|
||||||
|
]
|
||||||
llm_kwargs['api_key'] = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
|
llm_kwargs['api_key'] = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
|
||||||
if llm_kwargs['llm_model'] not in supported_llms:
|
if llm_kwargs['llm_model'] not in supported_llms:
|
||||||
chatbot.append([f"处理任务: {txt}", f"当前插件只支持{str(supported_llms)}, 当前模型{llm_kwargs['llm_model']}."])
|
chatbot.append([f"处理任务: {txt}", f"当前插件只支持{str(supported_llms)}, 当前模型{llm_kwargs['llm_model']}."])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user