# Project export: BlurredAI

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: Use ChatGPT? Got sensitive data? We got you. Hide your data from GPT-4 with local models on your laptop!
- Devpost: https://devpost.com/software/blurredai
- GitHub: https://github.com/rchtgpt/BlurredAI
- Video: https://www.youtube.com/embed/O9Tb7jkQ7uI?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Rachit Gupta (17 commits), xinyi-zhao (13 commits), Ken Liu (3 commits)

## Devpost submission (written by the team)

### Inspiration

Have you ever had sensitive questions or data that you didn't feel comfortable sending to ChatGPT? Probably all the time for your corporate activity—work emails, legal texts, internal finances. This extends beyond corporate use cases though; think about your medical history, tax forms, relationship problems. This is a clear gap: remote models are already sufficiently powerful for most tasks, but they're untrustworthy to deal with confidential information and hosting similarly powerful models locally can be expensive.

### What it does

Our project, BlurredAI, enables a collaboration between small & large models. A lightweight LLM, hosted locally on your laptop, privatizes your queries on private data before sending them to powerful remote models such as GPT-4. It then reconstructs the original context/data locally from the remote response, ensuring privacy without compromising the quality of insights. Check our demo video for concrete examples!

### How we built it

There are a few core components to BlurredAI: Hosting large language models locally, essential for privacy guarantees. Adapting local models to different workflows, such as privatizing emails, parsing legal texts, understanding spreadsheets. A natural, intuitive UI where users can chat with and ask questions about their sensitive texts, documents, or PDFs. For #1 we used TogetherAI for local development and (plan to use) Ollama for hosting on laptops. For #2, we crafted numerous prompts for different privacy workflows. For #3, we employed Streamlit for the frontend and Python, including PDF & CSV parsers, for the backend.

### Challenges we ran into

Local models often aren't powerful enough to coherently privatize sensitive data, presenting an efficiency-utility trade-off. Adapting the local models to various workflows; for example, the work done by the local model varies greatly between making spreadsheets private and making legal texts private.

### Accomplishments we're proud of

The novelty of our idea is what sets us apart. Unlike other companies, we are not taking the user's data. We don't even have a database. The user (business/individual) needs to simply clone our open-source repository and run the app locally.

### What we learned

Privacy is multi-faceted and context-dependent. In some cases, it means redacting names, numbers, and emails, while in others it involves providing plausible deniability to the user. Open-source LLMs for local hosting are still brittle, lacking strong reasoning capabilities without specific adaptations for different workflows. Beyond standard privacy/cryptography tools, user-acceptable private inference can be achieved through a combination of appropriate anonymization, distributed computing, and careful human-computer interface design.

### What's next

Publishing as a PyPi package to simplify installation. Extending to early adopters (e.g., mid-size companies like Esri) based on our user research. Enhancing the local model for privatization (e.g., text redaction, rephrasing, shifting points of view) through better prompts, local fine-tuning, or integrating larger open-source models locally.

## README (from the GitHub repository)

<p align="center">
  <img src="https://github.com/rchtgpt/BlurredAI/assets/44428198/a8eede03-dacf-4a34-a543-c33ce92aa07d" alt="cover">
</p>

# BlurredAI 
Hide your data from GPT-4 with local models on your laptop! 

## Inspiration

Have you ever had sensitive questions or data that you didn't feel comfortable sending to ChatGPT? Probably all the time for your corporate activity—work emails, legal texts, internal finances. This extends beyond corporate use cases though; think about your medical history, tax forms, relationship problems. This is a clear gap: **remote models are already sufficiently powerful for most tasks, but they're untrustworthy to deal with confidential information and hosting similarly powerful models locally can be expensive.**

## What it does

Our project, BlurredAI, enables a collaboration between small & large models. A lightweight LLM, hosted locally on your laptop, privatizes your queries on private data before sending them to powerful remote models such as GPT-4. It then reconstructs the original context/data locally from the remote response, ensuring privacy without compromising the quality of insights. Check our demo video for concrete examples!

## How we built it

There are a few core components to BlurredAI:
1. Hosting large language models locally, essential for privacy guarantees.
2. Adapting local models to different workflows, such as privatizing emails, parsing legal texts, understanding spreadsheets.
3. A natural, intuitive UI where users can chat with and ask questions about their sensitive texts, documents, or PDFs.

For #1 we used TogetherAI for local development and (plan to use) Ollama for hosting on laptops. For #2, we crafted numerous prompts for different privacy workflows. For #3, we employed Streamlit for the frontend and Python, including PDF & CSV parsers, for the backend.

## Challenges we ran into


- Local models often aren't powerful enough to coherently privatize sensitive data, presenting an efficiency-utility trade-off.
- Adapting the local models to various workflows; for example, the work done by the local model varies greatly between making spreadsheets private and making legal texts private.


## Accomplishments that we're proud of

The novelty of our idea is what sets us apart. Unlike other companies, we are not taking the user's data. We don't even have a database. The user (business/individual) needs to simply clone our open-source repository and run the app locally.


## What we learned


- Privacy is multi-faceted and context-dependent. In some cases, it means redacting names, numbers, and emails, while in others it involves providing plausible deniability to the user.
- Open-source LLMs for local hosting are still brittle, lacking strong reasoning capabilities without specific adaptations for different workflows.
- Beyond standard privacy/cryptography tools, user-acceptable private inference can be achieved through a combination of appropriate anonymization, distributed computing, and careful human-computer interface design.




## What's next for BlurredAI

- Publishing as a PyPi package to simplify installation.
- Extending to early adopters (e.g., mid-size companies like Esri) based on our user research.
- Enhancing the local model for privatization (e.g., text redaction, rephrasing, shifting points of view) through better prompts, local fine-tuning, or integrating larger open-source models locally.







## Detected evidence (automated analysis)

Indexed codebase: 9 recognized source files, 44 KB.
- Python (language) — detected in the code
- Streamlit (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (14 of 14)

```
.DS_Store
.gitignore
about.py
app.py
backend/localcall.py
backend/main.py
backend/prompts.py
backend/remotecall.py
backend/table.py
backend/utils.py
blurai-test/email-example.txt
blurai-test/EmployData.csv
README.md
uploaded_files/try.csv
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Update README.md
- jai mata di
- remove api keys (both don't work now btw)
- Update README.md
- Merge remote-tracking branch 'refs/remotes/origin/main'
- add change
- update 0.1 version
- Create README.md
- closer to final push
- edit frontend
- add csv logic
- add redacted instruction on rhs panel
- add redacted instruction on rhs panel
- text input and private data works
- modify frontend
- Merge branch 'main' of https://github.com/rchtgpt/BlurredAI
- add frontend code
- add python-based unblurring; minor formatting
- add backend integration
- write something related to blur_data

## Key source files (fetched from GitHub, selected and truncated for size)

### app.py

```python
from openai import OpenAI
import streamlit as st
from st_pages import Page, show_pages
import time
import pandas as pd
from io import StringIO
import sys
from tabulate import tabulate
import os
import re
sys.path.append(f"./backend/")
from main import user_input, reblur_data, process_request
from pdfminer.high_level import extract_text
UPLOAD_FOLDER = 'uploaded_files/'

def main():
    st.set_page_config(layout="wide", initial_sidebar_state="collapsed", page_title="BlurredAI", page_icon="https://media.discordapp.net/attachments/713817450130571416/1208719786041810984/icon.png?ex=65e44f05&is=65d1da05&hm=080bc21bdb34c2fcc95dc6e6bfbc7332223822f3fc1b536762bfc2df879eb3a0&=&format=webp&quality=lossless&width=1376&height=1376")
    st.markdown(
        """
        <style>
        [data-testid="stSidebar"][aria-expanded="false"] > div:first-child{
            width: 400px;
            margin-left: -400px;
        }
        
        """,
        unsafe_allow_html=True,
    )

    show_pages(
        [
        Page("app.py", "Chat", ":thought_balloon:"),
        Page("about.py", "About", ":information_source:")
        ]
    )

    # localModelMapping = {'LLaMA-2 Chat (70B)' : 'meta-llama/Llama-2-70b-chat-hf', 'LLaMA-2 Chat (13B)' : 'meta-llama/Llama-2-13b-chat-hf', 'LLaMA-2 Chat (7B)' : 'meta-llama/Llama-2-7b-chat-hf', 'Mistral (7B) Instruct v0.2' : 'mistralai/Mistral-7B-Instruct-v0.2', 'Mixtral-8x7B Instruct (46.7B)' : 'mistralai/Mixtral-8x7B-Instruct-v0.1'}
    localModelMapping = {'LLaMA-2 Chat (70B)' : 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'LLaMA-2 Chat (13B)' : 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'LLaMA-2 Chat (7B)' : 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'Mistral (7B) Instruct v0.2' : 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'Mixtral-8x7B Instruct (46.7B)' : 'mistralai/Mixtral-8x7B-Instruct-v0.1'}

    remoteModelMapping = {'GPT-4':'gpt-4-turbo-preview', 'GPT-3.5':'gpt-3.5-turbo', 'Gemini-1.0 Pro': 'gemini-1.0-pro'}
    redactedInstruction = ""
    redactedText = ""
    rawData = ""
    unblurredData = ""
    currentPrompt = ""
    file_path = ""
    redactedDataApproved = False
    private_data = ""

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

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

    if 'redacted' not in st.session_state:
        st.session_state.redacted = redactedText

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

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

    if 'unblurredData' not in st.session_state:
        st.session_state.unblurredData = unblurredData
    
    if 'running_state' not in st.session_state:
        st.session_state.running_state = ""
    
    if 'file_path' not in st.session_state:
        st.session_state.file_path = ""
    
    if 'private_data' not in st.session_state:
        st.session_state.private_data = ""

    with st.sidebar:
        
        # Set up sidebar for chat history
        st.title("Chat History")
        st.write("This is where your chat history goes.")
        "[Model Duplication Warning...](https://platform.openai.com/account/api-keys)"
        "[Higher level data insights...](https://github.com/streamlit/llm-examples/blob/main/Chatbot.py)"
        "[Git rebase branching...](https://github.com/streamlit/llm-examples/blob/main/Chatbot.py)"

    userInputted = False

    # Create two columns for the panels
    col0, col1, col2 = st.columns([2, 3, 3])

    def stream_data(textToDisplay, stop_time = 0.03):
        for word in re.split(r'(\s+)', textToDisplay):
            yield word
            time.sleep(stop_time)

    # First panel covering half the page
    with col0:
        # st.title("BlurredAI")
        st.image("https://media.discordapp.net/attachments/713817450130571416/1208728527323668520/cover.png?ex=65e4572a&is=65d1e22a&hm=7f169f9aa186d86b8814c0dd124c3486e2db7280886fdf56d9dbf43ac4643e20&=&format=webp&quality=lossless&width=1410&height=452")
        st.caption("A privacy-first inference for any Large Language Model")
        private_data = st.text_area("Text your private data here", height=300)
        uploaded_file = st.file_uploader("Choose a file")

    with col1:
        localModelChosen = st.selectbox('Choose a local model to privatize your request',
                ('Mixtral-8x7B Instruct (46.7B)', 'Mistral (7B) Instruct v0.2', 'LLaMA-2 Chat (70B)', 'LLaMA-2 Chat (13B)', 'LLaMA-2 Chat (7B)',  ))
        with st.container(height=650, border=True):
            # Initialize chat history
            if "box1messages" not in st.session_state:
                st.session_state.box1messages = []
            # Display chat messages from history on app rerun
            for message in st.session_state.box1messages:
                if (message["role"] == "user"):
                    with st.chat_message(message["role"], avatar="https://github.com/rchtgpt.png"):
                        st.markdown(message["content"])
                if (message["role"] == "blurredAI"):
                    with st.chat_message("assistant", avatar="https://media.discordapp.net/attachments/713817450130571416/1208709666461323305/logo.jpeg?ex=65e44599&is=65d1d099&hm=ac498b5d773ee33297fa4932964e5f6dd146d14fe2250026967cde3e3f60e16c&=&format=webp&width=1006&height=1008"):
                        st.markdown(message["content"])
            
            if st.session_state.running_state == "prompting":
                prompt = st.session_state.currentPrompt
                private_data = st.session_state.private_data
                uploaded_file = st.uploaded_file
                file_path = st.session_state.file_path
                st.session_state.running_state = "blurring"
                if(st.session_state.currentPrompt != ""):
                    with st.chat_message("user", avatar="https://git
[truncated — 8327 more characters]
```

### backend/main.py

```python
from pdfminer.high_level import extract_text
from utils import get_redacted_text, get_mapping, get_unblur_response
from remotecall import remote_call
from table import get_redacted_csv, get_response_csv

import textwrap

Filter_result = {}
Sensitive_mapping = {}
is_csv = False


def user_input(instruction="",
               data_str="",
               local_model="mistralai/Mixtral-8x7B-Instruct-v0.1",
               file_path=""):
    if (data_str == "" and file_path == ""):
        return "I see that you have not provided any data"
    return blur_data(instruction, data_str, local_model, file_path)


def process_request(instruction="",
                    blurred_data="",
                    local_model="mistralai/Mixtral-8x7B-Instruct-v0.1",
                    remote_model="gpt-3.5-turbo"):
    remote_response = SendToRemote(instruction, blurred_data, remote_model)
    global Sensitive_mapping
    unblurred_response = UnblurResponse(remote_response, Sensitive_mapping, local_model)
    return remote_response, unblurred_response


def reblur_data(instruction="",
                data_str="",
                blurred_data="",
                local_model="mistralai/Mixtral-8x7B-Instruct-v0.1",
                file_path=""):
    print(instruction, data_str, blurred_data, local_model, file_path)
    return blur_data(instruction, data_str, local_model, file_path)


def blur_data(instruction, data_str, local_model, file_path):
    file_data = ""
    global is_csv
    is_csv = False
    global Sensitive_mapping
    if (file_path != None):
        if (file_path.endswith(".pdf")):
            file_data = extract_text(file_path)
            file_data = file_data.replace("\n\n", "\n")
        if (file_path.endswith(".txt")):
            file_data = extract_text(file_path)
        if (file_path.endswith(".csv")):
            redacted_data, mapping = get_redacted_csv(data_str, file_path, local_model)
            Sensitive_mapping = mapping
            is_csv = True
            instruction = instruction.lower()
            for key,value in Sensitive_mapping.items():
                instruction = instruction.replace(key, value)
            return instruction, redacted_data
    data = data_str + file_data
    redacted_data = get_redacted_text(instruction, data, local_model)
    mapping = get_mapping(instruction, data, redacted_data, local_model)
    Sensitive_mapping = mapping
    return instruction, redacted_data


def SendToRemote(instruction, blurred_data, remote_model):
    prompt = textwrap.dedent(f"""\
        Instruction: "{instruction}"
        Data: "{blurred_data}"
    """)
    response = remote_call(prompt, remote_model)
    return response


def UnblurResponse(remote_response="",
                   mapping={},
                   local_model="mistralai/Mixtral-8x7B-Instruct-v0.1"):
    if is_csv:
        response = get_response_csv(remote_response, mapping, local_model)
    else:
        response = get_unblur_response(remote_response, mapping, local_model)
    return response


if __name__ == '__main__':
    instruction, output = user_input(instruction = "Can you give me some high-level insights from the following CSV file between salary and created revenue?", data_str = "", file_path = "/Users/xiqiao/Documents/_hacker2/BlurredAI/uploaded_files/test.csv")    
    print("\n===instruction===")
    print(instruction)
    print("\n===output===")
    print(output)
    print("\n===Sensitive_mapping===")
    print(Sensitive_mapping)
    raw_output, unblurred_response = process_request(instruction=instruction, blurred_data=output)
    print("\n===raw_output===")
    print(raw_output)
    print("\n===unblurred_response===")
    print(unblurred_response)
#     assert("False")
#     data = """Dear Sam Altman,

# I am excited to submit my application for the CEO position at OpenAI. As a mid-level professional with 30 years of experience in Artificial Intelligence, I am confident that my skills and experience make me a strong candidate for the role.

# In my current position at Deepmind, I have honed my skills in Artificial Int, which I believe would be a valuable asset to your team. I am particularly drawn to OpenAI's reputation for , and I am eager to contribute my expertise to help achieve the company's goals."""
#     print("\n===data===")
#     print(data)
#     output = user_input(instruction="", data_str=data)
#     print("\n===output===")
#     print(output)
#     print("\n===Sensitive_mapping===")
#     print(Sensitive_mapping)
#     raw_output, unblurred_response = process_request(instruction=instructon, blurred_data=output)
#     print("\n===raw_output===")
#     print(raw_output)
#     print("\n===unblurred_response===")
#     print(unblurred_response)
#     #print(output)

```

### about.py

```python
import streamlit as st

st.title('Learn about BlurredAI!⚡')

with st.expander('What is this app about?'):
    st.write('''
    We are a team of 3 Computer Science researchers who care deeply about privacy. Yap yap yap yap.
    ''')
```

### backend/remotecall.py

```python
import openai

openai.api_key = ""

def remote_call(prompt, remote_model = "gpt-3.5-turbo"):
    if (remote_model[0:3] == "gpt"):
        completion = openai.chat.completions.create(
            model=remote_model,
            messages=[
                {
                    "role": "user",
                    "content": prompt
                },
            ],
        )
        response = completion.choices[0].message.content
    return response

```

### backend/table.py

```python
import pandas as pd
import re
from tabulate import tabulate

def get_redacted_csv(data_str = "", file_path = "", local_model = ""):
    data = pd.read_csv(file_path)
    data.columns = [col.lower() for col in data.columns]
    for column in data.columns:
        if data[column].dtype == object:  # Checking for string columns
            data[column] = data[column].str.lower()
    
    i = 0
    mapping = {}
    for col in data.columns:
        mapping[col] = "[column{}]".format(i)
        i+=1
    changed_columns = []
    for column in data.columns:
        print(data[column].dtype, data[column].dtype == 'object')
        if data[column].dtype == 'object':
            changed_columns.append(column)
    for it, row in data.iterrows():
        for column in changed_columns:
            mapping[row[column]] = "[{}_{}]".format(mapping[column], it)
    column_mapping = {}
    for col in data.columns:
        if col in mapping:
            column_mapping[col] = mapping[col]
        else:
            column_mapping[col] = col
    data.replace(mapping, inplace=True)
    data.rename(columns=column_mapping, inplace=True)
    ret_data = tabulate(data, headers=data.columns,tablefmt="orgtbl", showindex=False)
    return ret_data.replace('\n', '\n\n'), mapping

def get_response_csv(response, Sensitive_mapping, local_model):
    response = re.sub(r'\[([a-zA-Z0-9_]+)\]', r'\1', response)
    Sensitive_mapping = sorted(Sensitive_mapping.items(), key=lambda item: len(item[1]), reverse=True)
    for key,value in Sensitive_mapping:
        value = re.sub(r'\[([a-zA-Z0-9_]+)\]', r'\1', value)
        response = response.replace(value, key)
    return response
```

### backend/localcall.py

```python
from openai import OpenAI
import os

TOGETHER_API_KEY = ""

def local_call(prompt, system_prompt = "You are an AI assistant", local_model = "mistralai/Mixtral-8x7B-Instruct-v0.1", streaming = False, source = "together", max_tokens = 1024, response_format = None):
   if source == "together":
      return together_call(prompt = prompt, system_prompt = system_prompt, local_model = local_model)
   else:
      return ""
   
def together_call(prompt, system_prompt, local_model, streaming = False, max_tokens = 1024, response_format = None):
    client = OpenAI(
        api_key=TOGETHER_API_KEY,
        base_url='https://api.together.xyz',

    )
    messages = [{
        "role": "system",
        "content": system_prompt,
    }, {
        "role": "user",
        "content": prompt,
    }]
    if response_format == None:
      chat_completion = client.chat.completions.create(messages=messages,
                                                      model=local_model,
                                                      max_tokens=max_tokens,
                                                      #response_format={ "type": "json_object" },
                                                      stream=streaming)
    else:
      chat_completion = client.chat.completions.create(messages=messages,
                                                      model=local_model,
                                                      max_tokens=max_tokens,
                                                      response_format={ "type": "json_object" },
                                                      stream=False)
    response = chat_completion.choices[0].message.content
    return response



if __name__ == "__main__":
  data = """Hello Mr. Landlord, My name is Tonia Glover and I'm interested in your rental at 55 Quail Dr. My roommate and I are searching for a peaceful place to live near campus. We are quiet and studious, majoring in physics and psychology, and capable of paying rent through jobs and financial support from parents. Our application packet is ready for review; I would love to set up an appointment to see the property. My phone number is 831-555-5555. 
Thank you for your time. I look forward to hearing from you.Tonia"""


```

### backend/utils.py

```python
import json
import re
from ast import literal_eval
from prompts import get_redactor_prompt, redactor_system_prompt, get_mapper_prompt, mapper_system_prompt, get_unblur_prompt, unblur_system_prompt
from localcall import local_call


def get_dictionary_response(response):
    # parse the mapper model's response to a dictionary
    response_line = response.split("\n")
    flag = False
    ret = ""
    for line in response_line:
        if (line.find("{") != -1):
            flag = True
        ret += line
        if (line.find("}") != -1):
            break
    ret = ret.replace("\n", "").replace("\t", "").replace("\\", "")
    if flag:
        try:
            return json.loads(ret)
        except:
            print("Error in parsing the response")
    print("No dictionary found in the response")
    return {}


def get_redacted_text(instruction, data_str, local_model):

    prompt = get_redactor_prompt(data_str)
    response = local_call(prompt, system_prompt=redactor_system_prompt, local_model=local_model)
    response = "".join(response).strip('```').strip()
    if response.find("```") != -1:
        response = response.split("```")[0]
    return response


def get_mapping(instruction, data, redacted_data, local_model):
    prompt = get_mapper_prompt(data, redacted_data)
    response = local_call(prompt, system_prompt=mapper_system_prompt, local_model=local_model)
    response = "".join(response).strip('```').strip()
    response = get_dictionary_response(response)
    if (type(response) == dict):
        return response
    else:
        return {}


def get_unblur_response(remote_response, sensitive_mapping: dict, local_model, use_python=True):
    if use_python:
        ## simple python-based replacement
        # First make sure all the keys in the mappings don't have any special characters
        # apart from square brackets and underscore
        for key in sensitive_mapping.keys():
            new_key = re.sub(r'[^a-zA-Z0-9_\[\]]', '', key)
            if new_key != key:
                sensitive_mapping[new_key] = sensitive_mapping.pop(key)

        # Since the original text may have square brackets around the keys, we need to
        # replace them with the keys without the square brackets
        unblurred_response = re.sub(r'\[([a-zA-Z0-9_]+)\]', r'\1', remote_response)
        sensitive_mapping = sorted(sensitive_mapping.items(), key=lambda item: len(item[0]), reverse=True)
        # Now replace the keys with the values
        for key, value in sensitive_mapping:
            unblurred_response = unblurred_response.replace(key, value)

        return unblurred_response

    else:
        ## Original version using model
        prompt = get_unblur_prompt(remote_response, sensitive_mapping)
        response = local_call(prompt, system_prompt=unblur_system_prompt, local_model=local_model)
        response = "".join(response).strip('```').strip()
        if (response.find("```") != -1):
            response = response.split("```")[0]
        return response

```

### backend/prompts.py

```python
import os
import textwrap


def Filter_prompt(user_prompt, file_prompt):
    return f"""please remove all sensitive data from the document below{user_prompt}{file_prompt}
and return in json format as {{"sensitive_data": , "filtered_data": }}. """


def Extract_prompt(response_prompt, sensitive_data):
    return f"""please fill the sensitive_data {sensitive_data} into {response_prompt} and return"""


redactor_system_prompt = textwrap.dedent("""
You are a privacy-aware text redaction tool designed to identify and redact sensitive information in text inputs. Your task involves scanning the provided text for specific types of sensitive information: personal names, addresses, and phone numbers. Once identified, you will redact them with generic placeholders such as "[PERSON_1]", "[LOCATION_1]", "[NUMBER_1]", ensuring each unique piece of sensitive data has a distinct numeric identifier. Otherwise, keep all non-sensitive text in tact. Note that the input text can be also contain instructions or questions; the sensitive information should be redacted from these instructions as well, but the instructions should remain readable and coherent.
""".strip())

redactor_incontext_examples = textwrap.dedent("""
The following is a list of examples of the input and output of the redactor system. Complete the task by redacting the sensitive information in the input text:
---
Input:
```
Sailing from Long Beach, California, Peter arrived over the recovery site on 4 July 1974 and conducted salvage operations for more than two months under total secrecy.
```
Output:
```
Sailing from [LOCATION_1], [PERSON_1] arrived over the recovery site on 4 July 1974 and conducted salvage operations for more than two months under total secrecy.
```
---
Input:
```
Hello Mr. Landlord,

My name is Tonia Glover and I'm interested in your rental at 55 Quail Dr. My roommate and I are searching for a peaceful place to live near campus. We are quiet and studious, majoring in physics and psychology, and capable of paying rent through jobs and financial support from parents. Our application packet is ready for review; I would love to set up an appointment to see the property. My phone number is 831-555-5555. Thank you for your time. I look forward to hearing from you.
Tonia
```
Output:
```
Hello [PERSON_1],

My name is [PERSON_2] and I'm interested in your rental at [LOCATION_1]. My roommate and I are searching for a peaceful place to live near campus. We are quiet and studious, majoring in physics and psychology, and capable of paying rent through jobs and financial support from parents. Our application packet is ready for review; I would love to set up an appointment to see the property. My phone number is [NUMBER_1]. Thank you for your time. I look forward to hearing from you.

[PERSON_2]
```
---
Input:
```
After reviewing the financial reports, CEO Johnathan Green of Sterling Tech Solutions announced an impressive 25% increase in quarterly profits during the shareholder meeting held at their headquarters in San Francisco, California.
```
Output:
```
After reviewing the financial reports, [PERSON_1] announced an impressive [NUMBER_1] increase in quarterly profits during the shareholder meeting held at their headquarters in [LOCATION_1].
```
---
""".strip())

# NOTE: The following template is deprecrated.
# Since we are using instruction-following models, having the instruction in it
# will cause the model to respond to these istructions than just focusing on
# redacting the data.
# redactor_incontext_examples = textwrap.dedent("""
# ---
# Input:
# ```
# Sailing from Long Beach, California, Peter arrived over the recovery site on 4 July 1974 and conducted salvage operations for more than two months under total secrecy.
# ```
# Output:
# ```
# Sailing from [LOCATION_1], [PERSON_1] arrived over the recovery site on 4 July 1974 and conducted salvage operations for more than two months under total secrecy.
# ```
# ---
# Input:
# ```
# Could you please help me re-write the following email from Tonia?

# Hello Mr. Landlord,

# My name is Tonia Glover and I'm interested in your rental at 55 Quail Dr. My roommate and I are searching for a peaceful place to live near campus. We are quiet and studious, majoring in physics and psychology, and capable of paying rent through jobs and financial support from parents. Our application packet is ready for review; I would love to set up an appointment to see the property. My phone number is 831-555-5555. Thank you for your time. I look forward to hearing from you.
# Tonia
# ```
# Output:
# ```
# Could you please help me re-write the following email from [PERSON_2]?

# Hello [PERSON_1],

# My name is [PERSON_2] and I'm interested in your rental at [LOCATION_1]. My roommate and I are searching for a peaceful place to live near campus. We are quiet and studious, majoring in physics and psychology, and capable of paying rent through jobs and financial support from parents. Our application packet is ready for review; I would love to set up an appointment to see the property. My phone number is [NUMBER_1]. Thank you for your time. I look forward to hearing from you.

# [PERSON_2]
# ```
# ---
# Input:
# ```
# Summarize the following announcement from Johnathan Green:

# After reviewing the financial reports, CEO Johnathan Green of Sterling Tech Solutions announced an impressive 25% increase in quarterly profits during the shareholder meeting held at their headquarters in San Francisco, California.
# ```
# Output:
# ```
# Summarize the following announcement from [PERSON_1]:

# After reviewing the financial reports, [PERSON_1] announced an impressive [NUMBER_1] increase in quarterly profits during the shareholder meeting held at their headquarters in [LOCATION_1].
# ```
# ---
# """.strip())


def get_redactor_prompt(data):
    redactor_prompt_template = redactor_incontext_examples + textwrap.dedent('''
      Input:
      ```
      {}
      ```
      Output:
      ```
      ''')
    return redactor_prompt_tem
[truncated — 8777 more characters]
```