File size: 9,775 Bytes
bfd4c2e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1601185
bfd4c2e
 
 
 
 
1601185
bfd4c2e
 
 
 
 
 
 
23cd59d
 
 
59e5930
 
23cd59d
 
bfd4c2e
 
 
23cd59d
bfd4c2e
23cd59d
bfd4c2e
 
 
 
23cd59d
 
099d0f1
bfd4c2e
 
 
 
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
import json
import numpy as np
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"

# Load all test data into list of dictionaries
#summary_data_path = 'sci-news-sum-kr-50/data/'
#summary_objects = []
#for root, dirs, files in os.walk(summary_data_path):
#    files.sort() # Sort file names
#    for ifile, file_name in enumerate(files):
#        with open(os.path.join(root, file_name)) as f:
#            s = json.load(f)
#            s['index'] = file_name.replace('.json','') # index = 'XY' for file 'XY.json' 
#            s['sentences'] = [sen + '.' for sen in s['sentences']] # Add punctuation to all sentences
#            s['body'] = ' '.join(s['sentences']) # body is all sentenecs concantenatd with spaces in between
#            summary_objects.append(s)

# Load spacy to split text into sentences
import spacy

# Cache language model
nlp = spacy.load("ko_core_news_sm")
nlp.select_pipes(disable=
                        ['tok2vec','tagger','morphologizer','parser','lemmatizer','attribute_ruler','ner']
                        )
nlp.enable_pipe('senter')

def text_to_sentences(nlp, text):
    """Split Korean text into sentences."""
    doc = nlp(text)
    sentences = [sen for sen in doc.sents]
    return sentences

from transformers import AutoConfig, AutoTokenizer, AutoModel
from summarizer import Summarizer

model_path = 'skt/kobert-base-v1'

# Load model, model config and tokenizer via Transformers
custom_config = AutoConfig.from_pretrained(model_path)
custom_config.output_hidden_states=True
custom_tokenizer = AutoTokenizer.from_pretrained(model_path, do_lower_case=False)
custom_model = AutoModel.from_pretrained(model_path, config=custom_config)
model = Summarizer(custom_model=custom_model, custom_tokenizer=custom_tokenizer)

def create_summary(nlp, model, text):
    """Create summary from text of an article using given model"""
    
    # print(model(s['body']))
    k = model.calculate_optimal_k(text, k_max=10)
    return text_to_sentences(nlp, model(text, num_sentences=k))

from urllib.request import urlopen
from bs4 import BeautifulSoup

def extract_naver_news(url):
    """Get title, subtitle, and article body from Naver news"""
    html = urlopen(url).read()
    soup = BeautifulSoup(html, features="html.parser")
    
    title = soup.find(class_="media_end_head_headline").get_text()

    area = soup.find(id="dic_area")

    subtitle_tag = area.find('strong')
    if subtitle_tag: subtitle = area.strong.get_text('\n')
    else: subtitle = ''
    
    for tag in area.find_all(class_="img_desc"):
        tag.extract()
        
    # Add punctuation and spaces between sentences
    article = ' '.join( [text for text in area.stripped_strings if text[-1]=='.'] )
    result = {
        'title': title,
        'subtitle': subtitle,
        'article': article,
    }
    return result

import gradio as gr
def interface_handler(custom_text, naver_url, choice):
    if choice == 1:
        content = extract_naver_news(naver_url)
        summary_sentences = create_summary(nlp, model, content['article'])
        output_text = ""
        # output_text += f'제λͺ©:\n{content["title"]}\n'
        # output_text += f'λΆ€μ œ:\n{content["subtitle"]}\n'
        # output_text += '\nκ°œμš”:\n'
        for sen in summary_sentences:
            output_text += f'{sen}\n\n'
        return output_text
    else:
        output_text = ""
        summary_sentences = create_summary(nlp, model, custom_text)
        for sen in summary_sentences:
            output_text += f'{sen}\n\n'
        return output_text

default_url = "https://n.news.naver.com/article/015/0004692703?sid=102"
default_text = """
'λ‚˜μ„ ν˜• 신경망' ν•™μŠ΅ 기술. μΉ΄λ©”λΌλ‘œ 찍은 μ΄λ―Έμ§€μ—μ„œ νŠΉμ •ν•œ 사물 μ°ΎλŠ” 기술 ν™œμš©. μˆ²μ†μ—μ„œ λ“±μ‚°λ‘œ μ²™μ²™ μ°Ύμ•„ λ“œλ‘ μ΄ μ‚°μ•…κ΅¬μ‘°λŒ€ 역할도. λ―Έκ΅­ κ΅­λ°©λΆ€λŠ” μ§€λ‚œλ‹¬ 말 인곡지λŠ₯(AI)을 μ΄μš©ν•΄ 인간 도움 없이 적을 식별해 νƒ€κ²©ν•˜λŠ” λ“œλ‘ (무인 항곡기)을 μ‹œμ—°ν–ˆλ‹€. 이 λ“œλ‘ μ€ 카메라 ν™”λ©΄μ—μ„œ 총으둜 무μž₯ν•œ μ‚¬λžŒκ³Ό 무기가 μ—†λŠ” μ‚¬λžŒμ„ ꡬ뢄할 수 μžˆλ‹€. ν‘œμ μœΌλ‘œ μ •ν•œ μ‚¬λžŒμ„ μ°Ύμ•„ κ·Έκ°€ 탄 μžλ™μ°¨λ₯Ό μΆ”μ ν•˜λŠ” κΈ°λŠ₯도 μžˆλ‹€. μ‘°λ§Œκ°„ 원격 μ‘°μ’… 없이도 μ „μž₯μ—μ„œ νŠΉμˆ˜λΆ€λŒ€ κ΅°μΈλ“€μ²˜λŸΌ μž„λ¬΄λ₯Ό μˆ˜ν–‰ν•˜λŠ” λ“œλ‘ μ΄ λ“±μž₯ν•  전망이닀. 이 λ“œλ‘ μ΄ μ‚¬λžŒ 도움 없이 카메라 μ˜μƒμ—μ„œ λͺ©ν‘œλ¬Όμ„ μΈμ‹ν•˜κ³  좔적할 수 μžˆλŠ” 것은 λ°”λ‘œ β€˜λ¨Έμ‹ λŸ¬λ‹β€™ 덕뢄이닀. λ¨Έμ‹ λŸ¬λ‹μ€ AI의 ν•œ λΆ„μ•Όλ‘œ 컴퓨터가 μΈκ°„μ²˜λŸΌ 슀슀둜 ν•™μŠ΅ν•  수 μžˆλŠ” λŠ₯λ ₯을 λΆ€μ—¬ν•˜λŠ” μž‘μ—…μ„ λ§ν•œλ‹€. λ¨Έμ‹ λŸ¬λ‹μ˜ μ›λ¦¬λŠ” 인간을 ν¬ν•¨ν•œ 영μž₯λ₯˜ λ‘λ‡Œμ˜ 정보 처리 ꡬ쑰인 β€˜μ‹ κ²½λ§β€™μ„ λͺ¨μ‚¬ν•˜λŠ” 방식이닀. λ°”λ‘‘ λŒ€κ²°μ—μ„œ μ΄μ„ΈλŒ 9단을 이긴 κ΅¬κΈ€μ˜ β€˜μ•ŒνŒŒκ³ β€™ λ“± μ§€κΈˆκΉŒμ§€ μ†Œκ°œλœ AI λŒ€λΆ€λΆ„μ€ 심측신경망을 기반으둜 ν•œ λ¨Έμ‹ λŸ¬λ‹ μ•Œκ³ λ¦¬μ¦˜μ„ μ΄μš©ν•œλ‹€. μ΄λ―Έμ§€μ—μ„œ νŠΉμ • 사물을 μ°ΎλŠ” κΈ°μˆ μ€ 인간이 μ•„λ‹ˆλΌ 고양이 λ‡Œμ—μ„œ μœ λž˜ν–ˆλ‹€. 고양이 λ‡Œμ˜ μ‹œμ‹ κ²½μ—μ„œ λ°œκ²¬λ˜λŠ” β€˜λ‚˜μ„ ν˜• 신경망’ κ΅¬μ‘°λŠ” μ‹œκ°μ„Έν¬λ“€μ΄ λ³΄λ‚΄μ˜€λŠ” λ°˜μ‘μ„ λͺ¨μ•„ μ—¬λŸ¬ 개의 μΈ΅(ε±€)으둜 λ‚˜λˆˆλ‹€. 이λ₯Ό 3단계에 걸쳐 점차적으둜 λ‹¨μˆœν™”ν•˜λ©΄μ„œ 물체의 μƒ‰κΉ”μ΄λ‚˜ λͺ¨μ–‘을 νŒŒμ•…ν•œλ‹€. 이λ₯Ό 처음으둜 μ—°κ΅¬ν•œ λ°μ΄λΉ„λ“œ 휴벨과 ν† μ–΄μŠ€ν… 비저은 1981λ…„ 노벨 μƒλ¦¬μ˜ν•™μƒμ„ λ°›μ•˜λ‹€. AI κ³Όν•™μžλ“€μ€ λ‚˜μ„ ν˜• μ‹ κ²½λ§μ—μ„œ 아이디어λ₯Ό μ–»μ–΄ μ΄λ―Έμ§€μ—μ„œ 사물을 νŒλ³„ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ„ μ„€κ³„ν–ˆλ‹€. μš°μ„  μ΄λ―Έμ§€μ—μ„œ 큰 νŠΉμ§•μ„ μΆ”μΆœν•œ λ‹€μŒ 점차 μž‘κ³  λ³΅μž‘ν•œ νŠΉμ§•μ„ λ°œκ²¬ν•΄ λ‚˜κ°€λŠ” 방식이닀. μ˜ˆμ»¨λŒ€ 사진 속에 μžλ™μ°¨κ°€ μžˆλ‹€κ³  ν•΄ 보자. μ•Œκ³ λ¦¬μ¦˜μ€ μš°μ„  μ‚¬λ¬Όμ˜ 전체적인 μœ€κ³½μ„ λ¨Όμ € ν™•μΈν•œ λ’€ 기쑴에 μž…λ ₯된 사진 데이터와 비ꡐ해 β€˜νƒˆ κ²ƒβ€™μœΌλ‘œ λ²”μœ„λ₯Ό μ’νžŒλ‹€. 이후 νƒ€μ΄μ–΄λ‚˜ μ œμ‘°μ‚¬ μ— λΈ”λŸΌμ²˜λŸΌ 세뢀적인 νŠΉμ§•μ„ νŒŒμ•…ν•˜κ³  β€˜μ‚¬μ§„ 속에 μžˆλŠ” λ¬Όμ²΄λŠ” μžλ™μ°¨β€™λΌλŠ” 결둠을 λ‚΄λ¦¬κ²Œ λœλ‹€. μ œν”„ λ”˜ ꡬ글 μˆ˜μ„μ—°κ΅¬μ›μ€ β€œλ‚˜μ„ ν˜• 신경망은 λ‹€λ₯Έ λ¨Έμ‹ λŸ¬λ‹ ꡬ쑰듀과 비ꡐ할 λ•Œ μ˜μƒ, μŒμ„± λΆ„μ•Όμ—μ„œ 쒋은 μ„±λŠ₯을 보인닀”며 β€œμ΄λ₯Ό μ΄μš©ν•˜λ©΄ 컴퓨터가 처음 λ³Έ 사물도 무엇인지 νŒŒμ•…ν•  수 μžˆλ‹€β€κ³  μ„€λͺ…ν–ˆλ‹€. μ£Όλ³€μ—μ„œ λ³Ό 수 μžˆλŠ” μ˜μƒμ΄¬μ˜μš© λ“œλ‘ μ—λ„ μ΄λ³΄λ‹€λŠ” κ°„λ‹¨ν•˜μ§€λ§Œ λΉ„μŠ·ν•œ 기술이 μ΄μš©λœλ‹€. 세계 1μœ„ λ“œλ‘ μ—…μ²΄μΈ 쀑ꡭ DJI의 β€˜νŒ¬ν…€4β€™λŠ” μ‚¬λžŒ 눈처럼 두 개의 카메라 μ„Όμ„œλ₯Ό μž₯μ°©ν–ˆλ‹€. 이λ₯Ό 톡해 λŒ€μƒ 물체λ₯Ό ν™•μΈν•˜κ³  일정 거리λ₯Ό μœ μ§€ν•˜λ©΄μ„œ λ”°λΌλ‹€λ‹Œλ‹€. 이λ₯Έλ°” β€˜μ•‘ν‹°λΈŒ νŠΈλž™β€™ κΈ°λŠ₯이닀. μ•‘ν‹°λΈŒ νŠΈλž™ κΈ°λŠ₯을 켜면 μ΄μš©μžκ°€ μ§€μ •ν•œ μ‚¬λ¬Όμ΄λ‚˜ μ‚¬λžŒμ˜ μœ€κ³½μ„ μ„ μΈμ‹ν•˜κ³  ν”½μ…€(이미지λ₯Ό κ΅¬μ„±ν•˜λŠ” κ°€μž₯ μž‘μ€ λ‹¨μœ„μΈ λ„€λͺ¨ λͺ¨μ–‘μ˜ 점) λ‹¨μœ„λ‘œ μΈμ‹ν•œλ‹€. κ·Έ 픽셀을 κ³„μ†μ μœΌλ‘œ 같은 크기둜 μœ μ§€ν•˜κΈ° μœ„ν•΄ 기체가 μ΄λ™ν•œλ‹€. μ˜ˆμ»¨λŒ€ 주변에 μžˆλŠ” μ‚¬λžŒμ„ μ§€μ •ν–ˆμ„ λ•Œ ν”½μ…€ 크기가 μƒν•˜μ’Œμš° 100Γ—100 ν”½μ…€μ΄μ—ˆλ‹€κ³  ν•΄ 보자. κ·Έ μ‚¬λžŒμ΄ μ•žμœΌλ‘œ μ›€μ§μ—¬μ„œ 80Γ—80 ν”½μ…€ 크기둜 쀄어듀면 μ›λž˜ 수치인 100Γ—100 픽셀을 되찾기 μœ„ν•΄ λ“œλ‘ λ„ λ”°λΌμ„œ μ•žμœΌλ‘œ μ›€μ§μ΄λŠ” 방식이닀. κ³Όν•™μžλ“€μ€ λ‚˜μ„ ν˜• 신경망을 본뜬 λ¨Έμ‹ λŸ¬λ‹ κΈ°μˆ μ„ μ‘μš©ν•΄ 인간 삢을 μœ€νƒν•˜κ²Œ ν•  수 μžˆλŠ” κΈ°μˆ μ„ κ°œλ°œν•˜κ³  μžˆλ‹€. μŠ€μœ„μŠ€ μ·¨λ¦¬νžˆλŒ€ μ—°κ΅¬νŒ€μ€ λ“œλ‘ μ„ μ΄μš©ν•΄ μ•Œν”„μŠ€ μ‚°λ§₯μ—μ„œ μ‘°λ‚œμžλ₯Ό μ°ΎλŠ” κΈ°μˆ μ„ 연ꡬ 쀑이닀. μ—°κ΅¬νŒ€μ΄ κ°œλ°œν•œ AI λ“œλ‘ μ€ 카메라가 μ΄¬μ˜ν•œ 이미지λ₯Ό μ΄μš©ν•΄ 숲이 μš°κ±°μ§„ κ³³κ³Ό λ“±μ‚°λ‘œλ₯Ό κ΅¬λΆ„ν•œλ‹€. 이λ₯Ό λ“œλ‘ μ˜ λΉ„ν–‰ μ œμ–΄κΈ°λ‘œ 전달해 이동 λ°©ν–₯을 κ²°μ •ν•œλ‹€. μ˜¬ν•΄ 초 μ·¨λ¦¬νžˆλŒ€κ°€ μ™„λ£Œν•œ 첫 μ‹€ν—˜μ—μ„œλŠ” β€˜λ“œλ‘ μ΄ 인간보닀 λ“±μ‚°λ‘œλ₯Ό 잘 μ°ΎλŠ”λ‹€β€™λŠ” κ²°κ³Όκ°€ λ‚˜μ™”λ‹€. μ—°κ΅¬νŒ€μ€ μ•½ 2만μž₯의 μ•Œν”„μŠ€ μ‚° λ“±μ‚°λ‘œ 사진을 λ°”νƒ•μœΌλ‘œ 3일간 λ“œλ‘ μ— νƒ‘μž¬λœ 인곡지λŠ₯의 심측신경망을 ν•™μŠ΅μ‹œμΌ°λ‹€. 이후 λ“œλ‘ μ΄ μ „ν˜€ 가보지 λͺ»ν•œ λ“±μ‚°λ‘œλ₯Ό 였λ₯΄λ„둝 ν–ˆλ‹€. μ‹€ν—˜ κ²°κ³Ό μ‚¬λžŒ 눈으둜 μƒˆλ‘œμš΄ λ“±μ‚°λ‘œλ₯Ό 식별할 ν™•λ₯ μ€ 82%μ˜€μœΌλ‚˜ AI λ“œλ‘ μ€ 85%의 성곡λ₯ μ„ 보여쀬닀. μ·¨λ¦¬νžˆλŒ€ μ—°κ΅¬νŒ€μ€ β€œAI λ“œλ‘ μ€ μ‘°λ§Œκ°„ 싀전에 νˆ¬μž…λΌ μ‚°μ•…κ΅¬μ‘°λŒ€κ°€ μ‘°λ‚œμžλ₯Ό μ°ΎλŠ” 일을 λ„μšΈ 수 μžˆμ„ 것”이라고 λ§ν–ˆλ‹€. 신경망 ν•™μŠ΅ κΈ°μˆ μ€ λ‹€μ–‘ν•œ μš©λ„λ‘œ ν™œμš©ν•  수 μžˆλ‹€. λ¬Ένƒœν˜„ DJI코리아 λŒ€ν‘œλŠ” β€œAIλ₯Ό νƒ‘μž¬ν•œ λ“œλ‘ μ€ μ†‘μ „μ„ μ΄λ‚˜ μ†‘μœ κ΄€ λ“± μ‚°μ—…μ‹œμ„€λ¬Όμ˜ 결함 발견, μ‚°λΆˆ 감지, μž₯μ• λ¬Όμ΄λ‚˜ κ΅°μ‚¬μš© λͺ©ν‘œλ¬Ό 탐지 λ“± 이용 κ°€λŠ₯ λ²”μœ„κ°€ λ¬΄κΆλ¬΄μ§„ν•˜λ‹€β€κ³  λ§ν–ˆλ‹€."),
"""

title = "AI λ¬Έμ„œ μš”μ•½\nKorean text summarization"
with open('description.md',mode='r') as file:
    description = file.read()
with open('article.md',mode='r') as file:
    article = file.read()


demo = gr.Interface(
    fn=interface_handler,
    inputs=[
              gr.inputs.Textbox(lines=5, placeholder=None, default=default_text, label="μž„μ˜ λ¬Έμ„œ (Custom text)", optional=False),
              gr.inputs.Textbox(lines=1, placeholder=None, default=default_url, label="넀이버 λ‰΄μŠ€ 기사 λ§ν¬μ£Όμ†Œ (Naver News article URL)", optional=False),
              gr.inputs.Radio(["μž…λ ₯ λ¬Έμ„œ μš”μ•½", "넀이버 λ‰΄μŠ€ 기사 μš”μ•½"], type="index", default=None, label="μ˜΅μ…˜", optional=False)
           ],
    outputs=[
            gr.outputs.Textbox(label="κ°œμš”"),
            ],
    title=title,
    description=description,
    article=article,
)

if __name__ == "__main__":
    demo.launch(debug=True)