Open7

langchan を使用して複数の PDF を入力してチャットを行う機能ツールを作成する/

kaitokaito

openAI の API をそのまま使用して要約ツールを作成していたので, 要約作成が楽になるLangchain を導入したうえで, いい感じに要約文を作成してもらえるようにする.
更に一つのファイルだけではなく複数のファイルを使用できるようにしていく.

kaitokaito

Sequential Chain

出力したデータをもとにして新たに出力させるやつ.
サンプルコードが一部動かなかったため少し修正している.
openai APIの仕様が一部変わってるみたい.

from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain, SimpleSequentialChain

llm = ChatOpenAI(model_name="gpt-3.5-turbo")
prompt_1 = PromptTemplate(
    input_variables=["job"],
    template="{job}に一番オススメのプログラミング言語は?\nプログラミング言語:",
)
chain_1 = LLMChain(llm=llm, prompt=prompt_1)

prompt_2 = PromptTemplate(
    input_variables=["programming_language"],
    template="{programming_language}を学ぶためにやるべきことを3ステップで100文字で教えて。",
)
chain_2 = LLMChain(llm=llm, prompt=prompt_2)

overall_chain = SimpleSequentialChain(chains=[chain_1, chain_2], verbose=True)
print(overall_chain("消防士"))

参考 : https://zenn.dev/umi_mori/books/prompt-engineer/viewer/langchain_chains

kaitokaito

sonyの2023年度第三四半期の有価証券報告書をまとめさせる.
これだけでかけるのは便利だけど, どのモデル使ってるのかわからない.

from langchain.indexes import VectorstoreIndexCreator
from langchain_community.document_loaders.pdf import PyPDFLoader
from langchain_community.vectorstores.chroma import Chroma
from langchain_openai import OpenAIEmbeddings

loader = PyPDFLoader("sony.pdf")

index = VectorstoreIndexCreator(
    vectorstore_cls=Chroma, # Default
    embedding=OpenAIEmbeddings(), # Default
).from_loaders([loader])

query = "有価証券報告書の内容をまとめてください. 最後に今後の発展性について述べてください."

answer = index.query(query)
print(answer)
kaitokaito

複数のPDFを入力として与える.
2社の売上を比較すると下記のような返答を得られた.

Toyotaの売上は、2022年に27,464,033百万円、2023年に34,022,720百万円であり、営業利益はそれぞれ1,588億円となっています。一方、Sonyの売上は、2022年に25,383,850百万円、2023年に31,511,767百万円であり、営業利益はそれぞれ1,475億円となっています。
from langchain.indexes import VectorstoreIndexCreator
from langchain_community.document_loaders.pdf import PyPDFLoader
from langchain_community.vectorstores.chroma import Chroma
from langchain_openai import OpenAIEmbeddings

loader_sony = PyPDFLoader("sony.pdf")
loader_toyota = PyPDFLoader("toyota.pdf")


index = VectorstoreIndexCreator(
    vectorstore_cls=Chroma, # Default
    embedding=OpenAIEmbeddings(), # Default
).from_loaders([loader_sony, loader_toyota])

query = "Toyota と Sony それぞれの売上と利益を教えて下さい"

answer = index.query(query)
print(answer)
kaitokaito

コマンドライン上での簡単なチャット

from langchain.chains.conversation.base import ConversationChain
from langchain.memory import ConversationBufferMemory
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model_name="gpt-3.5-turbo")
template = '''
あなたは優秀なAIです. ユーザーからの質問に対して, あなたは適切な回答を返すことができます.

会話内容:
{history}
人間: {input}
AI:'''

prompt = PromptTemplate(
    input_variables=['history', 'input'],
    template=template
)

conversation = ConversationChain(
    llm=llm,
    prompt=prompt,
    memory=ConversationBufferMemory(
        human_prefix='人間'
    ),
    verbose=False)


def chat(message, history):
    history = history or []
    response = conversation.predict(input=message)
    history.append((message, response))

    return history, history


if __name__ == '__main__':
    history = []
    while True:
        message = input('人間:')
        history, response = chat(message, history)

        # 最新のレスポンスを表示
        ai_text = response[-1][1]
        print('AI:', ai_text)

``` python

## 参考

https://qiita.com/hideki/items/b26154ab503fd3394a0b
kaitokaito

大きなPDFファイルの要約

PDFによっては改行や句読点で区切ることが難しいことがあるので単純に

import PyPDF2
from langchain.chains.combine_documents.base import BaseCombineDocumentsChain
from langchain.chains.summarize import load_summarize_chain
from langchain.docstore.document import Document
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_text_splitters import RecursiveCharacterTextSplitter

refine_first_template = """
これからPDFファイルの要約を行います
テーマごとに文章をまとめてください.



# 要約する文章
{text}
"""
refine_template = """
これからPDFファイルの要約を行います
テーマごとに文章をまとめてください.

# 生成する文章の例
1章: ****
- 内容1
- 内容2

2章: ****
- 内容1
- 内容2

3章: ***

<同上>


# 要約する文章
{existing_answer}
{text}
"""

refine_first_prompt = PromptTemplate(input_variables=["text"], template=refine_first_template)
refine_prompt = PromptTemplate(input_variables=["existing_answer", "text"],
                               template=refine_template)

refine_chain: BaseCombineDocumentsChain = load_summarize_chain(
    ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo-16k"),
    chain_type="refine",
    question_prompt=refine_first_prompt,
    refine_prompt=refine_prompt)

pdf_path = "sony.pdf"

# PDFローダーの定義
read_text = ''
with open(pdf_path, 'rb') as f:
    reader = PyPDF2.PdfReader(f, strict=False)
    for i in range(len(reader.pages)):
        page = reader.pages[i]
        read_text += page.extract_text()

# 指定したサイズでテキストを分割する
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=10000, chunk_overlap=1000
)
texts = text_splitter.split_text(read_text)

docs = [Document(page_content=t) for t in texts]
result = refine_chain.invoke({"input_documents": docs}, return_only_outputs=True)
print(result["output_text"])

参考

https://zenn.dev/seiyakitazume/articles/d4a11404320a07

https://zenn.dev/tsuzukia/articles/05bfdcfcf5bd68#refine法

https://note.com/npaka/n/nda9dc5eae1df