허깅페이스 실습 및 스페이스에 프로젝트 등록

This commit is contained in:
Mingu Kim
2026-05-26 22:32:53 +09:00
parent ba88ef63f1
commit 4e33fb82af
16 changed files with 1180 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
import gradio as gr
from transformers import pipeline
# 요약
summarizer = pipeline("summarization")
# 감성분석
classifier = pipeline("sentiment-analysis")
# 개체명인식(NER)
ner = pipeline("ner", grouped_entities=True)
# 변역
translator = pipeline("translation_en_to_ko", model="facebook/m2m100_418M")
def analyze_news(article):
if not article:
return "", "", "", ""
# 1. 뉴스 요약
summary_result = summarizer(article)
summary = summary_result[0]['summary_text']
# 2. 감성분석(뉴스원문)
sentiment_result = classifier(article)
sentiment = (
f"감성 : {sentiment_result[0]['label']}"
f"score : {sentiment_result[0]['score']:.4f}"
)
# 3. 키워드 추철
ner_result = ner(article)
keywords = []
for item in ner_result:
word = item['word']
if word not in keywords:
keywords.append(word)
# 리스트 -> 문자열
keyword_text = ", ".join(keywords)
# 4. 번역
translation_result = translator(summary)
translator_summary = translation_result[0]['translation_text']
return summary, sentiment, keyword_text, translator_summary
with gr.Blocks(title="AI 뉴스 분석기") as demo:
gr.Markdown("## AI 뉴스 분석기")
with gr.Row():
with gr.Column(scale=2):
article_input = gr.Textbox(label = "영문 뉴스 기사 입력", lines=15, placeholder="영문 뉴스 기사를 입력하세요..",)
analyze_btn = gr.Button("뉴스 분석 시작")
with gr.Column(scale=2):
summary_output = gr.Textbox(label = "뉴스 요약", lines = 5)
sentiment_output = gr.Textbox(label = "감성 분석")
keyword_output = gr.Textbox(label = "키워드 추출")
translation_output = gr.Textbox(label = "한국어 번역 ", lines= 5)
analyze_btn.click(fn = analyze_news, inputs=article_input, outputs=[summary_output, sentiment_output, keyword_output, translation_output])
demo.launch()
+89
View File
@@ -0,0 +1,89 @@
import gradio as gr
from transformers import pipeline
import edge_tts
import asyncio
asr = pipeline("automatic-speech-recognition", model="openai/whisper-base")
generator = pipeline("text-generation", model="Qwen/Qwen2.5-0.5B-Instruct")
voice_txt, current_answer = "", ""
async def text_to_voice(text):
voice = "ko-KR-InJoonNeural"
communicate = edge_tts.Communicate(text, voice)
await communicate.save("answer.mp3")
def make_voice():
global current_answer
if not current_answer:
return None
asyncio.run(text_to_voice(current_answer))
return "answer.mp3"
def change_txt(file):
global voice_txt
result = asr(file, return_timestamps=True)
voice_txt = result['text']
return voice_txt
def question_answer(question):
"""_summary_
question 답변 생성 후 리턴
음성내용 -> 텍스트 변환한거 보내주고, 질문도 보내주고
Args:
question (_type_): _description_
"""
global voice_txt, current_answer
if not voice_txt:
return "음성을 텍스트로 변환한 후 질문하세요."
prompt = f"""
다음 음성 내용을 참고해서 질문에 답변하세요
음성내용 :
{voice_txt}
질문 :
{question}
답변:
"""
result = generator(prompt, max_new_tokens=50, return_full_text = False, do_sample= False, pad_token_id=generator.tokenizer.eos_token_id)
current_answer = result[0]['generated_text'].strip()
return current_answer
with gr.Blocks(title="AI 음성 챗봇") as demo:
gr.Markdown("## AI 음성 비서")
with gr.Row():
with gr.Column(scale=1):
file = gr.Audio(type="filepath")
txt_btn = gr.Button("텍스트 변환")
with gr.Column(scale=1):
out = gr.Textbox(label = "텍스트 변환", lines=3)
with gr.Row():
with gr.Column(scale=1):
question = gr.Textbox(label="질문하기")
question_btn = gr.Button("질문하기")
with gr.Column(scale=1):
answer = gr.Textbox(label = "answer", placeholder="답변")
voice_btn = gr.Button("답변 음성 전환")
with gr.Row():
audio_output = gr.Audio(label="AI 음성 답변", autoplay=True)
txt_btn.click(fn=change_txt, inputs=file, outputs=out)
question_btn.click(fn=question_answer, inputs = question, outputs = answer)
voice_btn.click(fn=make_voice, outputs= audio_output)
demo.launch()
Binary file not shown.
Binary file not shown.
+31
View File
@@ -0,0 +1,31 @@
review
"Absolutely loved this place! The pasta was cooked to perfection and the sauce had such a rich, deep flavor. Service was warm and attentive throughout the entire meal."
Best sushi I've had outside of Japan. The fish was incredibly fresh and the chef's omakase selection was creative and beautifully presented. Will definitely be back.
"The brunch here is phenomenal. Fluffy pancakes, perfectly poached eggs, and the freshest orange juice I've ever tasted. The staff made us feel right at home."
Waited over 45 minutes for our food and it arrived cold. The steak was overcooked despite asking for medium rare. Very disappointing experience overall.
"Found a hair in my soup halfway through eating. When I told the waiter, he just apologized without offering any compensation or replacement. Unacceptable."
The online menu prices don't match what's on the actual menu in the restaurant. Everything cost significantly more and felt like a bait-and-switch situation.
Fantastic Thai food with authentic flavors. The green curry had just the right level of heat and the spring rolls were crispy and light. Great value for money too.
"Incredible wood-fired pizza! The crust was thin and perfectly charred, the mozzarella was fresh, and the toppings were generous. Best pizza in the city by far."
Extremely noisy inside ??impossible to hold a conversation. The acoustics are terrible and the music was blasting way too loud for a dinner setting.
The portion sizes were shockingly small for the price. Paid $35 for an entree that looked like an appetizer. Left the restaurant still hungry.
The food itself was decent ??nothing extraordinary but nothing to complain about either. Service was a bit slow but the staff seemed genuinely busy. I might come back on a quieter night to give it a fair shot.
The tasting menu was an absolute culinary journey. Each course was thoughtfully crafted and the chef came out personally to explain every dish. Truly a memorable evening.
Great family-friendly spot with huge portions and friendly service. The BBQ ribs fell right off the bone and the homemade coleslaw was a perfect complement.
Staff completely ignored our table for the first 20 minutes. Had to flag someone down just to get water. The food was mediocre at best when it finally arrived.
"Restrooms were filthy and clearly hadn't been cleaned in a while. If the bathrooms are that dirty, I shudder to think what the kitchen looks like."
"Honestly torn on this one. The ambiance was lovely and our server was super friendly, but the main course was underwhelming for the price. The appetizers gave me high hopes that the entree just didn't live up to."
"The dim sum here rivals anything I've had in Hong Kong. Perfectly steamed dumplings, crispy turnip cakes, and the char siu bao was melt-in-your-mouth good."
Reservation was lost even though I had a confirmation email. They squeezed us into a tiny table by the kitchen door. Not what I expected for a so-called fine dining restaurant.
Food was way too salty ??everything from the soup to the main course. Couldn't even finish my plate. Seems like the kitchen has no quality control whatsoever.
"Mixed feelings about this visit. The steak was cooked perfectly and the wine list was impressive, but the side dishes tasted like they came out of a bag. For this price range, I expected everything on the plate to be equally good."
Such a warm and welcoming atmosphere. The owner greeted every table personally and the house-made bread that came with the meal was absolutely divine.
Exceptional farm-to-table concept with ingredients sourced locally. You can truly taste the freshness in every bite. The grilled salmon with herb butter was outstanding.
Ordered delivery and half the items were missing from my bag. Customer service kept me on hold for 30 minutes before hanging up. Never ordering from here again.
It's hard to rate this place. Some dishes were genuinely excellent ??the burrata and the risotto stood out ??but others were completely forgettable. Inconsistency seems to be the theme here. Might be worth another visit to see if it was just an off night.
Happy hour deals here are unbeatable. Craft cocktails at half price and the bar snacks ??especially the truffle fries ??are addictive. My new favorite after-work spot.
"Despite having a reservation, we waited 40 minutes to be seated. No apology, no complimentary drinks offered. The management clearly doesn't value their customers' time."
Dessert was clearly store-bought and not house-made as the menu claimed. The tiramisu tasted like it came straight from a grocery store freezer section.
"The lunch set looked great on Instagram but in person the portions were smaller than expected. That said, the flavors were genuinely good and the staff was very accommodating with my dietary restrictions. I'd probably try dinner here instead."
"The vegetarian options here are outstanding. The mushroom risotto was creamy and earthy, and the roasted cauliflower steak was surprisingly satisfying and full of flavor."
"The place looked nothing like the photos online. Dingy lighting, sticky tables, and an odd smell throughout. We left after appetizers and ate somewhere else."
1 review
2 Absolutely loved this place! The pasta was cooked to perfection and the sauce had such a rich, deep flavor. Service was warm and attentive throughout the entire meal.
3 Best sushi I've had outside of Japan. The fish was incredibly fresh and the chef's omakase selection was creative and beautifully presented. Will definitely be back.
4 The brunch here is phenomenal. Fluffy pancakes, perfectly poached eggs, and the freshest orange juice I've ever tasted. The staff made us feel right at home.
5 Waited over 45 minutes for our food and it arrived cold. The steak was overcooked despite asking for medium rare. Very disappointing experience overall.
6 Found a hair in my soup halfway through eating. When I told the waiter, he just apologized without offering any compensation or replacement. Unacceptable.
7 The online menu prices don't match what's on the actual menu in the restaurant. Everything cost significantly more and felt like a bait-and-switch situation.
8 Fantastic Thai food with authentic flavors. The green curry had just the right level of heat and the spring rolls were crispy and light. Great value for money too.
9 Incredible wood-fired pizza! The crust was thin and perfectly charred, the mozzarella was fresh, and the toppings were generous. Best pizza in the city by far.
10 Extremely noisy inside ??impossible to hold a conversation. The acoustics are terrible and the music was blasting way too loud for a dinner setting.
11 The portion sizes were shockingly small for the price. Paid $35 for an entree that looked like an appetizer. Left the restaurant still hungry.
12 The food itself was decent ??nothing extraordinary but nothing to complain about either. Service was a bit slow but the staff seemed genuinely busy. I might come back on a quieter night to give it a fair shot.
13 The tasting menu was an absolute culinary journey. Each course was thoughtfully crafted and the chef came out personally to explain every dish. Truly a memorable evening.
14 Great family-friendly spot with huge portions and friendly service. The BBQ ribs fell right off the bone and the homemade coleslaw was a perfect complement.
15 Staff completely ignored our table for the first 20 minutes. Had to flag someone down just to get water. The food was mediocre at best when it finally arrived.
16 Restrooms were filthy and clearly hadn't been cleaned in a while. If the bathrooms are that dirty, I shudder to think what the kitchen looks like.
17 Honestly torn on this one. The ambiance was lovely and our server was super friendly, but the main course was underwhelming for the price. The appetizers gave me high hopes that the entree just didn't live up to.
18 The dim sum here rivals anything I've had in Hong Kong. Perfectly steamed dumplings, crispy turnip cakes, and the char siu bao was melt-in-your-mouth good.
19 Reservation was lost even though I had a confirmation email. They squeezed us into a tiny table by the kitchen door. Not what I expected for a so-called fine dining restaurant.
20 Food was way too salty ??everything from the soup to the main course. Couldn't even finish my plate. Seems like the kitchen has no quality control whatsoever.
21 Mixed feelings about this visit. The steak was cooked perfectly and the wine list was impressive, but the side dishes tasted like they came out of a bag. For this price range, I expected everything on the plate to be equally good.
22 Such a warm and welcoming atmosphere. The owner greeted every table personally and the house-made bread that came with the meal was absolutely divine.
23 Exceptional farm-to-table concept with ingredients sourced locally. You can truly taste the freshness in every bite. The grilled salmon with herb butter was outstanding.
24 Ordered delivery and half the items were missing from my bag. Customer service kept me on hold for 30 minutes before hanging up. Never ordering from here again.
25 It's hard to rate this place. Some dishes were genuinely excellent ??the burrata and the risotto stood out ??but others were completely forgettable. Inconsistency seems to be the theme here. Might be worth another visit to see if it was just an off night.
26 Happy hour deals here are unbeatable. Craft cocktails at half price and the bar snacks ??especially the truffle fries ??are addictive. My new favorite after-work spot.
27 Despite having a reservation, we waited 40 minutes to be seated. No apology, no complimentary drinks offered. The management clearly doesn't value their customers' time.
28 Dessert was clearly store-bought and not house-made as the menu claimed. The tiramisu tasted like it came straight from a grocery store freezer section.
29 The lunch set looked great on Instagram but in person the portions were smaller than expected. That said, the flavors were genuinely good and the staff was very accommodating with my dietary restrictions. I'd probably try dinner here instead.
30 The vegetarian options here are outstanding. The mushroom risotto was creamy and earthy, and the roasted cauliflower steak was surprisingly satisfying and full of flavor.
31 The place looked nothing like the photos online. Dingy lighting, sticky tables, and an odd smell throughout. We left after appetizers and ate somewhere else.
+31
View File
@@ -0,0 +1,31 @@
review
음질이 정말 훌륭합니다. 저음이 풍부하고 착용감도 편안해서 장시간 사용해도 귀가 아프지 않아요. 강력 추천!
배송은 빨랐는데 제품 불량이 있었어요. 왼쪽 이어폰에서 잡음이 심하게 나고 연결도 자꾸 끊겨서 실망했습니다.
조립이 간단하고 높이 조절이 자유로워서 정말 편리해요. 재질도 튼튼하고 흔들림 없이 안정적입니다.
생각보다 플라스틱 재질이 저렴해 보이고 높이 조절 부분이 금방 헐거워졌어요. 내구성이 떨어집니다.
클릭감이 정말 좋고 손에 딱 맞는 그립감이에요. 배터리도 오래 가고 반응 속도도 빠릅니다. 만족스러운 구매!
스크롤 휠이 너무 뻑뻑하고 클릭 소리가 굉장히 시끄럽습니다. 사무실에서 쓰기엔 눈치가 보여요.
작동 소음이 거의 없고 공기가 확연히 달라진 게 느껴져요. 디자인도 세련되고 필터 교체도 간편합니다.
냄새 제거 기능이 광고와 다르게 별로예요. 담배 냄새는 전혀 없어지지 않고 소음도 생각보다 큽니다. 반품 원해요.
보온·보냉 기능이 뛰어나고 뚜껑이 잘 닫혀서 가방에 넣어도 걱정 없어요. 디자인도 예쁘고 색상 선택지도 다양합니다.
보온 성능은 좋은데 뚜껑 실리콘 부분에 냄새가 배어서 씻어도 잘 안 없어집니다. 위생 걱정이 되네요.
바퀴가 정말 부드럽게 굴러가고 잠금장치도 튼튼해요. 용량도 넉넉해서 해외여행에 딱 좋습니다. 재구매 의사 있어요!
첫 여행에서 지퍼가 터져버렸어요. 안에 옷이 다 쏟아질 뻔했습니다. 품질 관리가 너무 허술하네요.
면도날이 예리하고 피부 자극이 적어요. 충전도 빠르고 방수 기능도 있어서 샤워 중에도 사용 가능합니다.
3개월 만에 면도날 성능이 급격히 떨어졌어요. 가격 대비 내구성이 너무 아쉽습니다.
두께가 충분해서 무릎이 아프지 않고 미끄럼 방지도 잘 됩니다. 냄새도 거의 없고 청소하기도 편해요.
처음엔 냄새가 너무 심해서 며칠을 환기시켜야 했어요. 미끄럼 방지 기능도 땀이 나면 별로입니다.
밝기 조절이 세밀하게 가능하고 눈이 편안해요. USB 충전이라 어디서나 사용할 수 있어 출장 때도 유용합니다.
충전 포트가 약해서 충전할 때 자꾸 빠집니다. 밝기도 광고보다 어두워서 독서하기 불편해요.
원두 향이 그대로 살아 있고 추출 속도도 빠릅니다. 청소가 쉽고 디자인도 주방에 잘 어울려요. 완전 만족!
한 달 만에 물이 새기 시작했어요. AS 접수했더니 시간도 오래 걸리고 응대도 불친절했습니다. 다시는 이 브랜드 안 살 것 같아요.
앱 연동이 편리하고 체지방·근육량까지 측정해줘서 건강 관리에 도움이 많이 됩니다.
앱이 자꾸 튕기고 수치가 날마다 다르게 나와요. 정확도를 믿기 어렵습니다.
자외선 살균이 확실하게 되는 것 같고 건조까지 되니까 위생적으로 관리하기 편해요. 가족 모두가 만족합니다.
살균 기능은 좋은데 칫솔을 4개까지 넣기엔 공간이 너무 좁아요. 칫솔 헤드끼리 닿아서 오히려 위생이 걱정됩니다.
출퇴근용으로 구매했는데 너무 만족스러워요. 속도도 적당하고 배터리가 오래 가서 하루 이상 충분히 사용 가능합니다.
2주 만에 브레이크가 말을 안 듣기 시작했어요. 안전 문제라 정말 위험했습니다. 절대 추천하지 않습니다.
소형이라 책상 위에 두기 딱 좋고 작동 소음이 거의 없어요. 수면 중에도 방해되지 않아서 좋습니다.
물통이 너무 작아서 하루에 두 번 이상 채워야 해요. 청소도 구조가 복잡해서 손이 많이 갑니다.
착화감이 정말 좋고 쿠션이 뛰어나 장거리 러닝 후에도 발이 편안합니다. 디자인도 세련되어서 일상복에도 잘 어울려요.
사이즈 표기가 실제와 달라서 반품 처리했어요. 사이즈 하나 크게 샀는데도 발이 꽉 끼었습니다. 사이즈 가이드 개선이 필요합니다.
1 review
2 음질이 정말 훌륭합니다. 저음이 풍부하고 착용감도 편안해서 장시간 사용해도 귀가 아프지 않아요. 강력 추천!
3 배송은 빨랐는데 제품 불량이 있었어요. 왼쪽 이어폰에서 잡음이 심하게 나고 연결도 자꾸 끊겨서 실망했습니다.
4 조립이 간단하고 높이 조절이 자유로워서 정말 편리해요. 재질도 튼튼하고 흔들림 없이 안정적입니다.
5 생각보다 플라스틱 재질이 저렴해 보이고 높이 조절 부분이 금방 헐거워졌어요. 내구성이 떨어집니다.
6 클릭감이 정말 좋고 손에 딱 맞는 그립감이에요. 배터리도 오래 가고 반응 속도도 빠릅니다. 만족스러운 구매!
7 스크롤 휠이 너무 뻑뻑하고 클릭 소리가 굉장히 시끄럽습니다. 사무실에서 쓰기엔 눈치가 보여요.
8 작동 소음이 거의 없고 공기가 확연히 달라진 게 느껴져요. 디자인도 세련되고 필터 교체도 간편합니다.
9 냄새 제거 기능이 광고와 다르게 별로예요. 담배 냄새는 전혀 없어지지 않고 소음도 생각보다 큽니다. 반품 원해요.
10 보온·보냉 기능이 뛰어나고 뚜껑이 잘 닫혀서 가방에 넣어도 걱정 없어요. 디자인도 예쁘고 색상 선택지도 다양합니다.
11 보온 성능은 좋은데 뚜껑 실리콘 부분에 냄새가 배어서 씻어도 잘 안 없어집니다. 위생 걱정이 되네요.
12 바퀴가 정말 부드럽게 굴러가고 잠금장치도 튼튼해요. 용량도 넉넉해서 해외여행에 딱 좋습니다. 재구매 의사 있어요!
13 첫 여행에서 지퍼가 터져버렸어요. 안에 옷이 다 쏟아질 뻔했습니다. 품질 관리가 너무 허술하네요.
14 면도날이 예리하고 피부 자극이 적어요. 충전도 빠르고 방수 기능도 있어서 샤워 중에도 사용 가능합니다.
15 3개월 만에 면도날 성능이 급격히 떨어졌어요. 가격 대비 내구성이 너무 아쉽습니다.
16 두께가 충분해서 무릎이 아프지 않고 미끄럼 방지도 잘 됩니다. 냄새도 거의 없고 청소하기도 편해요.
17 처음엔 냄새가 너무 심해서 며칠을 환기시켜야 했어요. 미끄럼 방지 기능도 땀이 나면 별로입니다.
18 밝기 조절이 세밀하게 가능하고 눈이 편안해요. USB 충전이라 어디서나 사용할 수 있어 출장 때도 유용합니다.
19 충전 포트가 약해서 충전할 때 자꾸 빠집니다. 밝기도 광고보다 어두워서 독서하기 불편해요.
20 원두 향이 그대로 살아 있고 추출 속도도 빠릅니다. 청소가 쉽고 디자인도 주방에 잘 어울려요. 완전 만족!
21 한 달 만에 물이 새기 시작했어요. AS 접수했더니 시간도 오래 걸리고 응대도 불친절했습니다. 다시는 이 브랜드 안 살 것 같아요.
22 앱 연동이 편리하고 체지방·근육량까지 측정해줘서 건강 관리에 도움이 많이 됩니다.
23 앱이 자꾸 튕기고 수치가 날마다 다르게 나와요. 정확도를 믿기 어렵습니다.
24 자외선 살균이 확실하게 되는 것 같고 건조까지 되니까 위생적으로 관리하기 편해요. 가족 모두가 만족합니다.
25 살균 기능은 좋은데 칫솔을 4개까지 넣기엔 공간이 너무 좁아요. 칫솔 헤드끼리 닿아서 오히려 위생이 걱정됩니다.
26 출퇴근용으로 구매했는데 너무 만족스러워요. 속도도 적당하고 배터리가 오래 가서 하루 이상 충분히 사용 가능합니다.
27 2주 만에 브레이크가 말을 안 듣기 시작했어요. 안전 문제라 정말 위험했습니다. 절대 추천하지 않습니다.
28 소형이라 책상 위에 두기 딱 좋고 작동 소음이 거의 없어요. 수면 중에도 방해되지 않아서 좋습니다.
29 물통이 너무 작아서 하루에 두 번 이상 채워야 해요. 청소도 구조가 복잡해서 손이 많이 갑니다.
30 착화감이 정말 좋고 쿠션이 뛰어나 장거리 러닝 후에도 발이 편안합니다. 디자인도 세련되어서 일상복에도 잘 어울려요.
31 사이즈 표기가 실제와 달라서 반품 처리했어요. 사이즈 하나 크게 샀는데도 발이 꽉 끼었습니다. 사이즈 가이드 개선이 필요합니다.
+20
View File
@@ -0,0 +1,20 @@
review
음질이 정말 훌륭합니다. 저음이 풍부하고 착용감도 편안해서 장시간 사용해도 귀가 아프지 않아요. 강력 추천!
배송은 빨랐는데 제품 불량이 있었어요. 왼쪽 이어폰에서 잡음이 심하게 나고 연결도 자꾸 끊겨서 실망했습니다.
Waited over 45 minutes for our food and it arrived cold. The steak was overcooked despite asking for medium rare. Very disappointing experience overall.
"Found a hair in my soup halfway through eating. When I told the waiter, he just apologized without offering any compensation or replacement. Unacceptable."
The online menu prices don't match what's on the actual menu in the restaurant. Everything cost significantly more and felt like a bait-and-switch situation.
스크롤 휠이 너무 뻑뻑하고 클릭 소리가 굉장히 시끄럽습니다. 사무실에서 쓰기엔 눈치가 보여요.
첫 여행에서 지퍼가 터져버렸어요. 안에 옷이 다 쏟아질 뻔했습니다. 품질 관리가 너무 허술하네요.
"Honestly torn on this one. The ambiance was lovely and our server was super friendly, but the main course was underwhelming for the price. The appetizers gave me high hopes that the entree just didn't live up to."
Such a warm and welcoming atmosphere. The owner greeted every table personally and the house-made bread that came with the meal was absolutely divine.
Exceptional farm-to-table concept with ingredients sourced locally. You can truly taste the freshness in every bite. The grilled salmon with herb butter was outstanding.
Ordered delivery and half the items were missing from my bag. Customer service kept me on hold for 30 minutes before hanging up. Never ordering from here again.
It's hard to rate this place. Some dishes were genuinely excellent ??the burrata and the risotto stood out ??but others were completely forgettable. Inconsistency seems to be the theme here. Might be worth another visit to see if it was just an off night.
Happy hour deals here are unbeatable. Craft cocktails at half price and the bar snacks ??especially the truffle fries ??are addictive. My new favorite after-work spot.
"Despite having a reservation, we waited 40 minutes to be seated. No apology, no complimentary drinks offered. The management clearly doesn't value their customers' time."
한 달 만에 물이 새기 시작했어요. AS 접수했더니 시간도 오래 걸리고 응대도 불친절했습니다. 다시는 이 브랜드 안 살 것 같아요.
사이즈 표기가 실제와 달라서 반품 처리했어요. 사이즈 하나 크게 샀는데도 발이 꽉 끼었습니다. 사이즈 가이드 개선이 필요합니다.
앱이 자꾸 튕기고 수치가 날마다 다르게 나와요. 정확도를 믿기 어렵습니다.
The food itself was decent ??nothing extraordinary but nothing to complain about either. Service was a bit slow but the staff seemed genuinely busy. I might come back on a quieter night to give it a fair shot.
Staff completely ignored our table for the first 20 minutes. Had to flag someone down just to get water. The food was mediocre at best when it finally arrived.
1 review
2 음질이 정말 훌륭합니다. 저음이 풍부하고 착용감도 편안해서 장시간 사용해도 귀가 아프지 않아요. 강력 추천!
3 배송은 빨랐는데 제품 불량이 있었어요. 왼쪽 이어폰에서 잡음이 심하게 나고 연결도 자꾸 끊겨서 실망했습니다.
4 Waited over 45 minutes for our food and it arrived cold. The steak was overcooked despite asking for medium rare. Very disappointing experience overall.
5 Found a hair in my soup halfway through eating. When I told the waiter, he just apologized without offering any compensation or replacement. Unacceptable.
6 The online menu prices don't match what's on the actual menu in the restaurant. Everything cost significantly more and felt like a bait-and-switch situation.
7 스크롤 휠이 너무 뻑뻑하고 클릭 소리가 굉장히 시끄럽습니다. 사무실에서 쓰기엔 눈치가 보여요.
8 첫 여행에서 지퍼가 터져버렸어요. 안에 옷이 다 쏟아질 뻔했습니다. 품질 관리가 너무 허술하네요.
9 Honestly torn on this one. The ambiance was lovely and our server was super friendly, but the main course was underwhelming for the price. The appetizers gave me high hopes that the entree just didn't live up to.
10 Such a warm and welcoming atmosphere. The owner greeted every table personally and the house-made bread that came with the meal was absolutely divine.
11 Exceptional farm-to-table concept with ingredients sourced locally. You can truly taste the freshness in every bite. The grilled salmon with herb butter was outstanding.
12 Ordered delivery and half the items were missing from my bag. Customer service kept me on hold for 30 minutes before hanging up. Never ordering from here again.
13 It's hard to rate this place. Some dishes were genuinely excellent ??the burrata and the risotto stood out ??but others were completely forgettable. Inconsistency seems to be the theme here. Might be worth another visit to see if it was just an off night.
14 Happy hour deals here are unbeatable. Craft cocktails at half price and the bar snacks ??especially the truffle fries ??are addictive. My new favorite after-work spot.
15 Despite having a reservation, we waited 40 minutes to be seated. No apology, no complimentary drinks offered. The management clearly doesn't value their customers' time.
16 한 달 만에 물이 새기 시작했어요. AS 접수했더니 시간도 오래 걸리고 응대도 불친절했습니다. 다시는 이 브랜드 안 살 것 같아요.
17 사이즈 표기가 실제와 달라서 반품 처리했어요. 사이즈 하나 크게 샀는데도 발이 꽉 끼었습니다. 사이즈 가이드 개선이 필요합니다.
18 앱이 자꾸 튕기고 수치가 날마다 다르게 나와요. 정확도를 믿기 어렵습니다.
19 The food itself was decent ??nothing extraordinary but nothing to complain about either. Service was a bit slow but the staff seemed genuinely busy. I might come back on a quieter night to give it a fair shot.
20 Staff completely ignored our table for the first 20 minutes. Had to flag someone down just to get water. The food was mediocre at best when it finally arrived.
Binary file not shown.
+83
View File
@@ -0,0 +1,83 @@
import gradio as gr
from transformers import pipeline
import edge_tts
import asyncio
import torch
# generator = pipeline("text-generation", model="Qwen/Qwen2.5-1.5B-Instruct", top_k = None)
# generator = pipeline("text-generation", model="mistralai/Mistral-7B-Instruct-v0.3", top_k = None, device="mps")
generator = pipeline("text-generation", model="Qwen/Qwen2.5-1.5B-Instruct", device="mps")
voice_txt, current_answer = "", ""
async def text_to_voice(text):
voice = "ko-KR-InJoonNeural"
communicate = edge_tts.Communicate(text, voice)
await communicate.save("npc_dialogue.mp3")
def make_voice():
global current_answer
if not current_answer:
return None
asyncio.run(text_to_voice(current_answer))
return "npc_dialogue.mp3"
# 음성으로 생성
def question_answer(question):
global current_answer
prompt = f"""
당신은 30년 경력의 베테랑 대장장이 '바르칸'입니다.
[성격 및 말투]
- 거칠지만 의리가 있고, 대장간 일에 자부심이 강합니다.
- "~구먼", "~하겠나?", "~인가?"와 같은 단어를 말 끝에 붙이는 버릇이 있습니다. ex) 아이고 힘들구먼, 자네가 하겠나?, 무슨일 인가?
- 항상 망치질 소리나 쇠 타는 냄새와 관련된 의성어/의태어를 섞어서 대답하세요.
[수행 원칙]
1. 강화 질문 시: 재료 부족이나 무기의 상태를 먼저 언급한 뒤, 강화 성공률에 대해 솔직하게 이야기하세요.
2. 퀘스트 질문 시: 아주 위험하지만 보상이 큰 재료 수집 퀘스트(예: 화염 용의 비늘)를 제안하세요세요.
질문 :
{question}
답변:
"""
# 여기서 do_sample=True, temperature=0.7을 사용해야 감정이 실린 답변.
result = generator(
prompt,
max_new_tokens=300,
return_full_text=False,
do_sample=True, # 중요: True로 해야 감정이 섞인 답변
temperature=0.3, # 중요: 수치가 높을수록 더 창의적이고 감정적인 답변
pad_token_id=generator.tokenizer.eos_token_id
)
current_answer = result[0]['generated_text'].strip()
return current_answer
with gr.Blocks(title="NPC 대사 생성기") as demo:
gr.Markdown("## NPC 대사 생성기")
# npc 에게 질문 답변 생성 및 음성 생성
with gr.Row():
with gr.Column(scale=1):
question = gr.Textbox(label="질문하기")
question_btn = gr.Button("질문하기")
with gr.Column(scale=1):
answer = gr.Textbox(label = "answer", placeholder="답변")
voice_btn = gr.Button("답변 음성 전환")
with gr.Row():
audio_output = gr.Audio(label="AI NPC 음성 답변", autoplay=True)
question_btn.click(fn=question_answer, inputs = question, outputs = answer)
voice_btn.click(fn=make_voice, outputs= audio_output)
demo.launch()
+63
View File
@@ -0,0 +1,63 @@
annotated-doc==0.0.4
annotated-types==0.7.0
anyio==4.13.0
brotli==1.2.0
certifi==2026.4.22
charset-normalizer==3.4.7
click==8.4.0
fastapi==0.136.1
filelock==3.29.0
fsspec==2026.4.0
gradio==6.14.0
gradio_client==2.5.0
groovy==0.1.2
h11==0.16.0
hf-gradio==0.4.1
hf-xet==1.5.0
httpcore==1.0.9
httpx==0.28.1
huggingface_hub==0.36.2
idna==3.15
Jinja2==3.1.6
markdown-it-py==4.2.0
MarkupSafe==3.0.3
mdurl==0.1.2
mpmath==1.3.0
networkx==3.6.1
numpy==2.4.6
orjson==3.11.9
packaging==26.2
pandas==3.0.3
pillow==12.2.0
protobuf==7.35.0
pydantic==2.13.4
pydantic_core==2.46.4
pydub==0.25.1
Pygments==2.20.0
python-dateutil==2.9.0.post0
python-dotenv==1.2.2
python-multipart==0.0.29
pytz==2026.2
PyYAML==6.0.3
regex==2026.5.9
requests==2.34.2
rich==15.0.0
safehttpx==0.1.7
safetensors==0.7.0
semantic-version==2.10.0
sentencepiece==0.2.1
setuptools==81.0.0
shellingham==1.5.4
six==1.17.0
starlette==1.0.0
sympy==1.14.0
tokenizers==0.19.1
tomlkit==0.14.0
torch==2.12.0
tqdm==4.67.3
transformers==4.41.2
typer==0.25.1
typing-inspection==0.4.2
typing_extensions==4.15.0
urllib3==2.7.0
uvicorn==0.47.0
+53
View File
@@ -0,0 +1,53 @@
import gradio as gr
from transformers import pipeline
import re
english_classifier = pipeline("sentiment-analysis", top_k = None)
korean_classifier = pipeline("sentiment-analysis", model="WhitePeak/bert-base-cased-Korean-sentiment", top_k = None)
def is_korean(text):
korean = re.search(r"[가-힣]", text)
return korean is not None
def predict_sentiment(text):
# 한국말인지 확인하기
if is_korean(text):
language = "한국어 모델"
results = korean_classifier(text)[0]
else:
language = "영어 모델"
results = english_classifier(text)[0]
# {'label' : 'POSITIVE', 'score' : 0.9192341028490124}
# {'label' : 'LABEL_1', 'score' : 0.9192341028490124}
# label = results[0]["label"]
label_map = {"LABEL_0" : "부정 😡", "LABEL_1" : "긍정 😄", "NEGATIVE" : "부정 😡", "POSITIVE" : "긍정 😄"}
# label = label_map.get(label, label)
# score1 = result[0]["score"]
# score2 = result[1]["score"]
# return f"사용모델 : {language}\n 감정 : {label}\n 확률 : ({score1:.4f})\n OTHER : ({score2:.4f})"
scores = {}
for item in results:
label = item["label"]
scores[label_map.get(label, label)] = item["score"]
return scores
demo = gr.Interface(
fn = predict_sentiment,
inputs=[gr.Text(lines=3, placeholder="문장을 입력하세요")],
outputs=[gr.Label(num_top_classes=2)],
title = "AI 감정분석 웹",
description="HuggingFace Transformer 기반 감정 분석 프로그램",
)
demo.launch()
+53
View File
@@ -0,0 +1,53 @@
import gradio as gr
from transformers import pipeline
import re
english_classifier = pipeline("sentiment-analysis", top_k = None)
korean_classifier = pipeline("sentiment-analysis", model="WhitePeak/bert-base-cased-Korean-sentiment", top_k = None)
def is_korean(text):
korean = re.search(r"[가-힣]", text)
return korean is not None
def predict_sentiment(text):
# 한국말인지 확인하기
if is_korean(text):
language = "한국어 모델"
results = korean_classifier(text)[0]
else:
language = "영어 모델"
results = english_classifier(text)[0]
# {'label' : 'POSITIVE', 'score' : 0.9192341028490124}
# {'label' : 'LABEL_1', 'score' : 0.9192341028490124}
# label = results[0]["label"]
label_map = {"LABEL_0" : "부정 😡", "LABEL_1" : "긍정 😄", "NEGATIVE" : "부정 😡", "POSITIVE" : "긍정 😄"}
# label = label_map.get(label, label)
# score1 = result[0]["score"]
# score2 = result[1]["score"]
# return f"사용모델 : {language}\n 감정 : {label}\n 확률 : ({score1:.4f})\n OTHER : ({score2:.4f})"
scores = {}
for item in results:
label = item["label"]
scores[label_map.get(label, label)] = item["score"]
return scores
demo = gr.Interface(
fn = predict_sentiment,
inputs=[gr.Text(lines=3, placeholder="문장을 입력하세요")],
outputs=[gr.Label(num_top_classes=2)],
title = "AI 감정분석 웹",
description="HuggingFace Transformer 기반 감정 분석 프로그램",
)
demo.launch()
+66
View File
@@ -0,0 +1,66 @@
import gradio as gr
from transformers import pipeline
import re
# 문장 여러개 ( 파일 )
# 리뷰 데이터 -> 분석
english_classifier = pipeline("sentiment-analysis", top_k = None)
korean_classifier = pipeline("sentiment-analysis", model="WhitePeak/bert-base-cased-Korean-sentiment", top_k = None)
def is_korean(text):
korean = re.search(r"[가-힣]", text)
return korean is not None
def predict_sentiment(text):
# 엔터를 기준으로 문장 분리
sentences = text.splitlines()
sentences = [s.strip() for s in sentences if s.strip()]
results_text=[]
# 한국말인지 확인하기
if is_korean(text):
language = "한국어 모델"
results = korean_classifier(sentences)
else:
language = "영어 모델"
results = english_classifier(sentences)
# {'label' : 'POSITIVE', 'score' : 0.9192341028490124}
# {'label' : 'LABEL_1', 'score' : 0.9192341028490124}
# label = results[0]["label"]
label_map = {"LABEL_0" : "부정 😡", "LABEL_1" : "긍정 😄", "NEGATIVE" : "부정 😡", "POSITIVE" : "긍정 😄"}
# label = label_map.get(label, label)
# score1 = result[0]["score"]
# score2 = result[1]["score"]
# return f"사용모델 : {language}\n 감정 : {label}\n 확률 : ({score1:.4f})\n OTHER : ({score2:.4f})"
for sentence, result in zip(sentences, results):
# 결과를 전체 다 받은 상태
best = max(result, key=lambda x:x['score'])
label = best["label"]
label = label_map.get(label, label)
score = best['score']
# results_text += (f"문장 : {sentence}\n 감정 : {label}\n 확률 : {score:.4f}\n\n")
results_text.append([sentence, label, score])
return results_text
demo = gr.Interface(
fn = predict_sentiment,
inputs=[gr.Textbox(lines=3, placeholder="문장을 입력하세요")],
# outputs=[gr.Textbox(label="분석결과", lines=10)],
outputs=[gr.Dataframe(headers=["문장", "감정", "확률"])],
title = "AI 감정분석 웹",
description="HuggingFace Transformer 기반 감정 분석 프로그램",
)
demo.launch()
+143
View File
@@ -0,0 +1,143 @@
import gradio as gr
from transformers import pipeline
import re
import pandas as pd
import matplotlib.pyplot as plt
import koreanize_matplotlib
# 문장 여러개 ( 파일 )
# 리뷰 데이터 -> 분석
english_classifier = pipeline("sentiment-analysis", top_k = None)
korean_classifier = pipeline("sentiment-analysis", model="WhitePeak/bert-base-cased-Korean-sentiment", top_k = None)
def is_korean(text):
korean = re.search(r"[가-힣]", text)
return korean is not None
def predict_sentiment(file):
# 1. file => pandas
df = pd.read_csv(file)
reviews = df['review'].to_list()
results_text = []
# [수정] 변수 초기화 추가
positive_count, negative_count = 0, 0
positive_scores, negative_scores = 0.0, 0.0
best_positive_score, best_negative_score = 0.0, 0.0
best_positive_review, best_negative_review = "", ""
positive_length, negative_length = [], []
label_map = {"LABEL_0" : "부정 😡", "LABEL_1" : "긍정 😄", "NEGATIVE" : "부정 😡", "POSITIVE" : "긍정 😄"}
for sentence in reviews:
# 한국말인지 확인하기
if is_korean(sentence):
result = korean_classifier(sentence)[0]
else:
result = english_classifier(sentence)[0]
best = max(result, key=lambda x:x['score'])
label = best["label"]
label = label_map.get(label, label)
score = best['score']
# 가장 긍정적인 리뷰 (best_positive_review)와 확률(best_positive_score)
# 가장 부정적인 리뷰 (best_negative_review)와 확률(best_negative_score)
# 긍정 점수 평균 positive_scores
# 부정 점수 평균 negative_scores
review_length = len(sentence)
if label =="긍정 😄":
positive_count += 1
positive_scores += score
positive_length.append(review_length)
if best_positive_score < score :
best_positive_score = score
best_positive_review = sentence
else:
negative_count += 1
negative_scores += score
negative_length.append(review_length)
if best_negative_score < score :
best_negative_score = score
best_negative_review = sentence
results_text.append([sentence, label, score])
# 총 리뷰수 : 20개
total = len(reviews)
# 긍정 리뷰 : 4개
# 부정 리뷰 : 16개
# 긍정 비율 : 21.05%
positive_ration = positive_count / total * 100
# 부정 비율 : 78.95%
negative_ration = negative_count / total * 100
# 부정 긍정 점수 평균
avg_positive = positive_scores / positive_count if positive_count > 0 else 0
avg_negative = negative_scores / negative_count if negative_count > 0 else 0
# 리뷰 길이 평균
avg_positive_length = sum(positive_length) / len(positive_length) if positive_length else 0
avg_negative_length = sum(negative_length) / len(negative_length) if negative_length else 0
stats = f"""
총 리뷰 수 : {total}
긍정 리뷰 😄 : {positive_count}
부정 리뷰 😡 : {negative_count}
긍정 비율 😄 : {positive_ration:.2f}%
부정 비율 😡 : {negative_ration:.2f}%
가장 긍정적인 리뷰 😄 : {best_positive_review} = {positive_length}
= (긍정 확률 {best_positive_score:.4f})
가장 부정적인 리뷰 😡 : {best_negative_review} = {negative_length}
= (부정 확률 {best_negative_score:.4f})
긍정 점수 평균 😄 : {avg_positive:.2f}
부정 점수 평균 😡 : {avg_negative:.2f}
평균 긍정 리뷰 길이 😄 = {avg_positive_length:.2f}
평균 부정 리뷰 길이 😡 = {avg_negative_length:.2f}
"""
#차트
fig, ax = plt.subplots()
ax.pie(
[positive_count, negative_count],
labels=["긍정", "부정"],
autopct="%.1f%%",
startangle=90,
counterclock=False
)
return (
gr.update(value=results_text, visible=True),
gr.update(value=stats, visible=True),
gr.update(value=fig, visible=True),
)
with gr.Blocks() as demo :
gr.Markdown("HuggingFace Transformer 기반 감정 분석 프로그램")
inp = gr.File()
btn = gr.Button("감정분석")
df = gr.Dataframe(headers=["문장", "감정", "확률"], visible=False)
stats = gr.Textbox(label="분석 결과", visible=False)
chart_box = gr.Plot(label="감정 비율", visible=False)
btn.click(fn=predict_sentiment, inputs = inp, outputs = [df, stats, chart_box])
demo.launch()
+404
View File
@@ -0,0 +1,404 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 12,
"id": "35e2dffa",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'label': 'LABEL_0', 'score': 0.851569652557373}]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"# distilbert/distilbert-base-uncased-finetuned-sst-2-english\n",
"classifier = pipeline(\"sentiment-analysis\", model=\"WhitePeak/bert-base-cased-Korean-sentiment\")\n",
"classifier(\"넌 나에게 목욕값을 줬어\")"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "82973a44",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/cooney/Documents/Source/HUGGINGFACE/.venv/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"# distilbert/distilbert-base-uncased-finetuned-sst-2-english\n",
"classifier = pipeline(\"sentiment-analysis\", model=\"WhitePeak/bert-base-cased-Korean-sentiment\", top_k=None)\n",
"\n",
"texts = \"\"\"\n",
"이 치킨은 맛도 없고 이상하다\n",
"나는 행복해\n",
"배고파\n",
"\"\"\"\n",
"\n",
"for t in texts:\n",
" classifier(t)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "42868611",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'label': 'POSITIVE', 'score': 0.6142739653587341}]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"classifier = pipeline(\"sentiment-analysis\", model=\"distilbert/distilbert-base-uncased-finetuned-sst-2-english\")\n",
"classifier(\"넌 나에게 목욕값을 줬어\")"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "7655a2a7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'label': 'neutral', 'score': 0.9992695450782776}]"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"classifier = pipeline(\"sentiment-analysis\", model=\"snunlp/KR-FinBert-SC\")\n",
"classifier(\"넌 나에게 목욕값을 줬어\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae0b9124",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'label': '3 stars', 'score': 0.24898932874202728}]"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"classifier = pipeline(\"sentiment-analysis\", model=\"nlptown/bert-base-multilingual-uncased-sentiment\")\n",
"classifier(\"넌 나에게 목욕값을 줬어\")"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "cd115b8d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'label': 'Very Negative', 'score': 0.42995747923851013}]"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"classifier = pipeline(\"sentiment-analysis\", model=\"tabularisai/multilingual-sentiment-analysis\")\n",
"classifier(\"넌 나에게 모욕감을 줬어\")"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "5592aeff",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"None\n",
"<re.Match object; span=(0, 1), match='안'>\n"
]
}
],
"source": [
"# 정규식\n",
"import re\n",
"\n",
"print(re.search(r\"[가-힣]\", \"abcdefg\"))\n",
"print(re.search(r\"[가-힣]\", \"안녕하세요.\"))"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "eb823f75",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['음질이 정말 훌륭합니다. 저음이 풍부하고 착용감도 편안해서 장시간 사용해도 귀가 아프지 않아요. 강력 추천!']\n",
"['배송은 빨랐는데 제품 불량이 있었어요. 왼쪽 이어폰에서 잡음이 심하게 나고 연결도 자꾸 끊겨서 실망했습니다.']\n",
"['조립이 간단하고 높이 조절이 자유로워서 정말 편리해요. 재질도 튼튼하고 흔들림 없이 안정적입니다.']\n",
"['생각보다 플라스틱 재질이 저렴해 보이고 높이 조절 부분이 금방 헐거워졌어요. 내구성이 떨어집니다.']\n",
"['클릭감이 정말 좋고 손에 딱 맞는 그립감이에요. 배터리도 오래 가고 반응 속도도 빠릅니다. 만족스러운 구매!']\n",
"['스크롤 휠이 너무 뻑뻑하고 클릭 소리가 굉장히 시끄럽습니다. 사무실에서 쓰기엔 눈치가 보여요.']\n",
"['작동 소음이 거의 없고 공기가 확연히 달라진 게 느껴져요. 디자인도 세련되고 필터 교체도 간편합니다.']\n",
"['냄새 제거 기능이 광고와 다르게 별로예요. 담배 냄새는 전혀 없어지지 않고 소음도 생각보다 큽니다. 반품 원해요.']\n",
"['보온·보냉 기능이 뛰어나고 뚜껑이 잘 닫혀서 가방에 넣어도 걱정 없어요. 디자인도 예쁘고 색상 선택지도 다양합니다.']\n",
"['보온 성능은 좋은데 뚜껑 실리콘 부분에 냄새가 배어서 씻어도 잘 안 없어집니다. 위생 걱정이 되네요.']\n",
"['바퀴가 정말 부드럽게 굴러가고 잠금장치도 튼튼해요. 용량도 넉넉해서 해외여행에 딱 좋습니다. 재구매 의사 있어요!']\n",
"['첫 여행에서 지퍼가 터져버렸어요. 안에 옷이 다 쏟아질 뻔했습니다. 품질 관리가 너무 허술하네요.']\n",
"['면도날이 예리하고 피부 자극이 적어요. 충전도 빠르고 방수 기능도 있어서 샤워 중에도 사용 가능합니다.']\n",
"['3개월 만에 면도날 성능이 급격히 떨어졌어요. 가격 대비 내구성이 너무 아쉽습니다.']\n",
"['두께가 충분해서 무릎이 아프지 않고 미끄럼 방지도 잘 됩니다. 냄새도 거의 없고 청소하기도 편해요.']\n",
"['처음엔 냄새가 너무 심해서 며칠을 환기시켜야 했어요. 미끄럼 방지 기능도 땀이 나면 별로입니다.']\n",
"['밝기 조절이 세밀하게 가능하고 눈이 편안해요. USB 충전이라 어디서나 사용할 수 있어 출장 때도 유용합니다.']\n",
"['충전 포트가 약해서 충전할 때 자꾸 빠집니다. 밝기도 광고보다 어두워서 독서하기 불편해요.']\n",
"['원두 향이 그대로 살아 있고 추출 속도도 빠릅니다. 청소가 쉽고 디자인도 주방에 잘 어울려요. 완전 만족!']\n",
"['한 달 만에 물이 새기 시작했어요. AS 접수했더니 시간도 오래 걸리고 응대도 불친절했습니다. 다시는 이 브랜드 안 살 것 같아요.']\n",
"['앱 연동이 편리하고 체지방·근육량까지 측정해줘서 건강 관리에 도움이 많이 됩니다.']\n",
"['앱이 자꾸 튕기고 수치가 날마다 다르게 나와요. 정확도를 믿기 어렵습니다.']\n",
"['자외선 살균이 확실하게 되는 것 같고 건조까지 되니까 위생적으로 관리하기 편해요. 가족 모두가 만족합니다.']\n",
"['살균 기능은 좋은데 칫솔을 4개까지 넣기엔 공간이 너무 좁아요. 칫솔 헤드끼리 닿아서 오히려 위생이 걱정됩니다.']\n",
"['출퇴근용으로 구매했는데 너무 만족스러워요. 속도도 적당하고 배터리가 오래 가서 하루 이상 충분히 사용 가능합니다.']\n",
"['2주 만에 브레이크가 말을 안 듣기 시작했어요. 안전 문제라 정말 위험했습니다. 절대 추천하지 않습니다.']\n",
"['소형이라 책상 위에 두기 딱 좋고 작동 소음이 거의 없어요. 수면 중에도 방해되지 않아서 좋습니다.']\n",
"['물통이 너무 작아서 하루에 두 번 이상 채워야 해요. 청소도 구조가 복잡해서 손이 많이 갑니다.']\n",
"['착화감이 정말 좋고 쿠션이 뛰어나 장거리 러닝 후에도 발이 편안합니다. 디자인도 세련되어서 일상복에도 잘 어울려요.']\n",
"['사이즈 표기가 실제와 달라서 반품 처리했어요. 사이즈 하나 크게 샀는데도 발이 꽉 끼었습니다. 사이즈 가이드 개선이 필요합니다.']\n"
]
}
],
"source": [
"#csv 파일 다루기\n",
"import csv\n",
"\n",
"with open(\"./data/reviews_ko.csv\", \"r\", encoding=\"utf-8\") as f:\n",
" reader = csv.reader(f)\n",
" \n",
" # 헤더명 없애기\n",
" next(reader)\n",
" \n",
" for r in reader:\n",
" print(r)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "9e70fcc6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>review</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>음질이 정말 훌륭합니다. 저음이 풍부하고 착용감도 편안해서 장시간 사용해도 귀가 아...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>배송은 빨랐는데 제품 불량이 있었어요. 왼쪽 이어폰에서 잡음이 심하게 나고 연결도 ...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>조립이 간단하고 높이 조절이 자유로워서 정말 편리해요. 재질도 튼튼하고 흔들림 없이...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>생각보다 플라스틱 재질이 저렴해 보이고 높이 조절 부분이 금방 헐거워졌어요. 내구성...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>클릭감이 정말 좋고 손에 딱 맞는 그립감이에요. 배터리도 오래 가고 반응 속도도 빠...</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" review\n",
"0 음질이 정말 훌륭합니다. 저음이 풍부하고 착용감도 편안해서 장시간 사용해도 귀가 아...\n",
"1 배송은 빨랐는데 제품 불량이 있었어요. 왼쪽 이어폰에서 잡음이 심하게 나고 연결도 ...\n",
"2 조립이 간단하고 높이 조절이 자유로워서 정말 편리해요. 재질도 튼튼하고 흔들림 없이...\n",
"3 생각보다 플라스틱 재질이 저렴해 보이고 높이 조절 부분이 금방 헐거워졌어요. 내구성...\n",
"4 클릭감이 정말 좋고 손에 딱 맞는 그립감이에요. 배터리도 오래 가고 반응 속도도 빠..."
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas as pd\n",
"\n",
"df = pd.read_csv(\"./data/reviews_ko.csv\")\n",
"df.head(5)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "02169e78",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>review</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>27</th>\n",
" <td>물통이 너무 작아서 하루에 두 번 이상 채워야 해요. 청소도 구조가 복잡해서 손이 ...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>28</th>\n",
" <td>착화감이 정말 좋고 쿠션이 뛰어나 장거리 러닝 후에도 발이 편안합니다. 디자인도 세...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>29</th>\n",
" <td>사이즈 표기가 실제와 달라서 반품 처리했어요. 사이즈 하나 크게 샀는데도 발이 꽉 ...</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" review\n",
"27 물통이 너무 작아서 하루에 두 번 이상 채워야 해요. 청소도 구조가 복잡해서 손이 ...\n",
"28 착화감이 정말 좋고 쿠션이 뛰어나 장거리 러닝 후에도 발이 편안합니다. 디자인도 세...\n",
"29 사이즈 표기가 실제와 달라서 반품 처리했어요. 사이즈 하나 크게 샀는데도 발이 꽉 ..."
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.tail(3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1f89b30",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+82
View File
@@ -0,0 +1,82 @@
import gradio as gr
from transformers import pipeline
from PIL import Image
captioner = pipeline("image-to-text")
generator = pipeline("text-generation", model="Qwen/Qwen2.5-1.5B-Instruct")
current_caption = ""
def chat(message, history) :
global current_caption
# message {'text': 'text', 'files': []}
# message {'text': '', 'files': ['/private/var/folders/_x/jfhn2s8d6t512jvv5lndzw2m0000gn/T/gradio/f299e1f235318c3c17f47efef61fabb3f52e14158f3c4e1a2f15b1cf0fb8329d/Gemini_Generated_Image_e9k4qje9k4qje9k4.png']}
# History[]
# History[{'role': 'user', 'metadata': None, 'content': [{'text': 'text', 'type': 'text'}], 'options': None}, {'role': 'assistant', ']
print("message", message)
print("history", history)
# message에서 텍스트와 이미지 분리
text = message["text"]
if message.get("files") :
image = message["files"][0]
if image :
result = captioner(image)
caption_result = result[0]["generated_text"]
# 전역변수에 저장
current_caption = caption_result
prompt = f"""
이미지 설명:
{caption_result}
사용자 질문:
{text}
"""
return prompt
elif text :
if not current_caption:
return f"""
사용자 질문
{text}
"""
prompt = f"""
당신은 이미지 분석 AI 입니다.
다음 이미지 설명을 참고하여 사용자의 질문에
한 문장으로 답하세요.
이미지 설명 :
{current_caption}
질문
{text}
답변:
"""
# caption_result 값이 있다면 적절한 문장 생성하도록 만들기
result = generator(prompt, max_new_tokens = 50, return_full_text = False, pad_token_id=generator.tokenizer.eos_token_id)
print("text result", result)
response = result[0]['generated_text']
answer = response.split("\n")[1].strip()
return answer
demo = gr.ChatInterface(
fn=chat,
multimodal=True,
title="멀티 모달 AI 챗봇",
description="이미지를 업로드하면 이미지에 대한 설명을 생성하는 챗봇입니다. 테스트로 질문도 가능합니다.",
)
demo.launch()