Spaces:
Sleeping
Sleeping
Auto commit at 07-2025-08 4:57:05
Browse files- app.py +74 -64
- app_250807_0446.py +177 -0
app.py
CHANGED
|
@@ -6,62 +6,85 @@ import torch
|
|
| 6 |
import fitz # PyMuPDF
|
| 7 |
from PIL import Image
|
| 8 |
import io
|
|
|
|
| 9 |
|
| 10 |
# --- 1. ์ ์ญ ๋ณ์ ๋ฐ ํ๊ฒฝ ์ค์ ---
|
| 11 |
tokenizer = None
|
| 12 |
model = None
|
| 13 |
MODEL_LOADED = False
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
# .env ํ์ผ์์ ํ๊ฒฝ ๋ณ์ ๋ก๋ (์ฃผ๋ก ๋ก์ปฌ์์ ์ฌ์ฉ)
|
| 16 |
try:
|
| 17 |
from dotenv import load_dotenv
|
| 18 |
-
|
| 19 |
-
|
|
|
|
| 20 |
except ImportError:
|
| 21 |
print("โ ๏ธ python-dotenv๊ฐ ์ค์น๋์ง ์์, ์์คํ
ํ๊ฒฝ ๋ณ์ ์ฌ์ฉ")
|
| 22 |
|
| 23 |
# ํ๊ฒฝ ๋ณ์์์ ํ ํฐ ๋ฐ ๋ชจ๋ธ ์ด๋ฆ ๊ฐ์ ธ์ค๊ธฐ
|
| 24 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
print(f"
|
|
|
|
|
|
|
|
|
|
| 28 |
print(f"๐ HF ํ ํฐ: {'โ
์ค์ ๋จ'if HF_TOKEN else 'โ ์ค์ ๋์ง ์์'}")
|
|
|
|
| 29 |
|
| 30 |
-
|
|
|
|
| 31 |
try:
|
| 32 |
print("๐ง ๋ชจ๋ธ ๋ฐ ํ ํฌ๋์ด์ ๋ก๋ฉ ์์...")
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
trust_remote_code=True
|
| 42 |
-
)
|
| 43 |
model = KananaVForConditionalGeneration.from_pretrained(
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
token=HF_TOKEN,
|
| 46 |
torch_dtype=torch.float16,
|
| 47 |
trust_remote_code=True,
|
| 48 |
-
device_map="auto" # GPU ์๋ ํ ๋น
|
| 49 |
)
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
print("โ ๏ธ HF ํ ํฐ์ด ์์ด ๊ณต๊ฐ ๋ชจ๋ธ(DialoGPT)๋ก ๋์ฒดํฉ๋๋ค.")
|
| 54 |
-
MODEL_NAME = "microsoft/DialoGPT-medium"
|
| 55 |
-
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
| 56 |
-
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, torch_dtype=torch.float16, device_map="auto")
|
| 57 |
-
MODEL_LOADED = True
|
| 58 |
|
| 59 |
except Exception as e:
|
| 60 |
print(f"โ ๋ชจ๋ธ ๋ก๋ฉ ์คํจ: {e}")
|
| 61 |
traceback.print_exc()
|
| 62 |
MODEL_LOADED = False
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
| 65 |
def extract_text_from_pdf(pdf_file):
|
| 66 |
try:
|
| 67 |
doc = fitz.open(stream=pdf_file.read(), filetype="pdf")
|
|
@@ -73,44 +96,28 @@ def extract_text_from_pdf(pdf_file):
|
|
| 73 |
return f"PDF ํ์ผ์ ์ฝ๋ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}"
|
| 74 |
|
| 75 |
def process_uploaded_file(file):
|
| 76 |
-
"""์
๋ก๋๋ ํ์ผ์ ํ
์คํธ์ ์ด๋ฏธ์ง ๊ฐ์ฒด๋ก ๋ถ๋ฆฌ"""
|
| 77 |
if file is None:
|
| 78 |
-
return "", None
|
| 79 |
-
|
| 80 |
file_path = file.name
|
| 81 |
file_extension = os.path.splitext(file_path)[1].lower()
|
| 82 |
-
|
| 83 |
if file_extension == '.pdf':
|
| 84 |
text_content = extract_text_from_pdf(file)
|
| 85 |
-
return text_content, None
|
| 86 |
elif file_extension in ['.png', '.jpg', '.jpeg']:
|
| 87 |
image = Image.open(file).convert('RGB')
|
| 88 |
-
# ์ด๋ฏธ์ง ํ์ผ ์์ฒด๋ฅผ ๋ฐํ (OCR ๋์ ๋ฉํฐ๋ชจ๋ฌ ์
๋ ฅ์ผ๋ก ์ฌ์ฉ)
|
| 89 |
return "์
๋ก๋๋ ์ด๋ฏธ์ง๊ฐ ์์ต๋๋ค.", image
|
| 90 |
else:
|
| 91 |
return f"์ง์ํ์ง ์๋ ํ์ผ ํ์: {file_extension}", None
|
| 92 |
|
| 93 |
-
# --- 4. ํต์ฌ ๋ก์ง: ํตํฉ ์๋ต ์์ฑ ํจ์ ---
|
| 94 |
def generate_response(prompt_template: str, message: str, file: Optional = None):
|
| 95 |
-
"""ํ
์คํธ์ ์ด๋ฏธ์ง๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌํ๋ ํตํฉ ์๋ต ์์ฑ ํจ์"""
|
| 96 |
if not MODEL_LOADED:
|
| 97 |
return "โ ๋ชจ๋ธ์ด ๋ก๋๋์ง ์์์ต๋๋ค. ๊ด๋ฆฌ์์๊ฒ ๋ฌธ์ํ์ธ์."
|
| 98 |
-
|
| 99 |
try:
|
| 100 |
-
# 1. ํ์ผ ์ฒ๋ฆฌ
|
| 101 |
file_text, pil_image = process_uploaded_file(file)
|
| 102 |
-
|
| 103 |
-
# 2. ์ ์ฒด ํ๋กฌํํธ ๊ตฌ์ฑ
|
| 104 |
-
full_message = message
|
| 105 |
-
if file_text:
|
| 106 |
-
full_message += f"\n\n[์ฒจ๋ถ ํ์ผ ๋ด์ฉ]\n{file_text}"
|
| 107 |
-
|
| 108 |
full_prompt = prompt_template.format(message=full_message)
|
| 109 |
-
|
| 110 |
-
# 3. ํ ํฌ๋์ด์ ๋ก ํ
์คํธ ์
๋ ฅ ๋ณํ
|
| 111 |
-
inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device)
|
| 112 |
|
| 113 |
-
# 4. ์์ฑ ํ๋ผ๋ฏธํฐ ์ค๋น
|
| 114 |
generation_args = {
|
| 115 |
"max_new_tokens": 512,
|
| 116 |
"temperature": 0.7,
|
|
@@ -118,38 +125,35 @@ def generate_response(prompt_template: str, message: str, file: Optional = None)
|
|
| 118 |
"pad_token_id": tokenizer.eos_token_id
|
| 119 |
}
|
| 120 |
|
| 121 |
-
# 5. ์ด๋ฏธ์ง๊ฐ ์๋ ๊ฒฝ์ฐ, ๋ฉํฐ๋ชจ๋ฌ ์
๋ ฅ ์ถ๊ฐ
|
| 122 |
if pil_image:
|
| 123 |
print("๐ผ๏ธ ์ด๋ฏธ์ง ํฌํจ, ๋ฉํฐ๋ชจ๋ฌ ๋ชจ๋๋ก ์์ฑ")
|
| 124 |
-
#
|
| 125 |
-
#
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
with torch.no_grad():
|
| 133 |
outputs = model.generate(**inputs, **generation_args)
|
| 134 |
|
| 135 |
-
# 7. ์์ฑ๋ ํ ํฐ ID๋ฅผ ํ
์คํธ๋ก ๋์ฝ๋ฉ
|
| 136 |
-
# ์
๋ ฅ ํ๋กฌํํธ ๋ถ๋ถ์ ์ ์ธํ๊ณ ์์ํ ๋ต๋ณ๋ง ์ถ์ถ
|
| 137 |
input_length = inputs["input_ids"].shape[1]
|
| 138 |
response_ids = outputs[0][input_length:]
|
| 139 |
response = tokenizer.decode(response_ids, skip_special_tokens=True).strip()
|
| 140 |
|
| 141 |
return response
|
| 142 |
-
|
| 143 |
except Exception as e:
|
| 144 |
print(f"โ ์๋ต ์์ฑ ์ค ์ค๋ฅ ๋ฐ์: {e}")
|
| 145 |
traceback.print_exc()
|
| 146 |
return f"์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}"
|
| 147 |
|
| 148 |
-
# ---
|
|
|
|
| 149 |
with gr.Blocks(title="Lily Math RAG System", theme=gr.themes.Soft()) as demo:
|
|
|
|
| 150 |
gr.Markdown("# ๐งฎ Lily Math RAG System")
|
| 151 |
gr.Markdown("์ํ ๋ฌธ์ ํด๊ฒฐ ๋ฐ ๋ฉํฐ๋ชจ๋ฌ ๋ํ๋ฅผ ์ํ AI ์์คํ
์
๋๋ค.")
|
| 152 |
-
|
| 153 |
with gr.Tabs():
|
| 154 |
with gr.Tab("๐ฌ ์ฑํ
"):
|
| 155 |
chat_prompt = "<|im_start|>user\n{message}<|im_end|>\n<|im_start|>assistant\n"
|
|
@@ -165,13 +169,19 @@ with gr.Blocks(title="Lily Math RAG System", theme=gr.themes.Soft()) as demo:
|
|
| 165 |
chat_history.append({"role": "user", "content": message})
|
| 166 |
chat_history.append({"role": "assistant", "content": bot_message})
|
| 167 |
return "", chat_history
|
| 168 |
-
|
| 169 |
msg.submit(respond, [msg, chatbot, file_input], [msg, chatbot])
|
| 170 |
|
| 171 |
with gr.Tab("โ๏ธ ์์คํ
์ ๋ณด"):
|
| 172 |
-
gr.Markdown(f"
|
|
|
|
| 173 |
gr.Markdown(f"**๋ชจ๋ธ ์ํ**: `{'โ
๋ก๋๋จ' if MODEL_LOADED else 'โ ๋ก๋ ์คํจ'}`")
|
| 174 |
|
| 175 |
if __name__ == "__main__":
|
| 176 |
-
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
import fitz # PyMuPDF
|
| 7 |
from PIL import Image
|
| 8 |
import io
|
| 9 |
+
from typing import Optional
|
| 10 |
|
| 11 |
# --- 1. ์ ์ญ ๋ณ์ ๋ฐ ํ๊ฒฝ ์ค์ ---
|
| 12 |
tokenizer = None
|
| 13 |
model = None
|
| 14 |
MODEL_LOADED = False
|
| 15 |
+
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
| 16 |
+
|
| 17 |
+
# ๋ก์ปฌ/์๋ฒ ํ๊ฒฝ ์๋ ๊ฐ์ง
|
| 18 |
+
IS_LOCAL = os.path.exists('.env') or os.path.exists('../.env') or os.getenv('IS_LOCAL') == 'true'
|
| 19 |
|
| 20 |
# .env ํ์ผ์์ ํ๊ฒฝ ๋ณ์ ๋ก๋ (์ฃผ๋ก ๋ก์ปฌ์์ ์ฌ์ฉ)
|
| 21 |
try:
|
| 22 |
from dotenv import load_dotenv
|
| 23 |
+
if IS_LOCAL:
|
| 24 |
+
load_dotenv()
|
| 25 |
+
print("โ
.env ํ์ผ ๋ก๋๋จ")
|
| 26 |
except ImportError:
|
| 27 |
print("โ ๏ธ python-dotenv๊ฐ ์ค์น๋์ง ์์, ์์คํ
ํ๊ฒฝ ๋ณ์ ์ฌ์ฉ")
|
| 28 |
|
| 29 |
# ํ๊ฒฝ ๋ณ์์์ ํ ํฐ ๋ฐ ๋ชจ๋ธ ์ด๋ฆ ๊ฐ์ ธ์ค๊ธฐ
|
| 30 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 31 |
+
MODEL_NAME_SERVER = os.getenv("MODEL_NAME", "gbrabbit/lily-math-model")
|
| 32 |
+
MODEL_PATH_LOCAL = "../lily_llm_core/models/kanana-1.5-v-3b-instruct" # ์ฌ์ฉ์ ๋ก์ปฌ ๋ชจ๋ธ ๊ฒฝ๋ก
|
| 33 |
+
|
| 34 |
+
# ์ต์ข
๋ชจ๋ธ ๊ฒฝ๋ก ์ค์
|
| 35 |
+
MODEL_PATH = MODEL_PATH_LOCAL if IS_LOCAL else MODEL_NAME_SERVER
|
| 36 |
|
| 37 |
+
print(f"============== ์์คํ
ํ๊ฒฝ ์ ๋ณด ==============")
|
| 38 |
+
print(f"๐ ์คํ ํ๊ฒฝ: {'๋ก์ปฌ' if IS_LOCAL else '์๋ฒ'}")
|
| 39 |
+
print(f"๐ ๋ชจ๋ธ ๊ฒฝ๋ก: {MODEL_PATH}")
|
| 40 |
+
print(f"๐ ์ฌ์ฉ ๋๋ฐ์ด์ค: {DEVICE.upper()}")
|
| 41 |
print(f"๐ HF ํ ํฐ: {'โ
์ค์ ๋จ'if HF_TOKEN else 'โ ์ค์ ๋์ง ์์'}")
|
| 42 |
+
print("==========================================")
|
| 43 |
|
| 44 |
+
|
| 45 |
+
# --- 2. ํต์ฌ ๋ก์ง: ์กฐ๊ฑด๋ถ ๋ชจ๋ธ ๋ฐ ํ ํฌ๋์ด์ ๋ก๋ฉ ---
|
| 46 |
try:
|
| 47 |
print("๐ง ๋ชจ๋ธ ๋ฐ ํ ํฌ๋์ด์ ๋ก๋ฉ ์์...")
|
| 48 |
+
from modeling import KananaVForConditionalGeneration # ์ปค์คํ
๋ชจ๋ธ ํด๋์ค import
|
| 49 |
+
|
| 50 |
+
if IS_LOCAL:
|
| 51 |
+
# ๋ก์ปฌ ํ์ผ ์์คํ
์์ ๋ชจ๋ธ ๋ก๋
|
| 52 |
+
if not os.path.exists(MODEL_PATH):
|
| 53 |
+
raise FileNotFoundError(f"๋ก์ปฌ ๋ชจ๋ธ ๊ฒฝ๋ก๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค: {MODEL_PATH}")
|
| 54 |
+
|
| 55 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True, local_files_only=True)
|
|
|
|
|
|
|
| 56 |
model = KananaVForConditionalGeneration.from_pretrained(
|
| 57 |
+
MODEL_PATH,
|
| 58 |
+
torch_dtype=torch.float16,
|
| 59 |
+
trust_remote_code=True,
|
| 60 |
+
local_files_only=True
|
| 61 |
+
).to(DEVICE) # ๋ก์ปฌ GPU/CPU์ ํ ๋น
|
| 62 |
+
print("โ
๋ก์ปฌ ๋ชจ๋ธ ๋ก๋ฉ ์๋ฃ!")
|
| 63 |
+
|
| 64 |
+
else: # ์๋ฒ ํ๊ฒฝ
|
| 65 |
+
if not HF_TOKEN:
|
| 66 |
+
raise ValueError("์๋ฒ ํ๊ฒฝ์์๋ Hugging Face ํ ํฐ(HF_TOKEN)์ด ๋ฐ๋์ ํ์ํฉ๋๋ค.")
|
| 67 |
+
|
| 68 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, token=HF_TOKEN, trust_remote_code=True)
|
| 69 |
+
model = KananaVForConditionalGeneration.from_pretrained(
|
| 70 |
+
MODEL_PATH,
|
| 71 |
token=HF_TOKEN,
|
| 72 |
torch_dtype=torch.float16,
|
| 73 |
trust_remote_code=True,
|
| 74 |
+
device_map="auto" # ์๋ฒ GPU ์๋ ํ ๋น
|
| 75 |
)
|
| 76 |
+
print("โ
์๋ฒ ๋ชจ๋ธ ๋ก๋ฉ ์๋ฃ!")
|
| 77 |
+
|
| 78 |
+
MODEL_LOADED = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
except Exception as e:
|
| 81 |
print(f"โ ๋ชจ๋ธ ๋ก๋ฉ ์คํจ: {e}")
|
| 82 |
traceback.print_exc()
|
| 83 |
MODEL_LOADED = False
|
| 84 |
|
| 85 |
+
|
| 86 |
+
# --- 3. ํ์ผ ์ฒ๋ฆฌ ๋ฐ ์๋ต ์์ฑ ๋ก์ง (์ด์ ๊ณผ ๋์ผ) ---
|
| 87 |
+
|
| 88 |
def extract_text_from_pdf(pdf_file):
|
| 89 |
try:
|
| 90 |
doc = fitz.open(stream=pdf_file.read(), filetype="pdf")
|
|
|
|
| 96 |
return f"PDF ํ์ผ์ ์ฝ๋ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}"
|
| 97 |
|
| 98 |
def process_uploaded_file(file):
|
|
|
|
| 99 |
if file is None:
|
| 100 |
+
return "", None
|
|
|
|
| 101 |
file_path = file.name
|
| 102 |
file_extension = os.path.splitext(file_path)[1].lower()
|
|
|
|
| 103 |
if file_extension == '.pdf':
|
| 104 |
text_content = extract_text_from_pdf(file)
|
| 105 |
+
return text_content, None
|
| 106 |
elif file_extension in ['.png', '.jpg', '.jpeg']:
|
| 107 |
image = Image.open(file).convert('RGB')
|
|
|
|
| 108 |
return "์
๋ก๋๋ ์ด๋ฏธ์ง๊ฐ ์์ต๋๋ค.", image
|
| 109 |
else:
|
| 110 |
return f"์ง์ํ์ง ์๋ ํ์ผ ํ์: {file_extension}", None
|
| 111 |
|
|
|
|
| 112 |
def generate_response(prompt_template: str, message: str, file: Optional = None):
|
|
|
|
| 113 |
if not MODEL_LOADED:
|
| 114 |
return "โ ๋ชจ๋ธ์ด ๋ก๋๋์ง ์์์ต๋๋ค. ๊ด๋ฆฌ์์๊ฒ ๋ฌธ์ํ์ธ์."
|
|
|
|
| 115 |
try:
|
|
|
|
| 116 |
file_text, pil_image = process_uploaded_file(file)
|
| 117 |
+
full_message = message + (f"\n\n[์ฒจ๋ถ ํ์ผ ๋ด์ฉ]\n{file_text}" if file_text else "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
full_prompt = prompt_template.format(message=full_message)
|
| 119 |
+
inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device if IS_LOCAL else model.device)
|
|
|
|
|
|
|
| 120 |
|
|
|
|
| 121 |
generation_args = {
|
| 122 |
"max_new_tokens": 512,
|
| 123 |
"temperature": 0.7,
|
|
|
|
| 125 |
"pad_token_id": tokenizer.eos_token_id
|
| 126 |
}
|
| 127 |
|
|
|
|
| 128 |
if pil_image:
|
| 129 |
print("๐ผ๏ธ ์ด๋ฏธ์ง ํฌํจ, ๋ฉํฐ๋ชจ๋ฌ ๋ชจ๋๋ก ์์ฑ")
|
| 130 |
+
# ์ฐธ๊ณ : ์ด image_processor ๋ถ๋ถ์ ์ค์ ์ฌ์ฉํ๋ ๋ชจ๋ธ์ ๋ง์ถฐ์ผ ํฉ๋๋ค.
|
| 131 |
+
# KananaV ๋ชจ๋ธ์ image_processor๊ฐ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
|
| 132 |
+
if hasattr(model, 'vision_model') and hasattr(model.vision_model, 'image_processor'):
|
| 133 |
+
pixel_values = model.vision_model.image_processor(pil_image, return_tensors='pt')['pixel_values']
|
| 134 |
+
generation_args["pixel_values"] = pixel_values.to(inputs.input_ids.device, dtype=torch.float16)
|
| 135 |
+
else:
|
| 136 |
+
print("โ ๏ธ ํ์ฌ ๋ชจ๋ธ์ 'image_processor'๊ฐ ์ ์๋์ง ์์ ์ด๋ฏธ์ง๋ฅผ ๋ฌด์ํฉ๋๋ค.")
|
| 137 |
+
|
| 138 |
with torch.no_grad():
|
| 139 |
outputs = model.generate(**inputs, **generation_args)
|
| 140 |
|
|
|
|
|
|
|
| 141 |
input_length = inputs["input_ids"].shape[1]
|
| 142 |
response_ids = outputs[0][input_length:]
|
| 143 |
response = tokenizer.decode(response_ids, skip_special_tokens=True).strip()
|
| 144 |
|
| 145 |
return response
|
|
|
|
| 146 |
except Exception as e:
|
| 147 |
print(f"โ ์๋ต ์์ฑ ์ค ์ค๋ฅ ๋ฐ์: {e}")
|
| 148 |
traceback.print_exc()
|
| 149 |
return f"์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}"
|
| 150 |
|
| 151 |
+
# --- 4. Gradio UI ๋ฐ ์กฐ๊ฑด๋ถ ์คํ ---
|
| 152 |
+
|
| 153 |
with gr.Blocks(title="Lily Math RAG System", theme=gr.themes.Soft()) as demo:
|
| 154 |
+
# UI ๊ตฌ์ฑ์ ์ด์ ๊ณผ ๋์ผ
|
| 155 |
gr.Markdown("# ๐งฎ Lily Math RAG System")
|
| 156 |
gr.Markdown("์ํ ๋ฌธ์ ํด๊ฒฐ ๋ฐ ๋ฉํฐ๋ชจ๋ฌ ๋ํ๋ฅผ ์ํ AI ์์คํ
์
๋๋ค.")
|
|
|
|
| 157 |
with gr.Tabs():
|
| 158 |
with gr.Tab("๐ฌ ์ฑํ
"):
|
| 159 |
chat_prompt = "<|im_start|>user\n{message}<|im_end|>\n<|im_start|>assistant\n"
|
|
|
|
| 169 |
chat_history.append({"role": "user", "content": message})
|
| 170 |
chat_history.append({"role": "assistant", "content": bot_message})
|
| 171 |
return "", chat_history
|
|
|
|
| 172 |
msg.submit(respond, [msg, chatbot, file_input], [msg, chatbot])
|
| 173 |
|
| 174 |
with gr.Tab("โ๏ธ ์์คํ
์ ๋ณด"):
|
| 175 |
+
gr.Markdown(f"**์คํ ํ๊ฒฝ**: `{'๋ก์ปฌ' if IS_LOCAL else '์๋ฒ'}`")
|
| 176 |
+
gr.Markdown(f"**๋ชจ๋ธ ๊ฒฝ๋ก**: `{MODEL_PATH}`")
|
| 177 |
gr.Markdown(f"**๋ชจ๋ธ ์ํ**: `{'โ
๋ก๋๋จ' if MODEL_LOADED else 'โ ๋ก๋ ์คํจ'}`")
|
| 178 |
|
| 179 |
if __name__ == "__main__":
|
| 180 |
+
if IS_LOCAL:
|
| 181 |
+
# ๋ก์ปฌ ํ๊ฒฝ์๏ฟฝ๏ฟฝ๋ ๊ณ ์ ๋ ์ฃผ์์ ํฌํธ๋ก ์คํ
|
| 182 |
+
print("\n๐ ๋ก์ปฌ ์๋ฒ๋ฅผ ์์ํฉ๋๋ค. http://127.0.0.1:7860")
|
| 183 |
+
demo.launch(server_name="127.0.0.1", server_port=7860)
|
| 184 |
+
else:
|
| 185 |
+
# ์๋ฒ ํ๊ฒฝ์์๋ ๊ณต๊ฐ ๋งํฌ๋ฅผ ์์ฑํ์ฌ ์คํ
|
| 186 |
+
print("\n๐ ์๋ฒ๋ฅผ ์์ํฉ๋๋ค...")
|
| 187 |
+
demo.launch(share=True)
|
app_250807_0446.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import os
|
| 3 |
+
import traceback
|
| 4 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 5 |
+
import torch
|
| 6 |
+
import fitz # PyMuPDF
|
| 7 |
+
from PIL import Image
|
| 8 |
+
import io
|
| 9 |
+
|
| 10 |
+
# --- 1. ์ ์ญ ๋ณ์ ๋ฐ ํ๊ฒฝ ์ค์ ---
|
| 11 |
+
tokenizer = None
|
| 12 |
+
model = None
|
| 13 |
+
MODEL_LOADED = False
|
| 14 |
+
|
| 15 |
+
# .env ํ์ผ์์ ํ๊ฒฝ ๋ณ์ ๋ก๋ (์ฃผ๋ก ๋ก์ปฌ์์ ์ฌ์ฉ)
|
| 16 |
+
try:
|
| 17 |
+
from dotenv import load_dotenv
|
| 18 |
+
load_dotenv()
|
| 19 |
+
print("โ
.env ํ์ผ ๋ก๋๋จ")
|
| 20 |
+
except ImportError:
|
| 21 |
+
print("โ ๏ธ python-dotenv๊ฐ ์ค์น๋์ง ์์, ์์คํ
ํ๊ฒฝ ๋ณ์ ์ฌ์ฉ")
|
| 22 |
+
|
| 23 |
+
# ํ๊ฒฝ ๋ณ์์์ ํ ํฐ ๋ฐ ๋ชจ๋ธ ์ด๋ฆ ๊ฐ์ ธ์ค๊ธฐ
|
| 24 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 25 |
+
MODEL_NAME = os.getenv("MODEL_NAME", "gbrabbit/lily-math-model")
|
| 26 |
+
|
| 27 |
+
print(f"๐ ๋ชจ๋ธ: {MODEL_NAME}")
|
| 28 |
+
print(f"๐ HF ํ ํฐ: {'โ
์ค์ ๋จ'if HF_TOKEN else 'โ ์ค์ ๋์ง ์์'}")
|
| 29 |
+
|
| 30 |
+
# --- 2. ํต์ฌ ๋ก์ง: ๋ชจ๋ธ ๋ฐ ํ ํฌ๋์ด์ ๋ก๋ฉ ---
|
| 31 |
+
try:
|
| 32 |
+
print("๐ง ๋ชจ๋ธ ๋ฐ ํ ํฌ๋์ด์ ๋ก๋ฉ ์์...")
|
| 33 |
+
|
| 34 |
+
# ์ปค์คํ
๋ชจ๋ธ ํด๋์ค import
|
| 35 |
+
from modeling import KananaVForConditionalGeneration
|
| 36 |
+
|
| 37 |
+
if HF_TOKEN:
|
| 38 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 39 |
+
MODEL_NAME,
|
| 40 |
+
token=HF_TOKEN,
|
| 41 |
+
trust_remote_code=True
|
| 42 |
+
)
|
| 43 |
+
model = KananaVForConditionalGeneration.from_pretrained(
|
| 44 |
+
MODEL_NAME,
|
| 45 |
+
token=HF_TOKEN,
|
| 46 |
+
torch_dtype=torch.float16,
|
| 47 |
+
trust_remote_code=True,
|
| 48 |
+
device_map="auto" # GPU ์๋ ํ ๋น (์๋ฒ ํ๊ฒฝ์ ํ์)
|
| 49 |
+
)
|
| 50 |
+
MODEL_LOADED = True
|
| 51 |
+
print("โ
์ปค์คํ
๋ชจ๋ธ ๋ก๋ฉ ์๋ฃ!")
|
| 52 |
+
else:
|
| 53 |
+
print("โ ๏ธ HF ํ ํฐ์ด ์์ด ๊ณต๊ฐ ๋ชจ๋ธ(DialoGPT)๋ก ๋์ฒดํฉ๋๋ค.")
|
| 54 |
+
MODEL_NAME = "microsoft/DialoGPT-medium"
|
| 55 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
| 56 |
+
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, torch_dtype=torch.float16, device_map="auto")
|
| 57 |
+
MODEL_LOADED = True
|
| 58 |
+
|
| 59 |
+
except Exception as e:
|
| 60 |
+
print(f"โ ๋ชจ๋ธ ๋ก๋ฉ ์คํจ: {e}")
|
| 61 |
+
traceback.print_exc()
|
| 62 |
+
MODEL_LOADED = False
|
| 63 |
+
|
| 64 |
+
# --- 3. ํ์ผ ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ ---
|
| 65 |
+
def extract_text_from_pdf(pdf_file):
|
| 66 |
+
try:
|
| 67 |
+
doc = fitz.open(stream=pdf_file.read(), filetype="pdf")
|
| 68 |
+
text = "".join(page.get_text() for page in doc)
|
| 69 |
+
doc.close()
|
| 70 |
+
return text
|
| 71 |
+
except Exception as e:
|
| 72 |
+
print(f"PDF ์ฒ๋ฆฌ ์ค๋ฅ: {e}")
|
| 73 |
+
return f"PDF ํ์ผ์ ์ฝ๋ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}"
|
| 74 |
+
|
| 75 |
+
def process_uploaded_file(file):
|
| 76 |
+
"""์
๋ก๋๋ ํ์ผ์ ํ
์คํธ์ ์ด๋ฏธ์ง ๊ฐ์ฒด๋ก ๋ถ๋ฆฌ"""
|
| 77 |
+
if file is None:
|
| 78 |
+
return "", None # ํ
์คํธ, ์ด๋ฏธ์ง ์์
|
| 79 |
+
|
| 80 |
+
file_path = file.name
|
| 81 |
+
file_extension = os.path.splitext(file_path)[1].lower()
|
| 82 |
+
|
| 83 |
+
if file_extension == '.pdf':
|
| 84 |
+
text_content = extract_text_from_pdf(file)
|
| 85 |
+
return text_content, None # PDF๋ ํ
์คํธ๋ง, ์ด๋ฏธ์ง๋ ์์
|
| 86 |
+
elif file_extension in ['.png', '.jpg', '.jpeg']:
|
| 87 |
+
image = Image.open(file).convert('RGB')
|
| 88 |
+
# ์ด๋ฏธ์ง ํ์ผ ์์ฒด๋ฅผ ๋ฐํ (OCR ๋์ ๋ฉํฐ๋ชจ๋ฌ ์
๋ ฅ์ผ๋ก ์ฌ์ฉ)
|
| 89 |
+
return "์
๋ก๋๋ ์ด๋ฏธ์ง๊ฐ ์์ต๋๋ค.", image
|
| 90 |
+
else:
|
| 91 |
+
return f"์ง์ํ์ง ์๋ ํ์ผ ํ์: {file_extension}", None
|
| 92 |
+
|
| 93 |
+
# --- 4. ํต์ฌ ๋ก์ง: ํตํฉ ์๋ต ์์ฑ ํจ์ ---
|
| 94 |
+
def generate_response(prompt_template: str, message: str, file: Optional = None):
|
| 95 |
+
"""ํ
์คํธ์ ์ด๋ฏธ์ง๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌํ๋ ํตํฉ ์๋ต ์์ฑ ํจ์"""
|
| 96 |
+
if not MODEL_LOADED:
|
| 97 |
+
return "โ ๋ชจ๋ธ์ด ๋ก๋๋์ง ์์์ต๋๋ค. ๊ด๋ฆฌ์์๊ฒ ๋ฌธ์ํ์ธ์."
|
| 98 |
+
|
| 99 |
+
try:
|
| 100 |
+
# 1. ํ์ผ ์ฒ๋ฆฌ
|
| 101 |
+
file_text, pil_image = process_uploaded_file(file)
|
| 102 |
+
|
| 103 |
+
# 2. ์ ์ฒด ํ๋กฌํํธ ๊ตฌ์ฑ
|
| 104 |
+
full_message = message
|
| 105 |
+
if file_text:
|
| 106 |
+
full_message += f"\n\n[์ฒจ๋ถ ํ์ผ ๋ด์ฉ]\n{file_text}"
|
| 107 |
+
|
| 108 |
+
full_prompt = prompt_template.format(message=full_message)
|
| 109 |
+
|
| 110 |
+
# 3. ํ ํฌ๋์ด์ ๋ก ํ
์คํธ ์
๋ ฅ ๋ณํ
|
| 111 |
+
inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device)
|
| 112 |
+
|
| 113 |
+
# 4. ์์ฑ ํ๋ผ๋ฏธํฐ ์ค๋น
|
| 114 |
+
generation_args = {
|
| 115 |
+
"max_new_tokens": 512,
|
| 116 |
+
"temperature": 0.7,
|
| 117 |
+
"do_sample": True,
|
| 118 |
+
"pad_token_id": tokenizer.eos_token_id
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
# 5. ์ด๋ฏธ์ง๊ฐ ์๋ ๊ฒฝ์ฐ, ๋ฉํฐ๋ชจ๋ฌ ์
๋ ฅ ์ถ๊ฐ
|
| 122 |
+
if pil_image:
|
| 123 |
+
print("๐ผ๏ธ ์ด๋ฏธ์ง ํฌํจ, ๋ฉํฐ๋ชจ๋ฌ ๋ชจ๋๋ก ์์ฑ")
|
| 124 |
+
# KananaV ๋ชจ๋ธ์ ๋ง๋ ํํ๋ก ์ด๋ฏธ์ง ์ ์ฒ๋ฆฌ
|
| 125 |
+
# (๋ชจ๋ธ์ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ์ด ๋ถ๋ถ์ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค)
|
| 126 |
+
pixel_values = model.vision_model.image_processor(pil_image, return_tensors='pt')['pixel_values']
|
| 127 |
+
generation_args["pixel_values"] = pixel_values.to(model.device, dtype=torch.float16)
|
| 128 |
+
else:
|
| 129 |
+
print("๐ ํ
์คํธ๋ง์ผ๋ก ์์ฑ")
|
| 130 |
+
|
| 131 |
+
# 6. ๋ชจ๋ธ์ ํตํด ์๋ต ์์ฑ (๋จ ํ ๋ฒ์ ์ฌ๋ฐ๋ฅธ ํธ์ถ)
|
| 132 |
+
with torch.no_grad():
|
| 133 |
+
outputs = model.generate(**inputs, **generation_args)
|
| 134 |
+
|
| 135 |
+
# 7. ์์ฑ๋ ํ ํฐ ID๋ฅผ ํ
์คํธ๋ก ๋์ฝ๋ฉ
|
| 136 |
+
# ์
๋ ฅ ํ๋กฌํํธ ๋ถ๋ถ์ ์ ์ธํ๊ณ ์์ํ ๋ต๋ณ๋ง ์ถ์ถ
|
| 137 |
+
input_length = inputs["input_ids"].shape[1]
|
| 138 |
+
response_ids = outputs[0][input_length:]
|
| 139 |
+
response = tokenizer.decode(response_ids, skip_special_tokens=True).strip()
|
| 140 |
+
|
| 141 |
+
return response
|
| 142 |
+
|
| 143 |
+
except Exception as e:
|
| 144 |
+
print(f"โ ์๋ต ์์ฑ ์ค ์ค๋ฅ ๋ฐ์: {e}")
|
| 145 |
+
traceback.print_exc()
|
| 146 |
+
return f"์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}"
|
| 147 |
+
|
| 148 |
+
# --- 5. Gradio UI ๋ฐ ์คํ ---
|
| 149 |
+
with gr.Blocks(title="Lily Math RAG System", theme=gr.themes.Soft()) as demo:
|
| 150 |
+
gr.Markdown("# ๐งฎ Lily Math RAG System")
|
| 151 |
+
gr.Markdown("์ํ ๋ฌธ์ ํด๊ฒฐ ๋ฐ ๋ฉํฐ๋ชจ๋ฌ ๋ํ๋ฅผ ์ํ AI ์์คํ
์
๋๋ค.")
|
| 152 |
+
|
| 153 |
+
with gr.Tabs():
|
| 154 |
+
with gr.Tab("๐ฌ ์ฑํ
"):
|
| 155 |
+
chat_prompt = "<|im_start|>user\n{message}<|im_end|>\n<|im_start|>assistant\n"
|
| 156 |
+
chatbot = gr.Chatbot(height=500, label="๋ํ์ฐฝ", type="messages")
|
| 157 |
+
with gr.Row():
|
| 158 |
+
with gr.Column(scale=4):
|
| 159 |
+
msg = gr.Textbox(label="๋ฉ์์ง", placeholder="์ด๋ฏธ์ง๋ PDF๋ฅผ ์ฒจ๋ถํ๊ณ ์ง๋ฌธํด๋ณด์ธ์!", lines=3, show_label=False)
|
| 160 |
+
with gr.Column(scale=1, min_width=150):
|
| 161 |
+
file_input = gr.File(label="ํ์ผ ์
๋ก๋", file_types=[".pdf", ".png", ".jpg", ".jpeg"])
|
| 162 |
+
|
| 163 |
+
def respond(message, chat_history, file):
|
| 164 |
+
bot_message = generate_response(chat_prompt, message, file)
|
| 165 |
+
chat_history.append({"role": "user", "content": message})
|
| 166 |
+
chat_history.append({"role": "assistant", "content": bot_message})
|
| 167 |
+
return "", chat_history
|
| 168 |
+
|
| 169 |
+
msg.submit(respond, [msg, chatbot, file_input], [msg, chatbot])
|
| 170 |
+
|
| 171 |
+
with gr.Tab("โ๏ธ ์์คํ
์ ๋ณด"):
|
| 172 |
+
gr.Markdown(f"**๋ชจ๋ธ**: `{MODEL_NAME}`")
|
| 173 |
+
gr.Markdown(f"**๋ชจ๋ธ ์ํ**: `{'โ
๋ก๋๋จ' if MODEL_LOADED else 'โ ๋ก๋ ์คํจ'}`")
|
| 174 |
+
|
| 175 |
+
if __name__ == "__main__":
|
| 176 |
+
# share=True๋ฅผ ์ฌ์ฉํ๋ฉด ์ธ๋ถ์์๋ ์ ์ ๊ฐ๋ฅํ ๊ณต๊ฐ ๋งํฌ๊ฐ ์์ฑ๋ฉ๋๋ค.
|
| 177 |
+
demo.launch(share=True)
|