Upload 2 files
Browse files- app_indigo4GB.py +737 -0
- requirements.txt +20 -0
app_indigo4GB.py
ADDED
@@ -0,0 +1,737 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os, tempfile
|
2 |
+
import re
|
3 |
+
import json
|
4 |
+
from pathlib import Path
|
5 |
+
import streamlit as st
|
6 |
+
st.set_page_config(page_title="QA_AIボット+要約")
|
7 |
+
st.title("Q&A-AIボット & 資料要約\n Demo running on just 4Core CPU/4GB RAM")
|
8 |
+
st.text("【取扱説明書等をアップロードすればその文書に関する質問にAIが回答します。資料の要約もできます。】")
|
9 |
+
st.text("""※アップロードされたファイルはサーバーには保存されず、ブラウザを閉じるとバイナリデータも自動的に消去されます。""")
|
10 |
+
#import torch
|
11 |
+
from typing import Any, List
|
12 |
+
from datetime import datetime
|
13 |
+
|
14 |
+
from llama_index import (
|
15 |
+
download_loader,
|
16 |
+
VectorStoreIndex,
|
17 |
+
ServiceContext,
|
18 |
+
StorageContext,
|
19 |
+
SimpleDirectoryReader,
|
20 |
+
)
|
21 |
+
from llama_index.postprocessor import SentenceEmbeddingOptimizer
|
22 |
+
from llama_index.prompts.prompts import QuestionAnswerPrompt
|
23 |
+
from llama_index.readers import WikipediaReader, Document
|
24 |
+
|
25 |
+
from langchain_community.chat_models import ChatOllama
|
26 |
+
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
27 |
+
from langchain.callbacks.base import BaseCallbackHandler
|
28 |
+
from langchain_community.document_loaders import TextLoader
|
29 |
+
from langchain_text_splitters import CharacterTextSplitter
|
30 |
+
|
31 |
+
from pysummarization.nlpbase.auto_abstractor import AutoAbstractor
|
32 |
+
from pysummarization.tokenizabledoc.mecab_tokenizer import MeCabTokenizer
|
33 |
+
from pysummarization.abstractabledoc.top_n_rank_abstractor import TopNRankAbstractor
|
34 |
+
from pysummarization.abstractabledoc.std_abstractor import StdAbstractor
|
35 |
+
from pysummarization.nlp_base import NlpBase
|
36 |
+
from pysummarization.similarityfilter.tfidf_cosine import TfIdfCosine
|
37 |
+
#from pysummarization.similarityfilter.dice import Dice
|
38 |
+
|
39 |
+
if "messages" not in st.session_state:
|
40 |
+
st.session_state.messages = []
|
41 |
+
class StreamHandler(BaseCallbackHandler):
|
42 |
+
def __init__(self, initial_text="お調べしますので少々お待ち下さい。\n\n"):
|
43 |
+
self.initial_text = initial_text
|
44 |
+
self.text = initial_text
|
45 |
+
self.flag = True
|
46 |
+
def on_llm_start(self, *args: Any, **kwargs: Any):
|
47 |
+
self.text = self.initial_text
|
48 |
+
with st.chat_message("assistant"):
|
49 |
+
self.container = st.empty()
|
50 |
+
self.container.markdown(self.text+" "+" ")
|
51 |
+
print("LLM start: ",datetime.now())
|
52 |
+
def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
|
53 |
+
if self.flag == True:
|
54 |
+
print("Stream start: ",datetime.now())
|
55 |
+
self.flag = False
|
56 |
+
self.text += token
|
57 |
+
self.container.markdown(self.text)
|
58 |
+
def on_llm_end(self, *args: Any, **kwargs: Any) -> None:
|
59 |
+
st.session_state.messages.append({
|
60 |
+
"role": "assistant",
|
61 |
+
"content": self.text
|
62 |
+
})
|
63 |
+
print("LLM end: ",datetime.now())
|
64 |
+
|
65 |
+
from rake_ja import JapaneseRake
|
66 |
+
from rake_ja.tokenizer import Tokenizer
|
67 |
+
tok = Tokenizer()
|
68 |
+
ja_rake = JapaneseRake()
|
69 |
+
|
70 |
+
import chromadb
|
71 |
+
from llama_index.vector_stores import ChromaVectorStore
|
72 |
+
|
73 |
+
import wikipedia
|
74 |
+
class JaWikipediaReader(WikipediaReader):
|
75 |
+
def load_wiki(self, pages: List[str], **load_kwargs: Any) -> List[Document]:
|
76 |
+
"""Load data from the input directory.
|
77 |
+
Args:
|
78 |
+
pages (List[str]): List of pages to read.
|
79 |
+
"""
|
80 |
+
wikipedia.set_lang('ja')
|
81 |
+
results = []
|
82 |
+
for page in pages:
|
83 |
+
page_content = wikipedia.page(page, **load_kwargs).content
|
84 |
+
results.append(page_content)
|
85 |
+
return results
|
86 |
+
|
87 |
+
from duckduckgo_search import DDGS
|
88 |
+
maxsearch_results = 3
|
89 |
+
def search_general(input_text):
|
90 |
+
with DDGS() as ddgs:
|
91 |
+
results = [r for r in ddgs.text(f"{input_text}", region="jp-jp", timelimit="y", max_results=maxsearch_results, safesearch="off")]
|
92 |
+
print(results)
|
93 |
+
return results
|
94 |
+
|
95 |
+
STORAGE_DIR = "./storage/"
|
96 |
+
TEMP_DIR = "./temp_data/"
|
97 |
+
HISTORY_DIR = "./history/"
|
98 |
+
SUMMARY_DIR = "./summary/"
|
99 |
+
|
100 |
+
os.makedirs(STORAGE_DIR, exist_ok=True)
|
101 |
+
os.makedirs(TEMP_DIR, exist_ok=True)
|
102 |
+
os.makedirs(HISTORY_DIR, exist_ok=True)
|
103 |
+
os.makedirs(SUMMARY_DIR, exist_ok=True)
|
104 |
+
|
105 |
+
|
106 |
+
class PDFReader:
|
107 |
+
def __init__(self):
|
108 |
+
self.pdf_reader = download_loader("PDFReader", custom_path="local_dir")()
|
109 |
+
def load_data(self, file_name):
|
110 |
+
return self.pdf_reader.load_data(file=Path(file_name))
|
111 |
+
|
112 |
+
ollama_url = "http://localhost:11434"
|
113 |
+
ollama_remote = "https://ai.pib.co.jp"
|
114 |
+
llamacpp_url = "http://localhost:8000/v1"
|
115 |
+
LM_Studio_url = "http://localhost:1234/v1"
|
116 |
+
class QAResponseGenerator:
|
117 |
+
def __init__(self, selected_model, pdf_reader, device=None):
|
118 |
+
stream_handler = StreamHandler()
|
119 |
+
#self.llm = ChatOllama(base_url=ollama_remote, model=selected_model, streaming=True, callbacks=[stream_handler], verbose=True)
|
120 |
+
self.llm = ChatOllama(base_url=ollama_url, model=selected_model, streaming=True, callbacks=[stream_handler], verbose=True)
|
121 |
+
self.pdf_reader = pdf_reader
|
122 |
+
if selected_model == "llama3":
|
123 |
+
self.QA_PROMPT_TMPL = "<|begin_of_text|><|start_header_id|>system<|end_header_id|>\nあなたは日本人のコールセンター管理者です。次の質問に日本語で回答してください。<|eot_id|><|start_header_id|>user<|end_header_id|>\n{query_str}<|eot_id|><start_header_id|>assistant<|end_header_id|><|eot_id|>"
|
124 |
+
#self.QA_PROMPT_TMPL = "<|begin_of_text|><|start_header_id|>system<|end_header_id|>あなたは日本語で回答するAIアシスタントです。<|eot_id|><|start_header_id|>user<|end_header_id|>\n{query_str}<|eot_id|><start_header_id|>assistant<|end_header_id|><|eot_id|>"
|
125 |
+
if selected_model == "Elyza":
|
126 |
+
self.QA_PROMPT_TMPL =("""<s>[INST] <<SYS>>#あなたは誠実で優秀な日本人のコールセンター管理者です。<</SYS>>{query_str} [/INST]""")
|
127 |
+
#self.QA_PROMPT_TMPL =("""<s>[INST] <<SYS>>#あなたは誠実で優秀な日本人のアシスタントです。<</SYS>>{query_str} [/INST]""")
|
128 |
+
self.CHAT_REFINE_PROMPT_TMPL_MSGS = ("""<s>[INST] <<SYS>>
|
129 |
+
"あなたは、既存の回答を改良する際に2つのモードで厳密に動作するQAシステムのエキスパートです。\n"
|
130 |
+
"1. 新しいコンテキストを使用して元の回答を**書き直す**。\n"
|
131 |
+
"2. 新しいコンテキストが役に立たない場合は、元の回答を**繰り返す**。\n"
|
132 |
+
"回答内で元の回答やコンテキストを直接参照しないでください。\n"
|
133 |
+
"疑問がある場合は、元の答えを繰り返してください。"
|
134 |
+
"New Context: {context_msg}\n"
|
135 |
+
<</SYS>>
|
136 |
+
"Query: {query_str}\n"
|
137 |
+
"Original Answer: {existing_answer}\n"
|
138 |
+
"New Answer: "
|
139 |
+
[/INST]"""
|
140 |
+
)
|
141 |
+
if selected_model == "swallow":
|
142 |
+
self.QA_PROMPT_TMPL ='### 指示:{query_str}\n ### 応答:'
|
143 |
+
#self.QA_PROMPT_TMPL ="""
|
144 |
+
#以下の「コンテキスト情報」を元に、質問に回答してください。
|
145 |
+
# コンテキスト情報
|
146 |
+
#---------------------
|
147 |
+
#{context_str}
|
148 |
+
#---------------------
|
149 |
+
# 制約条件
|
150 |
+
#- コンテキスト情報に無い情報は絶対に回答に含めないでください。
|
151 |
+
#- コンテキスト情報の内容を丸投げするのではなく、ちゃんと文章にして回答してください。
|
152 |
+
#- 質問の答えを知らない場合は、回答しないで知らない事を伝えてください。\n\n### 指示:\n{query_str}\n\n### 応答:
|
153 |
+
#"""
|
154 |
+
if selected_model == "mist300":
|
155 |
+
###Mistral/Stability系
|
156 |
+
#self.QA_PROMPT_TMPL = "<s>[INST]あなたは優秀な日本人のコールセンター管理者です。次の質問に回答して下さい。[/INST]</s> [INST]{query_str}[/INST]"
|
157 |
+
#self.QA_PROMPT_TMPL = r'<s>\n以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n'
|
158 |
+
self.QA_PROMPT_TMPL = r'<s>\n以下は、タスクを説明する指示です。要求を適切に満たす応答を書きなさい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n応答:\n'
|
159 |
+
#self.QA_PROMPT_TMPL ='### 指示:{query_str}\n ### 応答:'
|
160 |
+
#self.QA_PROMPT_TMPL ='### 指示:{query_str}\n ### 入力:{context_str}\n ### 応答:'
|
161 |
+
#self.QA_PROMPT_TMPL ="""### 指示:あなたは優秀なコールセンター管理者です。参考文献を元に次の質問に回答して下さい。###質問:{query_str}\n ### 応答:"""
|
162 |
+
#self.QA_PROMPT_TMPL ="あなたは優秀な日本人のコールセンター管理者です。次の質問に日本語で回答してください。{query_str}"
|
163 |
+
if selected_model == "TinyLlama":
|
164 |
+
###Tinyllama
|
165 |
+
#querystr = "上給水ハイブリッド加湿器のお手入れの仕方を、日本語で教えて下さい。"
|
166 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
167 |
+
#system_message = "あなたは優秀な日本人のコールセンター管理者です。"
|
168 |
+
self.QA_PROMPT_TMPL = "<|system|>\nあなたは日本人です。</s>\n<|user|>\n{query_str}</s>\n<|assistant|>"
|
169 |
+
if selected_model == "tinycodellamajp":
|
170 |
+
self.QA_PROMPT_TMPL = "<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
171 |
+
if selected_model == "tinyllamamoe":
|
172 |
+
self.QA_PROMPT_TMPL = "<|システム|>\nあなたは日本人のコールセンターの管理者です。参考情報を元に、日本語で質問に回答してください。</s>\n<|ユーザー|>\n{query_str}</s>\n<|アシスタント|>"
|
173 |
+
#self.QA_PROMPT_TMPL = "<|system|>\nあなたは日本人のコールセンターの管理者です。次の情報を元に質問に回答してください。\n{context_str}</s>\n<|user|>\n{query_str}</s>\n<|assistant|>"
|
174 |
+
#self.QA_PROMPT_TMPL = "<|システム|>\nあなたは日本人です。</s>\n<|ユーザー|>\n{query_str}</s>\n<|アシスタント|>"
|
175 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
176 |
+
if selected_model == "phillama":
|
177 |
+
self.QA_PROMPT_TMPL = "<|system|>\nあなたは日本人のコールセンターの管理者です。参考情報を元に質問に日本語で回答してください。<|end|><|user|>{query_str}<|end|><|assistant|>"
|
178 |
+
if selected_model == "stabilty":
|
179 |
+
#self.QA_PROMPT_TMPL = "### 指示: {query_str} \n ### 応答:"
|
180 |
+
#self.QA_PROMPT_TMPL = r"""<s>\n以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n"""
|
181 |
+
|
182 |
+
self.QA_PROMPT_TMPL = r"""<s>\nあなたは優秀なコールセンター管理者です。参考文献を元に次の質問に回答して下さい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n"""
|
183 |
+
#self.QA_PROMPT_TMPL = r"""<s>\nあなたは優秀なコールセンター管理者です。参考文献を元に次の質問に回答して下さい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n応答:\n"""
|
184 |
+
#self.QA_PROMPT_TMPL = r'<s>\n以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n'
|
185 |
+
if selected_model == "stabilq4":
|
186 |
+
#self.QA_PROMPT_TMPL = r"""<s>\nあなたは優秀なコールセンター管理者です。入力情報を元に次の質問に回答して下さい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n"""
|
187 |
+
self.QA_PROMPT_TMPL = """以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。
|
188 |
+
|
189 |
+
### 指示:
|
190 |
+
{query_str}
|
191 |
+
|
192 |
+
### 入力:
|
193 |
+
{context_str}
|
194 |
+
|
195 |
+
### 応答:
|
196 |
+
"""
|
197 |
+
if selected_model == "stabilq3":
|
198 |
+
#self.QA_PROMPT_TMPL = """以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。
|
199 |
+
|
200 |
+
### 指示:
|
201 |
+
#{query_str}
|
202 |
+
|
203 |
+
### 入力:
|
204 |
+
#{context_str}
|
205 |
+
|
206 |
+
### 応答:
|
207 |
+
#"""
|
208 |
+
self.QA_PROMPT_TMPL = '### 指示:{query_str}\n### 応答:'
|
209 |
+
#self.QA_PROMPT_TMPL = r"""<s>\nあなたは優秀なコールセンター管理者です。次の入力情報を元に指示に応答して下さい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n"""
|
210 |
+
#self.QA_PROMPT_TMPL = 'ユーザー: {query_str} システム: '
|
211 |
+
#self.QA_PROMPT_TMPL = """<|ユーザ|>{query_str}<|endoftext|> <|アシスタント|><|endoftext|>"""
|
212 |
+
#self.QA_PROMPT_TMPL = r"""
|
213 |
+
#<|system|>あなたは優秀なコールセンター管理者です。参考情報を元に質問に回答して下さい。<|endoftext|>
|
214 |
+
|
215 |
+
#<|user|>{query_str}<|endoftext|>
|
216 |
+
|
217 |
+
#<|assistant|>
|
218 |
+
#"""
|
219 |
+
if selected_model == "stabilzephyr":
|
220 |
+
#self.QA_PROMPT_TMPL = """<|ユーザ|>{query_str}<|endoftext|> <|アシスタント|><|endoftext|>"""
|
221 |
+
#self.QA_PROMPT_TMPL = """<|システム|>あなたは優秀なコールセンター管理者です。参考情報を元に質問に回答して下さい。<|endoftext|><|ユーザ|>{query_str}<|endoftext|><|アシスタント|> <|endoftext|>"""
|
222 |
+
#self.QA_PROMPT_TMPL = """<|ユーザ|>{query_str}<|endoftext|> <|アシスタント|>"""
|
223 |
+
#self.QA_PROMPT_TMPL = """<|ユーザ|>{query_str}<|endoftext|> <|アシスタント|><|endoftext|>"""
|
224 |
+
self.QA_PROMPT_TMPL = """
|
225 |
+
<|system|>あなたは優秀なコールセンター管理者です。参考情報を元に質問に回答して下さい。<|endoftext|>
|
226 |
+
|
227 |
+
<|user|>{query_str}<|endoftext|>
|
228 |
+
|
229 |
+
<|assistant|>
|
230 |
+
"""
|
231 |
+
#self.QA_PROMPT_TMPL = r"""
|
232 |
+
#<|system|>あなたは優秀なコールセンター管理者です。次の参考情報を元に質問に回答して下さい。{context_str}<|endoftext|>
|
233 |
+
|
234 |
+
#<|user|>{query_str}<|endoftext|>
|
235 |
+
|
236 |
+
#<|assistant|>
|
237 |
+
#"""
|
238 |
+
#self.QA_PROMPT_TMPL = """以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を書きなさい。
|
239 |
+
|
240 |
+
### 指示:
|
241 |
+
#{query_str}
|
242 |
+
|
243 |
+
### 入力:
|
244 |
+
#{context_str}
|
245 |
+
|
246 |
+
### 応答:
|
247 |
+
#"""
|
248 |
+
if selected_model == "stabil2instruct":
|
249 |
+
#self.QA_PROMPT_TMPL = """<|ユーザ|>{query_str}<|endoftext|> <|アシスタント|><|endoftext|>"""
|
250 |
+
self.QA_PROMPT_TMPL = r"""
|
251 |
+
<|system|>あなたは役立つアシスタントです。<|endoftext|>
|
252 |
+
|
253 |
+
<|user|>{query_str}<|endoftext|>
|
254 |
+
|
255 |
+
<|assistant|>
|
256 |
+
"""
|
257 |
+
#self.QA_PROMPT_TMPL = r"""
|
258 |
+
#<|system|>あなたは優秀なコールセンター管理者です。次の参考情報を元に質問に回答して下さい。{context_str}<|endoftext|>
|
259 |
+
|
260 |
+
#<|user|>{query_str}<|endoftext|>
|
261 |
+
|
262 |
+
#<|assistant|>
|
263 |
+
#"""
|
264 |
+
if selected_model == "h2o":
|
265 |
+
#self.QA_PROMPT_TMPL = 'ユーザー: {query_str} システム: '
|
266 |
+
self.QA_PROMPT_TMPL = "<|im_start|>システム\nあなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さい\n{context_str}<|im_end|>\n<|im_start|>ユーザー\n{query_str}<|im_end|>\n<|im_start|>アシスタント\n"
|
267 |
+
if selected_model == "phi2":
|
268 |
+
#self.QA_PROMPT_TMPL = """
|
269 |
+
# <|im_start|>システム
|
270 |
+
# あなたは日本人の優秀なコールセンター管理者です。
|
271 |
+
# <|im_end|>
|
272 |
+
# <|im_start|>ユーザー
|
273 |
+
# {query_str}
|
274 |
+
# <|im_end|>
|
275 |
+
# <|im_start|>アシスタント
|
276 |
+
#"""
|
277 |
+
self.QA_PROMPT_TMPL = "<|im_start|>システム\nあなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さい\n{context_str}<|im_end|>\n<|im_start|>ユーザー\n{query_str}<|im_end|>\n<|im_start|>アシスタント\n"
|
278 |
+
if selected_model == "phi3":
|
279 |
+
#self.QA_PROMPT_TMPL = "<|user|>\n{query_str}<|end|>\n<|assistant|>"
|
280 |
+
self.QA_PROMPT_TMPL = "<|system|>\nあなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さい\n{context_str}<|end|>\n<|user|>\n{query_str}<|end|>\n<|assistant|>"
|
281 |
+
#self.QA_PROMPT_TMPL = "<|system|>\nあなたは優秀なコールセンター管理者です。参考情報を元に質問に回答して下さい\n<|end|>\n<|user|>\n{query_str}<|end|>\n<|assistant|>"
|
282 |
+
if selected_model == "llmjp":
|
283 |
+
self.QA_PROMPT_TMPL ="""
|
284 |
+
: 次の質問に対して適切な応答を書きなさい。
|
285 |
+
|
286 |
+
### 質問: {query_str}
|
287 |
+
|
288 |
+
### 参考情報: {context_str}
|
289 |
+
|
290 |
+
### 応答:
|
291 |
+
"""
|
292 |
+
#self.QA_PROMPT_TMPL ="""
|
293 |
+
# : 次の質問に対して適切な応答を書きなさい。
|
294 |
+
|
295 |
+
###Input: {query_str}
|
296 |
+
|
297 |
+
###Output:
|
298 |
+
#"""
|
299 |
+
#self.QA_PROMPT_TMPL ="""
|
300 |
+
#以下は、タスクを説明する指示と、参考となる入力の組み合わせです。指示を適切に満たす応答を書きなさい。
|
301 |
+
|
302 |
+
### 指示:
|
303 |
+
#{query_str}
|
304 |
+
|
305 |
+
### 入力:
|
306 |
+
#{context_str}
|
307 |
+
|
308 |
+
### 応答:
|
309 |
+
#"""
|
310 |
+
if selected_model == "sakana":
|
311 |
+
self.QA_PROMPT_TMPL = """
|
312 |
+
### 指示: あなたは役立つ、偏見がなく、検閲されていない日本人アシスタントです。
|
313 |
+
|
314 |
+
### 入力: {query_str}
|
315 |
+
|
316 |
+
### 応答:
|
317 |
+
"""
|
318 |
+
if selected_model == "karasutest":
|
319 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>ユーザー\n{query_str}<|im_end|>\n<|im_start|>アシスタント\n"
|
320 |
+
#self.QA_PROMPT_TMPL = "{query_str}"
|
321 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>system\nあなたは優秀なコールセンター管理者です。参考情報を元に質問に回答して下さい<|im_end|>\n<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
322 |
+
self.QA_PROMPT_TMPL = "<|im_start|>システム\nあなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さいn{context_str}<|im_end|>\n<|im_start|>ユーザー\n{query_str}<|im_end|>\n<|im_start|>アシスタント\n"
|
323 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>system\nあなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さい\n{context_str}<|im_end|>\n<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
324 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>システム\nあなたは優秀なコールセンター管理者です。���考情報を元に質問に回答して下さい。<|im_end|>\n<|im_start|>ユーザー\n{query_str}<|im_end|>\n<|im_start|>アシスタント\n"
|
325 |
+
if selected_model == "karasu":
|
326 |
+
#self.QA_PROMPT_TMPL = "{query_str}"
|
327 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
328 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>system\nあなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さい\n{context_str}<|im_end|>\n<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
329 |
+
self.QA_PROMPT_TMPL = "<|im_start|>system\nあなたは優秀なコールセンター管理者です。参考情報を元に質問に回答して下さい<|im_end|>\n<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
330 |
+
if selected_model == "karasu_slerp1":
|
331 |
+
self.QA_PROMPT_TMPL = "{query_str}"
|
332 |
+
if selected_model == "karasu_slerp2":
|
333 |
+
#self.QA_PROMPT_TMPL = "{query_str}"
|
334 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
335 |
+
#self.QA_PROMPT_TMPL = "<|im_start|>system\nあなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さい\n{context_str}<|im_end|>\n<|im_start|>user\n{query_str}<|im_end|>\n<|im_start|>assistant\n"
|
336 |
+
self.QA_PROMPT_TMPL = """
|
337 |
+
<|im_start|>system
|
338 |
+
あなたは優秀なコールセンター管理者です。次の情報を元に質問に回答して下さい
|
339 |
+
{context_str}<|im_end|>
|
340 |
+
<|im_start|>user
|
341 |
+
{query_str}<|im_end|>
|
342 |
+
<|im_start|>assistant
|
343 |
+
"""
|
344 |
+
if selected_model == "suzume":
|
345 |
+
#self.QA_PROMPT_TMPL = "あなたは優秀なコールセンター管理者です。\n{query_str}"
|
346 |
+
self.QA_PROMPT_TMPL = "{query_str}"
|
347 |
+
if selected_model == "line":
|
348 |
+
self.QA_PROMPT_TMPL = 'ユーザー: {query_str} システム: '
|
349 |
+
if selected_model == "mist-merge":
|
350 |
+
self.QA_PROMPT_TMPL = r"""<s>\nあなたは優秀なコールセンター管理者です。参考文献を元に次の質問に回答して下さい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n"""
|
351 |
+
#self.QA_PROMPT_TMPL ='### 指示:{query_str}\n ### 応答:'
|
352 |
+
if selected_model == "rinna1":
|
353 |
+
self.QA_PROMPT_TMPL = r"""<s>\nあなたは優秀なコールセンター管理者です。参考文献を元に次の質問に回答して下さい。\n[SEP]\n指示:\n{query_str}\n[SEP]\n入力:\n{context_str}\n[SEP]\n応答:\n"""
|
354 |
+
#self.QA_PROMPT_TMPL ='### 指示:{query_str}\n ### 応答:'
|
355 |
+
if selected_model == "stockmark":
|
356 |
+
#self.QA_PROMPT_TMPL ='{query_str}\n'
|
357 |
+
self.QA_PROMPT_TMPL ="""
|
358 |
+
#「コンテキスト情報」を元に、質問に回答してください。
|
359 |
+
|
360 |
+
###質問:{query_str}
|
361 |
+
|
362 |
+
###「コンテキスト情報」:{context_str}
|
363 |
+
|
364 |
+
###回答:
|
365 |
+
"""
|
366 |
+
if selected_model == "rinna":
|
367 |
+
self.QA_PROMPT_TMPL ='ユーザー: {query_str} システム: '
|
368 |
+
#self.QA_PROMPT_TMPL ="""
|
369 |
+
#「コンテキスト情報」を元に、質問に回答してください。
|
370 |
+
|
371 |
+
###質問:{query_str}
|
372 |
+
|
373 |
+
###「コンテキスト情報」:{context_str}
|
374 |
+
|
375 |
+
###回答:
|
376 |
+
#"""
|
377 |
+
if device is None:
|
378 |
+
#device = "mps" if torch.backends.mps.is_available() else "cpu" #cubaをmpsに変更
|
379 |
+
device = "cpu"
|
380 |
+
#self.device = torch.device(device)
|
381 |
+
self.device = "cpu"
|
382 |
+
#print("torch.device,device:",torch.device(device),device)
|
383 |
+
self.embed_model = HuggingFaceEmbeddings(model_name="cheonboy/sentence_embedding_japanese", model_kwargs={"device": self.device})
|
384 |
+
#self.embed_model = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-base", model_kwargs={"device": self.device})
|
385 |
+
self.service_context = ServiceContext.from_defaults(llm=self.llm, embed_model=self.embed_model)
|
386 |
+
|
387 |
+
def generate(self, question, file_name, uploaded_file, maxsearch_results):
|
388 |
+
#質問文からキーワドを抽出
|
389 |
+
print(question)
|
390 |
+
text = question
|
391 |
+
#import re
|
392 |
+
#keywords = re.split('[のはがをとに]', text)
|
393 |
+
#exclude_kyw = ""
|
394 |
+
tokens = tok.tokenize(text)
|
395 |
+
ja_rake.extract_keywords_from_text(tokens)
|
396 |
+
ranked_phrases = ja_rake.get_ranked_phrases_with_scores()
|
397 |
+
print("ranked_phrases: ", ranked_phrases)
|
398 |
+
keyphrases = [x[0] for x in ranked_phrases], [x[1] for x in ranked_phrases]
|
399 |
+
keywords = [x[1] for x in ranked_phrases]
|
400 |
+
print("keyphrases: ", keyphrases, "keyphrases[0]: ", keyphrases[0])
|
401 |
+
print("keypwords: ", keywords)
|
402 |
+
|
403 |
+
#PDF検索処理
|
404 |
+
try:
|
405 |
+
db2 = chromadb.PersistentClient(path="./chroma_db")
|
406 |
+
chroma_collection = db2.get_collection(file_name)
|
407 |
+
print("chroma collection count: ",chroma_collection.count())
|
408 |
+
|
409 |
+
#chroma_st_conn =
|
410 |
+
|
411 |
+
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
|
412 |
+
pdf_index = VectorStoreIndex.from_vector_store(
|
413 |
+
vector_store,
|
414 |
+
service_context=self.service_context,
|
415 |
+
)
|
416 |
+
print("load existing file..")
|
417 |
+
except: #FileNotFoundError
|
418 |
+
print("loaddata from pdf file")
|
419 |
+
pdf_documents = self.pdf_reader.load_data(file_name)
|
420 |
+
#print("pdf_doc:", pdf_documents)
|
421 |
+
db = chromadb.PersistentClient(path="./chroma_db")
|
422 |
+
chroma_collection = db.get_or_create_collection(
|
423 |
+
name=uploaded_file.name,
|
424 |
+
metadata={"hnsw:space": "cosine"}
|
425 |
+
)
|
426 |
+
print("chroma collection count: ",chroma_collection.count())
|
427 |
+
vector_store = ChromaVectorStore(
|
428 |
+
chroma_collection=chroma_collection,
|
429 |
+
)
|
430 |
+
storage_context = StorageContext.from_defaults(vector_store=vector_store)
|
431 |
+
pdf_index = VectorStoreIndex.from_documents(
|
432 |
+
pdf_documents, storage_context=storage_context, service_context=self.service_context
|
433 |
+
)
|
434 |
+
print("save new file..")
|
435 |
+
#chat履歴をIndexに追加 sourceが書き変わってしまうのでsourceを削除
|
436 |
+
#history_docs = SimpleDirectoryReader("./history").load_data()
|
437 |
+
#for d in history_docs:
|
438 |
+
# pdf_index.insert(document = d, service_context = self.service_context)
|
439 |
+
#summaryをIndexに追加
|
440 |
+
#summary_docs = SimpleDirectoryReader(f"./summary/{file_name[:file_name.find('.')]}").load_data()
|
441 |
+
#summary_docs = SimpleDirectoryReader(
|
442 |
+
# input_files=[
|
443 |
+
# "./summary/"+str(file_name)[:file_name.find('.')]+"_summary1.txt",
|
444 |
+
# "./summary/"+str(file_name)[:file_name.find('.')]+"_summary2.txt"
|
445 |
+
# ]
|
446 |
+
#)
|
447 |
+
#summary_docs = SimpleDirectoryReader("./summary").load_data()
|
448 |
+
#print(type(summary_docs), summary_docs)
|
449 |
+
#for d in summary_docs:
|
450 |
+
# pdf_index.insert(document = d, service_context = self.service_context)
|
451 |
+
#pdf_index.insert(document = summary_docs, service_context = self.service_context)
|
452 |
+
pdf_engine = pdf_index.as_query_engine(
|
453 |
+
similarity_top_k=2,
|
454 |
+
text_qa_template=QuestionAnswerPrompt(self.QA_PROMPT_TMPL),
|
455 |
+
required_keywords= keywords[0] if keyphrases[0][0] > 0.5 else "",
|
456 |
+
#required_keywords=[keywords[0]]
|
457 |
+
#required_keywords=[keywords],
|
458 |
+
node_postprocessors=[SentenceEmbeddingOptimizer(embed_model=self.service_context.embed_model, threshold_cutoff=0.4)],
|
459 |
+
#node_postprocessors=[SentenceEmbeddingOptimizer(embed_model=self.service_context.embed_model,percentile_cutoff=0.9)],
|
460 |
+
#streaming=True,
|
461 |
+
)
|
462 |
+
try:
|
463 |
+
pdf_result = pdf_engine.query(question)
|
464 |
+
#pdf_result.print_response_stream()
|
465 |
+
print("Num of nodes:",len(pdf_result.source_nodes))
|
466 |
+
if len(pdf_result.source_nodes) == 1:
|
467 |
+
print("source_nodes.SCORE: ", pdf_result.source_nodes[0].score)
|
468 |
+
else:
|
469 |
+
print("source_nodes.SCORE: ", pdf_result.source_nodes[0].score, pdf_result.source_nodes[1].score)
|
470 |
+
#return pdf_result.response, pdf_result.get_formatted_sources(1000)
|
471 |
+
#match = re.findall('[1-9]+'+'.', pdf_result.response)
|
472 |
+
#print(pdf_result.response.replace(match, "\n"+match))
|
473 |
+
#return pdf_result.response.replace("\n", " "+" \n"), pdf_result.source_nodes[0].text.strip().replace(" ", "")
|
474 |
+
|
475 |
+
print("count before", chroma_collection.count())
|
476 |
+
doc_to_update = chroma_collection.get() #(limit=10)
|
477 |
+
chroma_collection.delete(ids=[id for id in doc_to_update["ids"]])
|
478 |
+
|
479 |
+
#print("count after", chroma_collection.count())
|
480 |
+
return pdf_result.response, pdf_result.source_nodes[0].text.strip().replace(" ", "")
|
481 |
+
#return re.sub("[1-9]+.", "\n[1-9]+.", pdf_result.response).replace("。", "。\n"), pdf_result.source_nodes[0].text.strip().replace(" ", "")
|
482 |
+
except ValueError as e:
|
483 |
+
print("PDF Error: ",e)
|
484 |
+
#st.session_state["chat_history"].append({"assistant": "所定のドキュメンには適切な情報が無いため、ネット検索で回答します(あくまで参考情報ですので、ご自身での確認をお勧めします)。"})
|
485 |
+
#st.write["chat_history"].append({"assistant": "所定のドキュメンには適切な情報が無いため、ネット検索で回答します(あくまで参考情報ですので、ご自身での確認をお勧めします)。"})
|
486 |
+
#検索前処理
|
487 |
+
count = len(keywords)
|
488 |
+
search_words = ""
|
489 |
+
for index in range(count): #最初と最後のワードを除く(製品名と製品番号があるとベター)
|
490 |
+
search_words += " " + keywords[index]
|
491 |
+
print("serch_words: ",search_words)
|
492 |
+
try:
|
493 |
+
#Wikipedia
|
494 |
+
wikidocuments = JaWikipediaReader().load_wiki(pages=[search_words])
|
495 |
+
strwikidocuments = "".join(map(str, wikidocuments))
|
496 |
+
#print("Wiki Contents: ",strwikidocuments)
|
497 |
+
with open("./temp_data/wiki/wikisearch.txt", "w") as fp:
|
498 |
+
fp.write(strwikidocuments)
|
499 |
+
wiki_documents = SimpleDirectoryReader("./temp_data//wiki").load_data()
|
500 |
+
wiki_index = VectorStoreIndex.from_documents(wiki_documents, service_context=self.service_context)
|
501 |
+
wiki_index.storage_context.persist(persist_dir=f"{STORAGE_DIR}"+"wikisearch.txt")
|
502 |
+
wiki_engine = wiki_index.as_query_engine(
|
503 |
+
similarity_top_k=2,
|
504 |
+
#text_qa_template=QuestionAnswerPrompt(self.QA_PROMPT_TMPL),
|
505 |
+
refine_template=QuestionAnswerPrompt(self.CHAT_REFINE_PROMPT_TMPL_MSGS),
|
506 |
+
#required_keywords=[keywords[0],keywords[1]],
|
507 |
+
#required_keywords=[search_words],
|
508 |
+
#exclude_keywords=[exclude_kyw],
|
509 |
+
#streaming=True,
|
510 |
+
)
|
511 |
+
#extend_answer(st.session_state["chat_history"])
|
512 |
+
wiki_result = wiki_engine.query(question)
|
513 |
+
#return wiki_result.print_response_stream, wiki_result.get_formatted_sources(1000)
|
514 |
+
return wiki_result.response, wiki_result.get_formatted_sources(1000)
|
515 |
+
except Exception as e:
|
516 |
+
#st.error(f"Error: {e}")
|
517 |
+
print("Wiki Error: ",e)
|
518 |
+
#Duck Search
|
519 |
+
try:
|
520 |
+
search_results = search_general(search_words)
|
521 |
+
#search_results = search_general(keywords[1])
|
522 |
+
#search_results = search_general(question)
|
523 |
+
with open("./temp_data/duck/ducksearch.txt", "w") as fp:
|
524 |
+
contents = ""
|
525 |
+
for index in range(maxsearch_results):
|
526 |
+
contents += json.dumps(search_results[index]).encode().decode('unicode-escape')
|
527 |
+
fp.write(contents)
|
528 |
+
web_documents = SimpleDirectoryReader("./temp_data/duck").load_data()
|
529 |
+
web_index = VectorStoreIndex.from_documents(web_documents, service_context=self.service_context)
|
530 |
+
web_index.storage_context.persist(persist_dir=f"{STORAGE_DIR}"+"ducksearch.txt")
|
531 |
+
web_engine = web_index.as_query_engine(
|
532 |
+
similarity_top_k=3,
|
533 |
+
#text_qa_template=QuestionAnswerPrompt(self.QA_PROMPT_TMPL),
|
534 |
+
refine_template=QuestionAnswerPrompt(self.CHAT_REFINE_PROMPT_TMPL_MSGS),
|
535 |
+
required_keywords=[search_words],
|
536 |
+
#required_keywords=[keywords[0],keywords[1],keywords[2]],
|
537 |
+
#exclude_keywords=[exclude_kyw],
|
538 |
+
#streaming=True,
|
539 |
+
)
|
540 |
+
#extend_answer(st.session_state["chat_history"])
|
541 |
+
web_result = web_engine.query(question)
|
542 |
+
#return web_result.print_response_stream, web_result.get_formatted_sources(1000)
|
543 |
+
return web_result.response, web_result.get_formatted_sources(1000)
|
544 |
+
except Exception as e:
|
545 |
+
#st.error(f"Error: {e}")
|
546 |
+
print("Duck Error: ",e)
|
547 |
+
#ここにWiki検索を追加する
|
548 |
+
return "現在Web検索が停止中。", "Wikipediaの検索結果で代替えします。"
|
549 |
+
|
550 |
+
def save_uploaded_file(uploaded_file, save_dir):
|
551 |
+
try:
|
552 |
+
with open(os.path.join(save_dir, uploaded_file.name), "wb") as f:
|
553 |
+
f.write(uploaded_file.getvalue())
|
554 |
+
return True
|
555 |
+
except Exception as e:
|
556 |
+
st.error(f"Error: {e}")
|
557 |
+
return False
|
558 |
+
|
559 |
+
def upload_pdf_file():
|
560 |
+
uploaded_file = st.sidebar.file_uploader("ファイルアップロード", type=["pdf", "txt"])
|
561 |
+
print("uploaded_file",uploaded_file)
|
562 |
+
if uploaded_file is not None:
|
563 |
+
st.success(f"ファイル {uploaded_file.name} のアップロードが完了しました.")
|
564 |
+
return uploaded_file
|
565 |
+
# if uploaded_file.type == "application/pdf" and save_uploaded_file(uploaded_file, PDF_DATA_DIR):
|
566 |
+
# st.success(f"ファイル {uploaded_file.name} は {PDF_DATA_DIR}に保存されました.")
|
567 |
+
# elif uploaded_file.type == "text/plain" and save_uploaded_file(uploaded_file, TXT_DATA_DIR):
|
568 |
+
# st.success(f"ファイル {uploaded_file.name} は {TXT_DATA_DIR}に保存されました.")
|
569 |
+
# else:
|
570 |
+
# st.error("このファイルは保存できません.")
|
571 |
+
|
572 |
+
def main():
|
573 |
+
#st.title('PDF Q&A app')
|
574 |
+
#file_list = []
|
575 |
+
#for file in os.listdir(PDF_DATA_DIR):
|
576 |
+
# if file.endswith(".pdf") and not file.startswith("._"):
|
577 |
+
# file_list.append(file)
|
578 |
+
#for file in os.listdir(TXT_DATA_DIR):
|
579 |
+
# if file.endswith(".txt") and not file.startswith("._"):
|
580 |
+
# file_list.append(file)
|
581 |
+
#file_name = st.sidebar.selectbox("ファイルの選択", file_list)
|
582 |
+
#if uploaded_file is not None:
|
583 |
+
# file_name = uploaded_file.name
|
584 |
+
# print("file_name",file_name)
|
585 |
+
pdf_reader = PDFReader()
|
586 |
+
|
587 |
+
#uploaded_file = upload_pdf_file()
|
588 |
+
uploaded_file = st.sidebar.file_uploader("ファイルアップロード", type=["pdf", "txt"])
|
589 |
+
if uploaded_file is not None:
|
590 |
+
st.sidebar.success(f"{uploaded_file.name} のアップロード完了")
|
591 |
+
with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
|
592 |
+
tmp_file.write(uploaded_file.read())
|
593 |
+
#selected_model = st.sidebar.selectbox("生成AIモデルの選択", ["phillama", "llama3", "line", "llmjp", "mist300", "TinyLlama", "stabilty", "stabilq4", "stabilq3", "Elyza", "swallow", "sakana", "karasu", "karasu_slerp1", "karasu_slerp2", "karasutest", "tinycodellamajp", "stockmark", "stabilzephyr", "h2o", "rinna", "phi2", "phi3", "suzume"])
|
594 |
+
selected_model = st.sidebar.selectbox("生成AIモデルの選択", ["標準", "次候補", "試行版", "llmjp"])
|
595 |
+
|
596 |
+
if selected_model == "標準":
|
597 |
+
selected_model = "line"
|
598 |
+
elif selected_model == "次候補":
|
599 |
+
selected_model = "karasu_slerp2" #"stabil2instruct"
|
600 |
+
elif selected_model == "試行版":
|
601 |
+
selected_model = "mist300" #"tinycodellamajp","karasu"
|
602 |
+
elif selected_model == "llmjp":
|
603 |
+
selected_model = "llmjp"
|
604 |
+
|
605 |
+
choice = st.radio("参照情報を表示:", ["表示する", "表示しない"])
|
606 |
+
question = st.text_input("質問入力")
|
607 |
+
response_generator = QAResponseGenerator(selected_model, pdf_reader)
|
608 |
+
|
609 |
+
# メインの画面に質問送信ボタンを設定
|
610 |
+
submit_question = st.button("質問")
|
611 |
+
clear_chat = st.sidebar.button("履歴消去")
|
612 |
+
st.session_state.last_updated = ""
|
613 |
+
st.session_state.last_updated_json = []
|
614 |
+
|
615 |
+
# チャット履歴を保存
|
616 |
+
if "chat_history" not in st.session_state:
|
617 |
+
st.session_state["chat_history"] = []
|
618 |
+
|
619 |
+
if clear_chat:
|
620 |
+
st.session_state["chat_history"] = []
|
621 |
+
st.session_state.last_updated = ""
|
622 |
+
st.session_state.last_updated_json = []
|
623 |
+
|
624 |
+
# 質問ボタンがクリックされた場合の処理
|
625 |
+
if submit_question:
|
626 |
+
print("pushed question button!")
|
627 |
+
if question: # 質問が入力されている場合
|
628 |
+
#response, source = response_generator.generate(question, file.name, maxsearch_results)
|
629 |
+
response, source = response_generator.generate(question, tmp_file.name, uploaded_file, maxsearch_results)
|
630 |
+
#response = re.sub("[1-9]"+".", "\n[1-9]"+".", response).replace("。", "。\n")
|
631 |
+
# 質問と応答をチャット履歴に追加
|
632 |
+
#response = response.replace("\n", " "+" \n")
|
633 |
+
st.session_state["chat_history"].append({"user": question})
|
634 |
+
st.session_state["chat_history"].append({"assistant": response})
|
635 |
+
if choice == "表示する":
|
636 |
+
source = source.replace("page_label", "該当ページ番号").replace("file_name", " ファイル名:"+uploaded_file.name)
|
637 |
+
response = f"\n\n参照した情報は次の通りです:\n\n{source}"
|
638 |
+
#st.session_state["chat_history"].append({"assistant": response})
|
639 |
+
#stored_response += f"\n\n参照した情報は次の通りです:\n\n{source}"
|
640 |
+
with st.chat_message("assistant"): #参照情報の表示
|
641 |
+
st.markdown(response)
|
642 |
+
#st.session_state.last_updated += json.dumps(st.session_state["chat_history"],indent=2, ensure_ascii=False).replace("]", ",\n{")+re.sub(r"\s", "", f"""\"source\":\"{source}\""""+"\n}\n]")
|
643 |
+
st.session_state.last_updated += json.dumps(st.session_state["chat_history"],indent=2, ensure_ascii=False)
|
644 |
+
with open("./history/chat_history.txt","w") as o:
|
645 |
+
print(st.session_state.last_updated,sep="",file=o)
|
646 |
+
with open("./history/chat_history.txt", "r") as f:
|
647 |
+
history_str = f.read()
|
648 |
+
history_json = json.loads(history_str)
|
649 |
+
#print(history_json)
|
650 |
+
with open("./history/chat_history.json", "w") as o:
|
651 |
+
json.dump(history_json, o, ensure_ascii=False)
|
652 |
+
|
653 |
+
elif st.button("要約開始"):
|
654 |
+
stream_handler = StreamHandler()
|
655 |
+
try:
|
656 |
+
with st.spinner('要約中...'):
|
657 |
+
#print("file_name",file_name)
|
658 |
+
if uploaded_file.name.endswith(".pdf"):
|
659 |
+
pdf_reader = download_loader("PDFReader", custom_path="local_dir")()
|
660 |
+
#docs = pdf_reader.load_data(file=PDF_DATA_DIR+file_name)
|
661 |
+
docs = pdf_reader.load_data(file=tmp_file.name)
|
662 |
+
alltext = ""
|
663 |
+
all_count = len(docs)
|
664 |
+
for count in range(all_count):
|
665 |
+
text = docs[count].text
|
666 |
+
alltext += text
|
667 |
+
#print("全文字数:",len(alltext))
|
668 |
+
elif uploaded_file.name.endswith(".txt"):
|
669 |
+
#loader = TextLoader(TXT_DATA_DIR+file_name)
|
670 |
+
loader = TextLoader(tmp_file.name)
|
671 |
+
documents = loader.load()
|
672 |
+
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
|
673 |
+
docs = text_splitter.split_documents(documents)
|
674 |
+
allcount = len(docs)
|
675 |
+
alltext = ""
|
676 |
+
for n in range(allcount):
|
677 |
+
text = docs[n].page_content
|
678 |
+
alltext += text
|
679 |
+
#print("alltext:",alltext)
|
680 |
+
#Summarize By pysummarization
|
681 |
+
auto_abstractor = AutoAbstractor()
|
682 |
+
auto_abstractor.tokenizable_doc = MeCabTokenizer()
|
683 |
+
auto_abstractor.delimiter_list = ["。", "\n"]
|
684 |
+
abstractable_doc = StdAbstractor()
|
685 |
+
result_dict = auto_abstractor.summarize(alltext, abstractable_doc)
|
686 |
+
summary1 = "Original word count(原文文字数): "+str(len(alltext))+"\n\n"
|
687 |
+
for x in result_dict["summarize_result"]:
|
688 |
+
summary1 += x+"\n"
|
689 |
+
summary1 = summary1+"\nNormal Summary word count(標準要約文字数): "+str(len(summary1))+" compression ratio(圧縮率): "+'{:.0%}'.format(len(summary1)/len(alltext))
|
690 |
+
similarity_limit = 0.8 #@param {type:"slider", min:0.05, max:0.5, step:0.05}
|
691 |
+
nlp_base = NlpBase()
|
692 |
+
nlp_base.tokenizable_doc = MeCabTokenizer()
|
693 |
+
similarity_filter = TfIdfCosine() #Cosine類似度
|
694 |
+
#similarity_filter = Jaccard()
|
695 |
+
#similarity_filter = Dice()
|
696 |
+
#similarity_filter = Simpson()
|
697 |
+
similarity_filter.nlp_base = nlp_base
|
698 |
+
similarity_filter.similarity_limit = similarity_limit
|
699 |
+
result_dict2 = auto_abstractor.summarize(alltext, abstractable_doc, similarity_filter)
|
700 |
+
summary2 = ''
|
701 |
+
for sentence in result_dict2["summarize_result"]:
|
702 |
+
summary2 += sentence+"\n"
|
703 |
+
summary2 = summary2+"\nFiltered Summary word count(フィルタ要約文字数): "+str(len(summary2))+" compression ratio(圧縮率): "+'{:.0%}'.format(len(summary2)/len(alltext))
|
704 |
+
auto_abstractor = AutoAbstractor()
|
705 |
+
auto_abstractor.tokenizable_doc = MeCabTokenizer()
|
706 |
+
auto_abstractor.delimiter_list = ["。", "\n"]
|
707 |
+
abstractable_doc = TopNRankAbstractor()
|
708 |
+
result_dict = auto_abstractor.summarize(alltext, abstractable_doc)
|
709 |
+
summary3 = ''
|
710 |
+
for x in result_dict["summarize_result"]:
|
711 |
+
summary3 += x+"\n"
|
712 |
+
summary3 = summary3+"\nTopNRank word count(トップNランク要約文字数): "+str(len(summary3))+" compression ratio(圧縮率): "+'{:.0%}'.format(len(summary3)/len(alltext))
|
713 |
+
#print("TopNrank_Sum文字数: ", len(summary3))
|
714 |
+
st.success("[pysum_nomal]\n"+summary1)
|
715 |
+
st.success("[pysum_filtered]\n"+summary2)
|
716 |
+
st.success("[pysum_topnrank]\n"+summary3)
|
717 |
+
st.download_button('要約1をダウンロード', summary1, file_name=uploaded_file.name[:uploaded_file.name.find('.')]+'_summary1.txt')
|
718 |
+
st.download_button('要約2をダウンロード', summary2, file_name=uploaded_file.name[:uploaded_file.name.find('.')]+'_summary2.txt')
|
719 |
+
st.download_button('要約2をダウンロード', summary3, file_name=uploaded_file.name[:uploaded_file.name.find('.')]+'_summary3.txt')
|
720 |
+
#with open("./summary/summary1.txt","w") as o:
|
721 |
+
# print(summary1,sep="",file=o)
|
722 |
+
#with open("./summary/summary2.txt","w") as o:
|
723 |
+
# print(summary2,sep="",file=o)
|
724 |
+
except Exception as e:
|
725 |
+
if 'NoneType' in str(e):
|
726 |
+
st.success("ファイルがアップロードされてません。先にアップロードして下さい。")
|
727 |
+
else:
|
728 |
+
st.exception(f"An error occurred: {e}")
|
729 |
+
|
730 |
+
if __name__ == "__main__":
|
731 |
+
try:
|
732 |
+
main()
|
733 |
+
except Exception as e:
|
734 |
+
if "'tmp_file' referenced before assignment" in str(e) :
|
735 |
+
st.success("ファイルがアップロードされてません。先にアップロードして下さい。")
|
736 |
+
else:
|
737 |
+
st.exception(f"An error occurred: {e}")
|
requirements.txt
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Automatically generated by https://github.com/damnever/pigar.
|
2 |
+
# Additional install :torch see https://pytorch.org/get-started/locally/
|
3 |
+
#Indigo4GBのubuntuLTS24.04はデフォルトpython 3.12.X
|
4 |
+
|
5 |
+
chromadb==0.5.0
|
6 |
+
duckduckgo_search==4.2
|
7 |
+
langchain==0.1.20
|
8 |
+
langchain_community==0.0.38
|
9 |
+
langchain_text_splitters==0.0.1
|
10 |
+
llama-index==0.9.34
|
11 |
+
pypdf[crypto]
|
12 |
+
pysummarization==1.1.9
|
13 |
+
rake_ja==0.0.1
|
14 |
+
#torch==2.3.0
|
15 |
+
wikipedia==1.4.0
|
16 |
+
streamlit
|
17 |
+
streamlit-chat
|
18 |
+
sentence-transformers
|
19 |
+
sentencepiece
|
20 |
+
#mecab-python3==1.0.8
|