yeelou commited on
Commit
5c76941
1 Parent(s): 3e2ea3b

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +143 -118
  2. requirements.txt +2 -2
app.py CHANGED
@@ -12,47 +12,54 @@ Original file is located at
12
  # !wget https://github.com/daac-tools/vibrato/releases/download/v0.5.0/ipadic-mecab-2_7_0.tar.xz
13
  # !tar xf ipadic-mecab-2_7_0.tar.xz
14
 
 
 
15
  import gradio as gr
16
- import pandas as pd
17
  import vibrato
18
  import zstandard
19
- import numpy as np
20
- import os
 
21
  # import wget
22
  # import tarfile
23
 
24
- from datasketch import MinHash, MinHashLSH
25
- from sentence_transformers import SentenceTransformer, util
26
 
27
  if not os.path.exists("./ipadic-mecab-2_7_0.tar.xz"):
28
- # wget.download("https://github.com/daac-tools/vibrato/releases/download/v0.5.0/ipadic-mecab-2_7_0.tar.xz")
29
- # with tarfile.open('ipadic-mecab-2_7_0.tar.xz', 'r:xf') as tar:
30
- # tar.extractall('ipadic-mecab-2_7_0')
31
- os.system("wget https://github.com/daac-tools/vibrato/releases/download/v0.5.0/ipadic-mecab-2_7_0.tar.xz")
32
- os.system("tar xf ipadic-mecab-2_7_0.tar.xz")
 
 
33
 
34
 
35
  dctx = zstandard.ZstdDecompressor()
36
- with open('ipadic-mecab-2_7_0/system.dic.zst', 'rb') as fp:
37
- with dctx.stream_reader(fp) as dict_reader:
38
- tokenizer = vibrato.Vibrato(dict_reader.read())
39
 
40
  dup_model_dict = {
41
- "cased":SentenceTransformer("sentence-transformers/distiluse-base-multilingual-cased-v2"),
42
- "cased_train":SentenceTransformer("yeelou/news-demo-trainingdup-multilingual-cased-v2"),
43
- }
44
-
45
- exp_list = ["金融庁は、朝日火災海上保険(以下、朝日火災)が20年以上にわたり無資格で保険を販売していたとして、保険業法に基づく業務改善命令を発出したことが読売新聞と日本経済新聞の報道で明らかになりました。この業務改善命令は、2020年12月28日に行われました。朝日火災は、長年にわたり保険業法を遵守しない行為を続けてきたことが問題視されています。",
46
- "読売新聞・日本経済新聞によると、金融庁は12月28日(UTC+9、以下同様)に、20年以上に亘り無資格で保険を販売していたとして、朝日火災海上保険(以下、「朝日火災」)に対し、保険業法に基づく業務改善命令を出した。また、同社の所属代理店であるヤマト運輸と沖縄ヤマト運輸に対しても、2010年1月15日から1週間の保険販売停止と業務改善命令を出した。",
47
- "インド洋北東部のベンガル湾で発生したサイクロンが、沿岸部のインドとバングラデシュに甚大な被害をもたらしたと、ロイターと朝日新聞が報じています。この自然災害は、両国の多くの地域に深刻な影響を与え、人々の生活に大きな打撃を与えました。被害の全容はまだ明らかになっていませんが、地方によっては被害状況の把握と報告が進んでいるところもあります。一方で、被害者数に関する情報は混乱しており、一部報道機関は当初報じた数字を訂正しています。",
48
- "ロイター、朝日新聞によると、インド洋北東部のベンガル湾でサイクロンが発生し、沿岸のインドとバングラデシュに甚大な被害を及ぼした。被害者についての情報は混乱している。地方によって被害の把握により報告が増すところがある一方、一部の報道機関は当初伝えた被害者の数を訂正している。",
49
- "沖縄気象台は9日(UTC+9)、同日ごろに沖縄地方が梅雨明けしたとみられると発表した。平年の6月23日より14日、昨年の6月19日より10日早い。琉球新報によると、1951年の気象庁の統計開始以降、史上最も早い梅雨明けとなる。",
50
- "沖縄気象台は、202469日(UTC+9)に沖縄地方が梅雨明けしたと見られると発表しました。これは平年の6月23日よりも14日早く、また前年の6月19日よりも10日早い梅雨明けとなります。琉球新報の報道によると、1951年に気象庁が統計を開始して以来、これが史上最も早い梅雨明けと記録されました。",
51
- "警視庁八王子警察署は、1995730日に八王子市内のスーパーで起きた拳銃殺害事件で、犯人逮捕のための有力な情報に対し、300万円の懸賞金を支払うことを明らかにした。",
52
- "警視庁八王子警察署は、1995年7月30日に八王子市内のスーパーで発生した拳銃による殺害事件に関連して、犯人の逮捕につながる重要な情報提供者に対し、300万円の懸賞金の支払いを発表しました。",
53
- "対話型AIサービス「チャットGPT」を開発した米オープンAIは8日、サム・アルトマン最高経営責任者が取締役に復帰すると発表した。",
54
- "対話型AI(人工知能)サービス「チャットGPT」を開発した米オープンAIは8日、サム・アルトマン最高経営責任者(CEO)が取締役に復帰すると発表した。"
55
- ]
 
 
 
 
 
56
 
57
  minh_threshold = 0.8
58
  minh_num_perm = 128
@@ -66,69 +73,77 @@ mk_output = """
66
 
67
  """
68
 
 
69
  def tokenized(text):
70
- tokenized=[]
71
- tokens = tokenizer.tokenize(text)
72
- tokens = [token.surface() for token in tokens]
73
- tokenized.extend(tokens)
74
- return tokenized
 
75
 
76
  def get_minhash(text):
77
- text_tokenized = tokenized(text)
78
- m_tmp = MinHash(num_perm=minh_num_perm)
79
- for d in text_tokenized:
80
- m_tmp.update(d.encode('utf8'))
81
- return m_tmp
 
 
 
 
 
82
 
83
- def lsh_query(text,texts,lsh):
84
- q_min = get_minhash(text)
85
- return [(i,q_min.jaccard(get_minhash(texts[int(i)]))) for i in lsh.query(q_min)]
86
 
87
  def minhash(texts):
88
- lsh = MinHashLSH(threshold=minh_threshold, num_perm=minh_num_perm)
89
- for idx, val in enumerate(texts):
90
- lsh.insert(f"{idx}", get_minhash(val))
91
-
92
- dup_dict = {}
93
- dup_list = []
94
- for idx, val in enumerate(texts):
95
- if val not in dup_list:
96
- res_query = lsh_query(val,texts,lsh)
97
- res_query = [[texts[int(i[0])],i[1]] for i in res_query if int(i[0]) != idx]
98
- if res_query == []:
99
- dup_dict[val] = [("no duplicate news",0)]
100
- else:
101
- dup_dict[val] = res_query
102
- for x in res_query:
103
- dup_list.append(x[0])
104
- else:
105
- pass
106
- return dup_dict
 
 
 
107
 
108
  def run_dup_model(model, sim, texts):
109
- paraphrases = util.paraphrase_mining(model, texts)
110
- news_paraphrases = paraphrases[:len(texts)]
111
- res_cased = [p for p in paraphrases if p[0]>=sim]
112
- res_cased_dict = {}
113
- for i in res_cased:
114
- # print(i)
115
- t = texts[i[1]]
116
- v = texts[i[2]]
117
- s = i[0]
118
- if t not in res_cased_dict.keys():
119
- res_cased_dict[t]=[]
120
- if v not in res_cased_dict.keys():
121
- res_cased_dict[v]=[]
122
- res_cased_dict[t].append([v,s])
123
- dup_dict = {}
124
- for text in texts:
125
- if text not in res_cased_dict.keys():
126
- dup_dict[text] = [("no duplicate news",0)]
127
- elif res_cased_dict[text] == []:
128
- pass
129
- else:
130
- dup_dict[text] = res_cased_dict[text]
131
- return dup_dict
 
132
 
133
  # dup_model_dict.keys()
134
 
@@ -144,46 +159,56 @@ def run_dup_model(model, sim, texts):
144
  # )
145
  # mk_all+=mk_tmp
146
 
 
147
  def dup_report(choice, *args):
148
- texts = list(args)
149
- print("choice = ", choice)
150
- print("texts = ", texts)
151
- print("texts nums = ", len(texts))
152
- texts = [i for i in texts if i != ""]
153
- if choice == "minhash":
154
- res = minhash(texts)
155
- else:
156
- res = run_dup_model(dup_model_dict[choice], minh_threshold, exp_list)
157
-
158
- mk_all = ""
159
- for idx, (key, vals) in enumerate(res.items()):
160
- for val in vals:
161
- mk_tmp = mk_output.format(
162
- idx = idx,
163
- text = key,
164
- dup_text = val[0],
165
- score = val[1],
166
- )
167
- mk_all+=mk_tmp
168
- return mk_all
 
169
 
170
  with gr.Blocks(title="類似文検索POC", theme="bethecloud/storj_theme") as demo:
171
- gr.Markdown("# 類似度比較POC")
172
- gr.Markdown("""
 
173
  * POC内容:重複処理
174
  * 以下三つの方法で例文の中から類似文を比較する。
175
  * minhash: ハッシュ計算で類似度を比較。(一般的に文字の類似度比較に使用される)
176
  * cased: 既存モデルで、Cos方法で類似度比較。
177
  * cased_train: 60件のトレーニングデータを用いて再学習してからCos方法で類似度比較。
178
- """)
179
- choice = gr.Radio(choices = ["minhash", "cased", "cased_train"], label = "検索方法", value = "minhash")
180
- input_dict={}
181
- for idx, exp in enumerate(exp_list):
182
- input_dict[f"{idx}"] = gr.Textbox(label=f"ニュース {idx+1}",value=exp)
183
- gen_btn = gr.Button("比較")
184
- gr.Markdown("アウトプット")
185
- output = gr.Markdown(label="レポート")
186
- # gen_btn.click(fn=dup_report, inputs=[input_dict, choice], outputs=output)
187
- gen_btn.click(fn=dup_report, inputs=[choice] + [input_dict[i] for i in input_dict.keys()], outputs=output)
188
-
189
- demo.launch(inline=False, share=True, debug=True)
 
 
 
 
 
 
 
 
12
  # !wget https://github.com/daac-tools/vibrato/releases/download/v0.5.0/ipadic-mecab-2_7_0.tar.xz
13
  # !tar xf ipadic-mecab-2_7_0.tar.xz
14
 
15
+ import os
16
+
17
  import gradio as gr
 
18
  import vibrato
19
  import zstandard
20
+ from datasketch import MinHash, MinHashLSH
21
+ from sentence_transformers import SentenceTransformer, util
22
+
23
  # import wget
24
  # import tarfile
25
 
 
 
26
 
27
  if not os.path.exists("./ipadic-mecab-2_7_0.tar.xz"):
28
+ # wget.download("https://github.com/daac-tools/vibrato/releases/download/v0.5.0/ipadic-mecab-2_7_0.tar.xz")
29
+ # with tarfile.open('ipadic-mecab-2_7_0.tar.xz', 'r:xf') as tar:
30
+ # tar.extractall('ipadic-mecab-2_7_0')
31
+ os.system(
32
+ "wget https://github.com/daac-tools/vibrato/releases/download/v0.5.0/ipadic-mecab-2_7_0.tar.xz"
33
+ )
34
+ os.system("tar xf ipadic-mecab-2_7_0.tar.xz")
35
 
36
 
37
  dctx = zstandard.ZstdDecompressor()
38
+ with open("ipadic-mecab-2_7_0/system.dic.zst", "rb") as fp:
39
+ with dctx.stream_reader(fp) as dict_reader:
40
+ tokenizer = vibrato.Vibrato(dict_reader.read())
41
 
42
  dup_model_dict = {
43
+ "cased": SentenceTransformer(
44
+ "sentence-transformers/distiluse-base-multilingual-cased-v2"
45
+ ),
46
+ "cased_train": SentenceTransformer(
47
+ "yeelou/news-demo-trainingdup-multilingual-cased-v2"
48
+ ),
49
+ }
50
+
51
+ exp_list = [
52
+ "金融庁は、朝日火災海上保険(以下、朝日火災)が20年以上にわたり無資格で保険を販売していたとして、保険業法に基づく業務改善命令を発出したことが読売新聞と日本経済新聞の報道で明らかになりました。この業務改善命令は、20201228日に行われました。朝日火災は、長年にわたり保険業法を遵守しない行為を続けてきたことが問題視されています。",
53
+ "読売新聞・日本経済新聞によると、金融庁は12月28日(UTC+9、以下同様)に、20年以上に亘り無資格で保険を販売していたとして、朝日火災海上保険(以下、「朝日火災」)に対し、保険業法に基づく業務改善命令を出した。また、同社の所属代理店であるヤマト運輸と沖縄ヤマト運輸に対しても、2010115日から1週間の保険販売停止と業務改善命令を出した。",
54
+ "インド洋北東部のベンガル湾で発生したサイクロンが、沿岸部のインドとバングラデシュに甚大な被害をもたらしたと、ロイターと朝日新聞が報じています。この自然災害は、両国の多くの地域に深刻な影響を与え、人々の生活に大きな打撃を与えました。被害の全容はまだ明らかになっていませんが、地方によっては被害状況の把握と報告が進んでいるところもあります。一方で、被害者数に関する情報は混乱しており、一部報道機関は当初報じた数字を訂正しています。",
55
+ "ロイター、朝日新聞によると、インド洋北東部のベンガル湾でサイクロンが発生し、沿岸のインドとバングラデシュに甚大な被害を及ぼした。被害者についての情報は混乱している。地方によって被害の把握により報告が増すところがある一方、一部の報道機関は当初伝えた被害者の数を訂正している。",
56
+ "沖縄気象台は9日(UTC+9)、同日ごろに沖縄地方が梅雨明けしたとみられると発表した。平年の6月23日より14日、昨年の6月19日より10日早い。琉球新報によると、1951年の気象庁の統計開始以降、史上最も早い梅雨明けとなる。",
57
+ "沖縄気象台は、2024年6月9日(UTC+9)に沖縄地方が梅雨明けしたと見られると発表しました。これは平年の6月23日よりも14日早く、また前年の6月19日よりも10日早い梅雨明けとなります。琉球新報の報道によると、1951年に気象庁が統計を開始して以来、これが史上最も早い梅雨明けと記録されました。",
58
+ "警視庁八王子警察署は、1995年7月30日に八王子市内のスーパーで起きた拳銃殺害事件で、犯人逮捕のための有力な情報に対し、300万円の懸賞金を支払うことを明らかにした。",
59
+ "警視庁八王子警察署は、1995年7月30日に八王子市内のスーパーで発生した拳銃による殺害事件に関連して、犯人の逮捕につながる重要な情報提供者に対し、300万円の懸賞金の支払いを発表しました。",
60
+ "対話型AIサービス「チャットGPT」を開発した米オープンAIは8日、サム・アルトマン最高経営責任者が取締役に復帰すると発表した。",
61
+ "対話型AI(人工知能)サービス「チャットGPT」を開発した米オープンAIは8日、サム・アルトマン最高経営責任者(CEO)が取締役に復帰すると発表した。",
62
+ ]
63
 
64
  minh_threshold = 0.8
65
  minh_num_perm = 128
 
73
 
74
  """
75
 
76
+
77
  def tokenized(text):
78
+ tokenized = []
79
+ tokens = tokenizer.tokenize(text)
80
+ tokens = [token.surface() for token in tokens]
81
+ tokenized.extend(tokens)
82
+ return tokenized
83
+
84
 
85
  def get_minhash(text):
86
+ text_tokenized = tokenized(text)
87
+ m_tmp = MinHash(num_perm=minh_num_perm)
88
+ for d in text_tokenized:
89
+ m_tmp.update(d.encode("utf8"))
90
+ return m_tmp
91
+
92
+
93
+ def lsh_query(text, texts, lsh):
94
+ q_min = get_minhash(text)
95
+ return [(i, q_min.jaccard(get_minhash(texts[int(i)]))) for i in lsh.query(q_min)]
96
 
 
 
 
97
 
98
  def minhash(texts):
99
+ lsh = MinHashLSH(threshold=minh_threshold, num_perm=minh_num_perm)
100
+ for idx, val in enumerate(texts):
101
+ lsh.insert(f"{idx}", get_minhash(val))
102
+
103
+ dup_dict = {}
104
+ dup_list = []
105
+ for idx, val in enumerate(texts):
106
+ if val not in dup_list:
107
+ res_query = lsh_query(val, texts, lsh)
108
+ res_query = [
109
+ [texts[int(i[0])], i[1]] for i in res_query if int(i[0]) != idx
110
+ ]
111
+ if res_query == []:
112
+ dup_dict[val] = [("no duplicate news", 0)]
113
+ else:
114
+ dup_dict[val] = res_query
115
+ for x in res_query:
116
+ dup_list.append(x[0])
117
+ else:
118
+ pass
119
+ return dup_dict
120
+
121
 
122
  def run_dup_model(model, sim, texts):
123
+ paraphrases = util.paraphrase_mining(model, texts)
124
+ news_paraphrases = paraphrases[: len(texts)]
125
+ res_cased = [p for p in news_paraphrases if p[0] >= sim]
126
+ res_cased_dict = {}
127
+ for i in res_cased:
128
+ # print(i)
129
+ t = texts[i[1]]
130
+ v = texts[i[2]]
131
+ s = i[0]
132
+ if t not in res_cased_dict.keys():
133
+ res_cased_dict[t] = []
134
+ if v not in res_cased_dict.keys():
135
+ res_cased_dict[v] = []
136
+ res_cased_dict[t].append([v, s])
137
+ dup_dict = {}
138
+ for text in texts:
139
+ if text not in res_cased_dict.keys():
140
+ dup_dict[text] = [("no duplicate news", 0)]
141
+ elif res_cased_dict[text] == []:
142
+ pass
143
+ else:
144
+ dup_dict[text] = res_cased_dict[text]
145
+ return dup_dict
146
+
147
 
148
  # dup_model_dict.keys()
149
 
 
159
  # )
160
  # mk_all+=mk_tmp
161
 
162
+
163
  def dup_report(choice, *args):
164
+ texts = list(args)
165
+ print("choice = ", choice)
166
+ print("texts = ", texts)
167
+ print("texts nums = ", len(texts))
168
+ texts = [i for i in texts if i != ""]
169
+ if choice == "minhash":
170
+ res = minhash(texts)
171
+ else:
172
+ res = run_dup_model(dup_model_dict[choice], minh_threshold, exp_list)
173
+
174
+ mk_all = ""
175
+ for idx, (key, vals) in enumerate(res.items()):
176
+ for val in vals:
177
+ mk_tmp = mk_output.format(
178
+ idx=idx,
179
+ text=key,
180
+ dup_text=val[0],
181
+ score=val[1],
182
+ )
183
+ mk_all += mk_tmp
184
+ return mk_all
185
+
186
 
187
  with gr.Blocks(title="類似文検索POC", theme="bethecloud/storj_theme") as demo:
188
+ gr.Markdown("# 類似度比較POC")
189
+ gr.Markdown(
190
+ """
191
  * POC内容:重複処理
192
  * 以下三つの方法で例文の中から類似文を比較する。
193
  * minhash: ハッシュ計算で類似度を比較。(一般的に文字の類似度比較に使用される)
194
  * cased: 既存モデルで、Cos方法で類似度比較。
195
  * cased_train: 60件のトレーニングデータを用いて再学習してからCos方法で類似度比較。
196
+ """
197
+ )
198
+ choice = gr.Radio(
199
+ choices=["minhash", "cased", "cased_train"], label="検索方法", value="minhash"
200
+ )
201
+ input_dict = {}
202
+ for idx, exp in enumerate(exp_list):
203
+ input_dict[f"{idx}"] = gr.Textbox(label=f"ニュース {idx+1}", value=exp)
204
+ gen_btn = gr.Button("比較")
205
+ gr.Markdown("アウトプット")
206
+ output = gr.Markdown(label="レポート")
207
+ # gen_btn.click(fn=dup_report, inputs=[input_dict, choice], outputs=output)
208
+ gen_btn.click(
209
+ fn=dup_report,
210
+ inputs=[choice] + [input_dict[i] for i in input_dict.keys()],
211
+ outputs=output,
212
+ )
213
+
214
+ demo.launch(inline=False, share=True, debug=True)
requirements.txt CHANGED
@@ -1,7 +1,7 @@
1
- gradio==4.44.1
2
  datasketch
3
  vibrato
4
  zstandard
5
  # wget
6
  transformers
7
- sentence-transformers
 
 
 
1
  datasketch
2
  vibrato
3
  zstandard
4
  # wget
5
  transformers
6
+ sentence-transformers
7
+ gradio==4.44.1