Best option to create a Smartsheet API Coding Expert

Hello,

I am a relatively inexperienced ‘developer’. I have been working on building a tool that lets me do advanced operations with my Smartsheet environment via the Smartsheet API. I have managed to set up a google cloud server and get basic communication with the Smartsheet API working. I have done this all with the help of ChatGPT.

The challenge I have is chatGPT’s limited knowledge of the Smartsheet API documentation. As a result it takes many iterations of it writing code snippets to get things working, and it has a very difficult time keeping the whole thing working as we add more code.

I have the entire Smartsheet API documentation in json file. I want to build a coding gpt that can reference the entire document when writing the python code i need.

I dont have a specific approach I want to use (i.e. customGPT, Assistant AI, python scripts, other?). I’m looking for suggestions of the best path to take so I dont waste time on dead ends.

Thanks!

2 Likes

What I’ve been doing is just copy/pasting the documentation into a GPT-4 Turbo streamlit page I made, I’ll probably make an assistant with it as a .txt file soon though.

I just love that they can help us build themselves lol

So as I noted, I’m very much a novice at this. Know enough to be dangerous. What is a streamlit page?

1 Like

Streamlit is just a basic webpage builder that works solely through python. It’s very basic, but good enough to allow me to interact with the big and shiny new API stuff.

import openai
import streamlit as st
import requests
import base64
from openai import OpenAI
client = OpenAI()



thread = client.beta.threads.create()

openai.api_key = st.secrets["OPENAI_API_KEY"]

# Streamlit Configuration
st.set_page_config(
    page_title="AI Exploration",
    page_icon="https://haloarc.co.uk/wp-content/themes/halo/images/logo.png",
    layout="wide"
)

def get_state_variable(var_name, default_value):
    if 'st_state' not in st.session_state:
        st.session_state['st_state'] = {}
    if var_name not in st.session_state['st_state']:
        st.session_state['st_state'][var_name] = default_value
    return st.session_state['st_state'][var_name]

# Initialize session state for authentication
if 'is_authenticated' not in st.session_state:
    st.session_state.is_authenticated = False

def get_text_file_buffer(text):
    """Generates a text file buffer from a string."""
    import io
    buffer = io.StringIO()
    buffer.write(text)
    buffer.seek(0)
    return buffer

def display_dashboard():
    #st.title("GPT4 - API")


    # Create columns for the image, title, and page selector
    col_img, col_title, col_select = st.columns([2, 9, 3])

    # Upload the image to the left-most column
    with col_img:
        st.image("https://s3-eu-west-1.amazonaws.com/tpd/logos/5a95521f54e2c70001f926b8/0x0.png")


    # Determine the page selection using the selectbox in the right column
    with col_select:
        page_selection = st.selectbox(
            "Select a Page:",
            ["GPT4 - API", "Excellence Guru", "DALL·E 3 - API", "Tips and Tricks"],
            index=0,
            key='page_selector'
        )


    # Set the title in the middle column based on page selection
    with col_title:
        if page_selection == "GPT4 - API":
            st.title("GPT4 - API")
        elif page_selection == "Excellence Guru":
            st.title("Excellence Guru")
        elif page_selection == "DALL·E 3 - API":
            st.title("DALL·E 3 - API")
        elif page_selection == "Tips and Tricks":
            st.title("Tips and Tricks for Prompting")
        elif page_selection == "Crashy":
            st.title("Crashy")



    def gpt4():

        if "openai_model" not in st.session_state:
            st.session_state["openai_model"] = "gpt-4-1106-preview"

        if "messages" not in st.session_state:
            st.session_state.messages = []

        # Create two columns
        col1, col2 = st.columns([4, 1])

        # Empty space in the first column
        col1.empty()

        # Add a button to clear the chat in the second column
        if col2.button('Clear Chat'):
            st.session_state.messages = []

        for message in st.session_state.messages:
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

        if prompt := st.chat_input("What is up?"):
            st.session_state.messages.append({"role": "user", "content": prompt})
            with st.chat_message("user"):
                st.markdown(prompt)

            with st.chat_message("assistant"):
                message_placeholder = st.empty()
                full_response = ""
                for response in client.chat.completions.create(
                    model=st.session_state["openai_model"],
                    messages=[
                        {"role": m["role"], "content": m["content"]}
                        for m in st.session_state.messages
                    ],
                    stream=True,
                    max_tokens=4000,
                ):
                    


                    # Extract the message content using the proper JSON keys
                    #st.write(response)
                    # Access the first 'Choice' object in the 'choices' list.
                    choice = response.choices[0]  # 'choices' is a list, so you can use index access here.

                    # Access the 'ChoiceDelta' object from 'choice' which contains 'content' field.
                    choice_delta = choice.delta  # 'delta' is an attribute of 'Choice' object.

                    # Access the 'content' field from 'choice_delta'.
                    message_content = choice_delta.content  # 'content' is an attribute of 'ChoiceDelta' object.

                    # Append the extracted content to the 'full_response' string with a newline character
                    full_response += message_content if message_content is not None else ""

                    # Update the placeholder with the 'full_response' using Streamlit's markdown to render it
                    message_placeholder.markdown(full_response + "▌")

                    #content = response.choices
                    #full_response += content.text.value + "\n"  # `.text.value` instead of content["text"]["value"]
                    #full_response += response['choices'][0]['message']['content']
                    #message_placeholder.markdown(full_response + "▌")
                message_placeholder.markdown(full_response)
            st.session_state.messages.append({"role": "assistant", "content": full_response})
            #st.write(thread)
        if st.button('Download Chat Log'):
            chat_log_str = "\n".join([f"{m['role']}: {m['content']}" for m in st.session_state.messages])
            buffer = get_text_file_buffer(chat_log_str)
            b64 = base64.b64encode(buffer.getvalue().encode()).decode()
            st.markdown(f'<a href="data:file/txt;base64,{b64}" download="chat_log.txt">Download Chat Log</a>', unsafe_allow_html=True)




    # Main GPT-4 powered chat function with Knowledge Retrieval
    def gpthalo():

        st.session_state.assistant_id = "asst_leEKL6iSg073ECfwgi1uBdaK"

        # Initialize session state for the model, messages, and assistant id if not already present
        if "openai_model" not in st.session_state:
            st.session_state["openai_model"] = "gpt-4-1106-preview"
        if "messages" not in st.session_state:
            st.session_state.messages = []
        if "assistant_id" not in st.session_state:
            st.session_state.assistant_id = None
            # Upload a file with an "assistants" purpose


        # Create two columns for chat interface
        col1, col2 = st.columns([4, 1])
        col1.empty()  # Placeholder

        if col2.button('Clear Chat'):
            st.session_state.messages = []

        # Display chat messages
        for message in st.session_state.messages:
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

        # Input for new messages
        if prompt := st.chat_input("What is up?"):

            # Print the current state of the messages to debug
            #print("Current state of messages before appending new message: ", st.session_state.messages)

            # Append new user message
            st.session_state.messages.append({"role": "user", "content": prompt})

            # Print after appending to check update
            #st.write("State of messages after appending new user message: ", st.session_state.messages)

            #st.session_state.messages.append({"role": "user", "content": prompt})
            with st.chat_message("user"):
                st.markdown(prompt)

            messages=[
                    {"role": m["role"], "content": m["content"]}
                    for m in st.session_state.messages
            ]

            #st.write("Messages: ", messages)
            # Construct a string representation of the conversation
            conversation_str = "\n".join([f"{message['role']}: {message['content']}" for message in st.session_state.messages])
            #st.write(conversation_str)  # This will print the entire conversation as a string

            # Create and send a message to the thread
            message = client.beta.threads.messages.create(
                thread_id=thread.id,
                role="user",
                content=conversation_str
            )
            
            # Create a response using Knowledge Retrieval
            run = client.beta.threads.runs.create(
                thread_id=thread.id,
                assistant_id="asst_leEKL6iSg073ECfwgi1uBdaK",
                #instructions="Excellence Guru's primary function is to provide detailed, specific guidance and information on company processes using the core file named 'Halo New Starters Notion' as its sole information source. In cases where the query extends beyond the scope of the document, the GPT is to acknowledge the limitation and direct the user to consult with a member of the Center of Excellence team for further assistance. The GPT's interactions are grounded in the knowledge contained within this core file, ensuring accuracy and relevance. It will avoid speculation and will not use any information outside of this document. If a search within the document yields no answer, the GPT will state so transparently but will never mention the document's existence."
            )

            with st.chat_message("assistant"):
                message_placeholder = st.empty()
                full_response = ""

                # Wait for the run to complete and get the response
                while run.status not in ["completed", "failed"]:
                    run = client.beta.threads.runs.retrieve(
                        thread_id=thread.id,
                        run_id=run.id
                    )

                # If the run completed successfully, get the latest messages
                if run.status == "completed":
                    messages = client.beta.threads.messages.list(
                        thread_id=thread.id
                    )
                    for msg in messages:
                        #if msg.role == "assistant":
                            #full_response += msg.content[0].delta.get("content", "")
                        if msg.role == "assistant":  # `.role` instead of msg["role"]
                                for content in msg.content:  # `.content` instead of msg["content"]
                                    if content.type == "text":  # `.type` instead of content["type"]
                                        full_response += content.text.value + "\n"  # `.text.value` instead of content["text"]["value"]
                            
                    message_placeholder.markdown(full_response)
                else:
                    message_placeholder.markdown("Something went wrong. Please try again.")

                # Append assistant's response
                st.session_state.messages.append({"role": "assistant", "content": full_response})

                # Final print to check conversation state
                #st.write("Final state of messages after appending assistant response: ", st.session_state.messages)

                #st.session_state.messages.append({"role": "assistant", "content": full_response})
                #print(st.session_state.messages)

        # Button to download the chat log
        if st.button('Download Chat Log'):
            chat_log_str = "\n".join([f"{m['role']}: {m['content']}" for m in st.session_state.messages])
            buffer = get_text_file_buffer(chat_log_str)
            b64 = base64.b64encode(buffer.getvalue().encode()).decode()
            st.markdown(f'<a href="data:file/txt;base64,{b64}" download="chat_log.txt">Download Chat Log</a>', unsafe_allow_html=True)






    # Main GPT-4 powered chat function with Knowledge Retrieval
    def crashy():

        st.session_state.assistant_id = "asst_wYvoZYYge5BalhvIKOvUWFpV"

        # Initialize session state for the model, messages, and assistant id if not already present
        if "openai_model" not in st.session_state:
            st.session_state["openai_model"] = "gpt-4-1106-preview"
        if "messages" not in st.session_state:
            st.session_state.messages = []
        if "assistant_id" not in st.session_state:
            st.session_state.assistant_id = None
            # Upload a file with an "assistants" purpose


        # Create two columns for chat interface
        col1, col2 = st.columns([4, 1])
        col1.empty()  # Placeholder

        if col2.button('Clear Chat'):
            st.session_state.messages = []

        # Display chat messages
        for message in st.session_state.messages:
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

        # Input for new messages
        if prompt := st.chat_input("What is up?"):

            # Print the current state of the messages to debug
            #print("Current state of messages before appending new message: ", st.session_state.messages)

            # Append new user message
            st.session_state.messages.append({"role": "user", "content": prompt})

            # Print after appending to check update
            #st.write("State of messages after appending new user message: ", st.session_state.messages)

            #st.session_state.messages.append({"role": "user", "content": prompt})
            with st.chat_message("user"):
                st.markdown(prompt)

            messages=[
                    {"role": m["role"], "content": m["content"]}
                    for m in st.session_state.messages
            ]

            #st.write("Messages: ", messages)
            # Construct a string representation of the conversation
            conversation_str = "\n".join([f"{message['role']}: {message['content']}" for message in st.session_state.messages])
            #st.write(conversation_str)  # This will print the entire conversation as a string

            # Create and send a message to the thread
            message = client.beta.threads.messages.create(
                thread_id=thread.id,
                role="user",
                content=conversation_str
            )
            
            # Create a response using Knowledge Retrieval
            run = client.beta.threads.runs.create(
                thread_id=thread.id,
                assistant_id="asst_wYvoZYYge5BalhvIKOvUWFpV",
                #instructions="Excellence Guru's primary function is to provide detailed, specific guidance and information on company processes using the core file named 'Halo New Starters Notion' as its sole information source. In cases where the query extends beyond the scope of the document, the GPT is to acknowledge the limitation and direct the user to consult with a member of the Center of Excellence team for further assistance. The GPT's interactions are grounded in the knowledge contained within this core file, ensuring accuracy and relevance. It will avoid speculation and will not use any information outside of this document. If a search within the document yields no answer, the GPT will state so transparently but will never mention the document's existence."
            )

            with st.chat_message("assistant"):
                message_placeholder = st.empty()
                full_response = ""

                # Wait for the run to complete and get the response
                while run.status not in ["completed", "failed"]:
                    run = client.beta.threads.runs.retrieve(
                        thread_id=thread.id,
                        run_id=run.id
                    )

                # If the run completed successfully, get the latest messages
                if run.status == "completed":
                    messages = client.beta.threads.messages.list(
                        thread_id=thread.id
                    )
                    for msg in messages:
                        #if msg.role == "assistant":
                            #full_response += msg.content[0].delta.get("content", "")
                        if msg.role == "assistant":  # `.role` instead of msg["role"]
                                for content in msg.content:  # `.content` instead of msg["content"]
                                    if content.type == "text":  # `.type` instead of content["type"]
                                        full_response += content.text.value + "\n"  # `.text.value` instead of content["text"]["value"]
                            
                    message_placeholder.markdown(full_response)
                else:
                    message_placeholder.markdown("Something went wrong. Please try again.")

                # Append assistant's response
                st.session_state.messages.append({"role": "assistant", "content": full_response})

                # Final print to check conversation state
                #st.write("Final state of messages after appending assistant response: ", st.session_state.messages)

                #st.session_state.messages.append({"role": "assistant", "content": full_response})
                #print(st.session_state.messages)

        # Button to download the chat log
        if st.button('Download Chat Log'):
            chat_log_str = "\n".join([f"{m['role']}: {m['content']}" for m in st.session_state.messages])
            buffer = get_text_file_buffer(chat_log_str)
            b64 = base64.b64encode(buffer.getvalue().encode()).decode()
            st.markdown(f'<a href="data:file/txt;base64,{b64}" download="chat_log.txt">Download Chat Log</a>', unsafe_allow_html=True)









    def chatgpt():

        if "openai_model" not in st.session_state:
            st.session_state["openai_model"] = "gpt-3.5-turbo-1106"

        if "messages" not in st.session_state:
            st.session_state.messages = []

        # Create two columns
        col1, col2 = st.columns([4, 1])

        # Empty space in the first column
        col1.empty()

        # Add a button to clear the chat in the second column
        if col2.button('Clear Chat'):
            st.session_state.messages = []

        for message in st.session_state.messages:
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

        if prompt := st.chat_input("What is up?"):
            st.session_state.messages.append({"role": "user", "content": prompt})
            with st.chat_message("user"):
                st.markdown(prompt)

            with st.chat_message("assistant"):
                message_placeholder = st.empty()
                full_response = ""
                for response in openai.ChatCompletion.create(
                    model=st.session_state["openai_model"],
                    messages=[
                        {"role": m["role"], "content": m["content"]}
                        for m in st.session_state.messages
                    ],
                    stream=True,
                ):
                    full_response += response.choices[0].delta.get("content", "")
                    message_placeholder.markdown(full_response + "▌")
                message_placeholder.markdown(full_response)
            st.session_state.messages.append({"role": "assistant", "content": full_response})
        if st.button('Download Chat Log'):
            chat_log_str = "\n".join([f"{m['role']}: {m['content']}" for m in st.session_state.messages])
            buffer = get_text_file_buffer(chat_log_str)
            b64 = base64.b64encode(buffer.getvalue().encode()).decode()
            st.markdown(f'<a href="data:file/txt;base64,{b64}" download="chat_log.txt">Download Chat Log</a>', unsafe_allow_html=True)


    def dalle():


        # Generate an image from a text prompt
        def generate_image(prompt):
            response = client.images.generate(
                model="dall-e-3",
                prompt=prompt,
                size="1024x1024",
                quality="standard",
                n=1,
            )
            image_url = response.data[0].url
            return image_url

        # Download the image and display it in Streamlit
        def display_image(url):
            response = requests.get(url)
            response.raise_for_status()
            image_bytes = response.content
            st.image(image_bytes, caption="Generated Image", use_column_width=True)

        # Text input for the prompt
        prompt = st.text_input('Enter your image prompt:')

        # Button to generate and display the image
        if st.button('Generate Image'):
            image_url = generate_image(prompt)
            display_image(image_url)

    def display_faq():
        #st.title("Tips and Tricks for GPT-4 and DALL·E 2 APIs")
        
        st.header("GPT-4 API - FAQ")
        
        st.subheader("1. How to Frame Specific Questions for Accurate Answers?")
        st.write("""
        Being vague will often yield general or ambiguous responses. Specificity narrows down the scope for GPT-4.
        - **Bad**: "Tell me about car repairs."
        - **Good**: "Explain the process of calibrating the front radar on a 2021 VW Golf and why it's important."
        """)

        st.subheader("2. How to Get Simplified Explanations?")
        st.write("""
        If you're looking for easy-to-understand answers, explicitly ask for them.
        - **Example**: "Explain like I'm 5, how does paintless dent repair work?"
        """)
        
        st.subheader("3. How to Receive a Concise Answer?")
        st.write("""
        To receive a summary-like answer that cuts through the fluff, guide the model with cues.
        - **Example**: "Summarize in one sentence, what steps should I take immediately after a minor car collision?"
        """)

        st.subheader("4. How to Ask Follow-up Questions?")
        st.write("""
        GPT-4 can handle a series of related queries. Just ensure your follow-up is directly related to the prior question for context.
        - **Example**: "You mentioned that a damaged frame can be risky. What are the signs of a damaged car frame?"
        """)
        
#        st.header("DALL·E 2 API - FAQ")
        
#        st.subheader("1. How to Get More Detailed Images?")
#        st.write("""
#        DALL·E 2 works best when you're descriptive. It gives the model a better understanding of what you're envisioning.
#        - **Bad**: "Draw a car."
#        - **Good**: "Generate a photorealistic image of a red 2020 Ford Mustang with a cracked windshield."
#        """)

#        st.subheader("2. How to Tweak or Iterate Over Generated Images?")
#        st.write("""
#        A slight change in phrasing can lead to different outputs. Feel free to iterate on your initial idea.
#        - **Example**: "Produce an image of a red 2020 Ford Mustang with a shattered windshield."
#        """)
        
#        st.subheader("3. How to Get Realistic Images?")
#        st.write("""
#        If you're looking for photorealistic outputs, it helps to specify this in your prompt.
#        - **Example**: "Generate a photorealistic image of a car collision involving a white SUV and a blue sedan."
#        """)

#        st.subheader("4. How to Influence the Style or Aesthetic?")
#        st.write("""
#        You can direct the style of the generated image by including artistic descriptors.
#        - **Example**: "Create an image of a damaged car in the style of a vintage 1950s advertisement."
#        """)









    if page_selection == "GPT4 - API":
        gpt4()
    elif page_selection == "Crashy":
        crashy()

    elif page_selection == "Excellence Guru":
        gpthalo()
        
    elif page_selection == "DALL·E 3 - API":
        dalle()
    elif page_selection == "Tips and Tricks":
        display_faq()



# Logic for password checking
def check_password():
    if not st.session_state.is_authenticated:
        password = st.text_input("Enter Password:", type="password")


            
        
        if password == st.secrets["db_password"]:
            st.session_state.is_authenticated = True
            st.rerun()
        elif password:
            st.write("Please enter the correct password to proceed.")
            
        blank, col_img, col_title = st.columns([2, 1, 3])

        # Upload the image to the left-most column
        with col_img:
            st.image("https://s3-eu-west-1.amazonaws.com/tpd/logos/5a95521f54e2c70001f926b8/0x0.png")


        # Determine the page selection using the selectbox in the right column
        with col_title:
            #st.title("Created By Halo")
            st.write("")
            st.markdown('<div style="text-align: left; font-size: 40px; font-weight: normal;">Created By Halo*</div>', unsafe_allow_html=True)
            
        blank2, col_img2, col_title2 = st.columns([2, 1, 3])

        # Upload the image to the left-most column
        with col_img2:
            st.image("https://th.bing.com/th/id/OIP.42nU_MRx_INTLq_ejdHxBQHaCe?pid=ImgDet&rs=1")


        # Determine the page selection using the selectbox in the right column
        with col_title2:
            
            #st.title("Powered By IRS")
            st.markdown('<div style="text-align: left; font-size: 30px; font-weight: normal;">Powered By IRS</div>', unsafe_allow_html=True)
        # Fill up space to push the text to the bottom
        for _ in range(20):  # Adjust the range as needed
            st.write("")

        # Write your text at the bottom left corner
        st.markdown('<div style="text-align: right; font-size: 10px; font-weight: normal;">* Trenton Dambrowitz, Special Projects Manager, is "Halo" in this case.</div>', unsafe_allow_html=True)



    else:
        print("Access granted, welcome to the app.")
        display_dashboard()


check_password()


This is the entire page, if you give it to GPT-4 it can help you run it and get it working for your purposes.

My coding is awful, but maybe it helps a bit

1 Like

If anyone else has additional suggestions I’d love to hear them!