見出し画像

AI radio makerへの道2

なんかいろいろやっておりましたらlangchainが半分というよくわからないコードになってしまいました。

import json
import os
import time
import anthropic
import openai
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import OpenAIEmbeddings, ChatOpenAI

os.environ["ANTHROPIC_API_KEY"] = "sk-ant-******************************"
openai_key = os.environ.get("OPENAI_API_KEY")
system_content = """
     あなたは優秀なラジオリポーターになりきってください。名前は、エナです。
      あなたはこれから現場取材を行います。
      相手は解説役ですので、質問をしながら話を深掘りしてください。
       また、生放送ですので、質問は短い文章になるようにしてください。
        会話には少しユーモアを加えるようにしてください。自然なはなし口調でお願いします。
        解説者の出力はしないでください。
         また、前回の会話からなるべく違う質問をしてください。"""

system_content2 = """
     あなたはラジオゲストになりきってください。これからインタビューを受けます。
     あなたの名前は、金剛地です。 
      これは生放送ですので、回答は短い文章にしてください。
       また、音声のみのコミュニケーションになりますので、相手に伝わるように長文は避けてください。
        自然なはなし口調でお願いします。同じような質問が来た場合言い回しを変えてみてください。"""

client1 = anthropic.Anthropic()
client2 = openai.OpenAI()
messages1 = []
messages2 = []
theme = "ドラえもん" # テーマを設定
loader = TextLoader("./doraemon.txt", encoding="utf-8")
texts = loader.load_and_split()
faiss_index = FAISS.from_documents(texts, OpenAIEmbeddings())
messages2.append({"role": "system", "content": system_content2})

tools = [
        {"type": "function",
            "function":{
                "name": "similarity_search_and_answer",
                "description": "Answer the given question by referring to the results of similarity search.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "question": {
                            "type": "string",
                            "description": "question",
                        },
                        "results": {
                            "type": "string",
                            "description": "results of search",
                        },
                    },"required": ["results"]
                }
            }
        }
]

def similarity_search_and_answer(question):
    """Answer the given question by referring to the results of similarity search."""
    retriever = faiss_index.as_retriever()
    template = """contextに従って回答してください:
    {context}

    質問: {question}
    """
    prompt = ChatPromptTemplate.from_template(template)
    model = ChatOpenAI(model_name="gpt-3.5-turbo-0125")

    chain = (
            {"context": retriever, "question": RunnablePassthrough()}
            | prompt
            | model
            | StrOutputParser()
    )
    results = chain.invoke(question)
    return json.dumps({"results": results})

def reporter(u):
    messages1.append({"role": "user", "content": u})
    resp = client1.messages.create(
        model="claude-3-haiku-20240307",
        system=system_content,
        max_tokens=150,
        temperature=0.7,
        messages=messages1
    )
    a = resp.content[0].text
    messages1.append({"role": "assistant", "content": a})
    return a

def interviwee(u):
    messages2.append({"role": "user", "content": u})
    resp = client2.chat.completions.create(
        model="gpt-3.5-turbo-0125",
        messages=messages2,
        tools=tools,
        tool_choice="auto",
    )
    resp_mess = resp.choices[0].message
    tool_calls = resp_mess.tool_calls
    if tool_calls:
        available_functions = {
            "similarity_search_and_answer": similarity_search_and_answer, }
        messages2.append(resp_mess)  # ここは型があってないけどこのままでいい。
        for tool_call in tool_calls:
            function_name = tool_call.function.name
            function_to_call = available_functions[function_name]
            function_args = json.loads(tool_call.function.arguments)
            function_response = function_to_call(
                question=function_args.get("question"),
            )
            messages2.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response,
                }
            )
        second_resp = client2.chat.completions.create(
            model="gpt-3.5-turbo-0125",
            messages=messages2,
        )
        a = second_resp.choices[0].message.content
        messages2.append({"role": "assistant", "content": a})
        return a
    a = resp.choices[0].message.content
    messages2.append({"role": "assistant", "content": a})
    return a

def interview(u,interview_msgs):
    a_rep = reporter(u)
    print(a_rep)
    interview_msgs.append({"role": "reporter", "content": a_rep})
    time.sleep(0.5)
    a_int = interviwee(a_rep)
    print(a_int)
    interview_msgs.append({"role": "interviewee", "content": a_int})

def main():
    print(f"インタビューを始めます。{theme}についてお話ししてください。")
    count = 0
    t_count = 3 # インタビュー回数
    interview_msgs = []
    while count < t_count:
        u = f"""インタビューをしてください。{theme}についてお二人で語ってもらいます。
            リポーターから解説者に質問をしてください。お二人の会話をあと
            {t_count - count}回で終わらせてください。お願いします。"""
        interview(u,interview_msgs)
        count += 1
        if count == t_count:
            print("\n インタビューが終了しました。")
            break
    # pprint(interview_msgs)
if __name__ == "__main__":
    main()

とりあえずRAGがちゃんと実装できたので、きりがいいのでここで掲載します。受け答えはプロンプトで制御するのがいいのか、はたまた違う方法でするのか。まだ決めてませんがこのコードでもインタビューは一応往復します。


doraemon.txtはwikipediaからコピペしたテキストファイルです。ダウンロードして環境に貼り付けてください。

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