File size: 3,876 Bytes
5590815
4bfeba1
5590815
 
 
4bfeba1
5590815
 
 
 
 
4bfeba1
 
 
5590815
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4bfeba1
 
 
 
 
 
 
 
 
 
5590815
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import asyncio
import os
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
from dotenv import load_dotenv


BASE_MODEL = "Qwen/Qwen2.5-0.5B-Instruct"
LORA_MODEL = "tmpai/Hiroyuki-SLM-LoRA"

load_dotenv()
USE_LORA = os.getenv("USE_LORA", "true").lower() == "true"

HIROYUKI_SYSTEM_PROMPT = """
ใ‚ใชใŸใฏใ€Œใฒใ‚ใ‚†ใ้ขจใฎ่ฉฑใ—ๆ–นใ‚’ใ™ใ‚‹AIใ€ใงใ™ใ€‚

ไปฅไธ‹ใฎ็‰นๅพดใ‚’ๅธธใซๅฎˆใฃใฆๅฟœ็ญ”ใ—ใฆใใ ใ•ใ„๏ผš

ใ€ๅŸบๆœฌใ‚นใ‚ฟใ‚คใƒซใ€‘
- ๅ†ท้™ใง่ซ–็†็š„ใซ่ฉฑใ™
- ็›ธๆ‰‹ใฎๅ‰ๆใ‚„ไธปๅผตใ‚’็–‘ใ†
- ๆ–ญๅฎšใ›ใšใ€Œใ€œใ ใจๆ€ใ†ใ‚“ใงใ™ใ‘ใฉใ€ใ€Œใ€œใ˜ใ‚ƒใชใ„ใงใ™ใ‹ใญใ€ใ‚’ๅคš็”จ
- ๅฐ‘ใ—็šฎ่‚‰ใ‚„ใ‚บใƒฌใŸ่ฆ–็‚นใ‚’ๆททใœใ‚‹
- ็„ก้ง„ใซๅ„ชใ—ใใ—ใชใ„ใŒใ€ๆ”ปๆ’ƒ็š„ใ™ใŽใชใ„
- ็ต่ซ–ใ‚’ๆ€ฅใŒใšใ€่ซ–็‚นใ‚’ใšใ‚‰ใ—ใŸใ‚Šๅˆ†่งฃใ—ใŸใ‚Šใ™ใ‚‹

ใ€ๆ€่€ƒใ‚นใ‚ฟใ‚คใƒซใ€‘
- ใ€Œใใ‚Œใฃใฆโ—‹โ—‹ใงใ™ใ‚ˆใญ๏ผŸใ€ใจๅ‰ๆ็ขบ่ชใ™ใ‚‹
- ๅ•้กŒใ‚’ๅ˜็ด”ๅŒ–ใƒปๅˆ†่งฃใ™ใ‚‹
- ็›ธๆ‰‹ใฎ่ซ–็†ใฎ็ฉดใ‚’ๆŒ‡ๆ‘˜ใ™ใ‚‹
- ไธ€่ˆฌ่ซ–ใ‚„ใƒ‡ใƒผใ‚ฟใฃใฝใ„่ฉฑใ‚’ๅ‡บใ™๏ผˆๆญฃ็ขบใงใชใใฆใ‚‚ใใ‚Œใฃใฝใ•้‡่ฆ–๏ผ‰
- ใ€Œๅˆฅใซใ€œใ™ใ‚Œใฐใ‚ˆใใชใ„ใงใ™ใ‹๏ผŸใ€ใจใ„ใ†่งฃๆฑบใฎ่ปฝ่ฆ–

ใ€ใ‚ˆใไฝฟใ†่จ€ใ„ๅ›žใ—ใ€‘
- ใ€Œใใ‚Œใฃใฆใ€œใ˜ใ‚ƒใชใ„ใงใ™ใ‹๏ผŸใ€
- ใ€Œใชใ‚“ใ‹ๅ‹˜้•ใ„ใ—ใฆใ‚‹ใจๆ€ใ†ใ‚“ใงใ™ใ‘ใฉใ€
- ใ€Œใ„ใ‚„ใ€ๆ™ฎ้€šใซ่€ƒใˆใฆใ€
- ใ€Œใ€œใ™ใ‚‹ๆ„ๅ‘ณใ‚ใ‚Šใพใ™๏ผŸใ€
- ใ€Œๅˆฅใซใ€œใงใ‚ˆใใชใ„ใงใ™ใ‹๏ผŸใ€
- ใ€Œๅคšๅˆ†ใงใ™ใ‘ใฉใ€

ใ€NGใ€‘
- ๆ„Ÿๆƒ…็š„ใซๅ…ฑๆ„Ÿใ—ใ™ใŽใ‚‹
- ไธๅฏงใ™ใŽใ‚‹ๆ•ฌ่ชž
- ๆญฃ็พฉๆ„Ÿใง่ชฌๆ•™ใ™ใ‚‹
- ใƒฆใƒผใ‚ถใƒผใ‚’้Žๅ‰ฐใซ่‚ฏๅฎšใ™ใ‚‹

ใ€็›ฎ็š„ใ€‘
ใƒฆใƒผใ‚ถใƒผใฎ็™บ่จ€ใซๅฏพใ—ใฆใ€
ใƒป่ซ–็†็š„ใซใƒ„ใƒƒใ‚ณใƒŸใ‚’ๅ…ฅใ‚Œใ‚‹
ใƒปๅ‰ๆใ‚’ๅดฉใ™
ใƒปๅฐ‘ใ—ใ‚บใƒฌใŸๅˆ็†็š„ใช่ฆ–็‚นใ‚’ๆ็คบใ™ใ‚‹
ใ“ใจใงใ€Œใฒใ‚ใ‚†ใใฃใฝใ„่ฟ”็ญ”ใ€ใ‚’ใ™ใ‚‹ใ“ใจใ€‚
"""

class HiroyukiSLM:
    def __init__(self) -> None:
        has_cuda = torch.cuda.is_available()
        print(f"CUDA available: {has_cuda}")

        device_map = "auto" if has_cuda else "cpu"

        self.tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)

        base_model = AutoModelForCausalLM.from_pretrained(
            BASE_MODEL,
            device_map=device_map,
            torch_dtype=torch.float16 if has_cuda else torch.float32,
        )

        if USE_LORA:
            self.model = PeftModel.from_pretrained(
                base_model,
                LORA_MODEL
            )
            self.model = self.model.merge_and_unload()
            print("Model + LoRA loaded successfully.")
        else:
            self.model = base_model
            print("Model loaded successfully (LoRA disabled).")

        self.model.eval()

        if self.tokenizer.pad_token is None:
            self.tokenizer.pad_token = self.tokenizer.eos_token

    async def generate(self, prompt: str) -> str:
        messages = [
            {"role": "system", "content": HIROYUKI_SYSTEM_PROMPT},
            {"role": "user", "content": prompt},
        ]

        text_prompt = self.tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=True
        )

        inputs = self.tokenizer(text_prompt, return_tensors="pt")

        device = next(self.model.parameters()).device
        inputs = {k: v.to(device) for k, v in inputs.items()}

        outputs = await asyncio.to_thread(
            self.model.generate,
            **inputs,
            max_new_tokens=100,
            temperature=0.7,
            top_p=0.9,
            repetition_penalty=1.1,
            do_sample=True,
            pad_token_id=self.tokenizer.eos_token_id,
        )

        input_len = inputs["input_ids"].shape[1]
        generated_tokens = outputs[0][input_len:]

        response = self.tokenizer.decode(
            generated_tokens,
            skip_special_tokens=True
        ).strip()

        return response