File size: 14,499 Bytes
bc93013
6d3e5c8
 
 
 
 
 
 
bc93013
 
 
6d3e5c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9c061f5
6d3e5c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6dddffe
6d3e5c8
bc93013
 
6d3e5c8
 
4483ff5
6d3e5c8
bc93013
 
 
 
 
 
 
 
 
6d3e5c8
 
c2efb94
 
ec8b6e5
 
6f0061a
 
ec8b6e5
6d3e5c8
 
 
 
ca58a4a
6d3e5c8
 
 
1153244
6d3e5c8
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import spaces
import gradio as gr
import requests
import json
import time
import random
import re
import os
from transformers import pipeline

pipe = pipeline("text-generation", model="jslin09/gemma2-2b-ner", device="cuda")

elements = {'LEO_SOC': ('犯罪主體', 'Subject of Crime'),
            'LEO_VIC': ('客體', 'Victim'),
            'LEO_ACT': ('不法行為', 'Behavior'),
            'LEO_SLE': ('主觀要件', 'Subjective Legal Element of the Offense'),
            'LEO_CAU': ('因果關係', 'Causation'),
            'LEO_ROH': ('危害結果', 'Result of Hazard'),
            'LEO_ATP': ('未遂', 'Attempted'),
            'LEO_ACC': ('既遂', 'Accomplished'),
            'LEO_ABA': ('中止', 'Abandonment'),
            'LEO_PRP': ('預備', 'Preparation'),
            'ILG_GLJ': ('阻卻違法事由', 'Ground of Legal Justification'),
            'ILG_SDE': ('正當防衛', 'Self-Defense'),
            'ILG_NEC': ('緊急避難', 'Emergency Avoidance'),
            'CUL_INS': ('心神喪失', 'Insane'),
            'CUL_FBD': ('精神耗弱', 'Feebleminded'),
            'CUL_ALC': ('原因自由行為', 'Actio Libera in Causa'),
            'CUL_RPS': ('責任能力', 'Responsibility'),
            'CUL_ANP': ('期待可能性', 'Anticipated Possibility'),
            'CUL_GUM': ('犯罪意識', 'Guilty Mind')
           }

secret = os.environ.get("HF_TOKEN")
llm_server = os.environ.get("REMOTE_LLM_SERVER")

def get_prompt(content, tag, tag_name):
    paragraph = content
    task = f"請標示出以下段落中的{tag_name}構成要件要素,對應的標籤是[{tag}]。\n\n"
    task_template = f'{task}#####\n{paragraph}\n\n#####\n構成要件要素:\n'
#    tag_result = f'{task_template}\n#####\n標註結果: \n'
    return task_template

def Jaccard(response_content, tag):
    '''
    說明:
        找出文本中有無指定的標籤。
    Parameters:
        response_content (str): 可能有標籤的文本。
        tag (str): 指定的標籤名稱,不包含方括號。
    Retrun:
        Jaccard_result (tuple): 回傳一個含有標籤名稱及布林值的 tuple。
                                如果有指定的標籤名稱,布林值為True。如果沒有指定的標籤,指定為 None。
    '''
    response_head = response_content.split("標註結果:\n")[0]
    try:
        response_body = response_content.split("標註結果:\n")[1]
    except IndexError: # 如果切不出結果,就把結果設定為字串 'None'。
        response_body = 'None'
    start_index = 0
    # 使用正規表示式找出所有構成要件要素文字的起始位置
#    print(f'尋找的目標字串: [{tag}]')
    # 加入 re.escape() 是為了避免處理到有逸脱字元的字串會報錯而中斷程式執行
    findall_open_tags = [m.start() for m in re.finditer(re.escape(f"[{tag}]"), response_body)]
    findall_close_tags = [m.start() for m in re.finditer(re.escape(f"[/{tag}]"), response_body)]
    try:
        parts = [response_body[start_index:findall_open_tags[0]]] # 第一個標籤之前的句子
    except IndexError:
        parts = []
    # 找出每個標籤所在位置,取出標籤文字。
    for j, idx in enumerate(findall_open_tags):
#        print(j, start_index, idx, response_content[start_index:idx])
        tag_text = response_body[idx + len(tag) + 2:findall_close_tags[j]]
        parts.append(tag_text) # 標籤所包住的文字
        closed_tag = findall_close_tags[j] + len(tag) + 3
        try:
            next_open_tag = findall_open_tags[j+1]
            parts.append(response_body[closed_tag: next_open_tag]) # 結束標籤之後到下一個標籤前的文字
        except IndexError:
            parts.append(response_body[findall_close_tags[-1] + len(tag) + 3 :]) # 加入最後一句
    # 把標籤以及分割後的句子合併起來
    result = ''
    for _, part in enumerate(parts):
        result = result + part
    if result == '':
        Jaccard_result = (tag, None)
    else:
        Jaccard_result = (tag, True)
    return Jaccard_result

def tag_in_color(tag_content, tag):
    '''
    說明:
        將標註結果依照標籤進行標色。
    Parameters:
        tag_content (str): 已經標註完畢並有標籤的內容。
        tag (str): 標籤名稱,英文,沒有括號。
    Return:
        parts (list[tuple]): 傳回包含標籤的 tuple 串列。每個 tuple 為 (str, tag_name) ,如果沒有要標色的tag_name傳回None。
    '''
    response_head = tag_content.split("標註結果:\n")[0]
    try:
        response_body = tag_content.split("標註結果:\n")[1]
    except IndexError:
        response_body = 'None'
#    print(f"分割後的內容:\n{response_body}")
    start_index = 0
    # 使用正規表示式找出所有構成要件要素文字的起始位置
#    print(f'尋找的目標字串: [{tag}]')
    # 加入 re.escape() 是為了避免處理到有逸脱字元的字串會報錯而中斷程式執行
    findall_open_tags = [m.start() for m in re.finditer(re.escape(f"[{tag}]"), response_body)]
    findall_close_tags = [m.start() for m in re.finditer(re.escape(f"[/{tag}]"), response_body)]
    try:
        parts = [(f"{response_body[start_index:findall_open_tags[0]]}", None)] # 第一個標籤之前的句子
    except IndexError:
        parts = []
    # 找出每個標籤所在位置,取出標籤文字並加以著色。
    # 回傳的標色字串串列,要標色的應該是一組 tuple: ('要標色的字串', tag_name)
    # 不標色的,就單純字串。
    # 然後組成一個串列回傳。
    for j, idx in enumerate(findall_open_tags):
#        print(j, start_index, idx, response_content[start_index:idx])
        tag_text = response_body[idx + len(tag) + 2:findall_close_tags[j]]
#        parts.append(f"{tag_color[tag]}" + tag_text + Style.RESET_ALL) # 標籤內文字著色
#        parts.append((f"{tag_text}", f"{tag}"))
        parts.append((f"{tag_text}", f"{elements[tag][0]}")) # 要標色的 tuple: ('要標色的字串', tag_name)
        closed_tag = findall_close_tags[j] + len(tag) + 3
        try:
            next_open_tag = findall_open_tags[j+1]
            parts.append((f"{response_body[closed_tag: next_open_tag]}", None)) # 結束標籤之後到下一個標籤前的文字
        except IndexError:
            parts.append((f"{response_body[findall_close_tags[-1] + len(tag) + 3 :]}", None)) # 加入最後一句
#    print(parts)
    return parts

@spaces.GPU
def le_tagger(content, tag):
    jaccard_score = [] # 紀錄單篇的分數
    score = ()
    random.seed(time.localtime(time.time())[5]) # 以時間為基礎的隨機種子
    tag = tag # 傳進來的標籤英文字串,不含方括號。
    prompt = get_prompt(content, tag, elements[tag][0]) # 將要標註的內文以及提示詞組合成作業提示詞
    loop_time = time.time()
    pipe_result = pipe(prompt, max_new_tokens=1200)
#    print(f"Pipe的回應內容:\n{pipe_result[0]['generated_text'].split('標註結果:')[1]}")
    actual_response = pipe_result[0]['generated_text']
#    print(actual_response)
    color_result = tag_in_color(actual_response, tag) # 將回應內容進行標籤標色
#    print(color_result)
#    score = Jaccard(actual_response, tag) # 算分數
#    jaccard_score.append(score)
    print(f"--- 執行耗時:{(time.time() - loop_time)}秒 ---\n")
    return color_result

examples = ["林珈羽能預見任意將所有之金融機構帳戶資料交付予他人,足供他人用為詐欺等犯罪後收受匯款,以遂其掩飾或隱匿犯罪所得財物目的之工具,詎以前開結果之發生亦不違其本意,竟基於幫助他人從事不法行為之犯意,於民國100年4月21日前之不詳時間,在不詳地點,將其向苗栗市農會所申請之帳號00000000000000號帳戶之存摺、提款卡(包括密碼),以不詳之代價,提供與不詳年籍之人使用。而該不詳年籍人士與詐騙集團成員,基於意圖為自己不法之所有,於同年月21日中午12時19分許,撥打電話向被害人張培超以假冒好友謊稱急需用錢等詐騙手法,使張培超誤以為真,而依指示操作後匯出款項新臺幣10萬元至林珈羽上開帳戶內而受騙。",
"錢旺來雖明知不法犯罪集團經常使用人頭帳戶,向被害人施用詐術,藉此逃避檢警人員之追緝,並預見向其取得帳戶之人,會以該帳戶作為詐欺取財之不法所用,竟仍基於幫助詐欺之犯意,於民國106年1月11日某時,將其所申辦之上海商業銀行(下稱上海商銀)帳號00000000000000號帳戶之提款卡、密碼,以宅急便之方式,寄送予某真實姓名年籍不詳之詐欺集團成員,供該詐欺集團成員用於詐欺取財之犯行。嗣該詐欺集團成員即意圖為自己不法之所有,於106年1月13日18時許,撥打電話予洪菁霞,向洪菁霞佯稱係其友人,急需資金周轉,致洪菁霞陷於錯誤,於同日14時35分許,至台中市○區○○路000號之郵局,臨櫃匯款新臺幣(下同)10萬元至錢旺來前揭上海商銀帳戶內,隨即遭提領一空。",
"梅友虔明知金融帳戶之存摺、提款卡及密碼係供自己使用之重要理財工具,關係個人財產、信用之表徵,並可預見一般人取得他人金融帳戶使用常與財產犯罪密切相關,且取得他人帳戶之目的在於掩飾犯罪所得之財物或財產上利益不易遭人追查,對於提供帳戶存摺、提款卡及密碼雖無引發他人萌生犯罪之確信,但仍以縱若有人持以犯罪,亦無違反其本意之幫助詐欺之不確定故意,於民國104年11月12日某時,在桃園市中壢區某便利商店內,將其所申辦之臺灣銀行中壢分行帳號000000000000號帳戶(下稱臺灣銀行帳戶)之存摺、提款卡及密碼,以宅急便方式寄送至高雄市○○區○○○路000號予「黃冠智」之成年人使用,容認該「黃冠智」得以使用作為詐欺取財之工具,並以此方式幫助其從事詐欺取財之犯行。迨「黃冠智」取得上開帳戶存摺、提款卡及密碼後,即基於意圖為自己不法所有之詐欺取財犯意,分別於附表所示時間撥打電話予謝家富、陳品蓁,佯以附表所示情節,致謝家富、陳品蓁均陷於錯誤,而分別於附表所示匯款時間,匯款如附表所示金額至上開帳戶內,並旋遭提領一空。案經謝家富、陳品蓁訴由桃園市政府警察局中壢分局移送臺灣桃園地方法院檢察署檢察官偵查後聲請簡易判決處刑。",
"李大明預見將自己金融機構帳戶存摺、金融卡及密碼提供他人使用,可能幫助他人從事財產犯罪,竟基於幫助他人犯詐欺取財罪之不確定故意,於民國106年7月3日前某日,將其申辦之中華郵政股份有限公司帳號00000000000000號帳戶(下稱本案帳戶)之存摺、金融卡及密碼交予姓名年籍不詳之詐欺集團成員使用,嗣該詐欺集團成員(無證據證明該集團成員達3人以上)取得本案帳戶資料後,即意圖為自己不法之所有,基於詐欺取財之犯意,於106年7月3日下午4時許,撥打電話予陳淑美,佯稱為其友人急需借款云云,致陳淑美陷於錯誤,而依指示於同日下午4時許,在桃園市○○區○○○路0段000號之合作金庫銀行內,臨櫃匯款新臺幣(下同)18萬元至本案帳戶內,旋遭提領一空。",
"林通海雖明知不法犯罪集團經常使用人頭帳戶,向被害人施用詐術,仍基於詐欺取財之犯意,於民國112年4月12日,與該不法犯罪集團成員共同謀議後,決定以電話詐騙方式,向被害人李小明實行詐術。其後,林通海等人依計劃行事,由集團成員甲先以電話假冒某知名電信公司的客服人員,告知被害人李小明其名下的手機帳戶有異常費用需支付,並要求被害人提供銀行帳戶資料以利後續處理。被害人李小明信以為真,遂依指示提供其銀行帳戶及相關資料。",
"公訴意旨略以:吳正義可預見將存摺、金融卡及提款密碼金融帳戶資料提供他人時,有供不法詐騙份子利用,而幫助他人為財產犯罪之虞,竟不違背其本意,基於幫助他人詐欺之犯意,於民國106年11月10日前之某日,將其申設之彰化商業銀行股份有限公司北屯分行帳號00000000000000號帳戶(下稱彰化銀行帳戶)之存摺、金融卡及提款密碼交付予真實姓名、年籍不詳之成年人,該成年人於取得上開帳戶資料後,即與詐欺集團之其他成員,共同基於意圖為自己不法所有之犯意聯絡,於106年11月10日18時20分許,撥打電話予黃怡菁,佯稱其係雄獅旅遊之員工,因黃怡菁購買之旅遊商品人員疏失設定為分期付款,需依指示操作自動櫃員機解除設定云云,致黃怡菁陷於錯誤,而於同日19時3分許,以轉帳匯款方式,將新臺幣(下同)2萬9,987元匯入吳正義上開彰化銀行帳戶內,旋遭提領殆盡。因認被告吳正義涉犯刑法第30條第1項、第339條第1項之幫助詐欺取財罪嫌。"            
]

with gr.Blocks(theme=gr.themes.Soft(primary_hue=gr.themes.colors.indigo, secondary_hue=gr.themes.colors.fuchsia)) as demo:
    gr.Markdown(
    """
    <h1 style="text-align: center;">詐欺罪判決書「犯罪事實」構成要件要素識別器</h1>
    """)
    with gr.Row() as row:
        with gr.Column():
            content = gr.Textbox(label="犯罪事實", lines=5, placeholder="輸入「犯罪事實」....,或是選取以下範例。")
            radio = gr.Radio(choices=[("犯罪主體", "LEO_SOC"), ("主觀要件", "LEO_SLE"), ("不法行為","LEO_ACT"), \
                              ('客體','LEO_VIC'), ("因果關係","LEO_CAU"), ("危害結果","LEO_ROH") \
                             ],
                             value="LEO_SOC", # 預設值
                             label="請選擇構成要件要素標籤"
    )
    with gr.Row():
        output = gr.HighlightedText(label="標註結果")
    with gr.Row():
        greet_btn = gr.Button("LE-NER", variant="primary")
        greet_btn.click(fn=le_tagger, inputs=[content, radio], outputs=output, api_name="le_tagger")
    gr.Examples(examples, label='Examples', inputs=[content])

demo.launch(share=False)