DEV Community

Cover image for Integrando a API do ChatGPT com o Google Firebase Firestore
Raphael Araújo
Raphael Araújo

Posted on

Integrando a API do ChatGPT com o Google Firebase Firestore

Como comentado no meu post anterior, eu desenvolvi uma arquitetura de serviços para tentar economizar um pouco na hora de consumir a API da OpenAI e o modelo gpt-3.5-turbo.

Arquitetura final descrita no [post anterior](https://dev.to/raphox/tentando-nao-ficar-pobre-antes-de-ficar-rico-criando-uma-startup-de-servicos-de-inteligencia-artificial-1mag).

Agora vou mostrar um pouco do código que inseri no Firebase functions que é chamado toda vez uma nova perguntar é inserida no Firestore.

const functions = require("firebase-functions");
require("dotenv").config();
exports.answerQuestion = functions.firestore
.document("/questions/{questionId}")
.onCreate((snap, context) => {
const data = snap.data();
functions.logger.log(
"Answering question",
context.params.questionId,
data.title,
);
fetch(process.env.RENDER_API_URL, {
method: "post",
body: JSON.stringify({
data,
collection: "questions",
document: context.params.questionId,
}),
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.SECURITY_TOKEN}`,
},
});
});
view raw index.js hosted with ❤ by GitHub

Essa função irá enviar os dados da pergunta cadastrada pelo usuário, para um serviço no Render.com onde a API do modelo do ChatGPT será consumida.

Estrutura de perguntas no Firestore.

Vale relembrar o motivo de eu não ter feito tudo do lado do Firebase Cloud Function:

O Cloud Function cobra de acordo com o tempo de execução da sua função, além do número de invocações e dos recursos provisionados. Como a API do ChatGPT pode demorar para responder, dependendo da complexidade da sua consulta, você pode acabar pagando muito pelo tempo que a sua função fica aguardando a resposta da API.

Ao fim do processo, a pergunta terá sua resposta atualizada no Firestore com base nos dados recibidos da API do ChatGPT.

import os
import time
import threading
import firebase_admin
from dotenv import load_dotenv
from firebase_admin import firestore, credentials
from langchain.schema import AIMessage
from flask import Flask, request
from flask_httpauth import HTTPTokenAuth
from ask import execute as ask_execute
from query import upsert_question, execute as query_execute
load_dotenv()
cred = credentials.Certificate("./serviceAccountKey.json")
firebase_admin.initialize_app(cred)
app = Flask(__name__)
auth = HTTPTokenAuth(scheme='Bearer')
tokens = {
os.environ.get('FIREBASE_TOKEN'): "firebase"
}
@auth.verify_token
def verify_token(token):
if token in tokens:
return tokens[token]
@app.route('/answer_question', methods=['POST'])
@auth.login_required
def answer_question():
data = request.get_json()
def long_running_task(**kwargs):
params = kwargs.get(
'post_data', {"data": {}, "collection": "", "document": ""}
)
data = params["data"]
collection_path = params["collection"]
document_path = params["document"]
client = firestore.client()
affected_doc = client.collection(
collection_path).document(document_path)
answer = None
question = data["title"]
similarity_search = query_execute(question, k=1, namespace="questions")
if similarity_search:
document, score = similarity_search[0]
if score > 0.95:
answer = AIMessage(content=document.metadata['answer'])
if not answer:
answer = ask_execute(question)
upsert_question(question, answer.content)
affected_doc.update({
u'answer': answer.content
})
thread = threading.Thread(
target=long_running_task,
kwargs={'post_data': data}
)
thread.start()
return {"message": "Accepted"}, 202
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
view raw app.py hosted with ❤ by GitHub

Podemos destacar alguns trechos importantes do código anterior:
  • Linhas 13 e 14: São métodos customizados que fazem a comunicação com o Pinecone e a API da OpenAI. Sugiro buscar mais informações em https://python.langchain.com/en/latest/use_cases/question_answering.html

  • Linha 60: Nas linhas anteriores, o código é responsável por buscar na base de dados de perguntas já realizadas pelos usuários e encontrar a pergunta mais parecida. Com base na pergunta mais parecida já feita anteriormente, a linha 60 é responsável por verificar se a similaridade é tão próxima (95%) que a resposta da pergunta anterior pode ser utilizada para responder a nova pergunta. Como comentei no meu post anterior, esse comparativo não se daria muito bem para diferenciar perguntas como: Quanto custa 1kg do seu produto?’ e ‘Quanto custa 1g do seu produto?’.

  • Linha 71: Essa parte do código foi responsável por sanar meu problema com o delay da API da OpenAI. Alguns podem estar se perguntando o porquê de eu não ter utilizado algo relacionado a filas de processamento em background. Mas como comentei no post anterior, meu objetivo por agora é buscar alternativas mais baratas. Contratar um banco Redis e um worker em periodo integral, não está nos meu planos por agora. Mas, mudar isso, com certeza está em um dos meu planos futuros.

Documentações que podem lhe ajudar no desenvolvimento:

Referências:

  1. https://flask-httpauth.readthedocs.io/en/latest/

  2. https://zoltan-varadi.medium.com/flask-api-how-to-return-response-but-continue-execution-828da40881e7

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay