Upload 4 files
Browse files
app.py
CHANGED
|
@@ -1,38 +1,158 @@
|
|
| 1 |
-
from transformers import pipeline
|
| 2 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
-
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
def
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
"
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
return result['answer']
|
| 16 |
|
| 17 |
-
#
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
if __name__ == "__main__":
|
| 38 |
-
demo.launch(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
+
import random
|
| 3 |
+
import requests
|
| 4 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 5 |
+
import io
|
| 6 |
+
import base64
|
| 7 |
+
from transformers import pipeline
|
| 8 |
+
from config import MEME_TEMPLATES, CHATBOT_RESPONSES, APP_CONFIG
|
| 9 |
+
from utils import create_meme_image, generate_response, add_text_to_image
|
| 10 |
+
|
| 11 |
+
# AI ๋ชจ๋ธ ์ด๊ธฐํ
|
| 12 |
+
try:
|
| 13 |
+
qa_pipeline = pipeline("question-answering", model="distilbert-base-cased-distilled-squad")
|
| 14 |
+
text_generator = pipeline("text-generation", model="gpt2", max_length=100)
|
| 15 |
+
except Exception as e:
|
| 16 |
+
print(f"๋ชจ๋ธ ๋ก๋ฉ ์ค๋ฅ: {e}")
|
| 17 |
+
qa_pipeline = None
|
| 18 |
+
text_generator = None
|
| 19 |
+
|
| 20 |
+
def create_meme(template_choice, top_text, bottom_text):
|
| 21 |
+
"""๋ฐ ์ด๋ฏธ์ง ์์ฑ ํจ์"""
|
| 22 |
+
try:
|
| 23 |
+
if template_choice in MEME_TEMPLATES:
|
| 24 |
+
template_info = MEME_TEMPLATES[template_choice]
|
| 25 |
+
# ๊ธฐ๋ณธ ํ
ํ๋ฆฟ ์ด๋ฏธ์ง ์์ฑ (์ค์ ๋ก๋ ๋ฏธ๋ฆฌ ์ค๋น๋ ์ด๋ฏธ์ง ์ฌ์ฉ)
|
| 26 |
+
img = create_meme_image(template_info, top_text, bottom_text)
|
| 27 |
+
return img
|
| 28 |
+
else:
|
| 29 |
+
return "ํ
ํ๋ฆฟ์ ์ ํํด์ฃผ์ธ์."
|
| 30 |
+
except Exception as e:
|
| 31 |
+
return f"๋ฐ ์์ฑ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}"
|
| 32 |
|
| 33 |
+
def chatbot_response(message, history):
|
| 34 |
+
"""์ฑ๋ด ์๋ต ์์ฑ"""
|
| 35 |
+
try:
|
| 36 |
+
if not message.strip():
|
| 37 |
+
return "๋ฉ์์ง๋ฅผ ์
๋ ฅํด์ฃผ์ธ์."
|
| 38 |
+
|
| 39 |
+
# ๊ฐ๋จํ ํค์๋ ๊ธฐ๋ฐ ์๋ต
|
| 40 |
+
response = generate_response(message, qa_pipeline, text_generator)
|
| 41 |
+
return response
|
| 42 |
+
|
| 43 |
+
except Exception as e:
|
| 44 |
+
return f"์๋ต ์์ฑ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}"
|
| 45 |
|
| 46 |
+
def analyze_meme_trend(keyword):
|
| 47 |
+
"""๋ฐ ํธ๋ ๋ ๋ถ์ (์๋ฎฌ๋ ์ด์
)"""
|
| 48 |
+
trends = [
|
| 49 |
+
f"'{keyword}' ๊ด๋ จ ๋ฐ์ด ์ต๊ทผ {random.randint(10, 50)}% ์ฆ๊ฐํ์ต๋๋ค.",
|
| 50 |
+
f"'{keyword}' ๋ฐ์ ์ธ๊ธฐ๋: {random.randint(70, 95)}/100",
|
| 51 |
+
f"์ ์ฌํ ํค์๋: {', '.join(random.sample(['์ฌ๋ฏธ์๋', '์๊ธด', '์ธ๊ธฐ', '๋ฐ์ด๋ด', 'ํธ๋ ๋'], 3))}"
|
| 52 |
+
]
|
| 53 |
+
return "\n".join(trends)
|
|
|
|
| 54 |
|
| 55 |
+
# Gradio ์ธํฐํ์ด์ค ๊ตฌ์ฑ
|
| 56 |
+
with gr.Blocks(title=APP_CONFIG["title"], theme=gr.themes.Soft()) as demo:
|
| 57 |
+
gr.Markdown("# ๐ญ ๋ฐ ์์ฑ & AI ์ฑ๋ด ์๋น์ค")
|
| 58 |
+
gr.Markdown("๋ฐ์ ๋ง๋ค๊ณ , AI์ ๋ํํ๋ฉฐ, ํธ๋ ๋๋ฅผ ๋ถ์ํด๋ณด์ธ์!")
|
| 59 |
+
|
| 60 |
+
with gr.Tabs():
|
| 61 |
+
# ๋ฐ ์์ฑ ํญ
|
| 62 |
+
with gr.TabItem("๐ผ๏ธ ๋ฐ ์์ฑ๊ธฐ"):
|
| 63 |
+
with gr.Row():
|
| 64 |
+
with gr.Column():
|
| 65 |
+
template_dropdown = gr.Dropdown(
|
| 66 |
+
choices=list(MEME_TEMPLATES.keys()),
|
| 67 |
+
label="๋ฐ ํ
ํ๋ฆฟ ์ ํ",
|
| 68 |
+
value=list(MEME_TEMPLATES.keys())[0]
|
| 69 |
+
)
|
| 70 |
+
top_text_input = gr.Textbox(
|
| 71 |
+
label="์๋จ ํ
์คํธ",
|
| 72 |
+
placeholder="์๋จ์ ๋ค์ด๊ฐ ํ
์คํธ๋ฅผ ์
๋ ฅํ์ธ์",
|
| 73 |
+
value="When you see a bug"
|
| 74 |
+
)
|
| 75 |
+
bottom_text_input = gr.Textbox(
|
| 76 |
+
label="ํ๋จ ํ
์คํธ",
|
| 77 |
+
placeholder="ํ๋จ์ ๋ค์ด๊ฐ ํ
์คํธ๋ฅผ ์
๋ ฅํ์ธ์",
|
| 78 |
+
value="But it works in production"
|
| 79 |
+
)
|
| 80 |
+
create_btn = gr.Button("๋ฐ ์์ฑํ๊ธฐ", variant="primary")
|
| 81 |
+
|
| 82 |
+
with gr.Column():
|
| 83 |
+
meme_output = gr.Image(label="์์ฑ๋ ๋ฐ")
|
| 84 |
+
|
| 85 |
+
create_btn.click(
|
| 86 |
+
fn=create_meme,
|
| 87 |
+
inputs=[template_dropdown, top_text_input, bottom_text_input],
|
| 88 |
+
outputs=meme_output
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
# AI ์ฑ๋ด ํญ
|
| 92 |
+
with gr.TabItem("๐ค AI ์ฑ๋ด"):
|
| 93 |
+
chatbot = gr.Chatbot(
|
| 94 |
+
label="AI ์ด์์คํดํธ",
|
| 95 |
+
placeholder="์๋
ํ์ธ์! ๋ฌด์์ ๋์๋๋ฆด๊น์?",
|
| 96 |
+
height=400
|
| 97 |
+
)
|
| 98 |
+
msg_input = gr.Textbox(
|
| 99 |
+
label="๋ฉ์์ง ์
๋ ฅ",
|
| 100 |
+
placeholder="๊ถ๊ธํ ๊ฒ์ ๋ฌผ์ด๋ณด์ธ์...",
|
| 101 |
+
lines=2
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
with gr.Row():
|
| 105 |
+
send_btn = gr.Button("์ ์ก", variant="primary")
|
| 106 |
+
clear_btn = gr.Button("๋ํ ์ด๊ธฐํ")
|
| 107 |
+
|
| 108 |
+
def user_message(message, history):
|
| 109 |
+
return "", history + [[message, None]]
|
| 110 |
+
|
| 111 |
+
def bot_message(history):
|
| 112 |
+
if history and history[-1][1] is None:
|
| 113 |
+
user_msg = history[-1][0]
|
| 114 |
+
bot_response = chatbot_response(user_msg, history)
|
| 115 |
+
history[-1][1] = bot_response
|
| 116 |
+
return history
|
| 117 |
+
|
| 118 |
+
msg_input.submit(user_message, [msg_input, chatbot], [msg_input, chatbot]).then(
|
| 119 |
+
bot_message, chatbot, chatbot
|
| 120 |
+
)
|
| 121 |
+
send_btn.click(user_message, [msg_input, chatbot], [msg_input, chatbot]).then(
|
| 122 |
+
bot_message, chatbot, chatbot
|
| 123 |
+
)
|
| 124 |
+
clear_btn.click(lambda: [], outputs=chatbot)
|
| 125 |
+
|
| 126 |
+
# ํธ๋ ๋ ๋ถ์ ํญ
|
| 127 |
+
with gr.TabItem("๐ ํธ๋ ๋ ๋ถ์"):
|
| 128 |
+
with gr.Row():
|
| 129 |
+
with gr.Column():
|
| 130 |
+
keyword_input = gr.Textbox(
|
| 131 |
+
label="ํค์๋ ์
๋ ฅ",
|
| 132 |
+
placeholder="๋ถ์ํ ํค์๋๋ฅผ ์
๋ ฅํ์ธ์",
|
| 133 |
+
value="AI"
|
| 134 |
+
)
|
| 135 |
+
analyze_btn = gr.Button("ํธ๋ ๋ ๋ถ์", variant="primary")
|
| 136 |
+
|
| 137 |
+
with gr.Column():
|
| 138 |
+
trend_output = gr.Textbox(
|
| 139 |
+
label="๋ถ์ ๊ฒฐ๊ณผ",
|
| 140 |
+
lines=5,
|
| 141 |
+
interactive=False
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
analyze_btn.click(
|
| 145 |
+
fn=analyze_meme_trend,
|
| 146 |
+
inputs=keyword_input,
|
| 147 |
+
outputs=trend_output
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
gr.Markdown("---")
|
| 151 |
+
gr.Markdown("๐ก **์ฌ์ฉ๋ฒ**: ๊ฐ ํญ์ ํด๋ฆญํ์ฌ ๋ฐ ์์ฑ, AI ์ฑํ
, ํธ๋ ๋ ๋ถ์ ๊ธฐ๋ฅ์ ์ด์ฉํ์ธ์!")
|
| 152 |
|
| 153 |
if __name__ == "__main__":
|
| 154 |
+
demo.launch(
|
| 155 |
+
server_name="0.0.0.0",
|
| 156 |
+
server_port=7860,
|
| 157 |
+
share=False
|
| 158 |
+
)
|
config.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
์ ํ๋ฆฌ์ผ์ด์
์ค์ ๋ฐ ์์ ์ ์
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
# ์ฑ ๊ธฐ๋ณธ ์ค์
|
| 6 |
+
APP_CONFIG = {
|
| 7 |
+
"title": "๋ฐ ์์ฑ & AI ์ฑ๋ด ์๋น์ค",
|
| 8 |
+
"description": "๋ฐ์ ๋ง๋ค๊ณ AI์ ๋ํํ๋ ์ฌ์ธ์ ์๋น์ค",
|
| 9 |
+
"version": "1.0.0"
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
# ๋ฐ ํ
ํ๋ฆฟ ์ ์
|
| 13 |
+
MEME_TEMPLATES = {
|
| 14 |
+
"๋๋ ์ดํฌ ๋ฐ": {
|
| 15 |
+
"description": "๋๋ ์ดํฌ๊ฐ ๊ฑฐ๋ถํ๊ณ ์น์ธํ๋ ๋ฐ",
|
| 16 |
+
"image_path": "drake_template.jpg",
|
| 17 |
+
"text_positions": [(50, 100), (50, 300)]
|
| 18 |
+
},
|
| 19 |
+
"๋์คํธ๋ํฐ๋ ๋ณด์ดํ๋ ๋": {
|
| 20 |
+
"description": "๋ค๋ฅธ ์ฌ์๋ฅผ ๋ณด๋ ๋จ์์น๊ตฌ ๋ฐ",
|
| 21 |
+
"image_path": "distracted_boyfriend.jpg",
|
| 22 |
+
"text_positions": [(100, 50), (300, 50), (500, 50)]
|
| 23 |
+
},
|
| 24 |
+
"์ฒด์ธ์ง ๋ง์ด ๋ง์ธ๋": {
|
| 25 |
+
"description": "๋ด ๋ง์์ ๋ฐ๊ฟ๋ด ๋ฐ",
|
| 26 |
+
"image_path": "change_my_mind.jpg",
|
| 27 |
+
"text_positions": [(200, 150)]
|
| 28 |
+
},
|
| 29 |
+
"์ ๋์ค ๋ซ ์ฌํ๋ฆฌ": {
|
| 30 |
+
"description": "๋จ์ํ ~ํ์ง ์๋๋ค ๋ฐ",
|
| 31 |
+
"image_path": "one_does_not_simply.jpg",
|
| 32 |
+
"text_positions": [(150, 50), (150, 350)]
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
# ์ฑ๋ด ๊ธฐ๋ณธ ์๋ต
|
| 37 |
+
CHATBOT_RESPONSES = {
|
| 38 |
+
"greetings": [
|
| 39 |
+
"์๋
ํ์ธ์! ๋ฌด์์ ๋์๋๋ฆด๊น์?",
|
| 40 |
+
"๋ฐ๊ฐ์ต๋๋ค! ๊ถ๊ธํ ๊ฒ์ด ์์ผ์๋ฉด ์ธ์ ๋ ๋ฌผ์ด๋ณด์ธ์.",
|
| 41 |
+
"์๋
ํ์ธ์! ๋ฐ ์์ฑ์ด๋ ๋ค๋ฅธ ๋์์ด ํ์ํ์๋ฉด ๋ง์ํด์ฃผ์ธ์."
|
| 42 |
+
],
|
| 43 |
+
"meme_help": [
|
| 44 |
+
"๋ฐ ์์ฑ๊ธฐ ํญ์์ ํ
ํ๋ฆฟ์ ์ ํํ๊ณ ํ
์คํธ๋ฅผ ์
๋ ฅํ๋ฉด ๋ฉ๋๋ค!",
|
| 45 |
+
"์ธ๊ธฐ ์๋ ๋ฐ ํ
ํ๋ฆฟ๋ค์ ์ค๋นํด๋์์ด์. ์ฐฝ์์ ์ธ ํ
์คํธ๋ฅผ ๋ฃ์ด๋ณด์ธ์!",
|
| 46 |
+
"์๋จ๊ณผ ํ๋จ ํ
์คํธ๋ฅผ ์
๋ ฅํ๋ฉด ์ฌ๋ฏธ์๋ ๋ฐ์ด ๋ง๋ค์ด์ง๋๋ค."
|
| 47 |
+
],
|
| 48 |
+
"default": [
|
| 49 |
+
"ํฅ๋ฏธ๋ก์ด ์ง๋ฌธ์ด๋ค์! ๋ ์์ธํ ์ค๋ช
ํด์ฃผ์๊ฒ ์ด์?",
|
| 50 |
+
"๊ทธ๊ฒ์ ๋ํด ๋ ์๊ณ ์ถ์ต๋๋ค. ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ค ๋ถ๋ถ์ด ๊ถ๊ธํ์ ๊ฐ์?",
|
| 51 |
+
"์ข์ ์ง๋ฌธ์
๋๋ค! ์ด๋ค ๋์์ด ํ์ํ์ ์ง ๋ง์ํด์ฃผ์ธ์."
|
| 52 |
+
]
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
# ์์ ๋ฐ ์คํ์ผ ์ค์
|
| 56 |
+
STYLE_CONFIG = {
|
| 57 |
+
"primary_color": "#FF6B6B",
|
| 58 |
+
"secondary_color": "#4ECDC4",
|
| 59 |
+
"background_color": "#F7F9FC",
|
| 60 |
+
"text_color": "#2C3E50",
|
| 61 |
+
"font_family": "Arial, sans-serif"
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
# API ๋ฐ ์ธ๋ถ ์๋น์ค ์ค์
|
| 65 |
+
API_CONFIG = {
|
| 66 |
+
"huggingface_api_url": "https://api-inference.huggingface.co/models/",
|
| 67 |
+
"timeout": 30,
|
| 68 |
+
"max_retries": 3
|
| 69 |
+
}
|
utils.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
์ ํธ๋ฆฌํฐ ํจ์๋ค
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import random
|
| 6 |
+
import requests
|
| 7 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 8 |
+
import io
|
| 9 |
+
from config import CHATBOT_RESPONSES, MEME_TEMPLATES
|
| 10 |
+
|
| 11 |
+
def create_meme_image(template_info, top_text, bottom_text):
|
| 12 |
+
"""๋ฐ ์ด๋ฏธ์ง ์์ฑ"""
|
| 13 |
+
try:
|
| 14 |
+
# ๊ธฐ๋ณธ ์บ๋ฒ์ค ์์ฑ (์ค์ ํ๊ฒฝ์์๋ ํ
ํ๋ฆฟ ์ด๋ฏธ์ง ๋ก๋)
|
| 15 |
+
width, height = 500, 400
|
| 16 |
+
img = Image.new('RGB', (width, height), color='white')
|
| 17 |
+
draw = ImageDraw.Draw(img)
|
| 18 |
+
|
| 19 |
+
# ํฐํธ ์ค์ (๊ธฐ๋ณธ ํฐํธ ์ฌ์ฉ)
|
| 20 |
+
try:
|
| 21 |
+
font_large = ImageFont.truetype("arial.ttf", 32)
|
| 22 |
+
font_small = ImageFont.truetype("arial.ttf", 24)
|
| 23 |
+
except:
|
| 24 |
+
font_large = ImageFont.load_default()
|
| 25 |
+
font_small = ImageFont.load_default()
|
| 26 |
+
|
| 27 |
+
# ๋ฐฐ๊ฒฝ ๊ทธ๋ผ๋ฐ์ด์
ํจ๊ณผ
|
| 28 |
+
for y in range(height):
|
| 29 |
+
color_value = int(255 * (y / height))
|
| 30 |
+
color = (color_value, color_value, 255)
|
| 31 |
+
draw.line([(0, y), (width, y)], fill=color)
|
| 32 |
+
|
| 33 |
+
# ํ
์คํธ ์ถ๊ฐ
|
| 34 |
+
if top_text:
|
| 35 |
+
# ์๋จ ํ
์คํธ
|
| 36 |
+
text_width = draw.textlength(top_text, font=font_large)
|
| 37 |
+
x = (width - text_width) // 2
|
| 38 |
+
y = 30
|
| 39 |
+
# ํ
์คํธ ์ธ๊ณฝ์
|
| 40 |
+
for dx in [-1, 0, 1]:
|
| 41 |
+
for dy in [-1, 0, 1]:
|
| 42 |
+
if dx != 0 or dy != 0:
|
| 43 |
+
draw.text((x+dx, y+dy), top_text, font=font_large, fill='black')
|
| 44 |
+
draw.text((x, y), top_text, font=font_large, fill='white')
|
| 45 |
+
|
| 46 |
+
if bottom_text:
|
| 47 |
+
# ํ๋จ ํ
์คํธ
|
| 48 |
+
text_width = draw.textlength(bottom_text, font=font_large)
|
| 49 |
+
x = (width - text_width) // 2
|
| 50 |
+
y = height - 70
|
| 51 |
+
# ํ
์คํธ ์ธ๊ณฝ์
|
| 52 |
+
for dx in [-1, 0, 1]:
|
| 53 |
+
for dy in [-1, 0, 1]:
|
| 54 |
+
if dx != 0 or dy != 0:
|
| 55 |
+
draw.text((x+dx, y+dy), bottom_text, font=font_large, fill='black')
|
| 56 |
+
draw.text((x, y), bottom_text, font=font_large, fill='white')
|
| 57 |
+
|
| 58 |
+
return img
|
| 59 |
+
|
| 60 |
+
except Exception as e:
|
| 61 |
+
print(f"์ด๋ฏธ์ง ์์ฑ ์ค๋ฅ: {e}")
|
| 62 |
+
return create_error_image(str(e))
|
| 63 |
+
|
| 64 |
+
def create_error_image(error_msg):
|
| 65 |
+
"""์๋ฌ ์ด๋ฏธ์ง ์์ฑ"""
|
| 66 |
+
img = Image.new('RGB', (400, 300), color='red')
|
| 67 |
+
draw = ImageDraw.Draw(img)
|
| 68 |
+
try:
|
| 69 |
+
font = ImageFont.load_default()
|
| 70 |
+
draw.text((50, 150), f"์ค๋ฅ: {error_msg}", font=font, fill='white')
|
| 71 |
+
except:
|
| 72 |
+
pass
|
| 73 |
+
return img
|
| 74 |
+
|
| 75 |
+
def add_text_to_image(img, text, position, font_size=32, color='white'):
|
| 76 |
+
"""์ด๋ฏธ์ง์ ํ
์คํธ ์ถ๊ฐ"""
|
| 77 |
+
draw = ImageDraw.Draw(img)
|
| 78 |
+
try:
|
| 79 |
+
font = ImageFont.truetype("arial.ttf", font_size)
|
| 80 |
+
except:
|
| 81 |
+
font = ImageFont.load_default()
|
| 82 |
+
|
| 83 |
+
x, y = position
|
| 84 |
+
# ์ธ๊ณฝ์ ํจ๊ณผ
|
| 85 |
+
for dx in [-1, 0, 1]:
|
| 86 |
+
for dy in [-1, 0, 1]:
|
| 87 |
+
if dx != 0 or dy != 0:
|
| 88 |
+
draw.text((x+dx, y+dy), text, font=font, fill='black')
|
| 89 |
+
draw.text((x, y), text, font=font, fill=color)
|
| 90 |
+
|
| 91 |
+
return img
|
| 92 |
+
|
| 93 |
+
def generate_response(message, qa_pipeline=None, text_generator=None):
|
| 94 |
+
"""์ฑ๋ด ์๋ต ์์ฑ"""
|
| 95 |
+
message_lower = message.lower()
|
| 96 |
+
|
| 97 |
+
# ์ธ์ฌ๋ง ์ฒ๋ฆฌ
|
| 98 |
+
if any(greeting in message_lower for greeting in ['์๋
', 'ํ์ด', 'ํฌ๋ก', '๋ฐ๊ฐ']):
|
| 99 |
+
return random.choice(CHATBOT_RESPONSES["greetings"])
|
| 100 |
+
|
| 101 |
+
# ๋ฐ ๊ด๋ จ ์ง๋ฌธ ์ฒ๋ฆฌ
|
| 102 |
+
if any(word in message_lower for word in ['๋ฐ', 'meme', '์ด๋ฏธ์ง', '์์ฑ']):
|
| 103 |
+
return random.choice(CHATBOT_RESPONSES["meme_help"])
|
| 104 |
+
|
| 105 |
+
# AI ๋ชจ๋ธ์ ์ฌ์ฉํ ์๋ต ์์ฑ ์๋
|
| 106 |
+
if qa_pipeline and len(message) > 10:
|
| 107 |
+
try:
|
| 108 |
+
# ๊ฐ๋จํ ์ปจํ
์คํธ๋ก QA ์ํ
|
| 109 |
+
context = "์ด๊ฒ์ ๋ฐ ์์ฑ๊ณผ AI ์ฑํ
์๋น์ค์
๋๋ค. ์ฌ์ฉ์๋ค์ด ์ฌ๋ฏธ์๋ ๋ฐ์ ๋ง๋ค๊ณ AI์ ๋ํํ ์ ์์ต๋๋ค."
|
| 110 |
+
result = qa_pipeline(question=message, context=context)
|
| 111 |
+
if result and 'answer' in result:
|
| 112 |
+
return f"๐ค {result['answer']}"
|
| 113 |
+
except Exception as e:
|
| 114 |
+
print(f"QA ํ์ดํ๋ผ์ธ ์ค๋ฅ: {e}")
|
| 115 |
+
|
| 116 |
+
# ํ
์คํธ ์์ฑ ๋ชจ๋ธ ์ฌ์ฉ ์๋
|
| 117 |
+
if text_generator:
|
| 118 |
+
try:
|
| 119 |
+
result = text_generator(f"์ฌ์ฉ์: {message}\n๋ด:", max_length=50, num_return_sequences=1)
|
| 120 |
+
if result and len(result) > 0:
|
| 121 |
+
generated_text = result[0]['generated_text']
|
| 122 |
+
bot_response = generated_text.split('๋ด:')[-1].strip()
|
| 123 |
+
if bot_response and len(bot_response) > 5:
|
| 124 |
+
return f"๐ค {bot_response}"
|
| 125 |
+
except Exception as e:
|
| 126 |
+
print(f"ํ
์คํธ ์์ฑ ์ค๋ฅ: {e}")
|
| 127 |
+
|
| 128 |
+
# ๊ธฐ๋ณธ ์๋ต
|
| 129 |
+
return random.choice(CHATBOT_RESPONSES["default"])
|
| 130 |
+
|
| 131 |
+
def validate_input(text, max_length=100):
|
| 132 |
+
"""์
๋ ฅ ํ
์คํธ ๊ฒ์ฆ"""
|
| 133 |
+
if not text or not text.strip():
|
| 134 |
+
return False, "ํ
์คํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์."
|
| 135 |
+
|
| 136 |
+
if len(text) > max_length:
|
| 137 |
+
return False, f"ํ
์คํธ๊ฐ ๋๋ฌด ๊น๋๋ค. {max_length}์ ์ดํ๋ก ์
๋ ฅํด์ฃผ์ธ์."
|
| 138 |
+
|
| 139 |
+
# ํน์๋ฌธ์ ํํฐ๋ง (์ ํ์ )
|
| 140 |
+
forbidden_chars = ['<', '>', '&', '"', "'"]
|
| 141 |
+
if any(char in text for char in forbidden_chars):
|
| 142 |
+
return False, "ํ์ฉ๋์ง ์๋ ํน์๋ฌธ์๊ฐ ํฌํจ๋์ด ์์ต๋๋ค."
|
| 143 |
+
|
| 144 |
+
return True, "๊ฒ์ฆ ํต๊ณผ"
|
| 145 |
+
|
| 146 |
+
def get_random_meme_idea():
|
| 147 |
+
"""๋๋ค ๋ฐ ์์ด๋์ด ์ ๊ณต"""
|
| 148 |
+
ideas = [
|
| 149 |
+
("When you finish your project", "But remember you didn't write tests"),
|
| 150 |
+
("Me: I'll go to bed early tonight", "Also me at 3 AM:"),
|
| 151 |
+
("CSS in theory", "CSS in practice"),
|
| 152 |
+
("My code works", "I have no idea why"),
|
| 153 |
+
("Expected behavior", "Actual behavior")
|
| 154 |
+
]
|
| 155 |
+
return random.choice(ideas)
|
| 156 |
+
|
| 157 |
+
def format_trend_data(keyword, data=None):
|
| 158 |
+
"""ํธ๋ ๋ ๋ฐ์ดํฐ ํฌ๋งทํ
"""
|
| 159 |
+
if not data:
|
| 160 |
+
# ์๋ฎฌ๋ ์ด์
๋ฐ์ดํฐ ์์ฑ
|
| 161 |
+
popularity = random.randint(60, 95)
|
| 162 |
+
growth = random.randint(-20, 50)
|
| 163 |
+
related_terms = random.sample([
|
| 164 |
+
'๋ฐ์ด๋ด', '์ธ๊ธฐ', 'ํธ๋ ๋', '์๊ธด', '์ฌ๋ฏธ์๋',
|
| 165 |
+
'ํซ์ด์', 'ํ์ ', '๋ฐ', 'ํจ๋ฌ๋', '์ ๋จธ'
|
| 166 |
+
], 3)
|
| 167 |
+
|
| 168 |
+
result = f"""
|
| 169 |
+
๐ '{keyword}' ํธ๋ ๋ ๋ถ์ ๊ฒฐ๊ณผ
|
| 170 |
+
|
| 171 |
+
๐ฅ ์ธ๊ธฐ๋: {popularity}/100
|
| 172 |
+
๐ ์ฑ์ฅ๋ฅ : {growth:+d}%
|
| 173 |
+
๐ท๏ธ ๊ด๋ จ ํค์๋: {', '.join(related_terms)}
|
| 174 |
+
โฐ ๋ถ์ ์๊ฐ: ๋ฐฉ๊ธ ์
|
| 175 |
+
|
| 176 |
+
๐ก ์ถ์ฒ: {'์์น ํธ๋ ๋์
๋๋ค!' if growth > 0 else '๊ด์ฌ์ ๋ ์ ์๋ ํค์๋์
๋๋ค.'}
|
| 177 |
+
"""
|
| 178 |
+
return result.strip()
|
| 179 |
+
|
| 180 |
+
return str(data)
|