Skip to content

Commit af8cb0e

Browse files
Merge pull request #124 from DeepInsight-AI/new_pre
V1.3.0
2 parents 6a59e81 + 9c7c194 commit af8cb0e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+335
-186
lines changed

Docker_install_CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ git clone http://github.com/DeepInsight-AI/DeepBI.git
201201
## 配置DeepBI
202202
- 下载代码```git clone git@github.com:DeepInsight-AI/DeepBI.git```
203203
- 运行命令到对应文件夹 ```cd DeepBI ```
204-
- 修改权限 ```sudo chmod+x ./Install.sh```
204+
- 修改权限 ```sudo chmod +x ./Install.sh```
205205
- 运行命令```sudo ./Install_cn.sh ``` 开始安装,安装结束后会有一个网址提示,直接浏览器访问即可
206206
- 从版本1.1 如果更新代码,直接拉取 新的代码```git pull```,然后重启docker即可 <br>
207207
停止命令 ```sudo docker-compose stop```<br>

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ The database connections supported by DeepBI are:
8888
Install directly on the ubuntu system, you need to install redis, postgresql python3.8.17 environment.
8989

9090
- Redis can be accessed directly through the 127.0.0.1 password-free command line.
91-
- Require python version 3.8+
91+
- Require python version 3.8.x
9292
- Recommend using virtual environments such as pyenv coda
9393
- postgresql needs to install postgresql-16 version
9494

README_CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ DeepBI 支持的数据库连接有:
7373
- 直接在ubuntu 系统安装,需要将安装redis,postgresql python3.8.17 环境
7474
- 环境建议
7575
1. redis 可以直接通过127.0.0.1,无密码命令行访问
76-
2. python版本要求3.8+ 建议使用pyenv coda 等虚拟环境
76+
2. python版本要求3.8.x 建议使用pyenv coda 等虚拟环境
7777
3. postgresql 需要安装postgresql-16 版本
7878
- 下载我们的代码
7979
```

ai/agents/agent_instance_util.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ def get_agent_bi_proxy(self):
725725
""",
726726
human_input_mode="NEVER",
727727
websocket=self.websocket,
728-
code_execution_config=False,
728+
code_execution_config={"last_n_messages": 1, "work_dir": "paper", "use_docker": False},
729729
default_auto_reply="TERMINATE",
730730
user_name=self.user_name,
731731
function_map={"run_mysql_code": BIProxyAgent.run_mysql_code,
@@ -931,7 +931,7 @@ def get_agent_python_executor(self, report_file_name=None):
931931
python_executor = PythonProxyAgent(
932932
name="python_executor",
933933
system_message="python executor. Execute the python code and report the result.",
934-
code_execution_config={"last_n_messages": 1, "work_dir": "paper"},
934+
code_execution_config={"last_n_messages": 1, "work_dir": "paper", "use_docker": False},
935935
human_input_mode="NEVER",
936936
websocket=self.websocket,
937937
user_name=self.user_name,
@@ -1074,6 +1074,7 @@ def get_agent_starrocks_echart_assistant(self, use_cache=True, report_file_name=
10741074
When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible.
10751075
Reply "TERMINATE" in the end when everything is done.
10761076
When you find an answer, You are a report analysis, you have the knowledge and skills to turn raw data into information and insight, which can be used to make business decisions.include your analysis in your reply.
1077+
Don't generate html files.
10771078
""" + '\n' + self.base_starrocks_info + '\n' + python_base_dependency + '\n' + MYSQL_ECHART_TIPS_MESS,
10781079
human_input_mode="NEVER",
10791080
user_name=self.user_name,
@@ -1265,7 +1266,7 @@ def set_language_mode(self, language_mode):
12651266
self.question_ask = ' 以下是我的问题,请用中文回答: '
12661267
self.quesion_answer_language = '用中文回答问题.'
12671268
self.data_analysis_error = '分析数据失败,请检查相关数据是否充分'
1268-
1269+
12691270
elif self.language_mode == language_japanese:
12701271
self.error_message_timeout = "申し訳ありませんが、今回のAI-GPTインターフェース呼び出しがタイムアウトしました。もう一度お試しください。"
12711272
self.question_ask = ' これが私の質問です。: '

ai/agents/agentchat/bi_proxy_agent.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,9 @@ async def run_echart_code(self, chart_code_str: str, name: str):
14901490
else:
14911491
str_obj = ast.literal_eval(chart_code_str)
14921492

1493+
if isinstance(str_obj, list):
1494+
return "Chart :" + name + " configuration should not be a list."
1495+
14931496
json_str = json.dumps(str_obj)
14941497

14951498
result_message = {

ai/agents/agentchat/chart_presenter_agent.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,18 @@ def find_extract_code(self, text: str):
192192
extracted.append(("", group2.strip()))
193193

194194
return extracted
195+
def extract_json_data(text: str):
196+
# 搜索 JSON 数据
197+
json_pattern = re.compile(r'\{(?:[^{}]|(?R))*\}')
198+
json_matches = json_pattern.findall(text)
199+
200+
# 提取有效的 JSON 数据
201+
extracted_json = None
202+
for match in json_matches:
203+
try:
204+
extracted_json = json.loads(match)
205+
break
206+
except json.JSONDecodeError:
207+
continue
208+
209+
return extracted_json

ai/agents/agentchat/python_proxy_agent.py

Lines changed: 131 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
66
from ai.agents import oai
77
from .agent import Agent
8+
import ast
9+
import re
10+
from ai.backend.util import base_util
811
from ai.agents.code_utils import (
912
DEFAULT_MODEL,
1013
UNKNOWN,
@@ -22,11 +25,19 @@
2225
try:
2326
from termcolor import colored
2427
except ImportError:
25-
2628
def colored(x, *args, **kwargs):
2729
return x
2830

2931

32+
# 函数,用于精确到小数点后两位
33+
def format_decimal(value):
34+
if isinstance(value, float):
35+
return round(value, 2)
36+
elif isinstance(value, int):
37+
return value
38+
return value
39+
40+
3041
class PythonProxyAgent(Agent):
3142
"""(In preview) A class for generic conversable agents which can be configured as assistant or user proxy.
3243
@@ -66,7 +77,6 @@ def __init__(
6677
db_id: Optional = None,
6778
is_log_out: Optional[bool] = True,
6879
report_file_name: Optional[str] = None,
69-
7080
):
7181
"""
7282
Args:
@@ -112,6 +122,7 @@ def __init__(
112122
"""
113123
super().__init__(name)
114124
# a dictionary of conversations, default value is list
125+
self.delay_messages = None
115126
self._oai_messages = defaultdict(list)
116127
self._oai_system_message = [{"content": system_message, "role": "system"}]
117128
self._is_termination_msg = (
@@ -147,6 +158,7 @@ def __init__(
147158
self.db_id = db_id
148159
self.is_log_out = is_log_out
149160
self.report_file_name = report_file_name
161+
delay_messages = self.delay_messages
150162

151163
def register_reply(
152164
self,
@@ -661,15 +673,16 @@ def generate_oai_reply(
661673

662674
return True, oai.ChatCompletion.extract_text_or_function_call(response)[0]
663675

664-
def generate_code_execution_reply(
676+
async def generate_code_execution_reply(
665677
self,
666678
messages: Optional[List[Dict]] = None,
667679
sender: Optional[Agent] = None,
668680
config: Optional[Any] = None,
681+
669682
):
670683
"""Generate a reply using code execution.
671684
"""
672-
685+
from ai.agents.agent_instance_util import AgentInstanceUtil
673686
code_execution_config = config if config is not None else self._code_execution_config
674687
# print('self._code_execution_config :', self._code_execution_config)
675688

@@ -678,6 +691,7 @@ def generate_code_execution_reply(
678691
if messages is None:
679692
messages = self._oai_messages[sender]
680693
last_n_messages = code_execution_config.pop("last_n_messages", 1)
694+
base_content = []
681695

682696
# iterate through the last n messages reversly
683697
# if code blocks are found, execute the code blocks and return the output
@@ -693,6 +707,7 @@ def generate_code_execution_reply(
693707

694708
if len(code_blocks) == 1 and code_blocks[0][0] != 'python':
695709
continue
710+
code_blocks = self.regex_fix_date_format(code_blocks)
696711

697712
if self.db_id is not None:
698713
obj = database_util.Main(self.db_id)
@@ -703,28 +718,110 @@ def generate_code_execution_reply(
703718
code_blocks]
704719

705720
# code_blocks = self.replace_ab_with_ac(code_blocks, db_info)
706-
print('new_code_blocks : ', code_blocks)
721+
# print('new_code_blocks : ', code_blocks)
707722

708723
# found code blocks, execute code and push "last_n_messages" back
709724
exitcode, logs = self.execute_code_blocks(code_blocks)
710725
code_execution_config["last_n_messages"] = last_n_messages
711726
exitcode2str = "execution succeeded" if exitcode == 0 else "execution failed"
712-
713727
length = 10000
714-
length1 = 10001
715728
if not str(logs).__contains__('echart_name'):
716729
if len(logs) > length:
717730
print(' ++++++++++ Length exceeds 10000 characters limit, cropped +++++++++++++++++')
718731
logs = logs[:length]
719-
else:
720-
if len(logs) > length1:
721-
print(' ++++++++++ Length exceeds 10001 characters limit, cropped +++++++++++++++++')
722-
logs = "The echarts code is too long, please simplify the code or data (for example, only keep two decimal places), and ensure that the echarts code length does not exceed 10001"
732+
return True, f"exitcode: {exitcode} ({exitcode2str})\nCode output: {logs}"
723733

724734

725-
return True, f"exitcode: {exitcode} ({exitcode2str})\nCode output: {logs}"
735+
else:
736+
try:
737+
if "'echart_name'" in str(logs):
738+
logs = json.dumps(eval(str(logs)))
739+
logs = json.loads(str(logs))
740+
except Exception as e:
741+
return True,f"exitcode:exitcode failed\nCode output: There is an error in the JSON code causing parsing errors,Please modify the JSON code for me:{traceback.format_exc()}"
742+
for entry in logs:
743+
if 'echart_name' in entry and 'echart_code' in entry:
744+
if isinstance(entry['echart_code'], str):
745+
entry['echart_code'] = json.loads(entry['entry']['echart_code'])
746+
if "series" in entry['echart_code']:
747+
series_data = entry['echart_code']['series']
748+
formatted_series_list = []
749+
for series_data in series_data:
750+
if series_data['type'] in ["bar", "line"]:
751+
formatted_series_data = [format_decimal(value) for value in series_data['data']]
752+
elif series_data['type'] in ["pie", "gauge", "funnel"]:
753+
formatted_series_data = [{"name": d["name"], "value": format_decimal(d["value"])} for
754+
d in series_data['data']]
755+
elif series_data['type'] in ['graph']:
756+
formatted_series_data = [
757+
{'name': data_point['name'], 'symbolSize': format_decimal(data_point['symbolSize'])}
758+
for data_point in series_data['data']]
759+
elif series_data['type'] in ["Kline", "radar", "heatmap", "scatter", "themeRiver",
760+
'parallel', 'effectScatter']:
761+
formatted_series_data = [[format_decimal(value) for value in sublist] for sublist in
762+
series_data['data']]
763+
else:
764+
formatted_series_data = series_data['data']
765+
series_data['data'] = formatted_series_data
766+
formatted_series_list.append(series_data)
767+
entry['echart_code']['series'] = formatted_series_list
768+
base_content.append(entry)
769+
770+
agent_instance_util = AgentInstanceUtil(user_name=str(self.user_name),
771+
delay_messages=self.delay_messages,
772+
outgoing=self.outgoing,
773+
incoming=self.incoming,
774+
websocket=self.websocket
775+
)
776+
bi_proxy = agent_instance_util.get_agent_bi_proxy()
777+
is_chart = False
778+
# Call the interface to generate pictures
779+
for img_str in base_content:
780+
echart_name = img_str.get('echart_name')
781+
echart_code = img_str.get('echart_code')
782+
783+
if len(echart_code) > 0 and str(echart_code).__contains__('x'):
784+
is_chart = True
785+
print("echart_name : ", echart_name)
786+
# 格式化echart_code
787+
# if base_util.is_json(str(echart_code)):
788+
# json_obj = json.loads(str(echart_code))
789+
# echart_code = json.dumps(json_obj)
790+
re_str = await bi_proxy.run_echart_code(str(echart_code), echart_name)
791+
# 初始化一个空列表来保存每个echart的信息
792+
echarts_data = []
793+
# 遍历echarts_code列表,提取数据并构造字典
794+
for echart in base_content:
795+
echart_name = echart['echart_name']
796+
series_data = []
797+
for serie in echart['echart_code']['series']:
798+
try:
799+
seri_info = {
800+
'type': serie['type'],
801+
'name': serie['name'],
802+
'data': serie['data']
803+
}
804+
except Exception as e:
805+
seri_info = {
806+
'type': serie['type'],
807+
'data': serie['data']
808+
}
809+
series_data.append(seri_info)
810+
if "xAxis" in echart["echart_code"]:
811+
xAxis_data = echart['echart_code']['xAxis'][0]['data']
812+
echart_dict = {
813+
'echart_name': echart_name,
814+
'series': series_data,
815+
'xAxis_data': xAxis_data
816+
}
817+
else:
818+
echart_dict = {
819+
'echart_name': echart_name,
820+
'series': series_data,
821+
}
822+
echarts_data.append(echart_dict)
823+
return True, f"exitcode: {exitcode} ({exitcode2str})\nCode output: 图像已生成,请直接分析图表数据:{echarts_data}"
726824

727-
# no code blocks are found, push last_n_messages back and return.
728825
code_execution_config["last_n_messages"] = last_n_messages
729826

730827
return False, None
@@ -1138,3 +1235,24 @@ async def ask_user(self, q_str):
11381235

11391236
# return "i have no question."
11401237
return None
1238+
1239+
def regex_fix_date_format(self, code_blocks):
1240+
# fix mysql generate %%Y %%m %%d code :list
1241+
pattern1 = r"%s"
1242+
patterns_replacements = [
1243+
(r"%%Y-%%m-%%d %%H", "%Y-%m-%d %H"),
1244+
(r"%%Y-%%m-%%d", "%Y-%m-%d"),
1245+
(r"%%Y-%%m", "%Y-%m"),
1246+
(r"%%H", "%H"),
1247+
(r"%%Y", "%Y"),
1248+
(r"%%Y-%%m-%%d %%H:%%i", "%Y-%m-%d %H:%i"),
1249+
(r"%%Y-%%m-%%d %%H:%%i:%%s", "%Y-%m-%d %H:%i:%s")]
1250+
1251+
if re.search(pattern1, str(code_blocks)):
1252+
for pattern, replacement in patterns_replacements:
1253+
code_blocks = [(language, re.sub(replacement, pattern, code)) for language, code in code_blocks]
1254+
else:
1255+
for pattern, replacement in patterns_replacements:
1256+
code_blocks = [(language, re.sub(pattern, replacement, code)) for language, code in code_blocks]
1257+
1258+
return code_blocks

ai/agents/agentchat/task_selector_agent.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
from ai.backend.util.write_log import logger
44
from .conversable_agent import ConversableAgent
55
from .agent import Agent
6-
from ai.backend.base_config import agents_functions
6+
from ai.backend.base_config import CONFIG
77
import re
88

9+
910
class TaskSelectorAgent(ConversableAgent):
1011
"""(In preview) A class for generic conversable agents which can be configured as assistant or user proxy.
1112
@@ -144,23 +145,32 @@ async def generate_reply(
144145
# {"qustion_message":"\nWhat is the most common house layout in the dataset?"}
145146
# **********************************************
146147
print('messages[-1][content] :', messages[-1]['content'])
147-
148+
148149
# suggest_function = {'role': 'assistant', 'content': None, 'function_call': {'name': 'task_base',
149150
# 'arguments': '{"qustion_message":"\\nWhat is the most common house layout in the dataset?"}'}}
150151
# Check if reply is in agents_functions
151-
if reply in agents_functions:
152-
suggest_function = {'role': 'assistant', 'content': None, 'function_call': {'name': reply,
153-
'arguments': '{"qustion_message":"' + str(
154-
messages[-1][
155-
'content']) + '"}'}}
156-
157-
# {"qustion_message": " """ + str(messages[-1]['content']) + """"}
158-
152+
is_func = False
153+
for func in CONFIG.agents_functions:
154+
if len(str(reply)) > 0 and func in str(reply):
155+
is_func = True
156+
suggest_function = {'role': 'assistant', 'content': None, 'function_call': {'name': func,
157+
'arguments': '{"qustion_message":"' + str(
158+
messages[
159+
-1][
160+
'content']) + '"}'}}
161+
print('reply : ', reply)
162+
# return reply
163+
return suggest_function
164+
165+
if not is_func:
166+
suggest_function = {'role': 'assistant', 'content': None,
167+
'function_call': {'name': CONFIG.default_agents_functions,
168+
'arguments': '{"qustion_message":"' + str(
169+
messages[-1][
170+
'content']) + '"}'}}
159171
print('reply : ', reply)
160-
161172
# return reply
162173
return suggest_function
163174

164-
165175
# return messages
166176
return self._default_auto_reply

0 commit comments

Comments
 (0)