🤖 Build an AI assistant with real-time web access in 100 lines of code using Python and GPT-4 🌍
Tags: tutorial, python, productivity, beginners
Published: 2023-11-20 14:00:00

ChatGPT has definitely made me spoiled over the last year. 
It is my go to tool for everything, from getting code snippets to making memes, EXCEPT for internet research.

I mean, here's this cutting-edge AI, but for some reason whenever I need it to grab some info off the web for me, I feel I'm having a conversation with a confused chimp 🤷‍♂️

Yesterday I decided that enough is enough, rolled up my sleeves and got to work. Enter my new project: an AI assistant that doesn't just sit there spitting out the few first Bing results at you. 
We're talking real-time, up-to-the-minute web access. 

**And now I'll show you how to build it yourself**

---

![patrick meme](https://i.imgflip.com/86fiop.jpg)

---

**Just a quick word about Pezzo:** It is the fastest growing open source LLMOps platform, and the only one built for full stack developers with first class TypeScript Support.

Like our mission? [Check Pezzo out and give us a star](https://github.com/pezzolabs/pezzo). We're building for developers, by developers 🧙‍♂️

---

# The setup
For best performance we will build this assistant with the newest GPT model `gpt-4-1106-preview` and Tavily API, both require an API key.

## Getting the API keys
- Tavily API is free up to 1,000 requests a month, you just need to register with your Google account. [Click here for Tavily API key.](https://app.tavily.com/)
- Get OpenAI API key [here.](https://platform.openai.com/api-keys)

## Project setup
- Create a new folder and inside it make a `main.py` and a `config.py` files.
- Install the latest OpenAI SDK
```
pip install --upgrade openai
```
- Install the Tavily SDK
```
pip install tavily-python
```

> How to fix `error: can't find Rust compiler` when installing Tavily:
> - Paste this in the terminal to install Rust.
> ```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
> ```
> - Than, paste this in the terminal to configure your shell to recognize the Rust compiler.
> ```
source $HOME/.cargo/env
> ```

# Let's get to work!
## Config file
We will save all of the API keys here and import them into the other file to be used. This is how your `config.py` should look like:
```py
OPENAI_API_KEY= "OPENAI_API_KEY"
TAVILY_API_KEY = "TAVILY_API_KEY"
```
## Main file
### Imports and clients init
First, import all of the libraries we'll need and initialize clients with API keys. 
```py
import json
import time
from config import OPENAI_API_KEY, TAVILY_API_KEY
from openai import OpenAI
from tavily import TavilyClient

client = OpenAI(api_key=OPENAI_API_KEY)
tavily_client = TavilyClient(api_key=TAVILY_API_KEY)
```

### Creating a new assistant
To keep the function creating the assistant simpler to understand we will create the assistant instructions in a separate variable and pass it to creation function.
```py
assistant_instruction = """You an analyst specializing in open-source intelligence, 
Your role is to gather and analyze publicly available information for market research and competitive analysis. 
You will provide insights, trends, and data-driven answers.
Never use your own knowledge to answer questions.
Always include the relevant urls for the sources you got the data from.`
"""
assistant = client.beta.assistants.create(
    instructions=assistant_instruction,
    model="gpt-4-1106-preview",
    tools=[{
        "type": "function",
        "function": {
            "name": "tavily_search",
            "description": "Get information on recent events from the web.",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "The search query to use. For example: 'Provide a competitive analysis of Open Source survey tools'"},
                },
                "required": ["query"]
            }
        }
    }]
)
```
### Real time internet access 
If you look closely at the creation function you can see I gave the assistant a tool to brows the web, lets add it in!
#### Tavily search
```py
def tavily_search(query):
    search_result = tavily_client.get_search_context(query, search_depth="advanced", max_tokens=8000)
    return search_result
```

#### Tavily output handler
```py
def submit_tool_outputs(thread_id, run_id, tools_to_call):
    tool_output_array = []
    for tool in tools_to_call:
        output = None
        tool_call_id = tool.id
        function_name = tool.function.name
        function_args = tool.function.arguments

        if function_name == "tavily_search":
            output = tavily_search(query=json.loads(function_args)["query"])

        if output:
            tool_output_array.append({"tool_call_id": tool_call_id, "output": output})

    return client.beta.threads.runs.submit_tool_outputs(
        thread_id=thread_id,
        run_id=run_id,
        tool_outputs=tool_output_array
    )
```
### Managing conversation 
The last thing we need to do is build a way for us to pass real time input to the assistant and a way to keep general track of what is going on. the code below does all of that. **To start the assistant just run the `main.py` file, the conversation will take place inside the terminal window. To end the conversation type `exit` in the terminal.**
```py
# Wait for a run to complete
def wait_for_run_completion(thread_id, run_id):
    while True:
        time.sleep(1)
        run = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run_id)
        print(f"Current run status: {run.status}")
        if run.status in ['completed', 'failed', 'requires_action']:
            return run

# Print messages from a thread
def print_messages_from_thread(thread_id):
    messages = client.beta.threads.messages.list(thread_id=thread_id)
    for msg in messages:
        print(f"{msg.role}: {msg.content[0].text.value}")


assistant_id = assistant.id
print(f"Assistant ID: {assistant_id}")

# Create a thread
thread = client.beta.threads.create()
print(f"Thread: {thread}")

# Conversation loop
while True:
    user_input = input("User input: ")
    if user_input.lower() == 'exit':
        break

    # Create a message
    message = client.beta.threads.messages.create(
        thread_id=thread.id,
        role="user",
        content=user_input,
    )

    # Create a run
    run = client.beta.threads.runs.create(
        thread_id=thread.id,
        assistant_id=assistant_id,
    )
    print(f"Run ID: {run.id}")

    # Wait for run to complete
    run = wait_for_run_completion(thread.id, run.id)

    if run.status == 'failed':
        print(run.error)
        continue
    elif run.status == 'requires_action':
        run = submit_tool_outputs(thread.id, run.id, run.required_action.submit_tool_outputs.tool_calls)
        run = wait_for_run_completion(thread.id, run.id)

    # Print messages from the thread
    print_messages_from_thread(thread.id)
```

This is what you should see in the terminal when running this file, the assistant is up and waiting for your input-
```
Assistant ID: asst_niCFSyEx6EVq1IQ32byEjLDn
Thread: Thread(id='thread_VjKfyeGpVWII05bALc1Arxdk', created_at=1700259453, metadata={}, object='thread')
User input: how can you help?
Run ID: run_46vRzPA40BPXaZ4Y68qSzuRn
Current run status: in_progress
Current run status: in_progress
Current run status: in_progress
Current run status: in_progress
Current run status: in_progress
Current run status: in_progress
Current run status: in_progress
Current run status: completed
assistant: As an open-source intelligence analyst, I can assist you by gathering and analyzing publicly available information to provide insights on various topics. This can include but is not limited to:

1. Market research: Compiling data on market trends, consumer behavior, industry analysis, and competitive landscapes.
2. Competitive analysis: Comparing products, services, and strategies of competitors within a market.
3. Technology tracking: Monitoring developments in technology, new product releases, and innovations.
4. Event tracking: Keeping up to date with recent events, announcements, and news related to specific industries or topics.
5. Sentiment analysis: Analyzing public opinion and sentiment towards brands, products, or topics on social media and other online platforms.

Based on the task at hand, I can utilize various tools available to me, such as running searches for recent events or conducting tailored research using specific queries.

Let me know how I can assist you today!
User input:
```

---

![end, remote](https://media.giphy.com/media/xUPOqo6E1XvWXwlCyQ/giphy.gif)

That's All Folks!

I've tested this assistant vs. chatGPT and this one is so much better! 
Now make your on spin on this- play around with it and let me know all the ways you find to make the most of this 💪