File size: 11,782 Bytes
7599676
 
8e04782
7599676
 
 
8e04782
7599676
 
 
 
 
4529c9d
8e04782
 
7599676
4529c9d
 
8e04782
4529c9d
8e04782
 
 
 
 
 
7599676
 
 
 
 
 
 
 
 
 
4529c9d
8e04782
 
 
 
 
 
7599676
4529c9d
8e04782
 
 
7599676
4529c9d
8e04782
 
 
7599676
4529c9d
 
 
 
 
 
 
 
8e04782
 
7599676
 
 
 
 
 
 
a7669c5
7599676
4529c9d
7599676
 
 
8e04782
4529c9d
8e04782
 
 
4529c9d
8e04782
4529c9d
8e04782
 
4529c9d
 
8e04782
 
4529c9d
a7669c5
 
8aad46a
7599676
8e04782
 
8aad46a
8e04782
a7669c5
4529c9d
 
8e04782
7599676
8e04782
 
7599676
8e04782
 
7599676
93669b9
8e04782
4529c9d
8e04782
 
4529c9d
 
8e04782
7599676
8e04782
 
 
 
 
 
 
4529c9d
8e04782
4529c9d
8e04782
4529c9d
8e04782
7599676
4529c9d
8e04782
a7669c5
8e04782
 
 
a7669c5
8e04782
 
 
4529c9d
8e04782
 
 
 
 
 
 
 
4529c9d
8e04782
 
4529c9d
a7669c5
4529c9d
8e04782
 
4529c9d
8e04782
4529c9d
8e04782
 
4529c9d
a7669c5
4529c9d
8e04782
 
4529c9d
8e04782
4529c9d
8e04782
4529c9d
8e04782
 
 
 
 
4529c9d
8e04782
 
 
 
 
 
 
4529c9d
8e04782
 
 
4529c9d
8e04782
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4529c9d
 
93669b9
4529c9d
 
 
 
 
8e04782
4529c9d
 
798a5a1
8e04782
 
 
4529c9d
 
7599676
 
4529c9d
 
93669b9
 
 
 
 
7599676
 
 
4529c9d
7599676
8e04782
 
7599676
 
 
 
 
8e04782
4529c9d
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
import streamlit as st
import streamlit_authenticator as stauth
from deta import Deta
import yaml
from yaml.loader import SafeLoader
import os
from cryptography.fernet import Fernet

from free_speech_app.DataLoadDb import *
from free_speech_app.FreeSpeechPromptsResponses import *
from langchain.chat_models import ChatOpenAI

# connect to/create Deta user database
deta = Deta(st.secrets["deta_key"])
db = deta.Base("user_data")

# fernet key (generated locally, stored in streamlit secrets)
fernet = Fernet(bytes(st.secrets["fernet_key"], 'utf-8'))

# activeloop_token
os.environ["ACTIVELOOP_TOKEN"] = st.secrets["deeplake_key"]

config_drive = deta.Drive("passwords")
config = config_drive.get("config.yaml").read()

config = yaml.load(config, Loader=SafeLoader)

# Create an authenticator
authenticator = stauth.Authenticate(
    config['credentials'],
    config['cookie']['name'],
    config['cookie']['key'],
    config['cookie']['expiry_days'],
    config['preauthorized']
)


def get_user_data(user):
    data = db.fetch().items
    for person in data:
        if person['key'] == user:
            return person
    return None


def encrypt(api_key: str, fernet) -> bytes:
    """Encrypt the API key."""
    return fernet.encrypt(api_key.encode())


def decrypt(encrypted_api_key: bytes, fernet) -> str:
    """Decrypt the encrypted API key."""
    return fernet.decrypt(encrypted_api_key).decode()


def add_logos():
    st.markdown(
        '![image](free_speech_app/logos/Future-of-Free-Speech-logo.png)')
    st.markdown(
        '![image](free_speech_app/logos/Vanderbilt-University-Logo.png)')


# Render the login module
name, authentication_status, username = authenticator.login('Login', 'main')

# If the user is authenticated
if authentication_status:
    authenticator.logout('Logout', 'main', key='unique_key')
    st.write(f'Welcome *{name}*')

    # Sidebar for navigation
    page = st.sidebar.radio("Choose a page", ["Account Setup", "API Key Help", "Respond to Post"])


    # Fetch user data from the database
    user_data = get_user_data(username)

    if page == "Account Setup":
        add_logos()

        st.title("Account Setup")
        st.markdown("Please use this page to provide your OpenAI API Key, Principles and Writing Style. **Please make sure to press the Save Changes button after providing the information.**")

        # Input boxes with existing data

        if 'api_key' not in st.session_state:
            st.session_state.api_key = ""
        api_input = st.text_input("Paste OpenAI API Key", value=decrypt(user_data["api_key"].encode()[
                                  2:-1], fernet) if user_data and "api_key" in user_data else "", type="password")
        encrypted_api_key = str(encrypt(api_input, fernet))
        st.session_state.api_key = api_input

        principles = st.text_area("My Principles (Paste Principles here)", height = 100, placeholder = "Enter the main principles of your life you wish this response to uphold", value=user_data["principles"] if user_data and "principles" in user_data else "")
        writing_style = st.text_area("My Writing Style (Paste Examples)", height = 100, placeholder = "Provide examples of your writing style here", value=user_data["writing_style"] if user_data and "writing_style" in user_data else "")
        #sources = st.text_area("Sources (This autopopulates for your reference)", value=st.session_state.sources if 'sources' in st.session_state else '', key = 'sources_key', height = 100)
    
        # Update button
        if st.button("Save Changes"):
            db.put({"key": username, "principles": principles, "writing_style": writing_style, "api_key": encrypted_api_key})
        
    if page == "API Key Help":
        add_logos()

        st.title("OpenAI API Key Setup")

        st.header('What is an API key?')
        st.write('An API (Application Programming Interface) key is like a password that allows you to access certain functions or data from a website or service. Many sites use API keys to identify you and control access to their APIs.')

        st.header('Why do you need an API key?')
        st.write('API keys allow sites to track usage and prevent abuse of their services. They help keep things secure. When you request an API key, the site knows the calls are coming from you.')

        image = 'apikeyex.png'
        st.header('How to get an OpenAI API key:')
        st.write('1. Go to https://platform.openai.com/account/api-keys')
        st.write('2. Log in or create an OpenAI account if you do not have one')
        st.write('3. Click "Create new secret key" and give your key a name')
        st.image(image, caption=None, width=None, use_column_width=None,
                 clamp=False, channels="RGB", output_format="auto")
        st.write('4. Copy the generated API key and keep it private like a password')

        st.header('Using your API key')
        st.write('When making calls to the OpenAI API, include your API key in the request headers or parameters to authenticate.')
        st.code('headers = {"Authorization": f"Bearer {YOUR_API_KEY}"}')

        st.warning('Treat your API key like a secret! Do not share it publicly.')

    elif page == "Respond to Post":
        add_logos()
        st.title("Respond to Post")

        left_col, right_col = st.columns(2)

        # Input boxes


        with right_col: 
            background_info = st.text_area("Background information on original post (This autopopulates for your reference)", height = 780, value=st.session_state.background_info if 'background_info' in st.session_state else '', key = 'background_info_key')

        with left_col:
            original_post = st.text_area("Paste Original Post Here \n", height=100)
            word_limit = st.text_input("Word Limit for Response", placeholder = "Please provide a word limit for the response")
            
            chat_mdl = None
            draft_response = ''

            # Check if the "Submit" button is clicked
            if st.button("Submit"):
                if st.session_state.api_key:
                    os.environ["OPENAI_API_KEY"] = st.session_state.api_key
                    # add condition to check for passphrase to allow use of DSI api key stored in secrets
                    if (os.environ["OPENAI_API_KEY"] == st.secrets["secret_passphrase"]):
                        os.environ["OPENAI_API_KEY"] = st.secrets["dsi_openai_key"]
                    chat_mdl = ChatOpenAI(model_name='gpt-4', temperature=0.1)

                if chat_mdl is not None:
                    if user_data is None:

                        draft_response, background_text = generate_custom_response(original_post, chat_mdl, "", "", word_limit)

                        st.session_state.draft_response = draft_response.content
                        st.session_state.background_text = background_text
                        # st.session_state.sources_text = sources_text
                        st.session_state.background_info = background_text
                        # st.session_state.sources = sources_text
                        st.rerun()
                    else:

                        draft_response, background_text = generate_custom_response(original_post, chat_mdl, user_data['principles'], user_data['writing_style'], word_limit)

                        st.session_state.draft_response = draft_response.content
                        st.session_state.background_text = background_text
                        # st.session_state.sources_text = sources_text
                        st.session_state.background_info = background_text
                        # st.session_state.sources = sources_text
                        st.rerun()

            # Ensure session state variables are initialized
            if 'draft_response' not in st.session_state:
                st.session_state.draft_response = ''
            if 'regenerate_prompt' not in st.session_state:
                st.session_state.regenerate_prompt = ''

            # Output from function
            response_textarea = st.text_area(
                label="Draft Response. Please edit here or prompt suggestions in the box below.",
                value=st.session_state.draft_response if 'draft_response' in st.session_state else '',
                height=350,
                key='draft_response_key'
            )

            # Initialization of the regeneration flag
            if 'is_regenerating' not in st.session_state:
                st.session_state.is_regenerating = False

            # Check if the app is in the "regeneration" phase
            if st.session_state.is_regenerating:
                # Display the regenerated response explicitly
                regenerate_prompt = st.text_area(
                    "Request a new draft",
                    value=st.session_state.regenerate_prompt,
                    placeholder="You may edit the regenerated draft directly above, or request further changes here.",
                    height=100,
                    key='regenerate_prompt_key'
                )
                # Reset the regeneration flag
                st.session_state.is_regenerating = False
            else:
                # Normal behavior: display the text area for manual input
                regenerate_prompt = st.text_area(
                    "Request a new draft",
                    placeholder="You may edit the draft directly above, or request a new draft with additional guidance here.",
                    height=100,
                    key='regenerate_prompt_key'
                )

            if (draft_response is not None) and (regenerate_prompt is not None):
                if st.button("Regenerate"):
                    if st.session_state.api_key:
                        os.environ['OPENAI_API_KEY'] = st.session_state.api_key
                        # add condition to check for passphrase to allow use of DSI api key stored in secrets
                        if (os.environ["OPENAI_API_KEY"] == st.secrets["secret_passphrase"]):
                            # umang key
                            os.environ["OPENAI_API_KEY"] = st.secrets["dsi_openai_key"]
                        elif (os.environ["OPENAI_API_KEY"] == st.secrets["secret_passphrase2"]):
                            # abbie key
                            os.environ["OPENAI_API_KEY"] = st.secrets["dsi_openai_key2"]
                        chat_mdl = ChatOpenAI(
                            model_name='gpt-4', temperature=0.1)

                    if chat_mdl is not None:
                        updated_response = regenerate_custom_response(
                            chat_mdl, regenerate_prompt, st.session_state.draft_response).content
                        st.session_state.draft_response = updated_response
                        st.session_state.is_regenerating = True

                    st.rerun()


elif authentication_status is False:
    st.error('Username/password is incorrect')
    # added registration module if username/password is incorrect

    try:
        if authenticator.register_user('New User Registration', preauthorization=False):
            st.success('User Registered Successfully! Please log in above.')
    except Exception as e:
        st.error(e)

elif authentication_status is None:
    st.warning('Please enter your username and password')

    try:
        if authenticator.register_user('New User Registration', preauthorization=False):
            st.success('User Registered Successfully! Please log in above.')
    except Exception as e:
        st.error(e)

with open('config.yaml', 'w') as file:
    yaml.dump(config, file, default_flow_style=False)

config_drive.put("config.yaml", path="config.yaml")