Jeong-hun Kim commited on
Commit
aab927d
ยท
1 Parent(s): 52718fa

add "start with localhost", code refactored

Browse files
.vscode/settings.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "python.analysis.extraPaths": [
3
+ "."
4
+ ],
5
+ "python.envFile": "${workspaceFolder}/.env"
6
+ }
app.py CHANGED
@@ -1,145 +1,21 @@
1
- from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
2
  import gradio as gr
3
- import torch
4
- import re
5
- import os
6
 
7
- print("[torch] is available:", torch.cuda.is_available())
8
- print("[device] default:", torch.device("cuda" if torch.cuda.is_available() else "cpu"))
 
9
 
10
- # ๋ชจ๋ธ ๋กœ๋“œ
11
- model_id = "naver-hyperclovax/HyperCLOVAX-SEED-Text-Instruct-1.5B"
 
12
 
13
- # ํ—ˆ๊น… ํŽ˜์ด์Šค secret์— ๋“ฑ๋ก๋œ ํ† ํฐ ๋กœ๋“œ
14
- access_token = os.environ.get("HF_TOKEN")
 
15
 
16
- tokenizer = AutoTokenizer.from_pretrained(model_id, token=access_token)
17
- model = AutoModelForCausalLM.from_pretrained(
18
- model_id,
19
- token=access_token
20
- )
21
- model.eval()
22
- llm = pipeline(
23
- "text-generation",
24
- model=model,
25
- tokenizer=tokenizer,
26
- torch_dtype=torch.float16
27
- )
28
 
29
- # ์ฑ—๋ด‡ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ
30
- def build_prompt(history, user_msg, user_name="User", bot_name="Tanjiro"):
31
- with open("assets/prompt/init.txt", "r", encoding="utf-8") as f:
32
- prompt = f.read().strip()
33
-
34
- for turn in history[-16:]:
35
- role = user_name if turn["role"] == "user" else bot_name
36
- prompt += f"{role}: {turn['text']}\n"
37
-
38
- prompt += f"{user_name}: {user_msg}\n"
39
- prompt += f"{bot_name}:"
40
- return prompt
41
-
42
- # ์ถœ๋ ฅ์—์„œ ์‘๋‹ต ์ถ”์ถœ
43
- def extract_response(full_text, prompt, bot_name="Tanjiro"):
44
- if full_text.startswith(prompt):
45
- reply = full_text[len(prompt):].strip()
46
- else:
47
- reply = full_text.split(f"{bot_name}:")[-1].strip()
48
- user_token = "\nUser:"
49
- if user_token in reply:
50
- reply = reply.split(user_token)[0].strip()
51
- return reply
52
-
53
- # ์ถœ๋ ฅ ์ƒ์„ฑ ํ•จ์ˆ˜
54
- def character_chat(user_msg, history):
55
- print("[debug] generationg...")
56
- prompt = build_prompt(history, user_msg)
57
- outputs = llm(
58
- prompt,
59
- do_sample=True,
60
- max_new_tokens=96,
61
- temperature=0.7,
62
- top_p=0.9,
63
- repetition_penalty=1.05,
64
- eos_token_id=tokenizer.eos_token_id,
65
- return_full_text=True
66
- )
67
- full_text = outputs[0]['generated_text']
68
- response = extract_response(full_text, prompt)
69
- return response
70
-
71
- # ์ค‘๋‹จ๋œ ์‘๋‹ต ์—ฌ๋ถ€ ๊ฒ€์‚ฌ
72
- def is_truncated_response(text: str) -> bool:
73
- return re.search(r"[.?!โ€ฆ\u2026\u2639\u263A\u2764\uD83D\uDE0A\uD83D\uDE22]$", text.strip()) is None
74
-
75
- # ๋‹ต๋ณ€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
76
- def is_valid_response(text: str, bot_name="Tanjiro", user_name="User") -> bool:
77
- if user_name + ":" in text:
78
- return False
79
- if bot_name + ":" in text:
80
- return False
81
- return True
82
-
83
- # ๋‹ต๋ณ€ ํ˜•์‹ ์ •๋ฆฌ
84
- def clean_response(text: str, bot_name="Tanjiro"):
85
- return re.sub(rf"{bot_name}:\\s*", "", text).strip()
86
-
87
- # Gradio ์ธํ„ฐํŽ˜์ด์Šค
88
- with gr.Blocks(css="""
89
- .chat-box { max-height: 500px; overflow-y: auto; padding: 10px; border: 1px solid #ccc; border-radius: 10px; }
90
- .bubble-left { background-color: #f1f0f0; border-radius: 10px; padding: 10px; margin: 5px; max-width: 70%; float: left; clear: both; }
91
- .bubble-right { background-color: #d1e7ff; border-radius: 10px; padding: 10px; margin: 5px; max-width: 70%; float: right; clear: both; text-align: right; }
92
- .reset-btn-container { text-align: right; margin-bottom: 10px; }
93
- """) as demo:
94
- gr.Markdown("### ํƒ„์ง€๋กœ์™€ ๋Œ€ํ™”ํ•˜๊ธฐ")
95
- with gr.Column():
96
- with gr.Row():
97
- gr.Markdown("")
98
- reset_btn = gr.Button("๐Ÿ” ๋Œ€ํ™” ์ดˆ๊ธฐํ™”", elem_classes="reset-btn-container", scale=1)
99
- chat_output = gr.HTML(elem_id="chat-box")
100
- user_input = gr.Textbox(label="๋ฉ”์‹œ์ง€ ์ž…๋ ฅ", placeholder="ํƒ„์ง€๋กœ์—๊ฒŒ ๋ง์„ ๊ฑธ์–ด๋ณด์„ธ์š”")
101
- state = gr.State([])
102
-
103
- def render_chat(history):
104
- html = ""
105
- for item in history:
106
- if item["role"] == "user":
107
- html += f"<div class='bubble-right'>{item['text']}</div>"
108
- elif item["role"] == "bot":
109
- html += f"<div class='bubble-left'>{item['text']}</div>"
110
- return gr.update(value=html)
111
-
112
- def on_submit(user_msg, history):
113
- history.append({"role": "user", "text": user_msg})
114
- html = render_chat(history)
115
- yield html, "", history
116
-
117
- #์‘๋‹ต ์ƒ์„ฑ
118
- while True:
119
- response = character_chat(user_msg, history)
120
- if is_valid_response(response):
121
- break
122
- response = clean_response(response)
123
- history.append({"role": "bot", "text": response})
124
-
125
- #์ค‘๊ฐ„์— ์‘๋‹ต์ด ๋Š๊ธด ๊ฒฝ์šฐ ์ถ”๊ฐ€ ์ƒ์„ฑ
126
- if is_truncated_response(response):
127
- while True:
128
- continuation = character_chat(response, history)
129
- if is_valid_response(continuation):
130
- break
131
- continuation = clean_response(continuation)
132
- history.append({"role": "bot", "text": continuation})
133
-
134
- html = render_chat(history)
135
- yield html, "", history
136
-
137
- def reset_chat():
138
- return gr.update(value=""), "", []
139
-
140
- user_input.submit(on_submit, inputs=[user_input, state], outputs=[chat_output, user_input, state], queue=True)
141
- reset_btn.click(reset_chat, inputs=None, outputs=[chat_output, user_input, state])
142
-
143
- #ํ—ˆ๊น…ํŽ˜์ด์Šค์—์„œ ์‹คํ–‰
144
- demo.launch()
145
 
 
 
1
  import gradio as gr
 
 
 
2
 
3
+ from core.make_pipeline import MakePipeline
4
+ from core.context_manager import ContextManager
5
+ from core.launch_gradio import create_interface
6
 
7
+ ###########################
8
+ # Upload to Huggling Face #
9
+ ###########################
10
 
11
+ # ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
12
+ makePipeline = MakePipeline()
13
+ makePipeline.build("hf")
14
 
15
+ # ์ฑ„ํŒ… ๊ธฐ๋ก ๊ด€๋ฆฌ์ž
16
+ ctx = ContextManager()
 
 
 
 
 
 
 
 
 
 
17
 
18
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค ์‹œ์ž‘
19
+ demo = create_interface(ctx, makePipeline)
20
+ demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
app/main.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from core.make_pipeline import MakePipeline
2
+ from core.context_manager import ContextManager
3
+ from core.launch_gradio import create_interface
4
+
5
+ ########################
6
+ # Start with localhost #
7
+ ########################
8
+
9
+ if __name__ == "__main__":
10
+ # ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
11
+ makePipeline = MakePipeline()
12
+ makePipeline.build("hf")
13
+
14
+ # ์ฑ„ํŒ… ๊ธฐ๋ก ๊ด€๋ฆฌ์ž
15
+ ctx = ContextManager()
16
+
17
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค ์‹œ์ž‘
18
+ demo = create_interface(ctx, makePipeline)
19
+ demo.launch()
{app โ†’ core}/__init__.py.py RENAMED
File without changes
core/context_manager.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class ContextManager:
2
+ # ์ „์—ญ ์ƒ์ˆ˜ ์„ค์ •
3
+ USER_NAME = "User"
4
+ BOT_NAME = "Tanjiro"
5
+
6
+ def __init__(self):
7
+ self.user_name = self.USER_NAME
8
+ self.bot_name = self.BOT_NAME
9
+ self.history = []
10
+
11
+ def getUserName(self) -> str:
12
+ return self.user_name
13
+
14
+ def getBotName(self) -> str:
15
+ return self.bot_name
16
+
17
+ def getHistory(self) -> str:
18
+ return self.history
19
+
20
+ def setHistory(self, new_history: list):
21
+ self.history = new_history
22
+
23
+ # ๋Œ€ํ™” ๊ธฐ๋ก์„ history์— ์ถ”๊ฐ€
24
+ def addHistory(self, role: str, text: str):
25
+ self.history.append({"role": role, "text": text})
26
+
27
+ # ๋Œ€ํ™” ๊ธฐ๋ก ์ดˆ๊ธฐํ™”
28
+ def clearHistory(self):
29
+ self.history = []
core/launch_gradio.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from context_manager import ContextManager
3
+ from make_pipeline import MakePipeline
4
+ from make_reply import generate_reply
5
+
6
+ def create_interface(ctx: ContextManager, makePipeline: MakePipeline):
7
+ with gr.Blocks(css="""
8
+ .chat-box { max-height: 500px; overflow-y: auto; padding: 10px; border: 1px solid #ccc; border-radius: 10px; }
9
+ .bubble-left { background-color: #f1f0f0; border-radius: 10px; padding: 10px; margin: 5px; max-width: 70%; float: left; clear: both; }
10
+ .bubble-right { background-color: #d1e7ff; border-radius: 10px; padding: 10px; margin: 5px; max-width: 70%; float: right; clear: both; text-align: right; }
11
+ .reset-btn-container { text-align: right; margin-bottom: 10px; }
12
+ """) as demo:
13
+ gr.Markdown("### ํƒ„์ง€๋กœ์™€ ๋Œ€ํ™”ํ•˜๊ธฐ")
14
+
15
+ with gr.Column():
16
+ with gr.Row():
17
+ gr.Markdown("")
18
+ reset_btn = gr.Button("๐Ÿ” ๋Œ€ํ™” ์ดˆ๊ธฐํ™”", elem_classes="reset-btn-container", scale=1)
19
+ chat_output = gr.HTML(elem_id="chat-box")
20
+ user_input = gr.Textbox(label="๋ฉ”์‹œ์ง€ ์ž…๋ ฅ", placeholder="ํƒ„์ง€๋กœ์—๊ฒŒ ๋ง์„ ๊ฑธ์–ด๋ณด์„ธ์š”")
21
+ state = gr.State(ctx)
22
+
23
+ # history ์ฝ์–ด์„œ ํ™”๋ฉด์— ๋ฟŒ๋ฆฌ๋Š” ์—ญํ• 
24
+ def render_chat(ctx: ContextManager):
25
+ html = ""
26
+ for item in ctx.getHistory():
27
+ if item["role"] == ctx.getUserName():
28
+ html += f"<div class='bubble-right'>{item['text']}</div>"
29
+ elif item["role"] == ctx.getBotName():
30
+ html += f"<div class='bubble-left'>{item['text']}</div>"
31
+ return gr.update(value=html)
32
+
33
+ def on_submit(user_msg: str, ctx: ContextManager):
34
+ # ์‚ฌ์šฉ์ž ๋ฉ”์„ธ์ง€ ์ถ”๊ฐ€
35
+ ctx.addMessage("user", user_msg)
36
+
37
+ # ์œ ์ € ๋‹ต๋ณ€์„ ํฌํ•จํ•œ HTML ๋ Œ๋”๋ง
38
+ html = render_chat(ctx)
39
+ yield html, "", ctx.getHistory()
40
+
41
+ # ๋ด‡ ์‘๋‹ต ์ƒ์„ฑ
42
+ generate_reply(ctx, makePipeline, user_msg)
43
+
44
+ # ๋ด‡ ๋‹ต๋ณ€์„ ํฌํ•จํ•œ HTML ๋ Œ๋”๋ง
45
+ html = render_chat(ctx)
46
+ yield html, "", ctx.getHistory()
47
+
48
+ # history ์ดˆ๊ธฐํ™”
49
+ def reset_chat():
50
+ ctx.resetHistory()
51
+ return gr.update(value=""), "", ctx.getHistory()
52
+
53
+ user_input.submit(on_submit, inputs=[user_input, state], outputs=[chat_output, user_input, state], queue=True)
54
+ reset_btn.click(reset_chat, inputs=None, outputs=[chat_output, user_input, state])
55
+
56
+ return demo
core/make_pipeline.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
2
+ import torch
3
+ import os
4
+
5
+ class MakePipeline:
6
+ # ๋ชจ๋ธ๋ช…
7
+ MODEL_ID = "naver-hyperclovax/HyperCLOVAX-SEED-Text-Instruct-1.5B"
8
+
9
+ # ๋ณ€์ˆ˜์ดˆ๊ธฐํ™”
10
+ # model_id
11
+ # tokenizer
12
+ # llm
13
+ def __init__(self, model_id: str = MODEL_ID):
14
+ print("[torch] is available:", torch.cuda.is_available())
15
+ print("[device] default:", torch.device("cuda" if torch.cuda.is_available() else "cpu"))
16
+ self.model_id = model_id
17
+ self.tokenizer = None
18
+ self.llm = None
19
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
20
+
21
+ # ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
22
+ def build(self, type: str):
23
+ if(type == 'hf'):
24
+ # ํ—ˆ๊น… ํŽ˜์ด์Šค secret์— ๋“ฑ๋ก๋œ ํ† ํฐ ๋กœ๋“œ
25
+ access_token = os.environ.get("HF_TOKEN")
26
+ else:
27
+ # ๋กœ์ปฌ ์‹คํ–‰์‹œ token.txt์—์„œ ํ† ํฐ ๋กœ๋“œ
28
+ with open("token.txt", "r") as f:
29
+ access_token = f.read().strip()
30
+
31
+ tokenizer = AutoTokenizer.from_pretrained(self.model_id, token=access_token)
32
+ model = AutoModelForCausalLM.from_pretrained(self.model_id, token=access_token)
33
+ self.tokenizer = tokenizer
34
+
35
+ # ํ—ˆ๊น… ํŽ˜์ด์Šค ์—…๋กœ๋“œ ์‹œ f16 ์‚ฌ์šฉ ์•ˆ ํ•จ
36
+ if(type == 'hf'):
37
+ llm = pipeline(
38
+ "text-generation",
39
+ model=model,
40
+ tokenizer=tokenizer,
41
+ )
42
+
43
+ else:
44
+ model.eval()
45
+ llm = pipeline(
46
+ "text-generation",
47
+ model=model,
48
+ tokenizer=tokenizer,
49
+ torch_dtype=torch.float16
50
+ )
51
+ if torch.cuda.is_available():
52
+ model.to("cuda")
53
+
54
+ self.llm = llm
55
+
56
+ # ๋ชจ๋ธ ์ถœ๋ ฅ ์ƒ์„ฑ ํ•จ์ˆ˜
57
+ def character_chat(self, prompt):
58
+ print("[debug] generating...")
59
+ outputs = self.llm(
60
+ prompt,
61
+ do_sample=True,
62
+ max_new_tokens=96,
63
+ temperature=0.7,
64
+ top_p=0.9,
65
+ repetition_penalty=1.05,
66
+ eos_token_id=self.tokenizer.eos_token_id,
67
+ return_full_text=True
68
+ )
69
+ full_text = outputs[0]['generated_text']
70
+ return full_text
core/make_reply.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ from core.make_pipeline import MakePipeline
4
+
5
+ # ์ƒ์„ฑ๋œ ๋ชจ๋“  ๋ด‡ ์‘๋‹ต ๊ธฐ๋ก
6
+ def generate_reply(ctx, makePipeLine: MakePipeline, user_msg):
7
+
8
+ # ์ตœ์ดˆ ์‘๋‹ต
9
+ response = generate_valid_response(ctx, makePipeLine, user_msg)
10
+ ctx.addHistory("bot", response)
11
+
12
+ # ์‘๋‹ต์ด ๋Š๊ฒผ๋‹ค๋ฉด ์ถ”๊ฐ€ ์ƒ์„ฑ
13
+ if is_truncated_response(response):
14
+ continuation = generate_valid_response(ctx, makePipeLine, response)
15
+ ctx.addHistory("bot", continuation)
16
+
17
+ # ๋ด‡ ์‘๋‹ต 1ํšŒ ์ƒ์„ฑ
18
+ def generate_valid_response(ctx, makePipeline: MakePipeline, user_msg: str) -> str:
19
+ user_name = ctx.getUserName()
20
+ bot_name = ctx.getBotName()
21
+
22
+ while True:
23
+ prompt = build_prompt(ctx.getHistory(), user_msg, user_name, bot_name)
24
+ full_text = makePipeline.character_chat(prompt)
25
+ response = extract_response(full_text, prompt, user_name, bot_name)
26
+ if is_valid_response(response, user_name, bot_name):
27
+ break
28
+ return clean_response(response, bot_name)
29
+
30
+ # ์ž…๋ ฅ ํ”„๋กฌํ”„ํŠธ ์ •๋ฆฌ
31
+ def build_prompt(history, user_msg, user_name, bot_name):
32
+ with open("assets/prompt/init.txt", "r", encoding="utf-8") as f:
33
+ prompt = f.read().strip()
34
+
35
+ for turn in history[-16:]:
36
+ role = user_name if turn["role"] == "user" else bot_name
37
+ prompt += f"{role}: {turn['text']}\n"
38
+
39
+ prompt += f"{user_name}: {user_msg}\n"
40
+ prompt += f"{bot_name}:"
41
+ return prompt
42
+
43
+ # ์ถœ๋ ฅ์—์„œ ์‘๋‹ต ์ถ”์ถœ
44
+ def extract_response(full_text, prompt, user_name, bot_name):
45
+ if full_text.startswith(prompt):
46
+ reply = full_text[len(prompt):].strip()
47
+ else:
48
+ reply = full_text.split(f"{bot_name}:")[-1].strip()
49
+ user_token = f"\n{user_name}:"
50
+ if user_token in reply:
51
+ reply = reply.split(user_token)[0].strip()
52
+ return reply
53
+
54
+ # ์‘๋‹ต ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
55
+ def is_valid_response(text: str, user_name, bot_name) -> bool:
56
+ if user_name + ":" in text:
57
+ return False
58
+ if bot_name + ":" in text:
59
+ return False
60
+ return True
61
+
62
+ # ์‘๋‹ต ํ˜•์‹ ์ •๋ฆฌ
63
+ def clean_response(text: str, bot_name):
64
+ return re.sub(rf"{bot_name}:\\s*", "", text).strip()
65
+
66
+ # ์ค‘๋‹จ๋œ ์‘๋‹ต ์—ฌ๋ถ€ ๊ฒ€์‚ฌ
67
+ def is_truncated_response(text: str) -> bool:
68
+ return re.search(r"[.?!โ€ฆ\u2026\u2639\u263A\u2764\uD83D\uDE0A\uD83D\uDE22]$", text.strip()) is None
{app โ†’ core}/utils.py RENAMED
File without changes
howToStart.txt CHANGED
@@ -7,11 +7,14 @@ python -m venv venv
7
  2. activate venv
8
  venv\Scripts\activate
9
 
10
- 3. install requirements
11
- pip install -r requirements.txt
 
12
 
13
  3.2. recieve hugging face token
14
  and write it into `./token.txt`
15
 
16
  4. start server
17
- python app\main.py
 
 
 
7
  2. activate venv
8
  venv\Scripts\activate
9
 
10
+ 3. install requirements_local
11
+ pip install -r requirements_local.txt
12
+ !! not `requirements` !!
13
 
14
  3.2. recieve hugging face token
15
  and write it into `./token.txt`
16
 
17
  4. start server
18
+ python app\main.py
19
+
20
+ 5. connect to localhost
requirements.txt CHANGED
@@ -25,8 +25,8 @@ markdown-it-py==3.0.0
25
  MarkupSafe==3.0.2
26
  mdurl==0.1.2
27
  mpmath==1.3.0
28
- networkx==3.5
29
- numpy==2.3.1
30
  orjson==3.10.18
31
  packaging==25.0
32
  pandas==2.3.1
@@ -57,7 +57,7 @@ sympy==1.13.3
57
  tiktoken==0.9.0
58
  tokenizers==0.21.2
59
  tomlkit==0.13.3
60
- torch==2.7.1+cu118
61
  tqdm==4.67.1
62
  transformers==4.53.2
63
  typer==0.16.0
@@ -66,4 +66,4 @@ typing_extensions==4.14.1
66
  tzdata==2025.2
67
  urllib3==2.5.0
68
  uvicorn==0.35.0
69
- websockets==15.0.1
 
25
  MarkupSafe==3.0.2
26
  mdurl==0.1.2
27
  mpmath==1.3.0
28
+ networkx==3.4.2
29
+ numpy==1.26.4
30
  orjson==3.10.18
31
  packaging==25.0
32
  pandas==2.3.1
 
57
  tiktoken==0.9.0
58
  tokenizers==0.21.2
59
  tomlkit==0.13.3
60
+ torch>=2.2,<2.8
61
  tqdm==4.67.1
62
  transformers==4.53.2
63
  typer==0.16.0
 
66
  tzdata==2025.2
67
  urllib3==2.5.0
68
  uvicorn==0.35.0
69
+ websockets==15.0.1
requirements_local.txt ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==24.1.0
2
+ annotated-types==0.7.0
3
+ anyio==4.9.0
4
+ blobfile==3.0.0
5
+ Brotli==1.1.0
6
+ certifi==2025.7.14
7
+ charset-normalizer==3.4.2
8
+ click==8.2.1
9
+ colorama==0.4.6
10
+ fastapi==0.116.1
11
+ ffmpy==0.6.0
12
+ filelock==3.18.0
13
+ fsspec==2025.5.1
14
+ gradio==5.37.0
15
+ gradio_client==1.10.4
16
+ groovy==0.1.2
17
+ h11==0.16.0
18
+ httpcore==1.0.9
19
+ httpx==0.28.1
20
+ huggingface-hub==0.33.4
21
+ idna==3.10
22
+ Jinja2==3.1.6
23
+ lxml==6.0.0
24
+ markdown-it-py==3.0.0
25
+ MarkupSafe==3.0.2
26
+ mdurl==0.1.2
27
+ mpmath==1.3.0
28
+ networkx==3.5
29
+ numpy==2.3.1
30
+ orjson==3.10.18
31
+ packaging==25.0
32
+ pandas==2.3.1
33
+ pillow==11.3.0
34
+ protobuf==6.31.1
35
+ pycryptodomex==3.23.0
36
+ pydantic==2.11.7
37
+ pydantic_core==2.33.2
38
+ pydub==0.25.1
39
+ Pygments==2.19.2
40
+ python-dateutil==2.9.0.post0
41
+ python-multipart==0.0.20
42
+ pytz==2025.2
43
+ PyYAML==6.0.2
44
+ regex==2024.11.6
45
+ requests==2.32.4
46
+ rich==14.0.0
47
+ ruff==0.12.3
48
+ safehttpx==0.1.6
49
+ safetensors==0.5.3
50
+ semantic-version==2.10.0
51
+ sentencepiece==0.2.0
52
+ shellingham==1.5.4
53
+ six==1.17.0
54
+ sniffio==1.3.1
55
+ starlette==0.47.1
56
+ sympy==1.13.3
57
+ tiktoken==0.9.0
58
+ tokenizers==0.21.2
59
+ tomlkit==0.13.3
60
+ torch==2.7.1+cu118
61
+ tqdm==4.67.1
62
+ transformers==4.53.2
63
+ typer==0.16.0
64
+ typing-inspection==0.4.1
65
+ typing_extensions==4.14.1
66
+ tzdata==2025.2
67
+ urllib3==2.5.0
68
+ uvicorn==0.35.0
69
+ websockets==15.0.1
todo.txt CHANGED
@@ -2,4 +2,5 @@
2
  ๋ˆ„์ ๋˜๋Š” ๋Œ€ํ™”๋ฅผ ํ”„๋กฌํ”„ํŠธ๋กœ ๋‹ค์‹œ ์‚ฌ์šฉํ•  ๋•Œ ์ ์ ˆํ•œ ๊ธธ์ด ์ฐพ๊ธฐ
3
  ์ด๋ฏธ์ง€ ์ถœ๋ ฅ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
4
  ์ถœ๋ ฅ ํ”„๋กฌํ”„ํŠธ ํŒŒ์‹ฑ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
5
- ์ž…๋ ฅ ํ”„๋กฌํ”„ํŠธ ํŒŒ์‹ฑ ๊ธฐ๋Šฅ
 
 
2
  ๋ˆ„์ ๋˜๋Š” ๋Œ€ํ™”๋ฅผ ํ”„๋กฌํ”„ํŠธ๋กœ ๋‹ค์‹œ ์‚ฌ์šฉํ•  ๋•Œ ์ ์ ˆํ•œ ๊ธธ์ด ์ฐพ๊ธฐ
3
  ์ด๋ฏธ์ง€ ์ถœ๋ ฅ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
4
  ์ถœ๋ ฅ ํ”„๋กฌํ”„ํŠธ ํŒŒ์‹ฑ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
5
+ ์ž…๋ ฅ ํ”„๋กฌํ”„ํŠธ ํŒŒ์‹ฑ ๊ธฐ๋Šฅ
6
+ character_chat ํ•จ์ˆ˜ ์„ค์ • json์œผ๋กœ ๋งŒ๋“ค๊ธฐ, gradio์—์„œ ์„ค์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ