Merge pull request #13 from sean1832/Major_Dev

Major dev 1.0.0
19-keywords-added-as-filtering-conditions 1.0.0
Zeke Zhang 1 year ago committed by GitHub
commit 39e0ee9676
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
{ {
"name": "GPT-Brain", "name": "GPT-Brain",
"version": "0.1.1", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"author": "Zeke Zhang", "author": "Zeke Zhang",
"homepage": "https://github.com/sean1832/GPT-Brain", "homepage": "https://github.com/sean1832/GPT-Brain",

@ -9,8 +9,15 @@
*💡本人并非专业程序猿并且是一个python小白此项目可能会出现各种bug。如果你遇到bug请在[问题栏](https://github.com/sean1832/GPT-Brain/issues)里提出,我会尽可能的进行修补。* *💡本人并非专业程序猿并且是一个python小白此项目可能会出现各种bug。如果你遇到bug请在[问题栏](https://github.com/sean1832/GPT-Brain/issues)里提出,我会尽可能的进行修补。*
### 简介
本程序利用[GPT-3](https://platform.openai.com/docs/models/gpt-3)和[3.5](https://platform.openai.com/docs/models/gpt-3-5)的能力,提供对原子笔记内容的概括,以及针对笔记的特定内容的回答。
该程序扫描指定目录通常是包含多个笔记的vault并将所有笔记的内容附加到单个文件中。
该文件随后用作用户查询的上下文。程序能够识别笔记内容之间的关系,并生成一个精炼的回答,概括关键要点。
尽管该程序与使用markdown或txt的其他笔记软件兼容但它主要是针对[Obsidian](https://obsidian.md/)设计的。
### 功能 ### 功能
- [x] 使用 [OpenAI GPT-3](https://platform.openai.com/docs/models/gpt-3) 生成回答。 - [x] 使用 [OpenAI GPT-3](https://platform.openai.com/docs/models/gpt-3)和 [GPT-3.5 (ChatGPT)](https://platform.openai.com/docs/models/gpt-3-5) 生成回答。
- [x] 使用 [OpenAI embedding](https://platform.openai.com/docs/guides/embeddings/what-are-embeddings) 对笔记内容和问题进行对称比较,以增强搜索效果。 - [x] 使用 [OpenAI embedding](https://platform.openai.com/docs/guides/embeddings/what-are-embeddings) 对笔记内容和问题进行对称比较,以增强搜索效果。
- [x] 可配置prompt。 - [x] 可配置prompt。
- [x] 可个性化的个人背景信息以获得更贴切的答案。 - [x] 可个性化的个人背景信息以获得更贴切的答案。
@ -23,13 +30,9 @@
- [x] 基本和高级参数滑块以便于调整OpenAI语言模型配置。 - [x] 基本和高级参数滑块以便于调整OpenAI语言模型配置。
### 未来计划 ### 未来计划
- [x] ~~batch脚本更新库。~~ - [ ] 支持PDF笔记格式。
- [x] ~~版本控制。~~ - [ ] 支持PDF OCR扫描。
- [x] ~~参数提示。~~ - [ ] 支持Word文档格式。
- [x] ~~支持多语言UI~~
- [x] ~~支持多语言检索。~~
- [ ] 提供详细操作指南。
- [ ] 发布windows版本。
## 安装 ## 安装
### 1. 所需条件 ### 1. 所需条件

@ -9,8 +9,19 @@
*💡私はプロのプログラマーではなく、Pythonにもかなり慣れていないため、このプロジェクトにはバグが含まれているかもしれません。もし何か問題があれば、[Issues section](https://github.com/sean1832/GPT-Brain/issues)で提案してください。* *💡私はプロのプログラマーではなく、Pythonにもかなり慣れていないため、このプロジェクトにはバグが含まれているかもしれません。もし何か問題があれば、[Issues section](https://github.com/sean1832/GPT-Brain/issues)で提案してください。*
### 紹介
このプログラムは、[GPT-3](https://platform.openai.com/docs/models/gpt-3)と[3.5](https://platform.openai.com/docs/models/gpt-3-5)の力を活用して、原子的なノートの内容の要約と、
特定のノートに関連する質問に回答することを提供します。
プログラムは、通常、複数のートを含むvaultとして指定されたディレクトリをスキャンし、
すべてのノートの内容を単一のファイルに追加します。
このファイルは、ユーザーのクエリの文脈として機能します。プログラムは、ノートの内容の関係を識別し、
主要なポイントを要約する洗練された応答を生成できます。
このプログラムは、markdownまたはtxtを使用する他のート取りソフトウェアでも互換性がありますが、
主に[Obsidian](https://obsidian.md/)を想定して設計されています。
### フィーチャー ### フィーチャー
- [x] [OpenAI GPT-3](https://platform.openai.com/docs/models/gpt-3)を使って、レスポンスを生成します。 - [x] [OpenAI GPT-3](https://platform.openai.com/docs/models/gpt-3)と[GPT-3.5 (ChatGPT)](https://platform.openai.com/docs/models/gpt-3-5)を使って、レスポンスを生成します。
- [x] [OpenAIエンベッディング](https://platform.openai.com/docs/guides/embeddings/what-are-embeddings)を使用して、質問とノートの内容を意味的に比較し、検索を強化します。 - [x] [OpenAIエンベッディング](https://platform.openai.com/docs/guides/embeddings/what-are-embeddings)を使用して、質問とノートの内容を意味的に比較し、検索を強化します。
- [x] 設定可能なプロンプト。 - [x] 設定可能なプロンプト。
- [x] より正確な回答を得るために、個人の背景情報をカスタマイズすることができます。 - [x] より正確な回答を得るために、個人の背景情報をカスタマイズすることができます。
@ -23,13 +34,9 @@
- [x] OpenAI言語モデルの構成に対する基本的および高度なパラメータースライダー。。 - [x] OpenAI言語モデルの構成に対する基本的および高度なパラメータースライダー。。
### Todo ### Todo
- [x] ~~ライブラリの更新を行うバッチスクリプト。~~ - [ ] PDFサポート。
- [x] ~~バージョニング。~~ - [ ] PDF OCRスキャンをサポート。
- [x] ~~パラメータに関するヒント。~~ - [ ] Word文書をサポート。
- [x] ~~多言語UI。~~
- [x] ~~多言語検索に対応。~~
- [ ] ユーザー向けの詳細なドキュメントを提供する。
- [ ] Windows用をリリース。
## 設置 ## 設置
### 1. 必要なもの ### 1. 必要なもの

@ -1,3 +1,3 @@
from GPT import query from GPT import query
from GPT import toolkit from GPT import gpt_tools
from GPT import model from GPT import model

@ -0,0 +1,94 @@
import openai
import numpy as np
import requests
import sseclient
# this function compare similarity between two vectors.
# The higher value the dot product have, the more alike between these vectors
def similarity(v1, v2):
return np.dot(v1, v2)
# return a list of vectors
def embedding(content, engine='text-embedding-ada-002'):
response = openai.Embedding.create(input=content, engine=engine)
vector = response['data'][0]['embedding']
return vector
def search_chunks(query, data, count=1):
vector = embedding(query)
points = []
for item in data:
# compare search terms with brain-data
point = similarity(vector, item['vector'])
points.append({
'content': item['content'],
'point': point
})
# sort points base on descendant order
ordered = sorted(points, key=lambda d: d['point'], reverse=True)
return ordered[0:count]
def gpt3(prompt, model, params):
response = openai.Completion.create(
model=model,
prompt=prompt,
temperature=params.temp,
max_tokens=params.max_tokens,
top_p=params.top_p,
frequency_penalty=params.frequency_penalty,
presence_penalty=params.present_penalty
)
text = response['choices'][0]['text'].strip()
return text
def gpt35(prompt, params, system_role_content: str = 'You are a helpful assistant.'):
completions = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
max_tokens=params.max_tokens,
temperature=params.temp,
top_p=params.top_p,
frequency_penalty=params.frequency_penalty,
presence_penalty=params.present_penalty,
messages=[
{"role": "system", "content": system_role_content},
{"role": "user", "content": prompt}
])
text = completions['choices'][0]['message']['content']
return text
def gpt3_stream(prompt, model, params):
response = openai.Completion.create(
model=model,
stream=True,
prompt=prompt,
temperature=params.temp,
max_tokens=params.max_tokens,
top_p=params.top_p,
frequency_penalty=params.frequency_penalty,
presence_penalty=params.present_penalty
)
return response
def gpt35_stream(prompt, params, system_role_content: str = 'You are a helpful assistant.'):
completions = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
max_tokens=params.max_tokens,
temperature=params.temp,
top_p=params.top_p,
frequency_penalty=params.frequency_penalty,
presence_penalty=params.present_penalty,
stream=True,
messages=[
{"role": "system", "content": system_role_content},
{"role": "user", "content": prompt}
])
return completions

@ -11,12 +11,12 @@ API_KEY = util.read_file(r'.user\API-KEYS.txt').strip()
openai.api_key = API_KEY openai.api_key = API_KEY
SESSION_LANG = st.session_state['SESSION_LANGUAGE'] SESSION_LANG = st.session_state['SESSION_LANGUAGE']
_ = language.set_language() _ = language.set_language()
def build(chunk_size=4000): def build(chunk_size=4000):
openai.api_key = API_KEY
all_text = util.read_file(r'.user\input.txt') all_text = util.read_file(r'.user\input.txt')
# split text into smaller chunk of 4000 char each # split text into smaller chunk of 4000 char each
@ -24,7 +24,7 @@ def build(chunk_size=4000):
chunk_count = len(chunks) chunk_count = len(chunks)
result = [] result = []
for idx, chunk in enumerate(chunks): for idx, chunk in enumerate(chunks):
embedding = GPT.toolkit.embedding(chunk.encode(encoding='ASCII', errors='ignore').decode()) embedding = GPT.gpt_tools.embedding(chunk.encode(encoding='ASCII', errors='ignore').decode())
info = {'content': chunk, 'vector': embedding} info = {'content': chunk, 'vector': embedding}
print(info, '\n\n\n') print(info, '\n\n\n')
@ -38,7 +38,7 @@ def build(chunk_size=4000):
def run(query, model, prompt_file, isQuestion, params, info_file=None): def run(query, model, prompt_file, isQuestion, params, info_file=None):
if isQuestion: if isQuestion:
data = util.read_json(INFO.BRAIN_DATA) data = util.read_json(INFO.BRAIN_DATA)
results = GPT.toolkit.search_chunks(query, data, params.chunk_count) results = GPT.gpt_tools.search_chunks(query, data, params.chunk_count)
answers = [] answers = []
for result in results: for result in results:
my_info = util.read_file(info_file) my_info = util.read_file(info_file)
@ -47,7 +47,10 @@ def run(query, model, prompt_file, isQuestion, params, info_file=None):
prompt = prompt.replace('<<QS>>', query) prompt = prompt.replace('<<QS>>', query)
prompt = prompt.replace('<<MY-INFO>>', my_info) prompt = prompt.replace('<<MY-INFO>>', my_info)
answer = GPT.toolkit.gpt3(prompt, model, params) if model == 'gpt-3.5-turbo':
answer = GPT.gpt_tools.gpt35(prompt, params)
else:
answer = GPT.gpt_tools.gpt3(prompt, model, params)
answers.append(answer) answers.append(answer)
all_response = '\n\n'.join(answers) all_response = '\n\n'.join(answers)
else: else:
@ -55,27 +58,38 @@ def run(query, model, prompt_file, isQuestion, params, info_file=None):
responses = [] responses = []
for chunk in chunks: for chunk in chunks:
prompt = util.read_file(prompt_file).replace('<<DATA>>', chunk) prompt = util.read_file(prompt_file).replace('<<DATA>>', chunk)
response = GPT.toolkit.gpt3(prompt, model, params) if model == 'gpt-3.5-turbo':
response = GPT.gpt_tools.gpt35(prompt, params)
else:
response = GPT.gpt_tools.gpt3(prompt, model, params)
responses.append(response) responses.append(response)
all_response = '\n\n'.join(responses) all_response = '\n\n'.join(responses)
return all_response return all_response
def run_stream(query, model, prompt_file, isQuestion, params, info_file=None): def get_stream_prompt(query, prompt_file, isQuestion, info_file=None):
client = None openai.api_key = API_KEY
if isQuestion: if isQuestion:
data = util.read_json(INFO.BRAIN_DATA) data = util.read_json(INFO.BRAIN_DATA)
results = GPT.toolkit.search_chunks(query, data, count=1) if data:
for result in results: result = GPT.gpt_tools.search_chunks(query, data, count=1)
my_info = util.read_file(info_file) my_info = util.read_file(info_file)
prompt = util.read_file(prompt_file) prompt = util.read_file(prompt_file)
prompt = prompt.replace('<<INFO>>', result['content']) prompt = prompt.replace('<<INFO>>', result[0]['content'])
prompt = prompt.replace('<<QS>>', query) prompt = prompt.replace('<<QS>>', query)
prompt = prompt.replace('<<MY-INFO>>', my_info) prompt = prompt.replace('<<MY-INFO>>', my_info)
client = GPT.toolkit.gpt3_stream(API_KEY, prompt, model, params) else:
prompt = ''
else: else:
chunk = textwrap.wrap(query, 10000)[0] chunk = textwrap.wrap(query, 10000)[0]
prompt = util.read_file(prompt_file).replace('<<DATA>>', chunk) prompt = util.read_file(prompt_file).replace('<<DATA>>', chunk)
client = GPT.toolkit.gpt3_stream(API_KEY, prompt, model, params) return prompt
def run_stream(query, model, prompt_file, isQuestion, params, info_file=None):
prompt = get_stream_prompt(query, prompt_file, isQuestion, info_file)
if model == 'gpt-3.5-turbo':
client = GPT.gpt_tools.gpt35_stream(prompt, params)
else:
client = GPT.gpt_tools.gpt3_stream(prompt, model, params)
return client return client

@ -1,71 +0,0 @@
import openai
import numpy as np
import requests
import sseclient
# this function compare similarity between two vectors.
# The higher value the dot product have, the more alike between these vectors
def similarity(v1, v2):
return np.dot(v1, v2)
# return a list of vectors
def embedding(content, engine='text-embedding-ada-002'):
response = openai.Embedding.create(input=content, engine=engine)
vector = response['data'][0]['embedding']
return vector
def search_chunks(text, data, count=1):
vector = embedding(text)
points = []
for item in data:
# compare search terms with brain-data
point = similarity(vector, item['vector'])
points.append({
'content': item['content'],
'point': point
})
# sort points base on descendant order
ordered = sorted(points, key=lambda d: d['point'], reverse=True)
return ordered[0:count]
def gpt3(prompt, model, params):
response = openai.Completion.create(
model=model,
prompt=prompt,
temperature=params.temp,
max_tokens=params.max_tokens,
top_p=params.top_p,
frequency_penalty=params.frequency_penalty,
presence_penalty=params.present_penalty
)
text = response['choices'][0]['text'].strip()
return text
def gpt3_stream(API_KEY, prompt, model, params):
url = 'https://api.openai.com/v1/completions'
headers = {
'Accept': 'text/event-stream',
'Authorization': 'Bearer ' + API_KEY
}
body = {
'model': model,
'prompt': prompt,
'max_tokens': params.max_tokens,
'temperature': params.temp,
'top_p': params.top_p,
'frequency_penalty': params.frequency_penalty,
'presence_penalty': params.present_penalty,
'stream': True,
}
req = requests.post(url, stream=True, headers=headers, json=body)
client = sseclient.SSEClient(req)
return client
# print(json.loads(event.data)['choices'][0]['text'], end='', flush=True)

@ -9,8 +9,23 @@
*💡As I am not a professional programmer and am fairly new to Python, this project may contain bugs. If you encounter any issues, please suggest them in the [Issues section](https://github.com/sean1832/GPT-Brain/issues).* *💡As I am not a professional programmer and am fairly new to Python, this project may contain bugs. If you encounter any issues, please suggest them in the [Issues section](https://github.com/sean1832/GPT-Brain/issues).*
### Description
This program leverages the power of [GPT-3](https://platform.openai.com/docs/models/gpt-3) & [3.5](https://platform.openai.com/docs/models/gpt-3-5) to provide a summary of the content of atomic notes,
as well as answer questions related specifically to your notes.
The program scans a designated directory,
which is typically a vault containing multiple notes,
and appends the contents of all the notes to a single file.
This file then serves as the context for the user's query.
The program is able to identify
relationships between the contents of the notes,
and generate a refined response that summarizes the key points.
Although the program is compatible with other note-taking software that uses
markdown or txt,
it is primarily designed with [Obsidian](https://obsidian.md/) in mind.
### Feature ### Feature
- [x] Use [OpenAI GPT-3](https://platform.openai.com/docs/models/gpt-3) to generate response. - [x] Use [OpenAI GPT-3](https://platform.openai.com/docs/models/gpt-3) and [GPT-3.5 (ChatGPT)](https://platform.openai.com/docs/models/gpt-3-5) to generate response.
- [x] Use [OpenAI embedding](https://platform.openai.com/docs/guides/embeddings/what-are-embeddings) for semetic comparison of question and note content for enhanced searching. - [x] Use [OpenAI embedding](https://platform.openai.com/docs/guides/embeddings/what-are-embeddings) for semetic comparison of question and note content for enhanced searching.
- [x] Configurable prompts. - [x] Configurable prompts.
- [x] Customizable personal background information for more accurate answers. - [x] Customizable personal background information for more accurate answers.
@ -23,13 +38,10 @@
- [x] Basic & Advanced parameter sliders for OpenAI Language model configurations. - [x] Basic & Advanced parameter sliders for OpenAI Language model configurations.
### Todo ### Todo
- [x] ~~Batch script to update library.~~ - [ ] Support PDF format。
- [x] ~~Versioning.~~ - [ ] Support PDF OCR scan。
- [x] ~~Tooltips for parameters.~~ - [ ] Support Word document。
- [x] ~~Multilingual support for UI.~~
- [x] ~~Multilingual search support.~~
- [ ] Provide detail documentation for users.
- [ ] Release for windows.
## Install ## Install
### 1. What you need ### 1. What you need

@ -64,12 +64,15 @@ with st.sidebar:
"your prompt plus `max_tokens` cannot exceed the model's context length. Most " "your prompt plus `max_tokens` cannot exceed the model's context length. Most "
"models have a context length of 2048 tokens (except for the newest models, " "models have a context length of 2048 tokens (except for the newest models, "
"which support 4096).")) "which support 4096)."))
chunk_size = st.slider(_('Chunk size'), 1500, 4500, col1, col2 = st.columns([3, 1])
value=util.read_json_at(INFO.BRAIN_MEMO, 'chunk_size', 4000), with col1:
help=_("The number of tokens to consider at each step. The larger this is, the more " chunk_size = st.slider(_('Chunk size'), 1500, 4500,
"context the model has to work with, but the slower generation and expensive " value=util.read_json_at(INFO.BRAIN_MEMO, 'chunk_size', 4000),
"will it be.")) help=_("The number of tokens to consider at each step. The larger this is, the more "
"context the model has to work with, but the slower generation and expensive "
"will it be."))
with col2:
update_brain = st.button(_('Update Brain'))
with st.expander(label=_('Advanced Options')): with st.expander(label=_('Advanced Options')):
top_p = st.slider(_('Top_P'), 0.0, 1.0, value=util.read_json_at(INFO.BRAIN_MEMO, 'top_p', 1.0), top_p = st.slider(_('Top_P'), 0.0, 1.0, value=util.read_json_at(INFO.BRAIN_MEMO, 'top_p', 1.0),
help=_("An alternative to sampling with temperature, called nucleus sampling, where the " help=_("An alternative to sampling with temperature, called nucleus sampling, where the "
@ -90,7 +93,7 @@ with st.sidebar:
"(https://platform.openai.com/docs/api-reference/parameter-details)")) "(https://platform.openai.com/docs/api-reference/parameter-details)"))
enable_stream = st_toggle.st_toggle_switch(_('Stream (experimental)'), enable_stream = st_toggle.st_toggle_switch(_('Stream (experimental)'),
default_value=util.read_json_at(INFO.BRAIN_MEMO, 'enable_stream', default_value=util.read_json_at(INFO.BRAIN_MEMO, 'enable_stream',
False)) True))
if not enable_stream: if not enable_stream:
chunk_count = st.slider(_('Answer count'), 1, 5, value=util.read_json_at(INFO.BRAIN_MEMO, 'chunk_count', 1), chunk_count = st.slider(_('Answer count'), 1, 5, value=util.read_json_at(INFO.BRAIN_MEMO, 'chunk_count', 1),
@ -136,7 +139,7 @@ with header:
# main # main
with body: with body:
question = st.text_area(_('Ask Brain: ')) query = st.text_area(_('Ask Brain: '))
col1, col2 = st.columns([1, 3]) col1, col2 = st.columns([1, 3])
with col1: with col1:
send = st.button(_('📩Send')) send = st.button(_('📩Send'))
@ -144,13 +147,49 @@ with body:
if os.path.exists(CURRENT_LOG_FILE): if os.path.exists(CURRENT_LOG_FILE):
st_tool.download_as(_("📥download log")) st_tool.download_as(_("📥download log"))
# execute brain calculation # execute brain calculation
if not question == '' and send: if update_brain:
st_tool.execute_brain(question, st_tool.rebuild_brain(chunk_size)
param, if not query == '':
op, if models.question_model == 'text-davinci-003' or 'text-davinci-003' in models.other_models:
models, max_model_token = 4096
prompt_core, elif models.question_model == 'gpt-3.5-turbo' or 'gpt-3.5-turbo' in models.other_models:
prompt_dictionary, max_model_token = 4096
_('question'), else:
enable_stream, max_model_token = 2048
SESSION_LANG)
tokens, isTokenZero = st_tool.predict_token(query, prompt_core)
token_panel = st.empty()
if isTokenZero:
token_panel.markdown('Prompt token: `Not Available`')
else:
token_panel.markdown(f'Prompt token: `{tokens}/{max_model_token}`')
if send:
st_tool.execute_brain(query,
param,
op,
models,
prompt_core,
prompt_dictionary,
_('question'),
enable_stream)
# convert param to dictionary
param_dict = vars(param)
# write param to json
for key in param_dict:
value = param_dict[key]
util.update_json(INFO.BRAIN_MEMO, key, value)
# write operation to json
util.update_json(INFO.BRAIN_MEMO, f'operations_{SESSION_LANG}', op.operations)
# write question model to json
util.update_json(INFO.BRAIN_MEMO, 'question_model', models.question_model)
# write other models to json
for i in range(len(op.operations_no_question)):
util.update_json(INFO.BRAIN_MEMO, f'{op.operations_no_question[i]}_model', models.other_models[i])
# write stream to json
util.update_json(INFO.BRAIN_MEMO, 'enable_stream', enable_stream)

@ -33,4 +33,4 @@ if 'FILTER_ROW_COUNT' not in st.session_state:
st.session_state['FILTER_ROW_COUNT'] = util.read_json_at(BRAIN_MEMO, 'filter_row_count', default_value=1) st.session_state['FILTER_ROW_COUNT'] = util.read_json_at(BRAIN_MEMO, 'filter_row_count', default_value=1)
# models # models
MODELS_OPTIONS = ['text-davinci-003', 'text-curie-001', 'text-babbage-001', 'text-ada-001'] MODELS_OPTIONS = ['gpt-3.5-turbo', 'text-davinci-003', 'text-curie-001', 'text-babbage-001', 'text-ada-001']

@ -77,7 +77,7 @@ def parse_data(data, delimiter='', force=False):
return data return data
def read_files(file_dir, delimiter='', force=False, single_string=True, exclude_dir: list = None, supported_formats: list = None): def read_bind_files(file_dir, delimiter='', force=False, single_string=True, exclude_dir: list = None, supported_formats: list = None):
contents = [] contents = []
if exclude_dir is None: if exclude_dir is None:
exclude_dir = [] exclude_dir = []

@ -132,13 +132,13 @@ def main():
exclude_dir = exclude_dir_official exclude_dir = exclude_dir_official
# if advanced mode enabled # if advanced mode enabled
if advanced_mode: if advanced_mode:
note_datas = util.read_files(note_dir, single_string=False, exclude_dir=exclude_dir) note_datas = util.read_bind_files(note_dir, single_string=False, exclude_dir=exclude_dir)
note_datas, filter_info = st_tools.filter_data(note_datas, add_filter_button, del_filter_button) note_datas, filter_info = st_tools.filter_data(note_datas, add_filter_button, del_filter_button)
# note_datas, filter_key, filter_logic, filter_val = filter_data(note_datas, True) # note_datas, filter_key, filter_logic, filter_val = filter_data(note_datas, True)
modified_data = util.parse_data(note_datas, delimiter, force_delimiter) modified_data = util.parse_data(note_datas, delimiter, force_delimiter)
else: else:
modified_data = util.read_files(note_dir, single_string=True, delimiter=delimiter, modified_data = util.read_bind_files(note_dir, single_string=True, delimiter=delimiter,
force=force_delimiter, exclude_dir=exclude_dir) force=force_delimiter, exclude_dir=exclude_dir)
# append mode # append mode
if append_mode: if append_mode:

@ -1,8 +1,10 @@
numpy==1.24.2 numpy==1.24.2
openai==0.26.5 openai==0.27.0
requests==2.28.2 requests==2.28.2
sseclient==0.0.27 sseclient==0.0.27
sseclient_py==1.7.2 sseclient_py==1.7.2
streamlit==1.18.1 streamlit==1.19.0
streamlit_tags==1.2.8 streamlit_tags==1.2.8
streamlit_toggle_switch==1.0.2 streamlit_toggle_switch==1.0.2
langchain==0.0.100
tiktoken==0.3.0

@ -4,6 +4,7 @@ import json
import streamlit as st import streamlit as st
import tkinter as tk import tkinter as tk
from tkinter import filedialog from tkinter import filedialog
from langchain.llms import OpenAI
import modules.utilities as util import modules.utilities as util
import modules.INFO as INFO import modules.INFO as INFO
@ -18,6 +19,16 @@ SESSION_TIME = st.session_state['SESSION_TIME']
CURRENT_LOG_FILE = f'{INFO.LOG_PATH}/log_{SESSION_TIME}.log' CURRENT_LOG_FILE = f'{INFO.LOG_PATH}/log_{SESSION_TIME}.log'
def predict_token(query: str, prompt_core: GPT.model.prompt_core) -> (int, bool):
"""predict how many tokens to generate"""
llm = OpenAI()
prompt = GPT.query.get_stream_prompt(query, prompt_file=prompt_core.question,
isQuestion=True,
info_file=prompt_core.my_info)
token = llm.get_num_tokens(prompt)
return token, token == 0
def create_log(): def create_log():
if not os.path.exists(CURRENT_LOG_FILE): if not os.path.exists(CURRENT_LOG_FILE):
util.write_file(f'Session {SESSION_TIME}\n\n', CURRENT_LOG_FILE) util.write_file(f'Session {SESSION_TIME}\n\n', CURRENT_LOG_FILE)
@ -229,69 +240,99 @@ def process_response_stream(query, target_model, prompt_file: str, params: GPT.m
# check if exclude model is not target model # check if exclude model is not target model
file_name = util.get_file_name(prompt_file) file_name = util.get_file_name(prompt_file)
with st.spinner(_('Thinking on ') + f"{file_name}..."): with st.spinner(_('Thinking on ') + f"{file_name}..."):
client = GPT.query.run_stream(query, responses = GPT.query.run_stream(query,
target_model, target_model,
prompt_file, prompt_file,
isQuestion=False, isQuestion=False,
params=params) params=params)
# displaying results # displaying results
st.header(f'📃{file_name}') st.header(f'📃{file_name}')
response_panel = st.empty() response_panel = st.empty()
previous_chars = '' previous_chars = ''
for event in client.events(): for response_json in responses:
if event.data != '[DONE]': choice = response_json['choices'][0]
char = json.loads(event.data)['choices'][0]['text'] if choice['finish_reason'] == 'stop':
response = previous_chars + char break
response_panel.info(f'{response}') # error handling
previous_chars += char if choice['finish_reason'] == 'length':
st.warning("⚠️ " + _('Result cut off. max_tokens') + f' ({params.max_tokens}) ' + _('too small. Consider increasing max_tokens.'))
break
if 'gpt-3.5-turbo' in target_model:
delta = choice['delta']
if "role" in delta or delta == {}:
char = ''
else:
char = delta['content']
else:
char = choice['text']
response = previous_chars + char
response_panel.info(f'{response}')
previous_chars += char
time.sleep(1) time.sleep(1)
log(previous_chars, delimiter=f'{file_name.upper()}') log(previous_chars, delimiter=f'{file_name.upper()}')
def rebuild_brain(chunk_size: int):
msg = st.warning(_('Updating Brain...'), icon="")
progress_bar = st.progress(0)
for idx, chunk_num in GPT.query.build(chunk_size):
progress_bar.progress((idx + 1) / chunk_num)
msg.success(_('Brain Updated!'), icon="👍")
time.sleep(2)
def execute_brain(q, params: GPT.model.param, def execute_brain(q, params: GPT.model.param,
op: GPT.model.Operation, op: GPT.model.Operation,
model: GPT.model.Model, model: GPT.model.Model,
prompt_core: GPT.model.prompt_core, prompt_core: GPT.model.prompt_core,
prompt_dictionary: dict, prompt_dictionary: dict,
question_prompt: str, question_prompt: str,
stream: bool, stream: bool
session_language,
): ):
# log question # log question
log(f'\n\n\n\n[{str(time.ctime())}] - QUESTION: {q}') log(f'\n\n\n\n[{str(time.ctime())}] - QUESTION: {q}')
if mod.check_update.is_input_updated() or mod.check_update.is_param_updated(params.chunk_size, 'chunk_size'): if mod.check_update.is_input_updated() or mod.check_update.is_param_updated(params.chunk_size, 'chunk_size'):
msg = st.warning(_('Updating Brain...'), icon="") rebuild_brain(params.chunk_size)
progress_bar = st.progress(0)
for idx, chunk_num in GPT.query.build(params.chunk_size):
progress_bar.progress((idx + 1) / chunk_num)
msg.success(_('Brain Updated!'), icon="👍")
time.sleep(2)
# =================stream================= # =================stream=================
if stream: if stream:
previous_chars = '' previous_chars = ''
is_question_selected = util.contains(op.operations, question_prompt) is_question_selected = util.contains(op.operations, question_prompt)
with st.spinner(_('Thinking on Answer')): with st.spinner(_('Thinking on Answer')):
answer_clients = GPT.query.run_stream(q, model.question_model, responses = GPT.query.run_stream(q, model.question_model,
prompt_file=prompt_core.question, prompt_file=prompt_core.question,
isQuestion=True, isQuestion=True,
params=params, params=params,
info_file=prompt_core.my_info) info_file=prompt_core.my_info)
if is_question_selected: if is_question_selected:
# displaying results # displaying results
st.header(_('💬Answer')) st.header(_('💬Answer'))
answer_panel = st.empty() answer_panel = st.empty()
for event in answer_clients.events(): for response_json in responses:
if event.data != '[DONE]': choice = response_json['choices'][0]
char = json.loads(event.data)['choices'][0]['text'] if choice['finish_reason'] == 'stop':
answer = previous_chars + char break
if is_question_selected: # error handling
answer_panel.info(f'{answer}') if choice['finish_reason'] == 'length':
previous_chars += char st.warning("⚠️ " + _('Result cut off. max_tokens') + f' ({params.max_tokens}) ' + _('too small. Consider increasing max_tokens.'))
break
if 'gpt-3.5-turbo' in model.question_model:
delta = choice['delta']
if "role" in delta or delta == {}:
char = ''
else:
char = delta['content']
else:
char = choice['text']
answer = previous_chars + char
if is_question_selected:
answer_panel.info(f'{answer}')
previous_chars += char
time.sleep(0.1) time.sleep(0.1)
log(previous_chars, delimiter='ANSWER') log(previous_chars, delimiter='ANSWER')
@ -304,42 +345,24 @@ def execute_brain(q, params: GPT.model.param,
else: else:
# thinking on answer # thinking on answer
with st.spinner(_('Thinking on Answer')): with st.spinner(_('Thinking on Answer')):
answer = GPT.query.run(q, model.question_model, responses = GPT.query.run(q, model.question_model,
prompt_file=prompt_core.question, prompt_file=prompt_core.question,
isQuestion=True, isQuestion=True,
params=params, params=params,
info_file=prompt_core.my_info) info_file=prompt_core.my_info)
if util.contains(op.operations, question_prompt): if util.contains(op.operations, question_prompt):
# displaying results # displaying results
st.header(_('💬Answer')) st.header(_('💬Answer'))
st.info(f'{answer}') st.info(f'{responses}')
time.sleep(1.5) time.sleep(1.5)
log(answer, delimiter='ANSWER') log(responses, delimiter='ANSWER')
# thinking on other outputs # thinking on other outputs
if len(op.operations_no_question) > 0: if len(op.operations_no_question) > 0:
for i in range(len(op.operations_no_question)): for i in range(len(op.operations_no_question)):
prompt_path = prompt_dictionary[op.operations_no_question[i]] prompt_path = prompt_dictionary[op.operations_no_question[i]]
other_model = model.other_models[i] other_model = model.other_models[i]
process_response(answer, other_model, prompt_path, params) process_response(responses, other_model, prompt_path, params)
# convert param to dictionary
param_dict = vars(params)
# write param to json
for key in param_dict:
value = param_dict[key]
util.update_json(INFO.BRAIN_MEMO, key, value)
# write operation to json
util.update_json(INFO.BRAIN_MEMO, f'operations_{session_language}', op.operations)
# write question model to json
util.update_json(INFO.BRAIN_MEMO, 'question_model', model.question_model)
# write other models to json
for i in range(len(op.operations_no_question)):
util.update_json(INFO.BRAIN_MEMO, f'{op.operations_no_question[i]}_model', model.other_models[i])
def message(msg, condition=None): def message(msg, condition=None):

@ -1,3 +1,7 @@
@echo off
echo Activating Virtural environment!
call .\venv\Scripts\activate
echo Checking library updates... echo Checking library updates...
set "REQUIREMENTS=requirements.txt" set "REQUIREMENTS=requirements.txt"
set "LAST_MODIFIED=requirements.temp" set "LAST_MODIFIED=requirements.temp"
@ -26,4 +30,4 @@ if "%mod_date%" neq "%last_mod_date%" (
) )
rem copy example prompt to user folder without overwrite rem copy example prompt to user folder without overwrite
xcopy "example_prompt\*.*" ".user\prompt" /I /E /Y /D xcopy "example_prompt\*.*" ".user\prompt" /I /E /Y /D
Loading…
Cancel
Save