File size: 9,553 Bytes
8b593b6
14e8dc8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12b1ff0
a98c1b4
440a9cf
14e8dc8
35b62b6
 
afdd574
ae3526d
 
b57b1fa
b3f1c98
01901e0
788e7b9
01901e0
8ab1139
14e8dc8
 
 
 
 
 
 
fad460a
14e8dc8
 
 
 
fad460a
14e8dc8
 
 
8b593b6
 
a98c1b4
8b593b6
 
 
0010fba
14e8dc8
 
0010fba
8b593b6
14e8dc8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5d61ee6
14e8dc8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
749fd07
 
8f5bff6
0010fba
30e2b7a
0010fba
30e2b7a
 
b57b1fa
30e2b7a
a3d08aa
ae3526d
 
14e8dc8
0010fba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14e8dc8
0010fba
 
 
 
 
def6d9f
0010fba
 
 
def6d9f
 
0010fba
eddde63
def6d9f
a551f8d
69713ba
df9f997
afdd574
df9f997
c6b250a
 
 
366190c
cdd2ded
def6d9f
 
524a7b5
8c48a8e
eca3c3a
 
 
 
 
64021df
 
eca3c3a
 
b3f1c98
 
 
 
 
 
 
 
 
 
 
 
7709d6e
0010fba
 
df9f997
59368b0
749fd07
 
59368b0
749fd07
14e8dc8
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# imports go here
import openai
import os
import base64
import glob
import json
import mistune
import pytz
import math
import requests

from datetime import datetime
from openai import ChatCompletion
from xml.etree import ElementTree as ET
from bs4 import BeautifulSoup
from collections import deque
from audio_recorder_streamlit import audio_recorder

import streamlit as st

if 'text_content' not in st.session_state:
    st.session_state.text_content = ''

st.set_page_config(page_title="Chat Toolkit",layout="wide")

with st.sidebar.expander("Model Options", expanded=False):
    menu = ["htm", "txt", "md"] 
    choice = st.selectbox("Output File Type:", menu)
    model_choice = st.radio("Select Model:", ('gpt-3.5-turbo', 'gpt-4'))


def generate_filename(prompt, file_type):
    central = pytz.timezone('US/Central')
    safe_date_time = datetime.now(central).strftime("%m%d_%I%M")  
    safe_prompt = "".join(x for x in prompt if x.isalnum())[:45]
    return f"{safe_date_time}_{safe_prompt}.{file_type}"

def chat_with_model(prompt, document_section):
    model = model_choice
    conversation = [{'role': 'system', 'content': 'You are a helpful assistant.'}]
    conversation.append({'role': 'user', 'content': prompt})
    if len(document_section)>0:
        conversation.append({'role': 'assistant', 'content': document_section})
    response = openai.ChatCompletion.create(model=model, messages=conversation)
    return response
    #return response['choices'][0]['message']['content']

def transcribe_audio(openai_key, file_path, model):

    OPENAI_API_URL = "https://api.openai.com/v1/audio/transcriptions"
    headers = {
        "Authorization": f"Bearer {openai_key}",
    }

    with open(file_path, 'rb') as f:
        data = {'file': f}
        # check for correctness - lively addition
        response = requests.post(OPENAI_API_URL, headers=headers, files=data, data={'model': model})
    if response.status_code == 200:
        st.write(response.json())
        response2 = chat_with_model(response.json().get('text'), '')
        st.write('Responses:')
        #st.write(response)
        st.write(response2)
        return response.json().get('text')
    else:
        st.write(response.json())
        st.error("Error in API call.")
        return None

def save_and_play_audio(audio_recorder):
    audio_bytes = audio_recorder()
    if audio_bytes:
        filename = generate_filename("Recording", "wav")
        with open(filename, 'wb') as f:
            f.write(audio_bytes)
        st.audio(audio_bytes, format="audio/wav")
        return filename
    return None

def create_file(filename, prompt, response):
    if filename.endswith(".txt"):
        with open(filename, 'w') as file:
            file.write(f"Prompt:\n{prompt}\nResponse:\n{response}")
    elif filename.endswith(".htm"):
        with open(filename, 'w') as file:
            file.write(f"<h1>Prompt:</h1> <p>{prompt}</p> <h1>Response:</h1> <p>{response}</p>")
    elif filename.endswith(".md"):
        with open(filename, 'w') as file:
            file.write(f"# Prompt:\n{prompt}\n# Response:\n{response}")
def truncate_document(document, length):
    return document[:length]
def divide_document(document, max_length):
    return [document[i:i+max_length] for i in range(0, len(document), max_length)]
def get_table_download_link(file_path):
    with open(file_path, 'r') as file:
        data = file.read()
    b64 = base64.b64encode(data.encode()).decode()  
    file_name = os.path.basename(file_path)
    ext = os.path.splitext(file_name)[1]  # get the file extension
    if ext == '.txt':
        mime_type = 'text/plain'
    elif ext == '.py':
        mime_type = 'text/plain'
    elif ext == '.xlsx':
        mime_type = 'text/plain'
    elif ext == '.csv':
        mime_type = 'text/plain'
    elif ext == '.htm':
        mime_type = 'text/html'
    elif ext == '.md':
        mime_type = 'text/markdown'
    else:
        mime_type = 'application/octet-stream'  # general binary data type
    href = f'<a href="data:{mime_type};base64,{b64}" target="_blank" download="{file_name}">{file_name}</a>'
    return href




def CompressXML(xml_text):
    root = ET.fromstring(xml_text)
    for elem in list(root.iter()):
        if isinstance(elem.tag, str) and 'Comment' in elem.tag:
            elem.parent.remove(elem)
    return ET.tostring(root, encoding='unicode', method="xml")
    
def read_file_content(file,max_length):
    if file.type == "application/json":
        content = json.load(file)
        return str(content)
    elif file.type == "text/html" or file.type == "text/htm":
        content = BeautifulSoup(file, "html.parser")
        return content.text
    elif file.type == "application/xml" or file.type == "text/xml":
        tree = ET.parse(file)
        root = tree.getroot()
        xml = CompressXML(ET.tostring(root, encoding='unicode'))
        return xml
    elif file.type == "text/markdown" or file.type == "text/md":
        md = mistune.create_markdown()
        content = md(file.read().decode())
        return content
    elif file.type == "text/plain":
        return file.getvalue().decode()
    else:
        return ""

def main():
    
    st.title('Chat Toolkit')
    api_key = st.sidebar.text_input("Enter OpenAI API Key:", type='password')
    if api_key:
        
        openai.api_key = api_key

        my_prompt = st.text_area("Enter prompts, instructions & questions:", '', height=100)
        
        st.session_state.text_content = my_prompt
        
        uploaded_file = st.sidebar.file_uploader("Add a file for context:", type=["xml", "json", "xlsx","csv","html", "htm", "md", "txt"])
        max_length = st.sidebar.slider("File section length for large files", min_value=1000, max_value=128000, value=12000, step=1000)
        
        document_sections = deque()
        document_responses = {}
    
        if uploaded_file is not None:
            file_content = read_file_content(uploaded_file, max_length)
            document_sections.extend(divide_document(file_content, max_length))
    
        if len(document_sections) > 0:
            
            if st.button("👁️ View Upload"):
                st.markdown("**Sections of the uploaded file:**")
                for i, section in enumerate(list(document_sections)):
                    st.markdown(f"**Section {i+1}**\n{section}")
            
            st.markdown("**Chat with the model:**")
            for i, section in enumerate(list(document_sections)):
                if i in document_responses:
                    st.markdown(f"**Section {i+1}**\n{document_responses[i]}")
                else:
                    if st.button(f"Chat about Section {i+1}"):
                        st.write('Reasoning with your inputs...')
                        response = chat_with_model(st.session_state.text_content, section)
                        st.write('Response:')
                        st.write(response)
                        document_responses[i] = response
                        filename = generate_filename(f"{st.session_state.text_content}_section_{i+1}", choice)
                        create_file(filename, st.session_state.text_content, response)
                        st.sidebar.markdown(get_table_download_link(filename), unsafe_allow_html=True)

        
        st.warning("This is made for rapid entry, so use your return key or command enter (for mac) to run your query, or audio record your prompts.")
        if st.session_state.text_content:
            st.write('Reasoning with your inputs...')
            response = chat_with_model(st.session_state.text_content, ''.join(list(document_sections)))
            st.write('Response:')
            # Convert the JSON data to a formatted string
            json_str = json.dumps(response, indent=4)
            # Display the JSON data in a text area
            st.text_area("JSON Data:", value=json_str, height=400)
            #st.write(response)
            filename = generate_filename(st.session_state.text_content, choice)
            create_file(filename, st.session_state.text_content, response)
        

        # with st.sidebar.expander("Recording Options", expanded=False):
        # Audio, transcribe, GPT:
        filename = save_and_play_audio(audio_recorder)
        if filename is not None:
            transcription = transcribe_audio(openai.api_key, filename, "whisper-1")
            st.session_state.text_content = transcription
            


        all_files = glob.glob("*.*")
        all_files = [file for file in all_files if len(os.path.splitext(file)[0]) >= 20]  # exclude files with short names
        all_files.sort(key=lambda x: (os.path.splitext(x)[1], x), reverse=True)  # sort by file type and file name in descending order
        
        for file in all_files:
            col1, col3 = st.sidebar.columns([5,1])  # adjust the ratio as needed
            with col1:
                st.markdown(get_table_download_link(file), unsafe_allow_html=True)
            with col3:
                if st.button("🗑", key="delete_"+file):
                    os.remove(file)
                    st.experimental_rerun()
 
                
    else:
            # image and api warning before rest of code
            st.warning('Please enter your OpenAI API key in the left sidebar.')
            left_col, center_col, right_col = st.columns([1, 6, 1])
        
            with center_col:  
                st.image('ai2.png', use_column_width=True)
            
if __name__ == "__main__":
    main()