Spaces:
Sleeping
Sleeping
Auto commit at 20-2025-08 20:10:37
Browse files
lily_llm_api/app_v2.py
CHANGED
|
@@ -191,7 +191,7 @@ def configure_cpu_threads():
|
|
| 191 |
else:
|
| 192 |
detected = os.cpu_count() or 2
|
| 193 |
# ์ปจํ
์ด๋/์๋ฒ์ vCPU ์๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ์ํ 8 ์ ์ฉ
|
| 194 |
-
threads = max(1, min(detected,
|
| 195 |
|
| 196 |
# OpenMP/MKL/numexpr
|
| 197 |
os.environ["OMP_NUM_THREADS"] = str(threads)
|
|
@@ -225,7 +225,7 @@ def select_model_interactive():
|
|
| 225 |
try:
|
| 226 |
# choice = input(f"\n๐ ์ฌ์ฉํ ๋ชจ๋ธ ๋ฒํธ๋ฅผ ์ ํํ์ธ์ (1-{len(available_models)}): ")
|
| 227 |
# selected_model = available_models[int(choice) - 1]
|
| 228 |
-
selected_model = available_models[
|
| 229 |
print(f"\nโ
'{selected_model['name']}' ๋ชจ๋ธ์ ์ ํํ์ต๋๋ค.")
|
| 230 |
return selected_model['model_id']
|
| 231 |
except (ValueError, IndexError):
|
|
@@ -540,6 +540,16 @@ def generate_sync(prompt: str, image_data_list: Optional[List[bytes]], max_lengt
|
|
| 540 |
gen_config['use_cache'] = True # ์บ์ ์ฌ์ฉ์ผ๋ก ์๋ ํฅ์
|
| 541 |
gen_config['pad_token_id'] = tokenizer.eos_token_id if tokenizer.eos_token_id else None
|
| 542 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
print(f"๐ [DEBUG] ๋ชจ๋ธ ์์ฑ ์์ - ํ
์คํธ๋ง")
|
| 544 |
print(f"๐ [DEBUG] ์ต์ข
์
๋ ฅ ํ
์ ๋๋ฐ์ด์ค: {input_ids.device}")
|
| 545 |
print(f"๐ [DEBUG] ์ต์ข
attention_mask ๋๋ฐ์ด์ค: {attention_mask.device}")
|
|
|
|
| 191 |
else:
|
| 192 |
detected = os.cpu_count() or 2
|
| 193 |
# ์ปจํ
์ด๋/์๋ฒ์ vCPU ์๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ์ํ 8 ์ ์ฉ
|
| 194 |
+
threads = max(1, min(detected, 16))
|
| 195 |
|
| 196 |
# OpenMP/MKL/numexpr
|
| 197 |
os.environ["OMP_NUM_THREADS"] = str(threads)
|
|
|
|
| 225 |
try:
|
| 226 |
# choice = input(f"\n๐ ์ฌ์ฉํ ๋ชจ๋ธ ๋ฒํธ๋ฅผ ์ ํํ์ธ์ (1-{len(available_models)}): ")
|
| 227 |
# selected_model = available_models[int(choice) - 1]
|
| 228 |
+
selected_model = available_models[2]
|
| 229 |
print(f"\nโ
'{selected_model['name']}' ๋ชจ๋ธ์ ์ ํํ์ต๋๋ค.")
|
| 230 |
return selected_model['model_id']
|
| 231 |
except (ValueError, IndexError):
|
|
|
|
| 540 |
gen_config['use_cache'] = True # ์บ์ ์ฌ์ฉ์ผ๋ก ์๋ ํฅ์
|
| 541 |
gen_config['pad_token_id'] = tokenizer.eos_token_id if tokenizer.eos_token_id else None
|
| 542 |
|
| 543 |
+
# EOS ํ ํฐ ๊ฐ์ ์ค์ - ๋ฌธ์ฅ ๋ ๋ฌธ์ ํด๊ฒฐ
|
| 544 |
+
if tokenizer.eos_token_id is not None:
|
| 545 |
+
gen_config['eos_token_id'] = tokenizer.eos_token_id
|
| 546 |
+
print(f"๐ [DEBUG] EOS ํ ํฐ ๊ฐ์ ์ค์ : {tokenizer.eos_token} (ID: {tokenizer.eos_token_id})")
|
| 547 |
+
else:
|
| 548 |
+
print(f"โ ๏ธ [DEBUG] EOS ํ ํฐ์ด ์ค์ ๋์ง ์์")
|
| 549 |
+
|
| 550 |
+
# ์์ฑ ์ค์ ์ต์ข
ํ์ธ
|
| 551 |
+
print(f"๐ [DEBUG] ์ต์ข
์์ฑ ์ค์ : {gen_config}")
|
| 552 |
+
|
| 553 |
print(f"๐ [DEBUG] ๋ชจ๋ธ ์์ฑ ์์ - ํ
์คํธ๋ง")
|
| 554 |
print(f"๐ [DEBUG] ์ต์ข
์
๋ ฅ ํ
์ ๋๋ฐ์ด์ค: {input_ids.device}")
|
| 555 |
print(f"๐ [DEBUG] ์ต์ข
attention_mask ๋๋ฐ์ด์ค: {attention_mask.device}")
|
lily_llm_api/models/polyglot_ko_1_3b_chat.py
CHANGED
|
@@ -25,7 +25,7 @@ class PolyglotKo13bChatProfile:
|
|
| 25 |
self.model_size = "1.3B"
|
| 26 |
|
| 27 |
def load_model(self) -> Tuple[AutoModelForCausalLM, AutoTokenizer]:
|
| 28 |
-
"""๋ชจ๋ธ ๋ก๋ (
|
| 29 |
logger.info(f"๐ฅ {self.display_name} ๋ชจ๋ธ ๋ก๋ ์ค...")
|
| 30 |
try:
|
| 31 |
use_local = Path(self.local_path).exists() and any(Path(self.local_path).iterdir())
|
|
@@ -39,8 +39,21 @@ class PolyglotKo13bChatProfile:
|
|
| 39 |
trust_remote_code=True,
|
| 40 |
local_files_only=use_local,
|
| 41 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
if tokenizer.pad_token is None:
|
|
|
|
| 43 |
tokenizer.pad_token = tokenizer.eos_token
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
# CPU์์๋ float32๊ฐ ๋ ์์ ์ , CUDA์์๋ float16 ์ฌ์ฉ
|
| 46 |
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
|
@@ -60,9 +73,9 @@ class PolyglotKo13bChatProfile:
|
|
| 60 |
raise
|
| 61 |
|
| 62 |
def format_prompt(self, user_input: str) -> str:
|
| 63 |
-
"""ํ๋กฌํํธ ํฌ๋งทํ
-
|
| 64 |
-
#
|
| 65 |
-
prompt = f"""AI ์ฑ๋ด์
๋๋ค. ๋์์ด ๋๊ณ ์ ์ตํ ๋ด์ฉ์
|
| 66 |
|
| 67 |
### ์ฌ์ฉ์:
|
| 68 |
{user_input}
|
|
@@ -72,7 +85,7 @@ class PolyglotKo13bChatProfile:
|
|
| 72 |
return prompt
|
| 73 |
|
| 74 |
def extract_response(self, full_text: str, formatted_prompt: str = None) -> str:
|
| 75 |
-
"""์๋ต ์ถ์ถ -
|
| 76 |
logger.info(f"--- Polyglot ์๋ต ์ถ์ถ ์์ ---")
|
| 77 |
logger.info(f"์ ์ฒด ์์ฑ ํ
์คํธ (Raw): \n---\n{full_text}\n---")
|
| 78 |
logger.info(f"์ฌ์ฉ๋ ํ๋กฌํํธ: {formatted_prompt}")
|
|
@@ -82,21 +95,34 @@ class PolyglotKo13bChatProfile:
|
|
| 82 |
response = full_text.split("### ์ฑ๋ด:")[-1].strip()
|
| 83 |
logger.info(f"โ
์ฑ๊ณต: '### ์ฑ๋ด:' ํ๊ทธ๋ก ์๋ต ์ถ์ถ")
|
| 84 |
logger.info(f"์ถ์ถ๋ ์๋ต: {response}")
|
| 85 |
-
|
|
|
|
|
|
|
| 86 |
return response
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
# 2์์: ํ๋กฌํํธ ์ ๊ฑฐ๋ก ์ถ์ถ ์๋
|
| 89 |
if formatted_prompt and formatted_prompt in full_text:
|
| 90 |
response = full_text.replace(formatted_prompt, "").strip()
|
| 91 |
logger.info(f"โ
์ฑ๊ณต: ํ๋กฌํํธ ์ ๊ฑฐ๋ก ์๋ต ์ถ์ถ")
|
| 92 |
logger.info(f"์ถ์ถ๋ ์๋ต: {response}")
|
| 93 |
-
|
|
|
|
| 94 |
return response
|
|
|
|
|
|
|
| 95 |
|
| 96 |
# 3์์: ์ผ๋ฐ์ ์ธ ํ๋กฌํํธ ํจํด ์ ๊ฑฐ ์๋
|
| 97 |
clean_text = full_text.strip()
|
| 98 |
patterns_to_remove = [
|
| 99 |
-
"๋น์ ์ AI ์ฑ๋ด์
๋๋ค.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
"### ์ฌ์ฉ์:",
|
| 101 |
"### ์ฑ๋ด:",
|
| 102 |
"์ฌ์ฉ์:",
|
|
@@ -113,28 +139,81 @@ class PolyglotKo13bChatProfile:
|
|
| 113 |
if clean_text and clean_text != full_text:
|
| 114 |
logger.info("โ
์ฑ๊ณต: ํจํด ์ ๊ฑฐ๋ก ์๋ต ์ ๋ฆฌ")
|
| 115 |
logger.info(f"์ ๋ฆฌ๋ ์๋ต: {clean_text}")
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
# 4์์: ์ ์ฒด ํ
์คํธ์์ ๋ถํ์ํ ๋ถ๋ถ๋ง ์ ๊ฑฐ
|
| 119 |
final_response = full_text.strip()
|
| 120 |
logger.warning("โ ๏ธ ๊ฒฝ๊ณ : ํน๋ณํ ์๋ต ์ถ์ถ ํจํด์ ์ฐพ์ง ๋ชปํ์ต๋๋ค. ์ ์ฒด ํ
์คํธ๋ฅผ ์ ๋ฆฌํ์ฌ ๋ฐํํฉ๋๋ค.")
|
| 121 |
logger.info(f"์ต์ข
๋ฐํ ํ
์คํธ: {final_response}")
|
| 122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
def get_generation_config(self) -> Dict[str, Any]:
|
| 125 |
-
"""์์ฑ ์ค์ -
|
| 126 |
return {
|
| 127 |
-
"max_new_tokens":
|
| 128 |
-
"temperature": 0.
|
| 129 |
-
"do_sample": True,
|
| 130 |
-
"top_k":
|
| 131 |
-
"top_p": 0.
|
| 132 |
-
"repetition_penalty": 1.
|
| 133 |
-
"no_repeat_ngram_size":
|
| 134 |
-
"pad_token_id": None,
|
| 135 |
-
"eos_token_id": None,
|
| 136 |
-
"use_cache": True,
|
| 137 |
-
"max_time": 60.0,
|
|
|
|
|
|
|
| 138 |
}
|
| 139 |
|
| 140 |
def get_model_info(self) -> Dict[str, Any]:
|
|
|
|
| 25 |
self.model_size = "1.3B"
|
| 26 |
|
| 27 |
def load_model(self) -> Tuple[AutoModelForCausalLM, AutoTokenizer]:
|
| 28 |
+
"""๋ชจ๋ธ ๋ก๋ (ํ ํฌ๋์ด์ ์ค์ ์์ )"""
|
| 29 |
logger.info(f"๐ฅ {self.display_name} ๋ชจ๋ธ ๋ก๋ ์ค...")
|
| 30 |
try:
|
| 31 |
use_local = Path(self.local_path).exists() and any(Path(self.local_path).iterdir())
|
|
|
|
| 39 |
trust_remote_code=True,
|
| 40 |
local_files_only=use_local,
|
| 41 |
)
|
| 42 |
+
|
| 43 |
+
# ํ ํฌ๋์ด์ ์ค์ ์์ - EOS ํ ํฐ ๋ฌธ์ ํด๊ฒฐ
|
| 44 |
+
if tokenizer.eos_token is None:
|
| 45 |
+
logger.warning("โ ๏ธ EOS ํ ํฐ์ด ์์ต๋๋ค. ๋ชจ๋ธ ๊ณต์ ๋ฌธ์์ ๋ฐ๋ผ <|endoftext|> ์ค์ ")
|
| 46 |
+
tokenizer.eos_token = "<|endoftext|>"
|
| 47 |
+
|
| 48 |
if tokenizer.pad_token is None:
|
| 49 |
+
logger.warning("โ ๏ธ PAD ํ ํฐ์ด ์์ต๋๋ค. EOS ํ ํฐ์ผ๋ก ์ค์ ")
|
| 50 |
tokenizer.pad_token = tokenizer.eos_token
|
| 51 |
+
|
| 52 |
+
# ํน์ ํ ํฐ ํ์ธ
|
| 53 |
+
logger.info(f"๐ ํ ํฌ๋์ด์ ์ค์ :")
|
| 54 |
+
logger.info(f" - EOS ํ ํฐ: {tokenizer.eos_token} (ID: {tokenizer.eos_token_id})")
|
| 55 |
+
logger.info(f" - PAD ํ ํฐ: {tokenizer.pad_token} (ID: {tokenizer.pad_token_id})")
|
| 56 |
+
logger.info(f" - BOS ํ ํฐ: {tokenizer.bos_token} (ID: {tokenizer.bos_token_id})")
|
| 57 |
|
| 58 |
# CPU์์๋ float32๊ฐ ๋ ์์ ์ , CUDA์์๋ float16 ์ฌ์ฉ
|
| 59 |
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
|
|
|
| 73 |
raise
|
| 74 |
|
| 75 |
def format_prompt(self, user_input: str) -> str:
|
| 76 |
+
"""ํ๋กฌํํธ ํฌ๋งทํ
- ๊ณต์ ๋ฌธ์์ ์ผ์น"""
|
| 77 |
+
# Hugging Face ๋ชจ๋ธ ํ์ด์ง์ ๊ณต์ ํ๋กฌํํธ ํ์ ์ฌ์ฉ
|
| 78 |
+
prompt = f"""๋น์ ์ AI ์ฑ๋ด์
๋๋ค. ์ฌ์ฉ์์๊ฒ ๋์์ด ๋๊ณ ์ ์ตํ ๋ด์ฉ์ ์ ๊ณตํด์ผํฉ๋๋ค. ๋ต๋ณ์ ๊ธธ๊ณ ์์ธํ๋ฉฐ ์น์ ํ ์ค๋ช
์ ๋ง๋ถ์ฌ์ ์์ฑํ์ธ์.
|
| 79 |
|
| 80 |
### ์ฌ์ฉ์:
|
| 81 |
{user_input}
|
|
|
|
| 85 |
return prompt
|
| 86 |
|
| 87 |
def extract_response(self, full_text: str, formatted_prompt: str = None) -> str:
|
| 88 |
+
"""์๋ต ์ถ์ถ - ํ์ง ๊ฒ์ฆ ๋ฐ ๊ฐ์ """
|
| 89 |
logger.info(f"--- Polyglot ์๋ต ์ถ์ถ ์์ ---")
|
| 90 |
logger.info(f"์ ์ฒด ์์ฑ ํ
์คํธ (Raw): \n---\n{full_text}\n---")
|
| 91 |
logger.info(f"์ฌ์ฉ๋ ํ๋กฌํํธ: {formatted_prompt}")
|
|
|
|
| 95 |
response = full_text.split("### ์ฑ๋ด:")[-1].strip()
|
| 96 |
logger.info(f"โ
์ฑ๊ณต: '### ์ฑ๋ด:' ํ๊ทธ๋ก ์๋ต ์ถ์ถ")
|
| 97 |
logger.info(f"์ถ์ถ๋ ์๋ต: {response}")
|
| 98 |
+
|
| 99 |
+
# ์๋ต ํ์ง ๊ฒ์ฆ
|
| 100 |
+
if self._validate_response_quality(response):
|
| 101 |
return response
|
| 102 |
+
else:
|
| 103 |
+
logger.warning("โ ๏ธ ์๋ต ํ์ง์ด ๋ฎ์ต๋๋ค. ํ์ง ๊ฐ์ ์ ์์ ์ถ๊ฐํฉ๋๋ค.")
|
| 104 |
+
return self._improve_response_quality(response)
|
| 105 |
|
| 106 |
# 2์์: ํ๋กฌํํธ ์ ๊ฑฐ๋ก ์ถ์ถ ์๋
|
| 107 |
if formatted_prompt and formatted_prompt in full_text:
|
| 108 |
response = full_text.replace(formatted_prompt, "").strip()
|
| 109 |
logger.info(f"โ
์ฑ๊ณต: ํ๋กฌํํธ ์ ๊ฑฐ๋ก ์๋ต ์ถ์ถ")
|
| 110 |
logger.info(f"์ถ์ถ๋ ์๋ต: {response}")
|
| 111 |
+
|
| 112 |
+
if self._validate_response_quality(response):
|
| 113 |
return response
|
| 114 |
+
else:
|
| 115 |
+
return self._improve_response_quality(response)
|
| 116 |
|
| 117 |
# 3์์: ์ผ๋ฐ์ ์ธ ํ๋กฌํํธ ํจํด ์ ๊ฑฐ ์๋
|
| 118 |
clean_text = full_text.strip()
|
| 119 |
patterns_to_remove = [
|
| 120 |
+
"๋น์ ์ ํ๊ตญ์ด AI ์ฑ๋ด์
๋๋ค. ๋ค์ ๊ท์น์ ์๊ฒฉํ ๋ฐ๋ผ์ฃผ์ธ์:",
|
| 121 |
+
"1. ๋ฐ๋์ ํ๊ตญ์ด๋ก๋ง ์๋ตํ์ธ์",
|
| 122 |
+
"2. ์์ฐ์ค๋ฝ๊ณ ์ผ๊ด์ฑ ์๋ ๋ํ๋ฅผ ์ ์งํ์ธ์",
|
| 123 |
+
"3. ์ฌ์ฉ์์ ์ง๋ฌธ์ ์ ํํ๊ณ ๋์์ด ๋๋ ๋ต๋ณ์ ์ ๊ณตํ์ธ์",
|
| 124 |
+
"4. ๋ฌธ์ฅ์ด ์ค๊ฐ์ ๋๊ธฐ์ง ์๋๋ก ์์ฑ๋ ๋ต๋ณ์ ์์ฑํ์ธ์",
|
| 125 |
+
"5. ์์ด๋ ๋ค๋ฅธ ์ธ์ด๋ฅผ ์ฌ์ฉํ์ง ๋ง์ธ์",
|
| 126 |
"### ์ฌ์ฉ์:",
|
| 127 |
"### ์ฑ๋ด:",
|
| 128 |
"์ฌ์ฉ์:",
|
|
|
|
| 139 |
if clean_text and clean_text != full_text:
|
| 140 |
logger.info("โ
์ฑ๊ณต: ํจํด ์ ๊ฑฐ๋ก ์๋ต ์ ๋ฆฌ")
|
| 141 |
logger.info(f"์ ๋ฆฌ๋ ์๋ต: {clean_text}")
|
| 142 |
+
|
| 143 |
+
if self._validate_response_quality(clean_text):
|
| 144 |
+
return clean_text
|
| 145 |
+
else:
|
| 146 |
+
return self._improve_response_quality(clean_text)
|
| 147 |
|
| 148 |
# 4์์: ์ ์ฒด ํ
์คํธ์์ ๋ถํ์ํ ๋ถ๋ถ๋ง ์ ๊ฑฐ
|
| 149 |
final_response = full_text.strip()
|
| 150 |
logger.warning("โ ๏ธ ๊ฒฝ๊ณ : ํน๋ณํ ์๋ต ์ถ์ถ ํจํด์ ์ฐพ์ง ๋ชปํ์ต๋๋ค. ์ ์ฒด ํ
์คํธ๋ฅผ ์ ๋ฆฌํ์ฌ ๋ฐํํฉ๋๋ค.")
|
| 151 |
logger.info(f"์ต์ข
๋ฐํ ํ
์คํธ: {final_response}")
|
| 152 |
+
|
| 153 |
+
if self._validate_response_quality(final_response):
|
| 154 |
+
return final_response
|
| 155 |
+
else:
|
| 156 |
+
return self._improve_response_quality(final_response)
|
| 157 |
+
|
| 158 |
+
def _validate_response_quality(self, response: str) -> bool:
|
| 159 |
+
"""์๋ต ํ์ง ๊ฒ์ฆ"""
|
| 160 |
+
if not response or len(response.strip()) < 5:
|
| 161 |
+
return False
|
| 162 |
+
|
| 163 |
+
# ์์ด๊ฐ ํฌํจ๋์ด ์์ผ๋ฉด ํ์ง ๋ฎ์
|
| 164 |
+
if any(char.isascii() and char.isalpha() for char in response):
|
| 165 |
+
return False
|
| 166 |
+
|
| 167 |
+
# ๋ฌธ์ฅ์ด ์ค๊ฐ์ ๋์ด์ง ๊ฒฝ์ฐ ํ์ง ๋ฎ์
|
| 168 |
+
if response.endswith(('ํ', '๋', '์', '๋ฅผ', '์ด', '๊ฐ', '์', '์', '๋ก')):
|
| 169 |
+
return False
|
| 170 |
+
|
| 171 |
+
# ์ค๋ณต๋ ๋จ์ด๊ฐ ๋ง์ผ๋ฉด ํ์ง ๋ฎ์
|
| 172 |
+
words = response.split()
|
| 173 |
+
if len(words) > 3 and len(set(words)) / len(words) < 0.7:
|
| 174 |
+
return False
|
| 175 |
+
|
| 176 |
+
return True
|
| 177 |
+
|
| 178 |
+
def _improve_response_quality(self, response: str) -> str:
|
| 179 |
+
"""์๋ต ํ์ง ๊ฐ์ """
|
| 180 |
+
# ๊ธฐ๋ณธ ์ ๋ฆฌ
|
| 181 |
+
improved = response.strip()
|
| 182 |
+
|
| 183 |
+
# ์์ด ์ ๊ฑฐ
|
| 184 |
+
import re
|
| 185 |
+
improved = re.sub(r'[a-zA-Z]+', '', improved)
|
| 186 |
+
|
| 187 |
+
# ์ค๋ณต ๊ณต๋ฐฑ ์ ๊ฑฐ
|
| 188 |
+
improved = re.sub(r'\s+', ' ', improved)
|
| 189 |
+
|
| 190 |
+
# ๋ฌธ์ฅ์ด ์ค๊ฐ์ ๋์ด์ง ๊ฒฝ์ฐ ์ฒ๋ฆฌ
|
| 191 |
+
if improved.endswith(('ํ', '๋', '์', '๋ฅผ', '์ด', '๊ฐ', '์', '์', '๋ก')):
|
| 192 |
+
improved += '๋๋ค.'
|
| 193 |
+
|
| 194 |
+
# ๋๋ฌด ์งง์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ ์๋ต ์ถ๊ฐ
|
| 195 |
+
if len(improved) < 10:
|
| 196 |
+
improved = f"{improved} (์๋ต์ด ๋๋ฌด ์งง์ต๋๋ค. ๋ ์์ธํ ๋ต๋ณ์ ์ํ์๋ฉด ๋ค์ ์ง๋ฌธํด์ฃผ์ธ์.)"
|
| 197 |
+
|
| 198 |
+
logger.info(f"๐ง ์๋ต ํ์ง ๊ฐ์ ์๋ฃ: {improved}")
|
| 199 |
+
return improved
|
| 200 |
|
| 201 |
def get_generation_config(self) -> Dict[str, Any]:
|
| 202 |
+
"""์์ฑ ์ค์ - ๊ณต์ EOS ํ ํฐ ์ฌ์ฉ"""
|
| 203 |
return {
|
| 204 |
+
"max_new_tokens": 128, # 64์์ 128๋ก ์ฆ๊ฐํ์ฌ ์์ฑ๋ ๋ต๋ณ ์์ฑ
|
| 205 |
+
"temperature": 0.3, # ์ผ๊ด์ฑ ํฅ์
|
| 206 |
+
"do_sample": True, # ์ํ๋ง ํ์ฑํ
|
| 207 |
+
"top_k": 20, # ํ์ง ํฅ์
|
| 208 |
+
"top_p": 0.8, # ์ผ๊ด์ฑ ํฅ์
|
| 209 |
+
"repetition_penalty": 1.2, # ๋ฐ๋ณต ๋ฐฉ์ง
|
| 210 |
+
"no_repeat_ngram_size": 4, # ๋ฐ๋ณต ๋ฐฉ์ง
|
| 211 |
+
"pad_token_id": None, # ๋ชจ๋ธ ๊ธฐ๋ณธ๊ฐ ์ฌ์ฉ
|
| 212 |
+
"eos_token_id": None, # None์ผ๋ก ์ค์ ํ์ฌ ๋ชจ๋ธ์ด <|endoftext|> ์๋ ๊ฐ์ง
|
| 213 |
+
"use_cache": True, # ์บ์ ์ฌ์ฉ์ผ๋ก ์๋ ํฅ์
|
| 214 |
+
"max_time": 60.0, # 60์ด ํ์์์
|
| 215 |
+
"early_stopping": False, # False๋ก ์ค์ ํ์ฌ <|endoftext|>๊น์ง ์์ฑ
|
| 216 |
+
"stopping_criteria": None, # ๊ธฐ๋ณธ ์ ์ง ๊ธฐ์ค ์ฌ์ฉ
|
| 217 |
}
|
| 218 |
|
| 219 |
def get_model_info(self) -> Dict[str, Any]:
|
lily_llm_api/models/polyglot_ko_5_8b_chat.py
CHANGED
|
@@ -1,31 +1,33 @@
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
-
|
|
|
|
| 4 |
"""
|
| 5 |
|
| 6 |
from typing import Dict, Any, Tuple
|
| 7 |
import torch
|
| 8 |
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 9 |
import logging
|
|
|
|
|
|
|
| 10 |
|
| 11 |
logger = logging.getLogger(__name__)
|
| 12 |
|
| 13 |
class PolyglotKo58bChatProfile:
|
| 14 |
-
"""
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
self.model_name = "heegyu/polyglot-ko-5.8b-chat"
|
| 18 |
self.local_path = "./lily_llm_core/models/polyglot_ko_5_8b_chat"
|
| 19 |
-
self.display_name = "
|
| 20 |
-
self.description = "
|
| 21 |
self.language = "ko"
|
| 22 |
self.model_size = "5.8B"
|
| 23 |
|
| 24 |
def load_model(self) -> Tuple[AutoModelForCausalLM, AutoTokenizer]:
|
| 25 |
-
"""๋ชจ๋ธ ๋ก๋ (
|
| 26 |
logger.info(f"๐ฅ {self.display_name} ๋ชจ๋ธ ๋ก๋ ์ค...")
|
| 27 |
try:
|
| 28 |
-
from pathlib import Path
|
| 29 |
use_local = Path(self.local_path).exists() and any(Path(self.local_path).iterdir())
|
| 30 |
model_path = self.local_path if use_local else self.model_name
|
| 31 |
|
|
@@ -37,11 +39,25 @@ class PolyglotKo58bChatProfile:
|
|
| 37 |
trust_remote_code=True,
|
| 38 |
local_files_only=use_local,
|
| 39 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
if tokenizer.pad_token is None:
|
|
|
|
| 41 |
tokenizer.pad_token = tokenizer.eos_token
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
|
|
|
| 43 |
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
| 44 |
-
selected_dtype = torch.float16 if device == 'cuda' else torch.
|
| 45 |
|
| 46 |
model = AutoModelForCausalLM.from_pretrained(
|
| 47 |
model_path,
|
|
@@ -57,33 +73,142 @@ class PolyglotKo58bChatProfile:
|
|
| 57 |
raise
|
| 58 |
|
| 59 |
def format_prompt(self, user_input: str) -> str:
|
| 60 |
-
"""ํ๋กฌํํธ ํฌ๋งทํ
"""
|
| 61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
-
def extract_response(self, full_text: str, formatted_prompt: str) -> str:
|
| 64 |
-
"""์๋ต ์ถ์ถ"""
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
else:
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
-
|
|
|
|
| 74 |
|
| 75 |
def get_generation_config(self) -> Dict[str, Any]:
|
| 76 |
-
"""์์ฑ ์ค์ """
|
| 77 |
return {
|
| 78 |
-
"max_new_tokens": 128,
|
| 79 |
-
"temperature": 0.
|
| 80 |
-
"do_sample": True,
|
| 81 |
-
"top_k":
|
| 82 |
-
"top_p": 0.
|
| 83 |
-
"repetition_penalty": 1.
|
| 84 |
-
"no_repeat_ngram_size":
|
| 85 |
-
"pad_token_id": None,
|
| 86 |
-
"eos_token_id": None,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
}
|
| 88 |
|
| 89 |
def get_model_info(self) -> Dict[str, Any]:
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
+
Polyglot-ko-5.8b-chat ๋ชจ๋ธ ํ๋กํ
|
| 4 |
+
heegyu/polyglot-ko-5.8b-chat ๋ชจ๋ธ์ฉ
|
| 5 |
"""
|
| 6 |
|
| 7 |
from typing import Dict, Any, Tuple
|
| 8 |
import torch
|
| 9 |
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 10 |
import logging
|
| 11 |
+
import os
|
| 12 |
+
from pathlib import Path
|
| 13 |
|
| 14 |
logger = logging.getLogger(__name__)
|
| 15 |
|
| 16 |
class PolyglotKo58bChatProfile:
|
| 17 |
+
"""Polyglot-ko-5.8b-chat ๋ชจ๋ธ ํ๋กํ"""
|
| 18 |
|
| 19 |
def __init__(self):
|
| 20 |
self.model_name = "heegyu/polyglot-ko-5.8b-chat"
|
| 21 |
self.local_path = "./lily_llm_core/models/polyglot_ko_5_8b_chat"
|
| 22 |
+
self.display_name = "Polyglot-ko-5.8b-chat"
|
| 23 |
+
self.description = "ํ๊ตญ์ด ์ฑํ
์ ์ฉ ๊ณ ์ฑ๋ฅ ๋ชจ๋ธ (5.8B)"
|
| 24 |
self.language = "ko"
|
| 25 |
self.model_size = "5.8B"
|
| 26 |
|
| 27 |
def load_model(self) -> Tuple[AutoModelForCausalLM, AutoTokenizer]:
|
| 28 |
+
"""๋ชจ๋ธ ๋ก๋ (ํ ํฌ๋์ด์ ์ค์ ์์ )"""
|
| 29 |
logger.info(f"๐ฅ {self.display_name} ๋ชจ๋ธ ๋ก๋ ์ค...")
|
| 30 |
try:
|
|
|
|
| 31 |
use_local = Path(self.local_path).exists() and any(Path(self.local_path).iterdir())
|
| 32 |
model_path = self.local_path if use_local else self.model_name
|
| 33 |
|
|
|
|
| 39 |
trust_remote_code=True,
|
| 40 |
local_files_only=use_local,
|
| 41 |
)
|
| 42 |
+
|
| 43 |
+
# ํ ํฌ๋์ด์ ์ค์ ์์ - EOS ํ ํฐ ๋ฌธ์ ํด๊ฒฐ
|
| 44 |
+
if tokenizer.eos_token is None:
|
| 45 |
+
logger.warning("โ ๏ธ EOS ํ ํฐ์ด ์์ต๋๋ค. ๋ชจ๋ธ ๊ณต์ ๋ฌธ์์ ๋ฐ๋ผ <|endoftext|> ์ค์ ")
|
| 46 |
+
tokenizer.eos_token = "<|endoftext|>"
|
| 47 |
+
|
| 48 |
if tokenizer.pad_token is None:
|
| 49 |
+
logger.warning("โ ๏ธ PAD ํ ํฐ์ด ์์ต๋๋ค. EOS ํ ํฐ์ผ๋ก ์ค์ ")
|
| 50 |
tokenizer.pad_token = tokenizer.eos_token
|
| 51 |
+
|
| 52 |
+
# ํน์ ํ ํฐ ํ์ธ
|
| 53 |
+
logger.info(f"๐ ํ ํฌ๋์ด์ ์ค์ :")
|
| 54 |
+
logger.info(f" - EOS ํ ํฐ: {tokenizer.eos_token} (ID: {tokenizer.eos_token_id})")
|
| 55 |
+
logger.info(f" - PAD ํ ํฐ: {tokenizer.pad_token} (ID: {tokenizer.pad_token_id})")
|
| 56 |
+
logger.info(f" - BOS ํ ํฐ: {tokenizer.bos_token} (ID: {tokenizer.bos_token_id})")
|
| 57 |
|
| 58 |
+
# CPU์์๋ float32๊ฐ ๋ ์์ ์ , CUDA์์๋ float16 ์ฌ์ฉ
|
| 59 |
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
| 60 |
+
selected_dtype = torch.float16 if device == 'cuda' else torch.float32
|
| 61 |
|
| 62 |
model = AutoModelForCausalLM.from_pretrained(
|
| 63 |
model_path,
|
|
|
|
| 73 |
raise
|
| 74 |
|
| 75 |
def format_prompt(self, user_input: str) -> str:
|
| 76 |
+
"""ํ๋กฌํํธ ํฌ๋งทํ
- ๊ณต์ ๋ฌธ์์ ์ผ์น"""
|
| 77 |
+
# Hugging Face ๋ชจ๋ธ ํ์ด์ง์ ๊ณต์ ํ๋กฌํํธ ํ์ ์ฌ์ฉ
|
| 78 |
+
prompt = f"""๋น์ ์ AI ์ฑ๋ด์
๋๋ค. ์ฌ์ฉ์์๊ฒ ๋์์ด ๋๊ณ ์ ์ตํ ๋ด์ฉ์ ์ ๊ณตํด์ผํฉ๋๋ค. ๋ต๋ณ์ ๊ธธ๊ณ ์์ธํ๋ฉฐ ์น์ ํ ์ค๋ช
์ ๋ง๋ถ์ฌ์ ์์ฑํ์ธ์.
|
| 79 |
+
|
| 80 |
+
### ์ฌ์ฉ์:
|
| 81 |
+
{user_input}
|
| 82 |
+
|
| 83 |
+
### ์ฑ๋ด:
|
| 84 |
+
"""
|
| 85 |
+
return prompt
|
| 86 |
|
| 87 |
+
def extract_response(self, full_text: str, formatted_prompt: str = None) -> str:
|
| 88 |
+
"""์๋ต ์ถ์ถ - ํ์ง ๊ฒ์ฆ ๋ฐ ๊ฐ์ """
|
| 89 |
+
logger.info(f"--- Polyglot 5.8B ์๋ต ์ถ์ถ ์์ ---")
|
| 90 |
+
logger.info(f"์ ์ฒด ์์ฑ ํ
์คํธ (Raw): \n---\n{full_text}\n---")
|
| 91 |
+
logger.info(f"์ฌ์ฉ๋ ํ๋กฌํํธ: {formatted_prompt}")
|
| 92 |
+
|
| 93 |
+
# 1์์: "### ์ฑ๋ด:" ํ๊ทธ๋ก ์ถ์ถ ์๋
|
| 94 |
+
if "### ์ฑ๋ด:" in full_text:
|
| 95 |
+
response = full_text.split("### ์ฑ๋ด:")[-1].strip()
|
| 96 |
+
logger.info(f"โ
์ฑ๊ณต: '### ์ฑ๋ด:' ํ๊ทธ๋ก ์๋ต ์ถ์ถ")
|
| 97 |
+
logger.info(f"์ถ์ถ๋ ์๋ต: {response}")
|
| 98 |
+
|
| 99 |
+
# ์๋ต ํ์ง ๊ฒ์ฆ
|
| 100 |
+
if self._validate_response_quality(response):
|
| 101 |
+
return response
|
| 102 |
+
else:
|
| 103 |
+
logger.warning("โ ๏ธ ์๋ต ํ์ง์ด ๋ฎ์ต๋๋ค. ํ์ง ๊ฐ์ ์ ์์ ์ถ๊ฐํฉ๋๋ค.")
|
| 104 |
+
return self._improve_response_quality(response)
|
| 105 |
+
|
| 106 |
+
# 2์์: ํ๋กฌ๏ฟฝ๏ฟฝ๏ฟฝํธ ์ ๊ฑฐ๋ก ์ถ์ถ ์๋
|
| 107 |
+
if formatted_prompt and formatted_prompt in full_text:
|
| 108 |
+
response = full_text.replace(formatted_prompt, "").strip()
|
| 109 |
+
logger.info(f"โ
์ฑ๊ณต: ํ๋กฌํํธ ์ ๊ฑฐ๋ก ์๋ต ์ถ์ถ")
|
| 110 |
+
logger.info(f"์ถ์ถ๋ ์๋ต: {response}")
|
| 111 |
+
|
| 112 |
+
if self._validate_response_quality(response):
|
| 113 |
+
return response
|
| 114 |
else:
|
| 115 |
+
return self._improve_response_quality(response)
|
| 116 |
+
|
| 117 |
+
# 3์์: ์ผ๋ฐ์ ์ธ ํ๋กฌํํธ ํจํด ์ ๊ฑฐ ์๋
|
| 118 |
+
clean_text = full_text.strip()
|
| 119 |
+
patterns_to_remove = [
|
| 120 |
+
"๋น์ ์ AI ์ฑ๋ด์
๋๋ค. ์ฌ์ฉ์์๊ฒ ๋์์ด ๋๊ณ ์ ์ตํ ๋ด์ฉ์ ์ ๊ณตํด์ผํฉ๋๋ค. ๋ต๋ณ์ ๊ธธ๊ณ ์์ธํ๋ฉฐ ์น์ ํ ์ค๋ช
์ ๋ง๋ถ์ฌ์ ์์ฑํ์ธ์.",
|
| 121 |
+
"### ์ฌ์ฉ์:",
|
| 122 |
+
"### ์ฑ๋ด:",
|
| 123 |
+
"์ฌ์ฉ์:",
|
| 124 |
+
"์ฑ๋ด:",
|
| 125 |
+
"assistant:",
|
| 126 |
+
"user:"
|
| 127 |
+
]
|
| 128 |
+
|
| 129 |
+
for pattern in patterns_to_remove:
|
| 130 |
+
clean_text = clean_text.replace(pattern, "")
|
| 131 |
+
|
| 132 |
+
clean_text = clean_text.strip()
|
| 133 |
+
|
| 134 |
+
if clean_text and clean_text != full_text:
|
| 135 |
+
logger.info("โ
์ฑ๊ณต: ํจํด ์ ๊ฑฐ๋ก ์๋ต ์ ๋ฆฌ")
|
| 136 |
+
logger.info(f"์ ๋ฆฌ๋ ์๋ต: {clean_text}")
|
| 137 |
+
|
| 138 |
+
if self._validate_response_quality(clean_text):
|
| 139 |
+
return clean_text
|
| 140 |
+
else:
|
| 141 |
+
return self._improve_response_quality(clean_text)
|
| 142 |
+
|
| 143 |
+
# 4์์: ์ ์ฒด ํ
์คํธ์์ ๋ถํ์ํ ๋ถ๋ถ๋ง ์ ๊ฑฐ
|
| 144 |
+
final_response = full_text.strip()
|
| 145 |
+
logger.warning("โ ๏ธ ๊ฒฝ๊ณ : ํน๋ณํ ์๋ต ์ถ์ถ ํจํด์ ์ฐพ์ง ๋ชปํ์ต๋๋ค. ์ ์ฒด ํ
์คํธ๋ฅผ ์ ๋ฆฌํ์ฌ ๋ฐํํฉ๋๋ค.")
|
| 146 |
+
logger.info(f"์ต์ข
๋ฐํ ํ
์คํธ: {final_response}")
|
| 147 |
+
|
| 148 |
+
if self._validate_response_quality(final_response):
|
| 149 |
+
return final_response
|
| 150 |
+
else:
|
| 151 |
+
return self._improve_response_quality(final_response)
|
| 152 |
+
|
| 153 |
+
def _validate_response_quality(self, response: str) -> bool:
|
| 154 |
+
"""์๋ต ํ์ง ๊ฒ์ฆ"""
|
| 155 |
+
if not response or len(response.strip()) < 5:
|
| 156 |
+
return False
|
| 157 |
+
|
| 158 |
+
# ์์ด๊ฐ ํฌํจ๋์ด ์์ผ๋ฉด ํ์ง ๋ฎ์
|
| 159 |
+
if any(char.isascii() and char.isalpha() for char in response):
|
| 160 |
+
return False
|
| 161 |
+
|
| 162 |
+
# ๋ฌธ์ฅ์ด ์ค๊ฐ์ ๋์ด์ง ๊ฒฝ์ฐ ํ์ง ๋ฎ์
|
| 163 |
+
if response.endswith(('ํ', '๋', '์', '๋ฅผ', '์ด', '๊ฐ', '์', '์', '๋ก')):
|
| 164 |
+
return False
|
| 165 |
+
|
| 166 |
+
# ์ค๋ณต๋ ๋จ์ด๊ฐ ๋ง์ผ๋ฉด ํ์ง ๋ฎ์
|
| 167 |
+
words = response.split()
|
| 168 |
+
if len(words) > 3 and len(set(words)) / len(words) < 0.7:
|
| 169 |
+
return False
|
| 170 |
+
|
| 171 |
+
return True
|
| 172 |
+
|
| 173 |
+
def _improve_response_quality(self, response: str) -> str:
|
| 174 |
+
"""์๋ต ํ์ง ๊ฐ์ """
|
| 175 |
+
# ๊ธฐ๋ณธ ์ ๋ฆฌ
|
| 176 |
+
improved = response.strip()
|
| 177 |
+
|
| 178 |
+
# ์์ด ์ ๊ฑฐ
|
| 179 |
+
import re
|
| 180 |
+
improved = re.sub(r'[a-zA-Z]+', '', improved)
|
| 181 |
+
|
| 182 |
+
# ์ค๋ณต ๊ณต๋ฐฑ ์ ๊ฑฐ
|
| 183 |
+
improved = re.sub(r'\s+', ' ', improved)
|
| 184 |
+
|
| 185 |
+
# ๋ฌธ์ฅ์ด ์ค๊ฐ์ ๋์ด์ง ๊ฒฝ์ฐ ์ฒ๋ฆฌ
|
| 186 |
+
if improved.endswith(('ํ', '๋', '์', '๋ฅผ', '์ด', '๊ฐ', '์', '์', '๋ก')):
|
| 187 |
+
improved += '๋๋ค.'
|
| 188 |
+
|
| 189 |
+
# ๋๋ฌด ์งง์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ ์๋ต ์ถ๊ฐ
|
| 190 |
+
if len(improved) < 10:
|
| 191 |
+
improved = f"{improved} (์๋ต์ด ๋๋ฌด ์งง์ต๋๋ค. ๋ ์์ธํ ๋ต๋ณ์ ์ํ์๋ฉด ๋ค์ ์ง๋ฌธํด์ฃผ์ธ์.)"
|
| 192 |
|
| 193 |
+
logger.info(f"๐ง ์๋ต ํ์ง ๊ฐ์ ์๋ฃ: {improved}")
|
| 194 |
+
return improved
|
| 195 |
|
| 196 |
def get_generation_config(self) -> Dict[str, Any]:
|
| 197 |
+
"""์์ฑ ์ค์ - ๊ณต์ EOS ํ ํฐ ์ฌ์ฉ"""
|
| 198 |
return {
|
| 199 |
+
"max_new_tokens": 128, # 5.8B ๋ชจ๋ธ์ ๋ ๊ธด ์๋ต ์์ฑ ๊ฐ๋ฅ
|
| 200 |
+
"temperature": 0.3, # ์ผ๊ด์ฑ ํฅ์
|
| 201 |
+
"do_sample": True, # ์ํ๋ง ํ์ฑํ
|
| 202 |
+
"top_k": 20, # ํ์ง ํฅ์
|
| 203 |
+
"top_p": 0.8, # ์ผ๊ด์ฑ ํฅ์
|
| 204 |
+
"repetition_penalty": 1.2, # ๋ฐ๋ณต ๋ฐฉ์ง
|
| 205 |
+
"no_repeat_ngram_size": 4, # ๋ฐ๋ณต ๋ฐฉ์ง
|
| 206 |
+
"pad_token_id": None, # ๋ชจ๋ธ ๊ธฐ๋ณธ๊ฐ ์ฌ์ฉ
|
| 207 |
+
"eos_token_id": None, # None์ผ๋ก ์ค์ ํ์ฌ ๋ชจ๋ธ์ด <|endoftext|> ์๋ ๊ฐ์ง
|
| 208 |
+
"use_cache": True, # ์บ์ ์ฌ์ฉ์ผ๋ก ์๋ ํฅ์
|
| 209 |
+
"max_time": 240.0, # 5.8B ๋ชจ๋ธ์ ๋ ๊ธด ์๊ฐ ํ์ (120์ด)
|
| 210 |
+
"early_stopping": False, # False๋ก ์ค์ ํ์ฌ <|endoftext|>๊น์ง ์์ฑ
|
| 211 |
+
"stopping_criteria": None, # ๊ธฐ๋ณธ ์ ์ง ๊ธฐ์ค ์ฌ์ฉ
|
| 212 |
}
|
| 213 |
|
| 214 |
def get_model_info(self) -> Dict[str, Any]:
|