Contexto

Experimento usando OpenAI - Assistants (Tools com LLM ) para um bot que faz agendamentos de consultas médicas com verificação de disponibilidade de agenda.

Exemplo da conversa do resultado do experimento:

USER> Olá! Gostaira de marcar uma consulta para João
BOT> Claro, posso ajudar com isso. Você tem alguma data e horário em mente para a consulta? E qual seria o procedimento? (consulta, exame, etc..)
USER> Uma consulta mesmo, as 10h na terça feira
BOT> Infelizmente, a Dra. Maria está disponível apenas à tarde na terça-feira, 6 de agosto de 2024. Você gostaria de sugerir outro horário ou talvez escolher outra data?
USER> pode ser as 14h então
BOT> A consulta para João foi agendada com sucesso para o dia 6 de agosto de 2024, às 14h. Se precisar de mais alguma coisa, estarei à disposição!

Implementação

Dependências usando pipenv

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
 
[packages]
requests = "*"
python-dotenv = "*"
openai = "*"
icecream = "*"
prompt-toolkit = "*"
ipdb = "*"
 
[dev-packages]
flake8 = "*"
 
[requires]
python_version = "3.10"

Código

from datetime import date
import json
import logging
 
from prompt_toolkit import PromptSession
from prompt_toolkit.history import FileHistory
from openai import OpenAI
from icecream import ic
 
 
logger = logging.getLogger(__name__)
 
client = OpenAI()
 
#current_date = date.today().isoformat()
current_date = '2024-08-03'
 
model = 'gpt-4o'
 
prompt_instructions = f'''Você é um secretário responsável por gerenciar a agenda de uma médica.
Auxilie a pessoa paciente a marcar uma consulta com a Dra. Maria, pergutando o que
for necessário para marcar a consulta. Basicamente uma data e qual o procedimento
(consulta, exame, etc), não esqueça de confirmar qual o nome do paciente.
Considere a data de hoje como {current_date}.'''
 
assistant = client.beta.assistants.create(
    name='Gustavo, secretário assistente para marcar consultas',
    instructions=prompt_instructions,
    tools=[
        {
            "type": "function",
            "function": {
                "name": "schedule_appointment",
                "description": "Agenda uma consulta com a médica para o paciente.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "name": {
                            "type": "string",
                            "description": "Nome da pessoa paciente",
                        },
                        "date_and_time": {
                            "type": "string",
                            "description": "Data e hora desejada para a consulta, YYYY-MM-DD HH:MM",
                        },
                        'procedure': {
                            'type': 'string',
                            'description': 'Procedimento que será realizado (exame, consulta, etc..).'
                        }
                    },
                    "required": ["date_and_time", "procedure"]
                }
            }
        },
        {
            "type": "function",
            "function": {
                "name": "get_calendar_availability",
                "description": "Retorna a disponibilidade da médica na agenda dada uma data.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "date": {
                            "type": "string",
                            "description": "A data (YYYY-MM-DD) para verificar a disponibilidade.",
                        },
                    },
                    "required": ["date_period"]
                }
            }
        },
    ],
    model=model,
)
 
 
def get_calendar_availability(date):
    results = {
        '2024-08-05': 'disponivel o dia todo',
        '2024-08-06': 'disponivel apenas a tarde',
        '2024-08-07': 'indisponivel',
        '2024-08-08': 'disponivel apenas de manha',
        '2024-08-09': 'disponivel o dia todo',
    }
 
    if date not in results:
        result = f'em {date} o médico não está disponível'
    else:
        result = f'em {date} o médico está {results[date]}'
 
    return result
 
 
def schedule_appointment(name, date_and_time, procedure):
    print(f'Agendando consulta para o paciente {name}, em', date_and_time, 'com procedimento:', procedure)
    return f'Consulta agendada para o paciente {name}, {date_and_time} com procedimento {procedure}'
 
 
tools_available = {
    'get_calendar_availability': get_calendar_availability,
    'schedule_appointment': schedule_appointment,
}
 
 
def main():
    '''Simple method to show current assistant'''
 
    exit_strings = set(['exit', 'quit', 'bye', 'goodbye', 'sair'])
 
    session = PromptSession()
    our_history = FileHistory(".example-history-file")
    session = PromptSession(history=our_history)
 
    text = session.prompt('USER> ')
 
    thread = client.beta.threads.create()
 
    while text.lower() not in exit_strings:
        client.beta.threads.messages.create(
            thread_id=thread.id,
            role="user",
            content=text)
 
        running = client.beta.threads.runs.create_and_poll(
            thread_id=thread.id,
            assistant_id=assistant.id)
 
        while running.status == 'requires_action':
            tool_outputs = []
 
            for tool_call in running.required_action.submit_tool_outputs.tool_calls:
                arguments = json.loads(tool_call.function.arguments)
                result = tools_available[tool_call.function.name](**arguments)
                tool_outputs.append({
                    'tool_call_id': tool_call.id,
                    'output': result
                })
 
            try:
                print('Tools outputs:', tool_outputs)
                running = client.beta.threads.runs.submit_tool_outputs_and_poll(
                    thread_id=thread.id,
                    run_id=running.id,
                    tool_outputs=tool_outputs)
                print("Tool outputs submitted successfully.")
            except Exception as e:
                print("Failed to submit tool outputs:", e)
 
        while running.status != 'completed':
            print('status:', running.status)
 
        messages = [msg for msg in client.beta.threads.messages.list(
            thread_id=thread.id)]
 
        content = messages[0].content
        print('BOT>', '\n'.join([c.text.value for c in content]))
 
        text = session.prompt('USER> ')
 
 
if __name__ == '__main__':
    main()