見出し画像

TeamsのbotでもChatGPTとChatをしたい


botは標準では前回の会話を覚えてない

botはもちろんTeamsが会話を覚えているはずがないので、前回のやり取りはすっかり忘れて毎回違う人と会話を始めている感じになります。それだとあまりユーザフレンドリーとは言えないので、多少、会話のようなものをできるようにしてみました。

仕組み

Azure OpenAI x Pinecone x TeamsでFAQ検索ボットを作成する~postgresqlアップロード編でも説明した通り、pineconeで勘違いをして、postgresqlを用意してしまいました。
そこでこのpostgresqlにユーザー毎の会話を保存し、promptで渡すことで、会話をある程度成立させようというものです。

app.pyの改良

@app.route('/chat', methods=['POST'])
def post_chat():
    keyname = "chat"

    try:     
        chat = request.json[keyname]
        secret_key = request.json['security']
        userid = request.json['uuid']
    except:
        return('"Message":"パラメータエラー"')

	#セキュリティキーをチェックします。APIKEY感覚です。
    if(secret_key != 'xxxxxxx'):
        return(webapp.secerr)

	#まずはpineconeにあてるため、質問を英語にします。    
    try:    
        chat_en = comp.transrate(request.json[keyname],'en')
    except:
        return('"Message":"Chat-GPTでエラーが発生しました。"')

    pcnapp = pa.init()
    pcnindex = pcnapp.Index(index_name=pcn.index_name)
    results = pa.search(pcnindex,chat_en)

    ids = []
    urls = []
    titles = []
    textdatas = []
    textdatas_en = []
    scores = []

    idkey = 'id'
    mtkey = 'matches'
    sckey = 'score'
    if len(results[mtkey]) > 0:
        for res in results[mtkey]:
            #類似スコア0.8以上を候補として表示する
            if res[sckey] > 0.80:
                ids.append(res[idkey])
                scores.append(round(float(res[sckey]),2))
                #事前にdbに保存したFAQのデータをqueryする
                count = db.session.query(originaldata).filter_by(id=res[idkey]).count()
                if(count != 0):
                    #最初の一件をCompletionに渡すため、取り出す
                    result = db.session.query(originaldata).filter_by(id=res[idkey]).first()
                    urls.append(result.url)
                    titles.append(result.title)
                    textdatas.append(result.textdata)
                    if result.textdata_en != None:
                        textdatas_en.append(result.textdata_en)
                        textdata_en = result.textdata_en
    #四分前までに会話したデータを検索してくる(要チューニング)
    mins = (datetime.now() + relativedelta(minutes=-4)).strftime('%Y-%m-%d %H:%M')
    count = db.session.query(history).filter(history.createdate>=mins,history.uuid==userid).order_by(history.createdate.desc()).count()
    preanswer = ""
    if(count != 0):
        result = db.session.query(history).filter(history.createdate>=mins,history.uuid==userid).order_by(history.createdate.desc()).all()
        #過去の回答はすべて結合する
        for res in result:
            preanswer += res.answer
        if(preanswer == 'Chat-GPTでエラーが発生しました。'):
            preanswer = ""
    #トークンの限界があるので、一旦1500文字で切る(要チューニング)
    preanswer = preanswer[:1500]

    response = ""
    
    if len(ids) > 0:
        try:
            response = comp.completion(chat,preanswer,textdatas[0])
            retnum = 0
            for url,title,score in zip(urls,titles,scores):
                if retnum == 0:
                    response += "この回答は下記のFAQをChat-GPTに渡して生成されたものです。"
                if retnum == 1:
                    response += "他にも候補があります。"
                response += f'<a href="{url}">"{title}"</a>&nbsp;&nbsp;&nbsp;類似度&nbsp;{score}'
                retnum += 1
        except:
            response = "Chat-GPTでエラーが発生しました。"
    else:
        response = comp.completion(chat,preanswer,"")

    ipaddr =request.environ.get('HTTP_X_REAL_IP', request.remote_addr)
    data = history(chat=chat,answer=response[0:pcn.textlength],ipaddress=ipaddr,uuid=userid)
    old = datetime.today() - relativedelta(days=90)
    s_old = old.strftime("%Y-%m-%d")
    sql = f"delete from history where createdate < '{s_old}'"
    db.session.execute(text(sql))
    db.session.commit()
    db.session.add(data)
    db.session.commit()
    
    return(response)

相変わらず、このままでは動きませんが、なんとなく流れの説明でソースを引用しておきます。やってることは難しくはないです。

completionの改良

def completion(question,preanswer,faqdata):
    openai.api_type = azai.api
    openai.api_base = azai.url
    openai.api_version = azai.completion_version
    openai.api_key = azai.key

    prompt = "君の回答は日本語で行うこと。"
    prompt += "君はassistantからの情報を最大限利用して回答すること。"
    prompt += "君はできないことはできないということ。"
    prompt += "君はユーザーに質問しないこと。"
    prompt += "君はassistantの情報がない場合に限り自由に回答すること。"

    assistant = ""
    if(len(preanswer)):
        assistant += "君の前回の回答は" + preanswer + "だった。"

    if(len(faqdata)):
        assistant += "ユーザーの質問が前回と関係があれば、次のデータも使って回答すること。\n" + faqdata

    response = openai.ChatCompletion.create(
        engine=azai.completion_engine40,
        messages = [
            {"role":"system","content":prompt},
            {"role":"assistant","content": assistant},
            {"role":"user","content": question},
        ],
        temperature=0.7,
        max_tokens=1000,
        frequency_penalty=0,
        presence_penalty=0,
        stop=None,
        request_timeout=120
    )

    ret = str(response.choices[0]['message']['content'].strip())
    return(ret)

こちらもこのままでは動きませんが、流れを説明するために掲載しておきます。

この記事が気に入ったらサポートをしてみませんか?