fea: add feature for codechat

This commit is contained in:
温进 2023-11-15 17:17:50 +08:00
parent d5e2bb7acc
commit 8deb7a3eec
15 changed files with 56 additions and 63 deletions

View File

@ -10,10 +10,11 @@
<br><br> <br><br>
</p> </p>
本项目是一个开源的 AI 智能助手专为软件开发的全生命周期而设计涵盖设计、编码、测试、部署和运维等阶段。通过知识检索、工具使用和沙箱执行Codefuse-ChatBot 能解答您开发过程中的各种专业问题、问答操作周边独立分散平台。 本项目是一个开源的 AI 智能助手,专为软件开发的全生命周期而设计,涵盖设计、编码、测试、部署和运维等阶段。通过知识检索、代码检索,工具使用和沙箱执行Codefuse-ChatBot 能解答您开发过程中的各种专业问题、问答操作周边独立分散平台。
## 🔔 更新 ## 🔔 更新
- [2023.11.15] 增加基于本地代码库的问答增强模式
- [2023.09.15] 本地/隔离环境的沙盒功能开放基于爬虫实现指定url知识检索 - [2023.09.15] 本地/隔离环境的沙盒功能开放基于爬虫实现指定url知识检索
## 📜 目录 ## 📜 目录
@ -29,6 +30,7 @@
💡 本项目旨在通过检索增强生成Retrieval Augmented GenerationRAG、工具学习Tool Learning和沙盒环境来构建软件开发全生命周期的AI智能助手涵盖设计、编码、测试、部署和运维等阶段。 逐渐从各处资料查询、独立分散平台操作的传统开发运维模式转变到大模型问答的智能化开发运维模式,改变人们的开发运维习惯。 💡 本项目旨在通过检索增强生成Retrieval Augmented GenerationRAG、工具学习Tool Learning和沙盒环境来构建软件开发全生命周期的AI智能助手涵盖设计、编码、测试、部署和运维等阶段。 逐渐从各处资料查询、独立分散平台操作的传统开发运维模式转变到大模型问答的智能化开发运维模式,改变人们的开发运维习惯。
- 📚 知识库管理DevOps专业高质量知识库 + 企业级知识库自助构建 + 对话实现快速检索开源/私有技术文档 - 📚 知识库管理DevOps专业高质量知识库 + 企业级知识库自助构建 + 对话实现快速检索开源/私有技术文档
- ⌨️ 代码知识库管理:支持本地代码库导入和代码结构解析 + 对话实现快速检索本地代码
- 🐳 隔离沙盒环境:实现代码的快速编译执行测试 - 🐳 隔离沙盒环境:实现代码的快速编译执行测试
- 🔄 React范式支撑代码的自我迭代、自动执行 - 🔄 React范式支撑代码的自我迭代、自动执行
- 🛠️ Prompt管理实现各种开发、运维任务的prompt管理 - 🛠️ Prompt管理实现各种开发、运维任务的prompt管理
@ -46,10 +48,11 @@
## 🎥 演示视频 ## 🎥 演示视频
为了帮助您更直观地了解 Codefuse-ChatBot 的功能和使用方法,我们录制了一个演示视频。您可以通过观看此视频,快速了解本项目的主要特性和操作流程。 为了帮助您更直观地了解 Codefuse-ChatBot 的功能和使用方法,我们录制了一系列演示视频。您可以通过观看这些视频,快速了解本项目的主要特性和操作流程。
[演示视频](https://www.youtube.com/watch?v=UGJdTGaVnNY&t=2s&ab_channel=HaotianZhu) - 知识库导入和问答:[演示视频](https://www.youtube.com/watch?v=UGJdTGaVnNY&t=2s&ab_channel=HaotianZhu)
- 本地代码库导入和问答:[演示视频](https://www.youtube.com/watch?v=ex5sbwGs3Kg)
## 🧭 技术路线 ## 🧭 技术路线

7
dev_opsgpt/__init__.py Normal file
View File

@ -0,0 +1,7 @@
# encoding: utf-8
'''
@author: 温进
@file: __init__.py.py
@time: 2023/11/9 下午4:01
@desc:
'''

View File

@ -74,6 +74,13 @@ class AgentChat:
# update configs # update configs
phase_configs, chain_configs, agent_configs = self.update_configs( phase_configs, chain_configs, agent_configs = self.update_configs(
custom_phase_configs, custom_chain_configs, custom_role_configs) custom_phase_configs, custom_chain_configs, custom_role_configs)
logger.info('phase_configs={}'.format(phase_configs))
logger.info('chain_configs={}'.format(chain_configs))
logger.info('agent_configs={}'.format(agent_configs))
logger.info('phase_name')
logger.info('chain_name')
# choose tools # choose tools
tools = toLangchainTools([TOOL_DICT[i] for i in choose_tools if i in TOOL_DICT]) tools = toLangchainTools([TOOL_DICT[i] for i in choose_tools if i in TOOL_DICT])
input_message = Message( input_message = Message(

View File

@ -71,9 +71,12 @@ class CodeChat(Chat):
node_name, node_type, node_score = node_info[0], node_info[1], node_info[2] node_name, node_type, node_score = node_info[0], node_info[1], node_info[2]
source_nodes.append(f'{inum + 1}. 节点名为 {node_name}, 节点类型为 `{node_type}`, 节点得分为 `{node_score}`') source_nodes.append(f'{inum + 1}. 节点名为 {node_name}, 节点类型为 `{node_type}`, 节点得分为 `{node_score}`')
logger.info('history={}'.format(history))
logger.info('message={}'.format([i.to_msg_tuple() for i in history] + [("human", CODE_PROMPT_TEMPLATE)]))
chat_prompt = ChatPromptTemplate.from_messages( chat_prompt = ChatPromptTemplate.from_messages(
[i.to_msg_tuple() for i in history] + [("human", CODE_PROMPT_TEMPLATE)] [i.to_msg_tuple() for i in history] + [("human", CODE_PROMPT_TEMPLATE)]
) )
logger.info('chat_prompt={}'.format(chat_prompt))
chain = LLMChain(prompt=chat_prompt, llm=model) chain = LLMChain(prompt=chat_prompt, llm=model)
result = {"answer": "", "codes": source_nodes} result = {"answer": "", "codes": source_nodes}
return chain, context, result return chain, context, result
@ -89,7 +92,7 @@ class CodeChat(Chat):
code_limit: int = Body(1, examples=['1']), code_limit: int = Body(1, examples=['1']),
stream: bool = Body(False, description="流式输出"), stream: bool = Body(False, description="流式输出"),
local_doc_url: bool = Body(False, description="知识文件返回本地路径(true)或URL(false)"), local_doc_url: bool = Body(False, description="知识文件返回本地路径(true)或URL(false)"),
request: Request = Body(None), request: Request = None,
**kargs **kargs
): ):
self.engine_name = engine_name if isinstance(engine_name, str) else engine_name.default self.engine_name = engine_name if isinstance(engine_name, str) else engine_name.default

View File

@ -200,7 +200,7 @@ $JSON_BLOB
``` ```
""" """
CODE_QA_PROMPT = """【指令】根据已知信息来回答问""" CODE_QA_PROMPT = """【指令】根据已知信息来回答问"""
AGETN_CONFIGS = { AGETN_CONFIGS = {

View File

@ -87,7 +87,6 @@ def create_app():
tags=["Chat"], tags=["Chat"],
summary="与代码库对话")(codeChat.chat) summary="与代码库对话")(codeChat.chat)
# Tag: Knowledge Base Management # Tag: Knowledge Base Management
app.get("/knowledge_base/list_knowledge_bases", app.get("/knowledge_base/list_knowledge_bases",
tags=["Knowledge Base Management"], tags=["Knowledge Base Management"],

View File

@ -1,6 +1,7 @@
from .server_utils import BaseResponse, ListResponse from .server_utils import BaseResponse, ListResponse
from .common_utils import func_timer from .common_utils import func_timer
from .postprocess import replace_lt_gt
__all__ = [ __all__ = [
"BaseResponse", "ListResponse", "func_timer" "BaseResponse", "ListResponse", "func_timer", 'replace_lt_gt'
] ]

View File

@ -0,0 +1,12 @@
# encoding: utf-8
'''
@author: 温进
@file: postprocess.py
@time: 2023/11/9 下午4:01
@desc:
'''
def replace_lt_gt(text: str):
text = text.replace('&lt;', '<')
text = text.replace('&gt;', '>')
return text

View File

@ -135,6 +135,6 @@ def code_page(api: ApiRequest):
): ):
ret = api.delete_code_base(cb, ret = api.delete_code_base(cb,
no_remote_api=True) no_remote_api=True)
st.toast(ret.get("msg", " ")) st.toast(ret.get("msg", "删除成功"))
time.sleep(1) time.sleep(0.5)
st.experimental_rerun() st.experimental_rerun()

View File

@ -248,8 +248,14 @@ def dialogue_page(api: ApiRequest):
st.error(error_msg) st.error(error_msg)
break break
text += t["answer"] text += t["answer"]
text = replace_lt_gt(text)
chat_box.update_msg(text) chat_box.update_msg(text)
logger.debug(f"text: {text}") logger.debug(f"text: {text}")
text = replace_lt_gt(text)
chat_box.update_msg(text, streaming=False) # 更新最终的字符串,去除光标 chat_box.update_msg(text, streaming=False) # 更新最终的字符串,去除光标
# 判断是否存在代码, 并提高编辑功能,执行功能 # 判断是否存在代码, 并提高编辑功能,执行功能
code_text = api.codebox.decode_code_from_text(text) code_text = api.codebox.decode_code_from_text(text)
@ -388,8 +394,12 @@ def dialogue_page(api: ApiRequest):
st.error(error_msg) st.error(error_msg)
text += d["answer"] text += d["answer"]
if idx_count % 10 == 0: if idx_count % 10 == 0:
text = replace_lt_gt(text)
chat_box.update_msg(text, element_index=0) chat_box.update_msg(text, element_index=0)
# postprocess
text = replace_lt_gt(text)
chat_box.update_msg(text, element_index=0, streaming=False) # 更新最终的字符串,去除光标 chat_box.update_msg(text, element_index=0, streaming=False) # 更新最终的字符串,去除光标
logger.debug('text={}'.format(text))
chat_box.update_msg("\n".join(d["codes"]), element_index=1, streaming=False, state="complete") chat_box.update_msg("\n".join(d["codes"]), element_index=1, streaming=False, state="complete")
# session state update # session state update
@ -467,6 +477,8 @@ def dialogue_page(api: ApiRequest):
): ):
chat_box.reset_history() chat_box.reset_history()
GLOBAL_EXE_CODE_TEXT = "" GLOBAL_EXE_CODE_TEXT = ""
if 'history_node_list' in st.session_state:
st.session_state['history_node_list'] = []
st.experimental_rerun() st.experimental_rerun()
export_btn.download_button( export_btn.download_button(

View File

@ -1,35 +0,0 @@
Stack trace:
Frame Function Args
065CA2341B0 00180064365 (001802A267B, 00180266FD1, 00180310720, 065CA234690)
065CA2346E0 001800499D2 (00000000000, 00000000000, 00000000000, 00000000000)
065CA2356F0 00180049A11 (00000000032, 000000018A1, 00180310720, 001803512E5)
065CA235720 0018017C34A (00000000000, 00000000000, 00000000000, 00000000000)
065CA2357C0 00180107A01 (065CA2369E8, 000000018A1, 00180310720, 000FFFFFFFF)
065CA236A50 0018016142F (7FFD86AEB0EB, 001803512E5, 065CA236A88, 00000000000)
065CA236BF0 00180142EBB (7FFD86AEB0EB, 001803512E5, 065CA236A88, 00000000000)
065CA236BF0 004B39318AE (24B346C45C0, 065CA236C98, 24B00A54270, 00000000000)
065CA236CD0 004B3936115 (00000000000, 24B36D861A0, FFC1F2061D5F707D, 065CA236DB0)
065CA236D80 7FFDB39F4541 (0000000000A, 065CA236FD0, 7FFDB39F4262, 00000000000)
065CA236DB0 7FFDB39F4332 (065CA237010, 00000000000, 24B594D6870, 00000000000)
065CA237010 7FFDB39F4212 (7FFD86AE24F7, 7FFD8696D680, 24B77D7BD60, 065CA236FB0)
065CA237010 7FFD8695CABF (004B39319D0, 065CA236FC0, 00000001101, 24B00000000)
065CA237010 7FFD8695D629 (24B00A4D6C0, 00000000000, 00000000000, 06500001101)
24B00A4DEE0 7FFD869577FD (24B00A573C0, 00000000000, 00000000000, 24B00A4FB20)
00000000000 7FFD86AE0256 (065CA237299, 24B00A4FB10, 24B2688BDF8, 00000000003)
065CA237299 7FFD86BC8D88 (24B594D6870, 065CA237299, 00000000000, 24B00A47F70)
065CA237299 7FFD86BC2DF8 (00000000000, 24B00A505B0, 00000000043, 24B00A47F70)
00000000001 7FFD86BC798A (00000000002, 24B00A4E898, 7FFD86B49A3A, 00000000001)
00000000000 7FFD86AE0AAF (065CA237599, 24B008E7BB8, 7FFD86B2B9DA, 24B008E7BA8)
065CA237599 7FFD86BC03F6 (24B75AE03C8, 24B752735CA, 000000000A0, 00000000062)
065CA237599 7FFD86BC8D88 (24B594D6870, 065CA237599, 24B75273340, 7FFD86E45B00)
065CA237599 7FFD86BC517F (00000000000, 24B00A50D40, 00000000040, 24B34AC8A08)
00000000000 7FFD86BC798A (00000000000, 24B00A4F180, 00000000000, 00000000000)
24B00A50D40 7FFD86BC17F4 (7FFD86D82364, 24B00A50D40, 00000000010, 24B00A20B30)
24B00A50D40 7FFD86BBCA4F (24B34AD0810, 24B34AD5478, 24B594D6870, 24B594D6870)
00000000000 7FFD86B26BF5 (24B34AD0810, 24B00A4F240, 7FFDCD9B5BA1, 065CA237840)
00000000000 7FFD86AE03A6 (24B00A52280, 24B00A4F240, 24B00A52298, 24B345B7B32)
24B00A4F240 7FFD86BC8EF0 (24B00A52280, 065CA237949, 24B34AD5470, 00000000038)
065CA237949 7FFD86BC52D8 (00000000000, 24B34AD99D0, 0000000004F, 00000000000)
00000000003 7FFD86BC798A (00000000001, 00000000000, 24B516F49B0, 00000000003)
00000000000 7FFD86AE0AAF (065CA237C49, 24B2687E5C8, 7FFD86B28DEE, 24B2687E5A8)
End of stack trace (more stack frames may be present)

View File

@ -111,8 +111,10 @@ def start_sandbox_service():
if check_docker(client, SANDBOX_CONTRAINER_NAME, do_stop=True, ): if check_docker(client, SANDBOX_CONTRAINER_NAME, do_stop=True, ):
container = start_docker(client, script_shs, ports, SANDBOX_IMAGE_NAME, SANDBOX_CONTRAINER_NAME, mounts=mounts, network=network_name) container = start_docker(client, script_shs, ports, SANDBOX_IMAGE_NAME, SANDBOX_CONTRAINER_NAME, mounts=mounts, network=network_name)
# 判断notebook是否启动 # 判断notebook是否启动
time.sleep(5)
retry_nums = 3 retry_nums = 3
while retry_nums>0: while retry_nums>0:
logger.info(f"http://localhost:{SANDBOX_SERVER['port']}")
response = requests.get(f"http://localhost:{SANDBOX_SERVER['port']}", timeout=270) response = requests.get(f"http://localhost:{SANDBOX_SERVER['port']}", timeout=270)
if response.status_code == 200: if response.status_code == 200:
logger.info("container & notebook init success") logger.info("container & notebook init success")
@ -180,7 +182,6 @@ def start_api_service(sandbox_host=DEFAULT_BIND_HOST):
webui_sh = "streamlit run webui.py" if USE_TTY else "streamlit run webui.py" webui_sh = "streamlit run webui.py" if USE_TTY else "streamlit run webui.py"
# #
if not NO_REMOTE_API and check_process("service/api.py"): if not NO_REMOTE_API and check_process("service/api.py"):
logger.info('check 1')
subprocess.Popen(api_sh, shell=True) subprocess.Popen(api_sh, shell=True)
# #
if USE_FASTCHAT and check_process("service/llm_api.py"): if USE_FASTCHAT and check_process("service/llm_api.py"):

View File

@ -1,5 +1,5 @@
langchain==0.0.266 langchain==0.0.266
openai openai==0.28.1
sentence_transformers sentence_transformers
fschat==0.2.24 fschat==0.2.24
transformers>=4.31.0 transformers>=4.31.0

View File

@ -1 +0,0 @@
{"url": "https://zhuanlan.zhihu.com/p/80963305", "host_url": "https://zhuanlan.zhihu.com", "title": "【工具类】PyCharm+Anaconda+jupyter notebook +pip环境配置 - 知乎", "all_text": "\n【工具类】PyCharm+Anaconda+jupyter notebook +pip环境配置 - 知乎切换模式写文章登录/注册【工具类】PyCharm+Anaconda+jupyter notebook +pip环境配置Joe.Zhao14 人赞同了该文章Pycharm是一个很好的python的IDEAnaconda是一个环境管理工具可以针对不同工作配置不同的环境如何在Pycharm中调用Anaconda中创建的环境Anaconda环境配置Anaconda 解决了官方 Python 的两大痛点第一:提供了包管理功能,解决安装第三方包经常失败第二:提供环境管理的功能,功能类似 Virtualenv解决了多版本Python并存、切换的问题。查看Anaconda中所有的Python环境Window环境下Anaconda Prompt中输入以下命令其中前面有个*’的代表当前环境\n```code\nconda info --env\n\n# conda environments:\n#\nbase * D:\\Anaconda3\ntf D:\\Anaconda3\\envs\\tf\n```\n创建新的Python环境\n```code\nconda create --name python35 python=3.5 #代表创建一个python3.5的环境我们把它命名为python35\n```\n激活进入创建的环境\n```code\nconda activate python35\n```\n在当前环境中安装package可以使用pip还可以用conda\n```code\npip install numpy\nconda install numpy\n```\n退出当前环境回到base环境\n```code\nconda deactivate\n```\n删除创建的环境conda创建的环境会在安装目录Anaconda3\\envs\\下面,每一个环境对应一个文件夹,当删除环境的时候,响应的文件夹也会被删除掉\n```code\nconda env remove --name python35 --all\nconda remove --name myenv --all\n```\nconda源头\n```code\nconda config --show channels\nchannels:\n- https://pypi.doubanio.com/simple/\n- defaults\n```\n添加新源\n```code\nconda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/\n```\n删除源\n```code\nconda config --remove channels https://pypi.doubanio.com/simple/\n```\n查看安装package\n```code\nconda list\n\n```\nPycharm 使用Anaconda创建的环境pycharm工程目录中打开/file/settings/Project Interpreter在Project Interpreter中打开Add左侧边栏目选择Conda Environment右侧选择Existing environment在文件路径中选择Anaconda安装目录下面的envs目录下面是该系统安装的所有anaconda环境进入文件夹选择python解释器这就就把Pycharm下使用Anconda环境的配置完成了。pip 环境配置conda 环境下也可以用pip来安装包pip安装\n```code\npip install 安装包名\n[...]\nSuccessfully installed SomePackage #安装成功\n```\npip 安装指定源\n```code\npip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple\n```\npip查看是否已安装\n```code\npip show --files 安装包名\n\nName:SomePackage # 包名\nVersion:1.0 # 版本号\nLocation:/my/env/lib/pythonx.x/site-packages # 安装位置\nFiles: # 包含文件等等\n../somepackage/__init__.py\n```\npip检查哪些包需要更新\n```code\npip list --outdated\n```\npip升级包\n```code\npip install --upgrade 要升级的包名\n```\npip卸载包\n```code\npip uninstall 要卸载的包名\n```\npip参数解释\n```code\npip --help\n```\nJupyter notebook使用在利用anaconda创建了tensorflowpytorch等儿女environment后想利用jupyter notebook发现jupyer notebook中只有系统的python3环境如何把conda创建的环境添加进jupyter notebook中呢终于解决了这个问题了1. 安装ipykernel\n```code\nconda install ipykernel\n```\n2. 将环境写入notebook的kernel中\n```code\npython -m ipykernel install --user --name your_env_name --display-name your_env_name\n\n//把conda environment pytorch_0.4 add to jupyter notebook kernel display as pytorch_0.4\npython -m ipykernel install --user --name pytorch_0.4 --display-name pytorch_0.4\n```\n3. 打开notebook\n```code\njupyter notebook\n```\n4. magic commands\n```code\n!git clone https://github.com/ultralytics/yolov5\n%ls\n%cd yolov5\n%pip install -qr requirements.txt\n```\n还有一些实用的魔术命令\n```code\n%magic——用来显示所有魔术命令的详细文档\n%time和%timeit——用来测试代码执行时间\n```\n参考文档编辑于 2023-05-21 20:41・IP 属地浙江PyCharmAnacondapip3赞同 142 条评论​分享​喜欢​收藏​申请转载​"}

View File

@ -1,16 +0,0 @@
import os, sys
src_dir = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
sys.path.append(src_dir)
from dev_opsgpt.text_splitter import LCTextSplitter
filepath = "D:/project/gitlab/llm/DevOpsGpt/knowledge_base/SAMPLES/content/test.txt"
lcTextSplitter = LCTextSplitter(filepath)
docs = lcTextSplitter.file2text()
print(docs[0])