workcha commited on
Commit
61b4ff5
ยท
verified ยท
1 Parent(s): fe8a5d3

Upload 19 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,11 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ images/01_main.png filter=lfs diff=lfs merge=lfs -text
37
+ images/02_models.png filter=lfs diff=lfs merge=lfs -text
38
+ images/03_model_card.png filter=lfs diff=lfs merge=lfs -text
39
+ images/04_spaces.png filter=lfs diff=lfs merge=lfs -text
40
+ images/05_tokens.png filter=lfs diff=lfs merge=lfs -text
41
+ images/06_new_space.png filter=lfs diff=lfs merge=lfs -text
42
+ images/09_app_logs.png filter=lfs diff=lfs merge=lfs -text
43
+ images/10_write_token.png filter=lfs diff=lfs merge=lfs -text
6์ฃผ์ฐจ_HuggingFace_์นผ๋กœ๋ฆฌ์นด์šดํ„ฐ.html ADDED
@@ -0,0 +1,1107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>6์ฃผ์ฐจ โ€” HuggingFace ร— Spaces ร— ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ</title>
7
+ <style>
8
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
9
+ body {
10
+ font-family: 'Segoe UI', 'Apple SD Gothic Neo', sans-serif;
11
+ font-size: 16px; line-height: 1.7; color: #1a1a2e;
12
+ background: #f8f9fc; overflow-x: hidden;
13
+ }
14
+ a { color: #f59e0b; text-decoration: none; font-weight: 600; }
15
+ a:hover { text-decoration: underline; }
16
+
17
+ .page-wrapper { max-width: 920px; margin: 0 auto; padding: 2rem 1.5rem 6rem; }
18
+
19
+ /* Hero */
20
+ .hero {
21
+ background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
22
+ border-radius: 20px; padding: 3rem 2.5rem; margin-bottom: 2rem;
23
+ color: white; position: relative; overflow: hidden;
24
+ }
25
+ .hero::after {
26
+ content: '๐Ÿค—๐Ÿฑ'; position: absolute; right: 2rem; top: 50%;
27
+ transform: translateY(-50%); font-size: 6rem; opacity: 0.2;
28
+ }
29
+ .hero .week-badge {
30
+ display: inline-block; background: rgba(255,255,255,0.25);
31
+ border: 1px solid rgba(255,255,255,0.5); border-radius: 999px;
32
+ padding: 0.3rem 1rem; font-size: 0.85rem; margin-bottom: 1rem;
33
+ }
34
+ .hero h1 { font-size: 2rem; font-weight: 700; margin-bottom: 0.5rem; }
35
+ .hero p { font-size: 1.05rem; opacity: 0.95; max-width: 600px; }
36
+
37
+ .objectives { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 2.5rem; }
38
+ .obj-tag {
39
+ background: white; border: 2px solid #f59e0b; border-radius: 999px;
40
+ padding: 0.35rem 1rem; font-size: 0.85rem; color: #b45309; font-weight: 700;
41
+ }
42
+
43
+ /* Sections */
44
+ .class-section {
45
+ background: white; border-radius: 16px; padding: 2rem;
46
+ margin-bottom: 1.6rem; box-shadow: 0 2px 12px rgba(0,0,0,0.06);
47
+ border-left: 5px solid;
48
+ }
49
+ .class-section.s1 { border-color: #f59e0b; }
50
+ .class-section.s2 { border-color: #ef4444; }
51
+ .class-section.s3 { border-color: #8b5cf6; }
52
+ .class-section.s4 { border-color: #10b981; }
53
+ .class-section.s5 { border-color: #3b82f6; }
54
+
55
+ .section-label {
56
+ font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em;
57
+ text-transform: uppercase; margin-bottom: 0.3rem; color: #6b7280;
58
+ }
59
+ .s1 .section-label { color: #b45309; }
60
+ .s2 .section-label { color: #b91c1c; }
61
+ .s3 .section-label { color: #6d28d9; }
62
+ .s4 .section-label { color: #047857; }
63
+ .s5 .section-label { color: #1d4ed8; }
64
+
65
+ .section-title {
66
+ font-size: 1.4rem; font-weight: 700; margin-bottom: 1rem; color: #1a1a2e;
67
+ }
68
+ h3 { font-size: 1.05rem; margin: 1.4rem 0 0.6rem; color: #1a1a2e; }
69
+ p { margin-bottom: 0.8rem; }
70
+ ul, ol { padding-left: 1.4rem; margin-bottom: 0.8rem; }
71
+ li { margin-bottom: 0.3rem; }
72
+ strong { color: #b45309; }
73
+
74
+ /* Why box */
75
+ .why-box {
76
+ background: linear-gradient(135deg, #fef3c7 0%, #fed7aa 100%);
77
+ border-left: 4px solid #f59e0b;
78
+ padding: 1.2rem 1.4rem; border-radius: 10px; margin: 1rem 0;
79
+ }
80
+ .why-box .label {
81
+ font-size: 0.7rem; font-weight: 800; color: #b45309;
82
+ letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.4rem;
83
+ }
84
+ .why-box p:last-child { margin-bottom: 0; }
85
+
86
+ /* Concept grid */
87
+ .concept-grid {
88
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
89
+ gap: 0.8rem; margin: 1rem 0;
90
+ }
91
+ .concept-card {
92
+ background: #fef3c7; border-radius: 12px; padding: 1rem;
93
+ text-align: center;
94
+ }
95
+ .concept-card .icon { font-size: 1.8rem; margin-bottom: 0.4rem; }
96
+ .concept-card .name { font-weight: 700; font-size: 0.95rem; color: #1a1a2e; margin-bottom: 0.3rem; }
97
+ .concept-card .desc { font-size: 0.78rem; color: #6b7280; line-height: 1.4; }
98
+
99
+ /* Compare table */
100
+ table {
101
+ width: 100%; border-collapse: collapse; margin: 1rem 0;
102
+ font-size: 0.9rem;
103
+ }
104
+ th, td {
105
+ border: 1px solid #e5e7eb; padding: 0.6rem 0.8rem; text-align: left;
106
+ vertical-align: top;
107
+ }
108
+ th { background: #fef3c7; font-weight: 700; color: #92400e; }
109
+ tr:nth-child(even) td { background: #fafafa; }
110
+
111
+ /* Code */
112
+ pre {
113
+ background: #1e293b; color: #e2e8f0; padding: 1rem 1.2rem;
114
+ border-radius: 10px; overflow-x: auto; font-size: 0.85rem;
115
+ margin: 0.8rem 0; line-height: 1.55;
116
+ }
117
+ code { font-family: 'Consolas', 'Monaco', monospace; }
118
+ p code, li code {
119
+ background: #fef3c7; color: #b45309; padding: 0.1rem 0.4rem;
120
+ border-radius: 4px; font-size: 0.88em;
121
+ }
122
+ .comment { color: #94a3b8; }
123
+ .kw { color: #f59e0b; }
124
+ .str { color: #86efac; }
125
+
126
+ /* TODO box */
127
+ .todo-box {
128
+ background: #fff7ed; border: 2px dashed #f59e0b;
129
+ border-radius: 10px; padding: 1rem 1.2rem; margin: 0.8rem 0;
130
+ }
131
+ .todo-box .num {
132
+ display: inline-block; background: #f59e0b; color: white;
133
+ width: 28px; height: 28px; border-radius: 50%;
134
+ text-align: center; line-height: 28px; font-weight: 700;
135
+ margin-right: 0.5rem;
136
+ }
137
+
138
+ /* Steps */
139
+ .step-list { counter-reset: step; list-style: none; padding: 0; }
140
+ .step-list li {
141
+ counter-increment: step; position: relative;
142
+ padding: 0.6rem 0 0.6rem 2.4rem; margin-bottom: 0.4rem;
143
+ }
144
+ .step-list li::before {
145
+ content: counter(step);
146
+ position: absolute; left: 0; top: 0.5rem;
147
+ width: 1.8rem; height: 1.8rem; background: #f59e0b;
148
+ color: white; border-radius: 50%; text-align: center;
149
+ line-height: 1.8rem; font-weight: 700; font-size: 0.85rem;
150
+ }
151
+
152
+ /* Q&A */
153
+ .qa { background: #f3f4f6; border-radius: 10px; padding: 1rem 1.2rem; margin: 0.8rem 0; }
154
+ .qa .q { font-weight: 700; color: #b91c1c; margin-bottom: 0.4rem; }
155
+ .qa .a { color: #374151; }
156
+
157
+ /* Glossary */
158
+ .glossary dt { font-weight: 700; color: #b45309; margin-top: 0.6rem; }
159
+ .glossary dd { margin-left: 1rem; color: #374151; font-size: 0.92rem; }
160
+
161
+ /* Mission */
162
+ .mission {
163
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
164
+ color: white; border-radius: 16px; padding: 2rem;
165
+ margin-top: 2rem;
166
+ }
167
+ .mission h2 { font-size: 1.5rem; margin-bottom: 1rem; }
168
+ .mission ul { list-style: none; padding: 0; }
169
+ .mission li { padding: 0.5rem 0 0.5rem 2rem; position: relative; }
170
+ .mission li::before {
171
+ content: 'โ˜'; position: absolute; left: 0;
172
+ font-size: 1.3rem; opacity: 0.9;
173
+ }
174
+
175
+ footer { text-align: center; color: #9ca3af; font-size: 0.85rem; margin-top: 3rem; }
176
+ </style>
177
+ </head>
178
+ <body>
179
+ <div class="page-wrapper">
180
+
181
+ <!-- HERO -->
182
+ <div class="hero">
183
+ <div class="week-badge">WEEK 06 ยท 2026 AI์›น์œตํ•ฉ</div>
184
+ <h1>HuggingFace๋กœ AI ์•ฑ ๋งŒ๋“ค๊ณ  ์„ธ์ƒ์— ๊ณต๊ฐœํ•˜๊ธฐ</h1>
185
+ <p>์Œ์‹ ์‚ฌ์ง„ ํ•œ ์žฅ์œผ๋กœ ์นผ๋กœ๋ฆฌ๋ฅผ ์ถ”์ •ํ•˜๋Š” ์•ฑ์„ ์ง์ ‘ ๋งŒ๋“ค๊ณ ,
186
+ HuggingFace Space์— ๋ฐฐํฌํ•ด ๋ˆ„๊ตฌ๋‚˜ ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐœ URL์„ ๋ฐ›๋Š”๋‹ค.</p>
187
+ </div>
188
+
189
+ <!-- OBJECTIVES -->
190
+ <div class="objectives">
191
+ <span class="obj-tag">๐Ÿค— HF ์ƒํƒœ๊ณ„ ์ดํ•ด</span>
192
+ <span class="obj-tag">๐Ÿง  ๋ชจ๋ธ vs ๋ฐ์ดํ„ฐ์…‹ vs Space</span>
193
+ <span class="obj-tag">๐Ÿ–ผ๏ธ Inference API ํ˜ธ์ถœ</span>
194
+ <span class="obj-tag">๐ŸŽ›๏ธ Gradio UI</span>
195
+ <span class="obj-tag">๐Ÿš€ Space ๋ฐฐํฌ</span>
196
+ </div>
197
+
198
+ <!-- SECTION 1 -->
199
+ <section class="class-section s1">
200
+ <div class="section-label">SECTION 1 ยท WHY</div>
201
+ <h2 class="section-title">์™œ HuggingFace๋ฅผ ๋ฐฐ์›Œ์•ผ ํ•˜๋Š”๊ฐ€?</h2>
202
+
203
+ <p>HuggingFace๋Š” ๋‹จ์ˆœํžˆ "AI ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ"๊ฐ€ ์•„๋‹ˆ๋‹ค.
204
+ <strong>์˜ค๋Š˜๋‚  ์˜คํ”ˆ์†Œ์Šค AI ์ƒํƒœ๊ณ„์˜ GitHub</strong>์— ํ•ด๋‹นํ•˜๋Š” ํ”Œ๋žซํผ์ด๋ฉฐ,
205
+ ์ „ ์„ธ๊ณ„ ์—ฐ๊ตฌ์ž/๊ธฐ์—…์ด ๋งŒ๋“  100๋งŒ ๊ฐœ ์ด์ƒ์˜ ๋ชจ๋ธยท๋ฐ์ดํ„ฐ์…‹ยท๋ฐ๋ชจ๊ฐ€ ๋ชจ์—ฌ ์žˆ๋‹ค.</p>
206
+
207
+ <div class="why-box">
208
+ <div class="label">ํ•œ ์ค„ ์š”์•ฝ</div>
209
+ <p>OpenAI/Anthropic ๊ฐ™์€ <strong>ํ์‡„ํ˜•(Closed) API</strong>๊ฐ€ "์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ์žํŒ๊ธฐ"๋ผ๋ฉด,
210
+ HuggingFace๋Š” <strong>์˜คํ”ˆ์†Œ์Šค(Open-weight) ๋ชจ๋ธ์„ ๊ณจ๋ผ์„œ ์ง์ ‘ ์กฐ๋ฆฝํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€ํ’ˆ ๊ฐ€๊ฒŒ + ์ž‘์—…์žฅ + ์ „์‹œ๊ด€</strong>์ด๋‹ค.</p>
211
+ </div>
212
+
213
+ <h3>๐Ÿ“Œ ํ•™์ƒ์œผ๋กœ์„œ HF๋ฅผ ๋ฐฐ์›Œ์•ผ ํ•˜๋Š” 5๊ฐ€์ง€ ์ด์œ </h3>
214
+ <ol>
215
+ <li><strong>๋น„์šฉ 0์›์œผ๋กœ ์‹œ์ž‘</strong> โ€” ๊ฐ€์ž…๋งŒ ํ•˜๋ฉด Inference API/Space๋ฅผ ๋ฌด๋ฃŒ๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค.
216
+ OpenAI์ฒ˜๋Ÿผ ์นด๋“œ ๋“ฑ๋ก๋„, ์ถฉ์ „๋„ ํ•„์š” ์—†๋‹ค.</li>
217
+ <li><strong>๋‹ค์–‘ํ•œ ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ</strong> โ€” GPT๋ฅ˜๋Š” ํ…์ŠคํŠธ ์ค‘์‹ฌ์ด์ง€๋งŒ, HF์—๋Š”
218
+ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ยท์Œ์„ฑ ์ธ์‹ยท๋ฒˆ์—ญยทOCRยท์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ๋“ฑ <em>ํŠน์ • ์ž‘์—…์— ํŠนํ™”๋œ ์ž‘์€ ๋ชจ๋ธ</em>์ด ์ˆ˜๋งŒ ๊ฐœ ์žˆ๋‹ค.</li>
219
+ <li><strong>๋ชจ๋ธ์˜ ๋‚ด๋ถ€๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค</strong> โ€” ๊ฐ€์ค‘์น˜(weights)ยท๊ตฌ์กฐยทํ•™์Šต ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๊ณต๊ฐœ๋˜์–ด ์žˆ์–ด
220
+ "AI๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€"๋ฅผ ์‹ค์ œ๋กœ ๋“ค์—ฌ๋‹ค๋ณผ ์ˆ˜ ์žˆ๋‹ค.</li>
221
+ <li><strong>ํ•œ ์ค„๋กœ ๋ฐฐํฌ</strong> โ€” GitHub์— ์ฝ”๋“œ ํ‘ธ์‹œํ•˜๋“ฏ Space์— ํ‘ธ์‹œํ•˜๋ฉด ๊ณง๋ฐ”๋กœ ๊ณต๊ฐœ URL์ด ์ƒ๊ธด๋‹ค.
222
+ ์„œ๋ฒ„ ์„ค์ •ยท๋„๋ฉ”์ธยทSSL ๊ฐ™์€ ์ธํ”„๋ผ ์ง€์‹์ด ์—†์–ด๋„ ๋œ๋‹ค.</li>
223
+ <li><strong>์ด๋ ฅ์„œ๊ฐ€ ๋œ๋‹ค</strong> โ€” ์ง์ ‘ ๋งŒ๋“  Space๋Š” ์ฑ„์šฉ ๋‹ด๋‹น์ž๋‚˜ ๊ต์ˆ˜์—๊ฒŒ
224
+ "๋‚˜๋Š” AI๋ฅผ ์“ธ ์ค„ ์•ˆ๋‹ค"๋ฅผ ์ฆ๋ช…ํ•˜๋Š” ๊ฐ€์žฅ ๋น ๋ฅธ ๋ฐฉ๋ฒ•์ด๋‹ค.</li>
225
+ </ol>
226
+
227
+ <h3>๐Ÿ†š OpenAI API vs HuggingFace</h3>
228
+ <table>
229
+ <tr><th>๊ด€์ </th><th>OpenAI API</th><th>HuggingFace</th></tr>
230
+ <tr><td>๋ชจ๋ธ ์ข…๋ฅ˜</td><td>GPT ๊ณ„์—ด ๋ช‡ ๊ฐœ</td><td>100๋งŒ+ ์˜คํ”ˆ ๋ชจ๋ธ</td></tr>
231
+ <tr><td>๋น„์šฉ</td><td>ํ† ํฐ๋‹น ๊ณผ๊ธˆ</td><td>๋ฌด๋ฃŒ ํ‹ฐ์–ด (Inference API/Space)</td></tr>
232
+ <tr><td>๋ชจ๋ธ ๊ฐ€์ค‘์น˜</td><td>๋น„๊ณต๊ฐœ</td><td>๋Œ€๋ถ€๋ถ„ ๊ณต๊ฐœ (๋‹ค์šด๋กœ๋“œ ๊ฐ€๋Šฅ)</td></tr>
233
+ <tr><td>๋กœ์ปฌ ์‹คํ–‰</td><td>๋ถˆ๊ฐ€๋Šฅ</td><td>๊ฐ€๋Šฅ (transformers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)</td></tr>
234
+ <tr><td>์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆ</td><td>ํ”„๋กฌ๏ฟฝ๏ฟฝ๏ฟฝํŠธ ์ˆ˜์ค€</td><td>ํŒŒ์ธํŠœ๋‹๊นŒ์ง€ ๊ฐ€๋Šฅ</td></tr>
235
+ <tr><td>UI ๋ฐฐํฌ</td><td>์ง์ ‘ ๋งŒ๋“ค์–ด์•ผ ํ•จ</td><td>Spaces๋กœ ํ•œ ๋ฒˆ์—</td></tr>
236
+ </table>
237
+
238
+ <div class="why-box">
239
+ <p>AI ๋ชจ๋ธ ์ƒํƒœ๊ณ„๋Š” ํฌ๊ฒŒ ๋‘ ์ง„์˜์œผ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค. <br>
240
+ <strong>Closed ์ง„์˜์˜ ๋Œ€ํ‘œ์ฃผ์ž๊ฐ€ OpenAI</strong>๋ผ๋ฉด,
241
+ <strong>Open ์ง„์˜์˜ ๋Œ€ํ‘œ์ฃผ์ž๊ฐ€ HuggingFace</strong>์ž…๋‹ˆ๋‹ค.
242
+ </p>
243
+ </div>
244
+ </section>
245
+
246
+ <!-- SECTION 2 -->
247
+ <section class="class-section s2">
248
+ <div class="section-label">SECTION 2 ยท CONCEPT</div>
249
+ <h2 class="section-title">HuggingFace ์ƒํƒœ๊ณ„ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ</h2>
250
+
251
+ <p>HF์— ์ฒ˜์Œ ๋“ค์–ด๊ฐ€๋ฉด ๋ฉ”๋‰ด๊ฐ€ ๋งŽ์•„ ์–ด์ง€๋Ÿฝ๋‹ค. ์‚ฌ์‹ค ํ•ต์‹ฌ์€ <strong>4๊ฐœ์˜ ๊ธฐ๋‘ฅ</strong>๋ฟ์ด๋‹ค.</p>
252
+
253
+ <div class="concept-grid">
254
+ <div class="concept-card">
255
+ <div class="icon">๐Ÿง </div>
256
+ <div class="name">Models</div>
257
+ <div class="desc">ํ•™์Šต๋œ AI ๋ชจ๋ธ ์ €์žฅ์†Œ.<br>๊ฐ€์ค‘์น˜ยท์ฝ”๋“œยท์‚ฌ์šฉ๋ฒ• ํฌํ•จ</div>
258
+ </div>
259
+ <div class="concept-card">
260
+ <div class="icon">๐Ÿ“Š</div>
261
+ <div class="name">Datasets</div>
262
+ <div class="desc">ํ•™์Šต/ํ‰๊ฐ€์šฉ ๋ฐ์ดํ„ฐ์…‹.<br>ํ•œ ์ค„ ์ฝ”๋“œ๋กœ ๋กœ๋”ฉ ๊ฐ€๋Šฅ</div>
263
+ </div>
264
+ <div class="concept-card">
265
+ <div class="icon">๐Ÿš€</div>
266
+ <div class="name">Spaces</div>
267
+ <div class="desc">AI ๋ฐ๋ชจ๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๋Š”<br>๋ฌด๋ฃŒ ์›น์•ฑ ํ”Œ๋žซํผ</div>
268
+ </div>
269
+ <div class="concept-card">
270
+ <div class="icon">โšก</div>
271
+ <div class="name">Inference API</div>
272
+ <div class="desc">๋ชจ๋ธ์„ ๋‹ค์šด ์•ˆ ๋ฐ›๊ณ <br>HTTP๋กœ ๋ฐ”๋กœ ํ˜ธ์ถœ</div>
273
+ </div>
274
+ </div>
275
+
276
+ <h3>๐Ÿง  Model Hub โ€” "AI ๋ชจ๋ธ์˜ GitHub"</h3>
277
+ <p>ํ•œ ๋ชจ๋ธ ํŽ˜์ด์ง€์—๋Š” ๋‹ค์Œ์ด ๋“ค์–ด ์žˆ๋‹ค:</p>
278
+ <ul>
279
+ <li><strong>Model Card</strong> โ€” ์ด ๋ชจ๋ธ์ด ๋ฌด์—‡์„ ํ•˜๋Š”์ง€, ์–ด๋–ป๊ฒŒ ํ•™์Šตํ–ˆ๋Š”์ง€, ํ•œ๊ณ„๋Š” ๋ฌด์—‡์ธ์ง€ ์ ํžŒ ์„ค๋ช…์„œ</li>
280
+ <li><strong>Files and versions</strong> โ€” ๊ฐ€์ค‘์น˜ ํŒŒ์ผ(.safetensors), ํ† ํฌ๋‚˜์ด์ €, ์„ค์ • ํŒŒ์ผ</li>
281
+ <li><strong>Inference API ์œ„์ ฏ</strong> โ€” ํŽ˜์ด์ง€ ์šฐ์ธก์—์„œ ๋ฐ”๋กœ ๋ชจ๋ธ์„ ํ…Œ์ŠคํŠธํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐ•์Šค</li>
282
+ <li><strong>์ปค๋ฎค๋‹ˆํ‹ฐ ํƒญ</strong> โ€” ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ/์ด์Šˆ</li>
283
+ </ul>
284
+ <p>์˜ค๋Š˜ ์šฐ๋ฆฌ๊ฐ€ ์“ธ ๋ชจ๋ธ: <code>nateraw/food</code> โ€” Vision Transformer(ViT)๋ฅผ
285
+ Food-101 ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ ํŒŒ์ธํŠœ๋‹ํ•œ ์Œ์‹ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜๊ธฐ.</p>
286
+
287
+ <h3>๐Ÿš€ Spaces โ€” "AI ๋ฐ๋ชจ์˜ Vercel/Netlify"</h3>
288
+ <p>Space๋Š” ํ•œ๋งˆ๋””๋กœ <strong>"AI ์•ฑ์„ ๊นƒ ํ‘ธ์‹œ ํ•œ ๋ฒˆ์œผ๋กœ ๋ฐฐํฌํ•ด์ฃผ๋Š” ๋ฌด๋ฃŒ ํ˜ธ์ŠคํŒ…"</strong>์ด๋‹ค.</p>
289
+ <ul>
290
+ <li>์ง€์› SDK: <strong>Gradio</strong>(ํŒŒ์ด์ฌ UI), <strong>Streamlit</strong>, <strong>Static HTML</strong>, <strong>Docker</strong></li>
291
+ <li>๋ฌด๋ฃŒ ํ•˜๋“œ์›จ์–ด: 2 vCPU + 16GB RAM (CPU Basic)</li>
292
+ <li>๊ฐ Space๋Š” git ์ €์žฅ์†Œ์ด๋ฉฐ <code>https://huggingface.co/spaces/&lt;์œ ์ €&gt;/&lt;์ด๋ฆ„&gt;</code> ์ฃผ์†Œ๋ฅผ ๋ฐ›๋Š”๋‹ค</li>
293
+ <li>๋น„๊ณต๊ฐœ ํ† ํฐ์€ <em>Settings โ†’ Secrets</em>์— ๋“ฑ๋กํ•œ๋‹ค (์ฝ”๋“œ์—๋Š” ์ ˆ๋Œ€ ์ ์ง€ ์•Š์Œ)</li>
294
+ </ul>
295
+
296
+ <h3>โšก Inference API โ€” "๋ชจ๋ธ์„ ๋ถ€๋ฅด๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•"</h3>
297
+ <table>
298
+ <tr><th>๋ฐฉ์‹</th><th>์‚ฌ์šฉ ์‹œ์ </th><th>ํŠน์ง•</th></tr>
299
+ <tr>
300
+ <td><strong>๋กœ์ปฌ ์‹คํ–‰</strong><br>(transformers)</td>
301
+ <td>๋ชจ๋ธ์„ ๋‚ด ์ปดํ“จํ„ฐ/์„œ๋ฒ„์— ๋‹ค์šด๋กœ๋“œํ•ด ์ง์ ‘ ๋Œ๋ฆผ</td>
302
+ <td>์†๋„ ๋น ๋ฆ„, ๋น„์šฉ 0, ๊ทธ๋Ÿฌ๋‚˜ GPU/RAM ํ•„์š”</td>
303
+ </tr>
304
+ <tr>
305
+ <td><strong>Inference API</strong><br>(InferenceClient)</td>
306
+ <td>HF ์„œ๋ฒ„์— HTTP ์š”์ฒญ๋งŒ ๋ณด๋‚ด๊ณ  ๊ฒฐ๊ณผ ๋ฐ›์Œ</td>
307
+ <td>์„ค์น˜ ๋ถˆํ•„์š”, ์ž‘์€ ๋…ธํŠธ๋ถ์—์„œ๋„ ๋™์ž‘ โœ…</td>
308
+ </tr>
309
+ </table>
310
+ <p>์ด๋ฒˆ ์ฃผ์ฐจ๋Š” ํ›„์ž(Inference API)๋ฅผ ์“ด๋‹ค. ํ•™์ƒ์šฉ ๋…ธํŠธ๋ถ์— GPU๊ฐ€ ์—†์–ด๋„ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.</p>
311
+ </section>
312
+
313
+ <!-- SECTION 2.5 -->
314
+ <section class="class-section s4">
315
+ <div class="section-label">SECTION 2.5 ยท GUIDED TOUR</div>
316
+ <h2 class="section-title">HuggingFace ์‚ฌ์ดํŠธ ์™„์ „ ์ •๋ณต ๊ฐ€์ด๋“œ</h2>
317
+
318
+ <p>์ฒ˜์Œ ์ ‘์†ํ•˜๋ฉด ๋ฉ”๋‰ด๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์•„ ๋‹นํ™ฉํ•œ๋‹ค. ์ด ์„น์…˜์€ <strong>"์–ด๋””๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฌด์—‡์ด ๋‚˜์˜ค๋Š”๊ฐ€"</strong>๋ฅผ
319
+ ์ง€๋„์ฒ˜๋Ÿผ ์ •๋ฆฌํ•œ ๊ฒƒ์ด๋‹ค. ๊ฐ•์˜ ์ค‘์— ํ™”๋ฉด์„ ๋„์›Œ๋†“๊ณ  ๊ฐ™์ด ๋”ฐ๋ผ๊ฐ€์ž.</p>
320
+
321
+ <h3>๐Ÿ  1. ๋ฉ”์ธ ํŽ˜์ด์ง€ โ€” ์ƒ๋‹จ ๋‚ด๋น„๊ฒŒ์ด์…˜</h3>
322
+ <p><a href="https://huggingface.co">huggingface.co</a> ์ ‘์† ์‹œ ์ƒ๋‹จ์— ๋ณด์ด๋Š” ๋ฉ”๋‰ด:</p>
323
+ <img src="images/01_main.png" alt="HuggingFace ๋ฉ”์ธ ํŽ˜์ด์ง€" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
324
+ <p style="color:#6b7280;font-size:0.9em;">์œ„ ์ด๋ฏธ์ง€์˜ ์ƒ‰๊น” ๋ฒˆํ˜ธ โ‘ ~โ‘ค๊ฐ€ ์•„๋ž˜ ํ‘œ์™€ ๋งค์นญ๋œ๋‹ค.</p>
325
+ <table>
326
+ <tr><th>๋ฒˆํ˜ธ</th><th>๋ฉ”๋‰ด</th><th>๋ฌด์—‡์ด ์žˆ๋Š”๊ฐ€</th><th>์–ธ์ œ ํด๋ฆญํ•˜๋‚˜</th></tr>
327
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;">1</span></td><td><strong>Models</strong></td><td>100๋งŒ+ ์‚ฌ์ „ํ•™์Šต ๋ชจ๋ธ</td><td>"์ด๋Ÿฐ ์ผ์„ ํ•˜๋Š” ๋ชจ๋ธ ์žˆ๋‚˜?" ๊ฒ€์ƒ‰ํ•  ๋•Œ</td></tr>
328
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#f97316;color:white;text-align:center;font-weight:bold;">2</span></td><td><strong>Datasets</strong></td><td>ํ•™์Šต/ํ‰๊ฐ€์šฉ ๋ฐ์ดํ„ฐ์…‹</td><td>๋ชจ๋ธ์„ ์ง์ ‘ ํ•™์Šต์‹œํ‚ฌ ๋•Œ</td></tr>
329
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;">3</span></td><td><strong>Spaces</strong></td><td>๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋งŒ๋“  AI ๋ฐ๋ชจ</td><td>์•„์ด๋””์–ด ์–ป๊ณ  ์‹ถ์„ ๋•Œ / ๋‚ด ์•ฑ ๋ฐฐํฌํ•  ๋•Œ</td></tr>
330
+ <tr><td>โ€”</td><td><strong>Buckets</strong> <span style="background:#fbbf24;color:#78350f;font-size:0.7em;padding:2px 6px;border-radius:4px;">NEW</span></td><td>AI ํŒ€์šฉ ์˜ค๋ธŒ์ ํŠธ ์Šคํ† ๋ฆฌ์ง€ (TB๋‹น $8~18/์›”, Xet ์ค‘๋ณต์ œ๊ฑฐ + CDN, <code>hf sync</code>๋กœ git ์—†์ด ๋Œ€์šฉ๋Ÿ‰ ๋™๊ธฐํ™”)</td><td>๋Œ€์šฉ๋Ÿ‰ ๋ชจ๋ธ/๋ฐ์ดํ„ฐ์…‹์„ S3 ๋Œ€์‹  HF์— ์ €์žฅํ•  ๋•Œ โ€” ์ˆ˜์—…์—์„œ๋Š” ๋ฌด์‹œ OK</td></tr>
331
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;">4</span></td><td><strong>Docs</strong></td><td>๊ณต์‹ ๋ฌธ์„œ</td><td>๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ๋ฒ• ๋ง‰ํž ๋•Œ</td></tr>
332
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#8b5cf6;color:white;text-align:center;font-weight:bold;">5</span></td><td><strong>Pricing</strong></td><td>๋ฌด๋ฃŒ/์œ ๋ฃŒ ํ”Œ๋žœ</td><td>"PRO ๊ณ„์ • ๋ญ”์ง€" ๊ถ๊ธˆํ•  ๋•Œ</td></tr>
333
+ </table>
334
+
335
+ <h3>๐Ÿง  2. Models ํƒญ ๊นŠ์ด ํŒŒ๊ธฐ</h3>
336
+ <p><a href="https://huggingface.co/models">huggingface.co/models</a> ์ ‘์† โ†’ ํ™”๋ฉด ๊ตฌ์„ฑ์€ ํฌ๊ฒŒ <strong>์ขŒ์ธก ์‚ฌ์ด๋“œ๋ฐ”(ํ•„ํ„ฐ)</strong> + <strong>๋ณธ๋ฌธ(๋ชจ๋ธ ๋ฆฌ์ŠคํŠธ)</strong>์ด๊ณ , ๋ณธ๋ฌธ ์šฐ์ธก ์ƒ๋‹จ์— <strong>๊ฒ€์ƒ‰์ฐฝ๊ณผ ์ •๋ ฌ ์˜ต์…˜</strong>์ด ๋ถ™์–ด์žˆ๋‹ค:</p>
337
+ <img src="images/02_models.png" alt="HuggingFace Models ํƒญ โ€” ์ขŒ์ธก ํ•„ํ„ฐ ์‚ฌ์ด๋“œ๋ฐ”, ๋ณธ๋ฌธ ๋ชจ๋ธ ๋ฆฌ์ŠคํŠธ, ์šฐ์ธก ์ƒ๋‹จ ๊ฒ€์ƒ‰/์ •๋ ฌ" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
338
+
339
+ <p style="color:#6b7280;font-size:0.9em;">์œ„ ์ด๋ฏธ์ง€์— โ‘ (๋นจ๊ฐ•) ์‚ฌ์ด๋“œ๋ฐ”, โ‘ก(ํŒŒ๋ž‘) ๋ชจ๋ธ ๋ฆฌ์ŠคํŠธ, โ‘ข(์ดˆ๋ก) ๊ฒ€์ƒ‰ยท์ •๋ ฌ ์˜์—ญ์ด ํ‘œ์‹œ๋˜์–ด ์žˆ๋‹ค.</p>
340
+
341
+ <h4 style="margin:0.8rem 0 0.4rem; color:#047857;"><span style="display:inline-block;width:22px;height:22px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;font-size:0.85em;">1</span> ์ขŒ์ธก ์‚ฌ์ด๋“œ๋ฐ”: ํ•„ํ„ฐ ํŒจ๋„</h4>
342
+ <ul>
343
+ <li><strong>Tasks</strong> โ€” ๋ชจ๋ธ์ด ํ•˜๋Š” ์ผ๋กœ ๊ฑฐ๋ฅด๊ธฐ. ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ:
344
+ <ul>
345
+ <li><em>Multimodal</em>: Image-Text-to-Text, Visual QA</li>
346
+ <li><em>Computer Vision</em>: Image Classification, Object Detection, Image Segmentation</li>
347
+ <li><em>Natural Language Processing</em>: Text Generation, Translation, Summarization, Sentiment</li>
348
+ <li><em>Audio</em>: Speech Recognition (ASR), Text-to-Speech (TTS)</li>
349
+ </ul>
350
+ </li>
351
+ <li><strong>Libraries</strong> โ€” Transformers / Diffusers / GGUF ๋“ฑ โ€” ์ผ๋‹จ ๊ธฐ๋ณธ๊ฐ’(Transformers)์œผ๋กœ ๋‘๋ฉด ๋จ</li>
352
+ <li><strong>Languages</strong> โ€” "korean" ์ฒดํฌํ•˜๋ฉด ํ•œ๊ตญ์–ด ์ง€์› ๋ชจ๋ธ๋งŒ ํ‘œ์‹œ</li>
353
+ <li><strong>Licenses</strong> โ€” ์ƒ์—…์  ์ด์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€. <em>apache-2.0</em>, <em>mit</em> = ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉ OK / <em>cc-by-nc</em> = ๋น„์ƒ์—…์šฉ๋งŒ</li>
354
+ </ul>
355
+
356
+ <h4 style="margin:0.8rem 0 0.4rem; color:#047857;"><span style="display:inline-block;width:22px;height:22px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;font-size:0.85em;">2</span> ๋ณธ๋ฌธ: ๋ชจ๋ธ ๋ฆฌ์ŠคํŠธ</h4>
357
+ <p>๊ฐ ์นด๋“œ์—๋Š” ๋‹ค์Œ ์ •๋ณด๊ฐ€ ๋ณด์ธ๋‹ค:</p>
358
+ <ul>
359
+ <li><strong>๋ชจ๋ธ ์ด๋ฆ„</strong> = <code>์œ ์ €ID/๋ชจ๋ธ๋ช…</code> ํ˜•์‹ (์˜ˆ: <code>nateraw/food</code>)</li>
360
+ <li><strong>โ™ฅ ์ข‹์•„์š” ์ˆ˜</strong> โ€” ์ปค๋ฎค๋‹ˆํ‹ฐ ์ธ๊ธฐ๋„</li>
361
+ <li><strong>โ†“ ๋‹ค์šด๋กœ๋“œ ์ˆ˜</strong> โ€” ์ง€๋‚œ ํ•œ ๋‹ฌ ์‚ฌ์šฉ๋Ÿ‰ (๊ฐ€์žฅ ์‹ ๋ขฐํ•  ๋งŒํ•œ ์ง€ํ‘œ)</li>
362
+ <li><strong>๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ ๋‚ ์งœ</strong> โ€” 1๋…„ ๋„˜์€ ๋ชจ๋ธ์€ ๋” ์ข‹์€ ํ›„์† ๋ชจ๋ธ์ด ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ</li>
363
+ </ul>
364
+ <div class="why-box">
365
+ <div class="label">์ดˆ๋ณด์ž์šฉ ๋ชจ๋ธ ๊ณ ๋ฅด๋Š” ๋ฒ• (3์ดˆ ๋ฃฐ)</div>
366
+ <p>โ‘  ๋‹ค์šด๋กœ๋“œ ์ˆ˜ 1๋งŒ+ &nbsp; โ‘ก ์ข‹์•„์š” 100+ &nbsp; โ‘ข ๋ผ์ด์„ ์Šค apache/mit &nbsp; โ‘ฃ ์ตœ๊ทผ 6๊ฐœ์›” ๋‚ด ์—…๋ฐ์ดํŠธ<br>
367
+ โ€” 4๊ฐœ ๋‹ค ๋งŒ์กฑํ•˜๋ฉด ์ผ๋‹จ ๋ฏฟ๊ณ  ์จ๋„ ๋œ๋‹ค.</p>
368
+ </div>
369
+
370
+ <h4 style="margin:0.8rem 0 0.4rem; color:#047857;"><span style="display:inline-block;width:22px;height:22px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;font-size:0.85em;">3</span> ๋ณธ๋ฌธ ์šฐ์ธก ์ƒ๋‹จ: ๊ฒ€์ƒ‰์ฐฝ + ์ •๋ ฌ</h4>
371
+ <ul>
372
+ <li><strong>๊ฒ€์ƒ‰์ฐฝ</strong>: ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ (์˜ˆ: "korean sentiment", "food", "whisper")</li>
373
+ <li><strong>Sort by</strong>: <em>Trending</em>(์š”์ฆ˜ ๋œจ๋Š” ๊ฒƒ) / <em>Most likes</em> / <em>Most downloads</em> / <em>Recently updated</em></li>
374
+ </ul>
375
+
376
+ <h3>๐Ÿ“„ 3. ๋ชจ๋ธ ์นด๋“œ ํŽ˜์ด์ง€ ํ•ด๋ถ€๋„</h3>
377
+ <p>์˜ˆ์‹œ: <a href="https://huggingface.co/nateraw/food">huggingface.co/nateraw/food</a> ํด๋ฆญ ์‹œ ๋ณด์ด๋Š” ํ™”๋ฉด.</p>
378
+ <img src="images/03_model_card.png" alt="nateraw/food ๋ชจ๋ธ ์นด๋“œ ํŽ˜์ด์ง€" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
379
+
380
+ <p style="color:#6b7280;font-size:0.9em;">์œ„ ์ด๋ฏธ์ง€์˜ ์ƒ‰๊น” ๋ฐ•์Šค โ‘ โ‘กโ‘ข ๊ฐ€ ์•„๋ž˜ ํ‘œ ํ•ญ๋ชฉ๊ณผ ๋งค์นญ๋œ๋‹ค.</p>
381
+ <table>
382
+ <tr><th>๋ฒˆํ˜ธ</th><th>์˜์—ญ</th><th>๋‚ด์šฉ</th><th>ํ•™์ƒ์ด ๋ด์•ผ ํ•  ๋ถ€๋ถ„</th></tr>
383
+ <tr>
384
+ <td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;">1</span></td>
385
+ <td><strong>ํƒญ ๋ฐ”</strong> โ€” Model card / Files and versions / Training metrics / Community</td>
386
+ <td><em>Model card</em>๋Š” README.md ๋ Œ๋”๋ง, <em>Files and versions</em>๋Š” ์‹ค์ œ ํŒŒ์ผ, <em>Training metrics</em>๋Š” ํ•™์Šต ๊ณก์„ , <em>Community</em>๋Š” ์ด์Šˆ ๊ฒŒ์‹œํŒ</td>
387
+ <td>๋จผ์ € <em>Model card</em> ๋งจ ์œ„ ํ•œ๋‘ ์ค„๋กœ "๋ญ ํ•˜๋Š” ๋ชจ๋ธ"์ธ์ง€ ํŒŒ์•… โ†’ <em>Files</em>์—์„œ <code>config.json</code>ยท<code>*.safetensors</code> ํ™•์ธ โ†’ <em>Community</em>์—์„œ ํ•จ์ • ์ •๋ณด ๊ฒ€์ƒ‰</td>
388
+ </tr>
389
+ <tr>
390
+ <td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;">2</span></td>
391
+ <td><strong>Inference Providers ๋ฐ•์Šค</strong> (์šฐ์ธก)</td>
392
+ <td><code>HF Inference API</code> ์ œ๊ณต์ž + ์ž‘์—…๋ช…(์˜ˆ: <em>Image Classification</em>) ํ‘œ์‹œ. ์ ์„  ๋ฐ•์Šค์— "Drag image file here or click to browse from your device"</td>
393
+ <td>์‚ฌ์ง„์„ ๋“œ๋ž˜๊ทธ/ํด๋ฆญ ์—…๋กœ๋“œํ•˜๋ฉด ๋ผ๋ฒจยท์ ์ˆ˜๊ฐ€ ์ฆ‰์‹œ ํ‘œ์‹œ. ์•„๋ž˜ <em>View Code Snippets</em> / <em>Maximize</em> ๋ฒ„ํŠผ์œผ๋กœ ์ฝ”๋“œ ๋ณด๊ธฐยทํ™•๋Œ€</td>
394
+ </tr>
395
+ <tr>
396
+ <td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;">3</span></td>
397
+ <td><strong>Deploy</strong> / <strong>Use this model</strong> ๋ฒ„ํŠผ (์ƒ๋‹จ ์šฐ์ธก)</td>
398
+ <td>์ฝ”๋“œ ์Šค๋‹ˆํŽซ ๋ณต๋ถ™์šฉ ๋“œ๋กญ๋‹ค์šด</td>
399
+ <td>Transformers / Inference Providers / Endpoints ์ฝ”๋“œ ์ž๋™ ์ƒ์„ฑ โ†’ ์šฐ๋ฆฌ ์‹ค์Šต์€ <em>Inference Providers</em>(=HF Inference API) ์‚ฌ์šฉ</td>
400
+ </tr>
401
+ <tr>
402
+ <td>โ€”</td>
403
+ <td>๋ชจ๋ธ ์นด๋“œ ํ•˜๋‹จ ๋ฉ”ํƒ€์ •๋ณด</td>
404
+ <td>license, base_model, datasets, metrics</td>
405
+ <td><strong>license</strong> โ€” ์ƒ์—…์  ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ / <strong>base_model</strong> โ€” ์–ด๋–ค ๋ชจ๋ธ์„ fine-tune ํ–ˆ๋Š”์ง€ ์ถ”์ </td>
406
+ </tr>
407
+ </table>
408
+
409
+ <h3>๐ŸŽฎ 4. ์œ„์ ฏ ์‚ฌ์šฉ๋ฒ• โ€” ์ฝ”๋“œ ํ•œ ์ค„ ์—†์ด ๋ชจ๋ธ ํ…Œ์ŠคํŠธ</h3>
410
+ <p>๋ชจ๋ธ ์นด๋“œ ์šฐ์ธก์˜ ๋ฐ•์Šค๊ฐ€ <strong>Inference API ์œ„์ ฏ</strong>์ด๋‹ค. ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ๋ณ„๋กœ ์ž…๋ ฅ ๋ฐฉ์‹์ด ๋‹ค๋ฅด๋‹ค:</p>
411
+ <ul>
412
+ <li><strong>Image Classification</strong>: ์‚ฌ์ง„ ๋“œ๋ž˜๊ทธ โ†’ "Compute" โ†’ top-5 ๋ผ๋ฒจ๊ณผ ์ ์ˆ˜๊ฐ€ ๋ง‰๋Œ€๊ทธ๋ž˜ํ”„๋กœ ํ‘œ์‹œ</li>
413
+ <li><strong>Text Generation</strong>: ํ…์ŠคํŠธ ์ž…๋ ฅ โ†’ ๋ชจ๋ธ์ด ์ด์–ด์„œ ์ƒ์„ฑ</li>
414
+ <li><strong>Translation</strong>: ์›๋ฌธ ์ž…๋ ฅ โ†’ ๋ฒˆ์—ญ ๊ฒฐ๊ณผ</li>
415
+ <li><strong>ASR</strong>: ์˜ค๋””์˜ค ํŒŒ์ผ ์—…๋กœ๋“œ ๋˜๋Š” ๋งˆ์ดํฌ ๋…น์Œ โ†’ ํ…์ŠคํŠธ</li>
416
+ <li><strong>Object Detection</strong>: ์‚ฌ์ง„ โ†’ ๋ฐ•์Šค๊ฐ€ ๊ทธ๋ ค์ง„ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€</li>
417
+ </ul>
418
+ <div class="why-box">
419
+ <div class="label">์œ„์ ฏ์ด ์•ˆ ๋ณด์ด๊ฑฐ๋‚˜ ์—๋Ÿฌ๊ฐ€ ๋‚  ๋•Œ</div>
420
+ <p>โ‘  "Inference API has been turned off" โ†’ ๋ชจ๋ธ ์ œ์ž‘์ž๊ฐ€ ๋น„ํ™œ์„ฑํ™”ํ•œ ๊ฒฝ์šฐ. ๋‹ค๋ฅธ ๋ชจ๋ธ๋กœ ๊ฐˆ์•„ํƒ„๋‹ค.<br>
421
+ โ‘ก ์ฒซ ํ˜ธ์ถœ์—์„œ ~20์ดˆ ๋ฉˆ์ถค โ†’ <strong>cold start</strong>. ํ•œ ๋ฒˆ ๋” ๋ˆ„๋ฅด๋ฉด ๋น ๋ฅด๋‹ค.<br>
422
+ โ‘ข "Loading..." ๋ฌดํ•œ ๋ฐ˜๋ณต โ†’ ๋ชจ๋ธ์ด ๋„ˆ๋ฌด ํผ. ๋” ์ž‘์€ ๋™๊ธ‰ ๋ชจ๋ธ ๊ฒ€์ƒ‰.</p>
423
+ </div>
424
+
425
+ <h3>๐Ÿ› ๏ธ 5. "Use this model" ๋ฒ„ํŠผ โ€” ์ฝ”๋“œ ์ž๋™ ์ƒ์„ฑ</h3>
426
+ <p>๋ชจ๋ธ ํŽ˜์ด์ง€ ์šฐ์ธก ์ƒ๋‹จ์˜ <strong>&lt;/&gt; Use this model</strong> ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋“œ๋กญ๋‹ค์šด์—์„œ ์‚ฌ์šฉ ๋ฐฉ์‹์„ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ๋‹ค:</p>
427
+ <table>
428
+ <tr><th>์˜ต์…˜</th><th>์˜๋ฏธ</th><th>์ด๋ฒˆ ์ฃผ์ฐจ์—์„œ</th></tr>
429
+ <tr><td><strong>Transformers</strong></td><td>๋กœ์ปฌ ๋‹ค์šด๋กœ๋“œ ํ›„ ์ง์ ‘ ์‹คํ–‰</td><td>โŒ (GPU ํ•„์š”)</td></tr>
430
+ <tr><td><strong>Inference API (Serverless)</strong></td><td>HF ์„œ๋ฒ„์— HTTP ํ˜ธ์ถœ โ€” ๋ฌด๋ฃŒ</td><td>โœ… <strong>์šฐ๋ฆฌ๊ฐ€ ์“ฐ๋Š” ๋ฐฉ์‹</strong></td></tr>
431
+ <tr><td><strong>Inference Endpoints</strong></td><td>์ „์šฉ ์ธ์Šคํ„ด์Šค โ€” ์œ ๋ฃŒ, ํ•ญ์ƒ ์ผœ์ง</td><td>โŒ (์‹ค์„œ๋น„์Šค์šฉ)</td></tr>
432
+ </table>
433
+ <p>๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด <strong>๋ณต๋ถ™ ๊ฐ€๋Šฅํ•œ Python ์ฝ”๋“œ</strong>๊ฐ€ ๋ฐ”๋กœ ๋‚˜์˜จ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์“ธ ํŒจํ„ด์€ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค:</p>
434
+ <pre><span class="kw">from</span> huggingface_hub <span class="kw">import</span> InferenceClient
435
+
436
+ client = InferenceClient(token=<span class="str">"hf_..."</span>)
437
+ result = client.image_classification(
438
+ <span class="str">"food.jpg"</span>,
439
+ model=<span class="str">"nateraw/food"</span>,
440
+ )
441
+ <span class="kw">print</span>(result)
442
+ <span class="comment"># [{'label': 'pizza', 'score': 0.92}, ...]</span></pre>
443
+
444
+ <h3>๐Ÿš€ 6. Spaces ํƒญ ํ™œ์šฉ๋ฒ•</h3>
445
+ <p><a href="https://huggingface.co/spaces">huggingface.co/spaces</a> โ€” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋งŒ๋“  AI ๋ฐ๋ชจ ๋ชจ์Œ.</p>
446
+ <img src="images/04_spaces.png" alt="HuggingFace Spaces โ€” Spaces of the week" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
447
+ <p style="color:#6b7280;font-size:0.9em;">์œ„ ์ด๋ฏธ์ง€์˜ โ‘ (๋นจ๊ฐ•) ์นดํ…Œ๊ณ ๋ฆฌ ํƒญ, โ‘ก(ํŒŒ๋ž‘) Spaces of the week ์นด๋“œ ๊ทธ๋ฆฌ๋“œ, โ‘ข(์ดˆ๋ก) ๊ฒ€์ƒ‰ยทํ•„ํ„ฐยท์ •๋ ฌ ์˜์—ญ.</p>
448
+ <ul>
449
+ <li><span style="display:inline-block;width:22px;height:22px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;font-size:0.85em;">1</span> <strong>์นดํ…Œ๊ณ ๋ฆฌ ํƒญ</strong> โ€” Image Generation, Video Generation, Speech Synthesis ๋“ฑ ์ž‘์—…๋ณ„๋กœ ๋น ๋ฅด๊ฒŒ ๋‘˜๋Ÿฌ๋ณด๊ธฐ</li>
450
+ <li><span style="display:inline-block;width:22px;height:22px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;font-size:0.85em;">2</span> <strong>Spaces of the week (์นด๋“œ ๊ทธ๋ฆฌ๋“œ)</strong> โ€” ๋งค์ฃผ ํ๋ ˆ์ด์…˜. ์นด๋“œ ํด๋ฆญ โ†’ ๋ฐ๋ชจ ์‹คํ–‰. ์šฐ์ธก <strong>โ‹ฎ โ†’ Duplicate this Space</strong>๋กœ ๋‚ด ๊ณ„์ •์— ๋ณต์‚ฌ โ†’ ์ฝ”๋“œ ์ˆ˜์ • ๊ฐ€๋Šฅ</li>
451
+ <li><span style="display:inline-block;width:22px;height:22px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;font-size:0.85em;">3</span> <strong>Filter / Sort</strong> โ€” ์ด๋ฆ„ ๊ฒ€์ƒ‰, Filters, Sort(Relevance / Trending / Most likes ๋“ฑ)</li>
452
+ <li><strong>์นด๋“œ ํด๋ฆญ ์‹œ Space ์ƒ์„ธ ํŽ˜์ด์ง€</strong>๋กœ ์ด๋™ โ€” ํŽ˜์ด์ง€ ์ƒ๋‹จ์— 4๊ฐœ ํƒญ์ด ์žˆ๋‹ค:
453
+ <ul>
454
+ <li><strong>App</strong>: ์‹ค์ œ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ฐ๋ชจ ํ™”๋ฉด (Gradio/Streamlit UI)</li>
455
+ <li><strong>Files</strong>: ์†Œ์Šค ์ฝ”๋“œ (<code>app.py</code>, <code>requirements.txt</code> ๋“ฑ). ์˜คํ”ˆ์†Œ์Šค๋ผ ๊ทธ๋Œ€๋กœ ์—ด๋žŒยท๋ณต์‚ฌ ๊ฐ€๋Šฅ</li>
456
+ <li><strong>Community</strong>: ์งˆ๋ฌธยท์ด์Šˆ ๊ฒŒ์‹œํŒ</li>
457
+ <li><strong>Settings</strong>: ์ž‘์„ฑ์ž๋งŒ ๋ณด๋Š” ์„ค์ • (Secrets, ํ•˜๋“œ์›จ์–ด ์„ ํƒ ๋“ฑ)</li>
458
+ </ul>
459
+ ๐Ÿ‘‰ ์ด๋ฒˆ ์ฃผ์ฐจ์— ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ๋ฐฐํฌํ•  Space๋„ <strong>๋˜‘๊ฐ™์€ 4๊ฐœ ํƒญ ๊ตฌ์กฐ</strong>๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค. ์ฆ‰ ์ง€๊ธˆ ๋ณด๋Š” ๋‚จ์˜ Space๊ฐ€ ๊ณง ๋‚ด Space์˜ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.</li>
460
+ </ul>
461
+
462
+ <h3>๐Ÿ”‘ 7. ํ† ํฐ ๋ฐœ๊ธ‰ โ€” ํ•œ ๋ฒˆ๋งŒ ํ•˜๋ฉด ํ‰์ƒ ์‚ฌ์šฉ</h3>
463
+ <img src="images/05_tokens.png" alt="Settings โ†’ Access Tokens ํŽ˜์ด์ง€" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
464
+ <ol class="step-list">
465
+ <li>์šฐ์ธก ์ƒ๋‹จ ํ”„๋กœํ•„ ์‚ฌ์ง„ โ†’ <strong>Settings</strong></li>
466
+ <li>์ขŒ์ธก ๋ฉ”๋‰ด์—์„œ <strong>Access Tokens</strong></li>
467
+ <li><strong>+ Create new token</strong> ๋ฒ„ํŠผ</li>
468
+ <li>Token type: <strong>Read</strong> (๊ฐ€์žฅ ์•ˆ์ „, Inference API ํ˜ธ์ถœ์— ์ถฉ๋ถ„)</li>
469
+ <li>์ด๋ฆ„์€ ์ž์œ ๋กญ๊ฒŒ (์˜ˆ: <code>week06-class</code>)</li>
470
+ <li>์ƒ์„ฑ๋œ ํ† ํฐ <code>hf_xxxxxxxxxx...</code>๋ฅผ ์ฆ‰์‹œ ๋ณต์‚ฌ โ†’ <strong>๋‹ค์‹œ๋Š” ๋ชป ๋ณธ๋‹ค</strong></li>
471
+ </ol>
472
+ <div class="why-box">
473
+ <div class="label">โš ๏ธ ํ† ํฐ ๋ณด์•ˆ 3์›์น™</div>
474
+ <p>โ‘  <strong>์ฝ”๋“œ์— ์ ˆ๋Œ€ ์ง์ ‘ ์ ์ง€ ์•Š๋Š”๋‹ค</strong> โ†’ <code>.env</code> ํŒŒ์ผ ๋˜๋Š” Space Secrets ์‚ฌ์šฉ<br>
475
+ โ‘ก <strong>git์— ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๋Š”๋‹ค</strong> โ†’ <code>.gitignore</code>์— <code>.env</code> ์ถ”๊ฐ€ ํ•„์ˆ˜<br>
476
+ โ‘ข <strong>์‹ค์ˆ˜๋กœ ๋…ธ์ถœ๋˜๋ฉด ์ฆ‰์‹œ Revoke</strong> โ†’ ํ† ํฐ ํŽ˜์ด์ง€์—์„œ ํœด์ง€ํ†ต ์•„์ด์ฝ˜ ํด๋ฆญ</p>
477
+ </div>
478
+
479
+ <h3>๐Ÿ” 8. ๊ฒ€์ƒ‰ ๊ฟ€ํŒ (์‹ค์ „)</h3>
480
+ <ul>
481
+ <li><strong>ํ•œ๊ตญ์–ด ๋ชจ๋ธ ์ฐพ๊ธฐ</strong>: ๊ฒ€์ƒ‰์ฐฝ์— <code>korean</code> + Languages ํ•„ํ„ฐ์—์„œ <code>ko</code> ์ฒดํฌ</li>
482
+ <li><strong>๊ฐ€๋ฒผ์šด ๋ชจ๋ธ ์šฐ์„ </strong>: ๋ชจ๋ธ ์ด๋ฆ„์— <code>tiny</code>, <code>small</code>, <code>base</code>, <code>distil</code>์ด ๋“ค์–ด๊ฐ„ ๊ฒƒ์€ ๊ฒฝ๋Ÿ‰ ๋ฒ„์ „</li>
483
+ <li><strong>์ตœ์‹  ๋ชจ๋ธ๋งŒ</strong>: Sort = "Recently updated" + 1์ฃผ์ผ ์ด๋‚ด</li>
484
+ <li><strong>ํŠน์ • ํšŒ์‚ฌ/์—ฐ๊ตฌ์†Œ ๋ชจ๋ธ</strong>: <code>google/</code>, <code>microsoft/</code>, <code>meta-llama/</code>, <code>openai/</code> ๊ฒ€์ƒ‰</li>
485
+ <li><strong>Trending</strong> ํƒญ๋งŒ ๋ด๋„ ์ผ์ฃผ์ผ์— 5๋ถ„์ด๋ฉด AI ์—…๊ณ„ ๋™ํ–ฅ์ด ์žกํžŒ๋‹ค</li>
486
+ </ul>
487
+
488
+ <h3>๐Ÿ—บ๏ธ 9. ์‹ค์Šต ์ „ ์ฒดํฌ๋ฆฌ์ŠคํŠธ (์ˆ˜์—… ์ค‘ ํ•จ๊ป˜ ์ง„ํ–‰)</h3>
489
+ <div class="todo-box">
490
+ <div><span class="num">โœ“</span>HF ๊ฐ€์ž… ์™„๋ฃŒ</div>
491
+ <div><span class="num">โœ“</span>ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋“ฑ๋ก (์„ ํƒ, ๋ถ„์œ„๊ธฐ UP)</div>
492
+ <div><span class="num">โœ“</span>Read ํ† ํฐ 1๊ฐœ ๋ฐœ๊ธ‰ โ†’ ์•ˆ์ „ํ•œ ๊ณณ์— ์ €์žฅ</div>
493
+ <div><span class="num">โœ“</span><code>nateraw/food</code> ๋ชจ๋ธ ํŽ˜์ด์ง€ ์—ด์–ด๋ณด๊ณ  ์œ„์ ฏ์— ์‚ฌ์ง„ 1์žฅ ๋„ฃ์–ด๋ณด๊ธฐ</div>
494
+ <div><span class="num">โœ“</span>Trending Spaces์—์„œ ๋งˆ์Œ์— ๋“œ๋Š” ๊ฑฐ 1๊ฐœ ์ฐพ์•„๋ณด๊ธฐ</div>
495
+ </div>
496
+ </section>
497
+
498
+ <!-- SECTION 3 -->
499
+ <section class="class-section s3">
500
+ <div class="section-label">SECTION 3 ยท APP DESIGN</div>
501
+ <h2 class="section-title">์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ์•ฑ: ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ</h2>
502
+
503
+ <p>์Œ์‹ ์‚ฌ์ง„ 1์žฅ โ†’ ์Œ์‹ ์ด๋ฆ„ + 1์ธ๋ถ„ ๊ธฐ์ค€ ์นผ๋กœ๋ฆฌยทํƒ„๋‹จ์ง€ ์ถ”์ •๊ฐ’์„ ๋Œ๋ ค์ฃผ๋Š” ์ž‘์€ AI ์•ฑ์ด๋‹ค.</p>
504
+
505
+ <h3>๐Ÿ”„ ๋ฐ์ดํ„ฐ ํ๋ฆ„ (Pipeline)</h3>
506
+ <pre><span class="comment"># [1] ์‚ฌ์šฉ์ž๊ฐ€ ์Œ์‹ ์‚ฌ์ง„ ์—…๋กœ๋“œ (Gradio UI)
507
+ โ†“
508
+ # [2] HF Vision ๋ชจ๋ธ (nateraw/food) ์ด top-3 ์Œ์‹ ํ›„๋ณด ๋ฐ˜ํ™˜
509
+ โ†“ e.g. [{label:"pizza", score:0.92}, ...]
510
+ # [3] LLM (Llama-3-8B-Instruct) ์—๊ฒŒ
511
+ "์ด ์Œ์‹์˜ 1์ธ๋ถ„ ์นผ๋กœ๋ฆฌ/ํƒ„๋‹จ์ง€๋ฅผ JSON์œผ๋กœ ์•Œ๋ ค์ค˜" ์š”์ฒญ
512
+ โ†“
513
+ # [4] JSON ํŒŒ์‹ฑ โ†’ Gradio๊ฐ€ ๊ฒฐ๊ณผ ์นด๋“œ๋กœ ํ‘œ์‹œ</span></pre>
514
+
515
+ <h3>๐Ÿงฉ ๋‘ ๋ชจ๋ธ์„ ์กฐํ•ฉํ•˜๋Š” ์ด์œ </h3>
516
+ <div class="why-box">
517
+ <div class="label">์„ค๊ณ„ ํฌ์ธํŠธ</div>
518
+ <p>์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ๋ชจ๋ธ์€ "์ด๊ฒŒ ํ”ผ์ž๋‹ค"๋Š” ์•Œ์ง€๋งŒ ์นผ๋กœ๋ฆฌ๋Š” ๋ชจ๋ฅธ๋‹ค.<br>
519
+ ๋ฐ˜๋Œ€๋กœ LLM์€ "ํ”ผ์ž 1์ธ๋ถ„ โ‰ˆ 285kcal"๋Š” ์•Œ์ง€๋งŒ ์‚ฌ์ง„์€ ๋ชป ๋ณธ๋‹ค.<br>
520
+ <strong>๋‘ ๋ชจ๋ธ์„ ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ์—ฐ๊ฒฐ</strong>ํ•˜๋Š” ๊ฒƒ์ด ์ด๋ฒˆ ์‹ค์Šต์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋‹ค.
521
+ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ž‘์€ ๋ชจ๋ธ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์—ฎ๋Š” ํŒจํ„ด์„
522
+ <em>compound AI system</em>์ด๋ผ ๋ถ€๋ฅธ๋‹ค.</p>
523
+ </div>
524
+
525
+ <h3>๐Ÿ“ ํŒŒ์ผ ๊ตฌ์กฐ</h3>
526
+ <pre>week06/
527
+ โ”œโ”€โ”€ app.py <span class="comment"># Gradio ์•ฑ ๋ณธ์ฒด (TODO 4๊ณณ์„ ์ฑ„์›Œ ์™„์„ฑ)</span>
528
+ โ”œโ”€โ”€ model_config.py <span class="comment"># HF ๋ชจ๋ธ ์ด๋ฆ„ + InferenceClient ํŒฉํ† ๋ฆฌ</span>
529
+ โ”œโ”€โ”€ requirements.txt <span class="comment"># Space๊ฐ€ ์„ค์น˜ํ•  ์˜์กด์„ฑ</span>
530
+ โ”œโ”€โ”€ .env.example <span class="comment"># HF_TOKEN ํ…œํ”Œ๋ฆฟ</span>
531
+ โ””โ”€โ”€ README.md <span class="comment"># ์•ž๋ถ€๋ถ„ YAML์ด Space ์„ค์ •</span></pre>
532
+ </section>
533
+
534
+ <!-- SECTION 4 -->
535
+ <section class="class-section s4">
536
+ <div class="section-label">SECTION 4 ยท HANDS-ON</div>
537
+ <h2 class="section-title">์‹ค์Šต: ์ฝ”๋“œ ์ฑ„์šฐ๊ธฐ โ†’ ๋กœ์ปฌ ์‹คํ–‰ โ†’ ๋ฐฐํฌ</h2>
538
+
539
+ <h3>โ‘  ์‚ฌ์ „ ์ค€๋น„</h3>
540
+ <ol class="step-list">
541
+ <li>HF ๊ฐ€์ž…: <a href="https://huggingface.co/join">huggingface.co/join</a></li>
542
+ <li>ํ† ํฐ ๋ฐœ๊ธ‰: <a href="https://huggingface.co/settings/tokens">Settings โ†’ Access Tokens โ†’ New token</a> (Read ๊ถŒํ•œ)</li>
543
+ <li><code>cp .env.example .env</code> ํ›„ <code>HF_TOKEN=hf_...</code> ์ž…๋ ฅ</li>
544
+ <li><code>uv pip install -r requirements.txt</code></li>
545
+ </ol>
546
+
547
+ <h3>โ‘ก ์ฑ„์›Œ์•ผ ํ•  TODO 4๊ณณ (app.py) โ€” LangChain LCEL ๋ฒ„์ „</h3>
548
+
549
+ <div class="why-box">
550
+ <div class="label">์™œ LangChain?</div>
551
+ <p>5์ฃผ์ฐจ์—์„œ LangGraph๋ฅผ ๋ฐฐ์› ๋‹ค. 6์ฃผ์ฐจ๋„ ๊ฐ™์€ ์ƒํƒœ๊ณ„(LangChain)๋กœ ์ด์–ด๊ฐ„๋‹ค.
552
+ LangChain์˜ <strong>LCEL(LangChain Expression Language)</strong>์€ ํŒŒ์ด์ฌ์˜ <code>|</code> ์—ฐ์‚ฐ์ž๋กœ
553
+ <em>prompt โ†’ llm โ†’ parser</em>๋ฅผ ํ•œ ์ค„๋กœ ์—ฎ๋Š” ํ‘œํ˜„์‹์ด๋‹ค.
554
+ ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ์˜ LLM ํŒŒํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ <strong>์ฒด์ธ ๊ฐ์ฒด</strong>๊ฐ€ ๋œ๋‹ค.</p>
555
+ </div>
556
+
557
+ <div class="todo-box">
558
+ <div><span class="num">1</span><strong>SYSTEM_PROMPT</strong> โ€” ์˜์–‘์‚ฌ ์—ญํ•  + JSON ์Šคํ‚ค๋งˆ ๊ฐ•์ œ
559
+ <br><em>(ChatPromptTemplate์— ๋“ค์–ด๊ฐ€๋ฏ€๋กœ JSON ์ค‘๊ด„ํ˜ธ๋Š” <code>{{ }}</code>๋กœ ์ด์Šค์ผ€์ดํ”„)</em></div>
560
+ <pre><span class="kw">SYSTEM_PROMPT</span> = <span class="str">"""๋„ˆ๋Š” ํ•œ๊ตญ ์˜์–‘์‚ฌ AI๋‹ค.
561
+ ์‚ฌ์šฉ์ž๊ฐ€ ์Œ์‹ ๋ถ„๋ฅ˜ ๊ฒฐ๊ณผ(top-k labels)๋ฅผ ์ฃผ๋ฉด,
562
+ ๊ฐ€์žฅ ๊ฐ€๋Šฅ์„ฑ ๋†’์€ ์Œ์‹ 1๊ฐœ์˜ 1์ธ๋ถ„ ๊ธฐ์ค€ ์˜์–‘์ •๋ณด๋ฅผ ์ถ”์ •ํ•ด
563
+ ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ JSON ์Šคํ‚ค๋งˆ๋งŒ ์ถœ๋ ฅํ•˜๋ผ. ๋‹ค๋ฅธ ํ…์ŠคํŠธ/๋งˆํฌ๋‹ค์šด ๊ธˆ์ง€.
564
+
565
+ {{"food": "์Œ์‹๋ช…", "confidence": 0.0~1.0,
566
+ "calories_kcal": ์ •์ˆ˜, "carbs_g": ์ •์ˆ˜,
567
+ "protein_g": ์ •์ˆ˜, "fat_g": ์ •์ˆ˜,
568
+ "note": "์ถ”์ • ๊ทผ๊ฑฐ ํ•œ ์ค„"}}"""</span></pre>
569
+ </div>
570
+
571
+ <div class="todo-box">
572
+ <div><span class="num">2</span><strong>classify_food()</strong> โ€” HF ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ํ˜ธ์ถœ
573
+ <br><em>(์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜๋Š” LangChain์— ๋ž˜ํผ๊ฐ€ ์—†์–ด์„œ InferenceClient ์ง์ ‘ ์‚ฌ์šฉ)</em></div>
574
+ <pre>raw = client.<span class="kw">image_classification</span>(image, model=VISION_MODEL)</pre>
575
+ </div>
576
+
577
+ <div class="todo-box">
578
+ <div><span class="num">3</span><strong>_chain_lazy()</strong> โ€” LCEL ์ฒด์ธ ๋งŒ๋“ค๊ธฐ (4๋‹จ๊ณ„)</div>
579
+ <pre><span class="comment"># 3-1. HF Inference Endpoint ์ƒ์„ฑ</span>
580
+ endpoint = <span class="kw">HuggingFaceEndpoint</span>(
581
+ repo_id=LLM_MODEL,
582
+ task=<span class="str">"text-generation"</span>,
583
+ max_new_tokens=300,
584
+ temperature=0.2,
585
+ huggingfacehub_api_token=get_token(),
586
+ )
587
+
588
+ <span class="comment"># 3-2. ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ฐ์‹ธ๊ธฐ</span>
589
+ llm = <span class="kw">ChatHuggingFace</span>(llm=endpoint)
590
+
591
+ <span class="comment"># 3-3. ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ</span>
592
+ prompt = <span class="kw">ChatPromptTemplate</span>.from_messages([
593
+ (<span class="str">"system"</span>, SYSTEM_PROMPT),
594
+ (<span class="str">"human"</span>, <span class="str">"๋‹ค์Œ์€ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜๊ธฐ์˜ top-k ๊ฒฐ๊ณผ๋‹ค:\n{labels_json}"</span>),
595
+ ])
596
+
597
+ <span class="comment"># 3-4. LCEL ํŒŒ์ดํ”„๋ผ์ธ โ€” ์ด ํ•œ ์ค„์ด ํ•ต์‹ฌ!</span>
598
+ _chain = prompt | llm | <span class="kw">JsonOutputParser</span>()</pre>
599
+ </div>
600
+
601
+ <div class="todo-box">
602
+ <div><span class="num">4</span><strong>estimate_calories()</strong> โ€” ์ฒด์ธ ์‹คํ–‰</div>
603
+ <pre>chain = _chain_lazy()
604
+ labels_json = json.dumps(labels, ensure_ascii=<span class="kw">False</span>)
605
+ <span class="kw">return</span> chain.<span class="kw">invoke</span>({<span class="str">"labels_json"</span>: labels_json})</pre>
606
+ </div>
607
+
608
+ <div class="why-box">
609
+ <div class="label">LCEL์˜ ์•„๋ฆ„๋‹ค์›€</div>
610
+ <p><code>prompt | llm | JsonOutputParser()</code> โ€” ์ด ํ•œ ์ค„์„ ๊ธฐ์–ตํ•˜์ž.<br>
611
+ โ‘  prompt๊ฐ€ ์ž…๋ ฅ dict๋ฅผ ๋ฐ›์•„ ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜<br>
612
+ โ‘ก llm์ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„ ์‘๋‹ต ์ƒ์„ฑ<br>
613
+ โ‘ข JsonOutputParser๊ฐ€ ์‘๋‹ต์—์„œ JSON๋งŒ ๋ฝ‘์•„ dict๋กœ ๋Œ๋ ค์คŒ<br>
614
+ ์ด ์„ธ ๋‹จ๊ณ„๊ฐ€ ํŒŒ์ด์ฌ์˜ <code>|</code> ์—ฐ์‚ฐ์ž ํ•˜๋‚˜๋กœ ์กฐ๋ฆฝ๋œ๋‹ค.
615
+ ๋‚˜์ค‘์— <em>retriever</em>, <em>tool</em>, <em>agent</em>๋ฅผ ์ถ”๊ฐ€ํ•ด๋„ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋Š˜์–ด๋‚œ๋‹ค.</p>
616
+ </div>
617
+
618
+ <h3>โ‘ข ๋กœ์ปฌ ์‹คํ–‰</h3>
619
+ <pre>uv run python app.py
620
+ <span class="comment"># โ†’ http://127.0.0.1:7860 ์ ‘์†</span></pre>
621
+
622
+ <h3>โ‘ฃ Space ๋ฐฐํฌ</h3>
623
+ <p>์™„์„ฑํ•œ ์•ฑ์„ HuggingFace Space์— ์˜ฌ๋ ค ๊ณต๊ฐœ URL๋กœ ๋งŒ๋“ ๋‹ค. ๋‹จ๊ณ„๋ณ„ ์ƒ์„ธ ๊ฐ€์ด๋“œ(Space ์ƒ์„ฑ โ†’ Secret ๋“ฑ๋ก โ†’ ํŒŒ์ผ ์—…๋กœ๋“œ โ†’ ๋นŒ๋“œ ๋กœ๊ทธ โ†’ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… โ†’ ์žฌ๋ฐฐํฌ)๋Š” ์•„๋ž˜ ์ „์šฉ ์„น์…˜์œผ๋กœ ์ •๋ฆฌํ•ด๋‘์—ˆ๋‹ค.</p>
624
+ <p>๐Ÿ‘‰ <a href="#section-deploy"><strong>SECTION 9 ยท DEPLOY โ€” HuggingFace Space ๋ฐฐํฌ A to Z</strong></a> ๋กœ ์ด๋™</p>
625
+ </section>
626
+
627
+
628
+ <!-- SECTION 5 -->
629
+ <section class="class-section s5">
630
+ <div class="section-label">SECTION 5 ยท DEEP DIVE</div>
631
+ <h2 class="section-title">์ž์ฃผ ๋‚˜์˜ค๋Š” ์งˆ๋ฌธ & ์šฉ์–ด ์ •๋ฆฌ</h2>
632
+
633
+ <div class="qa">
634
+ <div class="q">Q. ์™œ LLM์—๊ฒŒ "JSON๋งŒ ์ถœ๋ ฅํ•˜๋ผ"๊ณ  ๊ฐ•์ œํ•˜๋‚˜์š”?</div>
635
+ <div class="a">LLM์€ ์ž์—ฐ์–ด๋ฅผ ์ž˜ ๋งŒ๋“ค์ง€๋งŒ ์ž์œ ๋กญ๊ฒŒ ๋‘๋ฉด ๋งค๋ฒˆ ํ˜•์‹์ด ๋‹ฌ๋ผ์ง„๋‹ค.
636
+ ์•ฑ์—์„œ๋Š” ํ•ญ์ƒ ๊ฐ™์€ ํ‚ค(<code>calories_kcal</code> ๋“ฑ)๋กœ ๊ฐ’์„ ๊บผ๋‚ด์•ผ ํ•˜๋ฏ€๋กœ
637
+ <strong>๊ตฌ์กฐํ™”๋œ ์ถœ๋ ฅ(structured output)</strong>์ด ํ•„์ˆ˜๋‹ค. ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ๋กœ ์Šคํ‚ค๋งˆ๋ฅผ ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•.</div>
638
+ </div>
639
+
640
+ <div class="qa">
641
+ <div class="q">Q. ์นผ๋กœ๋ฆฌ๊ฐ€ ์ •ํ™•ํ•œ๊ฐ€์š”?</div>
642
+ <div class="a">์•„๋‹ˆ๋‹ค. LLM์ด ์ถ”์ •ํ•œ "์ฐธ๊ณ ์šฉ ์ˆ˜์น˜"๋‹ค.
643
+ ์‹ค์ œ ๋‹ค์ด์–ดํŠธ ์•ฑ์ด๋ผ๋ฉด USDA FoodData Central ๊ฐ™์€ <em>์‹ค์ œ ์˜์–‘ DB</em>๋ฅผ ๋ถ™์—ฌ์•ผ ํ•œ๋‹ค.
644
+ ์ด๋ฒˆ ์ฃผ์ฐจ๋Š” "AI ๋ชจ๋ธ ๋‘ ๊ฐœ๋ฅผ ์—ฎ๋Š” ํŒจํ„ด"์„ ์ตํžˆ๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ.</div>
645
+ </div>
646
+
647
+ <div class="qa">
648
+ <div class="q">Q. Inference API๊ฐ€ ๊ฐ‘์ž๊ธฐ 503 ์—๋Ÿฌ๋ฅผ ๋ฑ‰์–ด์š”.</div>
649
+ <div class="a">๋ฌด๋ฃŒ ํ‹ฐ์–ด ๋ชจ๋ธ์€ ์‚ฌ์šฉ๋Ÿ‰์ด ์—†์„ ๋•Œ ์ž ๋“ค์–ด ์žˆ๋‹ค๊ฐ€(<em>cold start</em>)
650
+ ์ฒซ ํ˜ธ์ถœ ์‹œ ~20์ดˆ ๋™์•ˆ ๋กœ๋”ฉํ•œ๋‹ค. ์ž ์‹œ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ์žฌ์‹œ๋„ํ•˜๋ฉด ๋œ๋‹ค.
651
+ ์‹ค์„œ๋น„์Šค๋ผ๋ฉด <em>Inference Endpoints</em>(์œ ๋ฃŒ, ํ•ญ์ƒ ์ผœ์ง)๋กœ ์ด์ „ํ•ด์•ผ ํ•œ๋‹ค.</div>
652
+ </div>
653
+
654
+ <div class="qa">
655
+ <div class="q">Q. Gradio ๋Œ€์‹  Streamlit์„ ์จ๋„ ๋˜๋‚˜์š”?</div>
656
+ <div class="a">๋ฌผ๋ก . Space ์ƒ์„ฑ ์‹œ SDK๋งŒ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋œ๋‹ค.
657
+ Gradio๋Š” "AI ๋ฐ๋ชจ"์—, Streamlit์€ "๋ฐ์ดํ„ฐ ๋Œ€์‹œ๋ณด๋“œ"์— ๋” ๊ฐ•ํ•˜๋‹ค.
658
+ ์ด๋ฒˆ ์ฃผ์ฐจ๋Š” ์ž…์ถœ๋ ฅ์ด ๋‹จ์ˆœํ•ด์„œ Gradio๊ฐ€ ๋” ๊ฐ„๊ฒฐํ•˜๋‹ค.</div>
659
+ </div>
660
+
661
+ <div class="qa">
662
+ <div class="q">Q. HF_TOKEN์„ ๊นœ๋นกํ•˜๊ณ  git์— ํ‘ธ์‹œํ–ˆ์–ด์š”.</div>
663
+ <div class="a">์ฆ‰์‹œ <a href="https://huggingface.co/settings/tokens">ํ† ํฐ ํŽ˜์ด์ง€</a>์—์„œ
664
+ <strong>ํ•ด๋‹น ํ† ํฐ์„ Revoke</strong>ํ•˜๊ณ  ์ƒˆ๋กœ ๋ฐœ๊ธ‰ํ•  ๊ฒƒ. git history์— ๋‚จ์•„ ์žˆ์–ด๋„ ๋ฌดํšจํ™”๋˜๋ฉด ์•ˆ์ „ํ•˜๋‹ค.</div>
665
+ </div>
666
+
667
+ <h3>๐Ÿ“– ํ•ต์‹ฌ ์šฉ์–ด</h3>
668
+ <dl class="glossary">
669
+ <dt>Pre-trained model</dt>
670
+ <dd>๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋กœ ๋ฏธ๋ฆฌ ํ•™์Šต๋œ ๋ชจ๋ธ. ์šฐ๋ฆฌ๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ ํ•™์Šตํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ๋‹ค ์“ด๋‹ค.</dd>
671
+ <dt>Fine-tuning</dt>
672
+ <dd>์‚ฌ์ „ํ•™์Šต ๋ชจ๋ธ ์œ„์— ํŠน์ • ๋„๋ฉ”์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ ๏ฟฝ๏ฟฝ๏ฟฝ์Šต์‹œํ‚ค๋Š” ๊ฒƒ. <code>nateraw/food</code>๋Š” ViT๋ฅผ ์Œ์‹ ์‚ฌ์ง„์œผ๋กœ ํŒŒ์ธํŠœ๋‹ํ•œ ๊ฒฐ๊ณผ.</dd>
673
+ <dt>Inference</dt>
674
+ <dd>ํ•™์Šต๋œ ๋ชจ๋ธ์— ์ž…๋ ฅ์„ ๋„ฃ์–ด ์˜ˆ์ธก์„ ์–ป๋Š” ๋‹จ๊ณ„. โ†” Training</dd>
675
+ <dt>Top-k</dt>
676
+ <dd>๋ถ„๋ฅ˜ ๋ชจ๋ธ์ด ๊ฐ€์žฅ ๊ฐ€๋Šฅ์„ฑ ๋†’๋‹ค๊ณ  ํŒ๋‹จํ•œ ์ƒ์œ„ k๊ฐœ ํ›„๋ณด. ๋‹จ์ผ ์ •๋‹ต๋ณด๋‹ค ํ›„๋ณด ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ LLM์— ๋„˜๊ธฐ๋ฉด ๋” ์•ˆ์ •์ ์ด๋‹ค.</dd>
677
+ <dt>System prompt</dt>
678
+ <dd>LLM์—๊ฒŒ "๋„ˆ๋Š” ๋ˆ„๊ตฌ์ด๋ฉฐ ์–ด๋–ป๊ฒŒ ํ–‰๋™ํ•ด์•ผ ํ•˜๋Š”๊ฐ€"๋ฅผ ์ง€์‹œํ•˜๋Š” ์ฒซ ๋ฉ”์‹œ์ง€. ์ถœ๋ ฅ ํ˜•์‹ ๊ฐ•์ œ์— ์ž์ฃผ ์“ฐ์ธ๋‹ค.</dd>
679
+ <dt>Cold start</dt>
680
+ <dd>์ž ๋“ค์–ด ์žˆ๋˜ ๋ฌด๋ฃŒ ๋ชจ๋ธ์ด ์ฒ˜์Œ ๊นจ์–ด๋‚˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์ง€์—ฐ ์‹œ๊ฐ„.</dd>
681
+ <dt>Compound AI system</dt>
682
+ <dd>์—ฌ๋Ÿฌ ๋ชจ๋ธ/๋„๊ตฌ๋ฅผ ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ์—ฎ์–ด ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‹œ์Šคํ…œ. ์šฐ๋ฆฌ ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ(๋ถ„๋ฅ˜๊ธฐ + LLM)๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ์˜ˆ์‹œ.</dd>
683
+ </dl>
684
+ </section>
685
+
686
+ <!-- SECTION 6 -->
687
+ <section class="class-section s1">
688
+ <div class="section-label">SECTION 6 ยท LAB A (20๋ถ„)</div>
689
+ <h2 class="section-title">Lab A. HF Hub ํƒํ—˜ & ๋ชจ๋ธ ๋ฐœํ‘œ</h2>
690
+
691
+ <p>HuggingFace๋ฅผ "์ฝ”๋“œ๋กœ๋งŒ" ๋งŒ๋‚˜๋ฉด ์ ˆ๋Œ€ ์ต์ˆ™ํ•ด์ง€์ง€ ์•Š๋Š”๋‹ค.
692
+ ๋จผ์ € <strong>์›น์‚ฌ์ดํŠธ๋ฅผ ์ง์ ‘ ์‡ผํ•‘๋ชฐ์ฒ˜๋Ÿผ ๋‘˜๋Ÿฌ๋ณด๋Š” ๊ฒฝํ—˜</strong>์ด ํ•„์š”ํ•˜๋‹ค.</p>
693
+
694
+ <h3>๐Ÿ—บ๏ธ ์ง„ํ–‰ ๋ฐฉ๋ฒ•</h3>
695
+ <ol class="step-list">
696
+ <li><a href="https://huggingface.co/models">huggingface.co/models</a> ์ ‘์† โ†’ ์ขŒ์ธก ํ•„ํ„ฐ์—์„œ <strong>Tasks</strong> ํŒจ๋„ ์—ด๊ธฐ</li>
697
+ <li>์•„๋ž˜ 5๊ฐœ ์นดํ…Œ๊ณ ๋ฆฌ ์ค‘ <strong>๋ณธ์ธ์ด ๋Œ๋ฆฌ๋Š” 1๊ฐœ</strong>๋ฅผ ๊ณ ๋ฅธ๋‹ค
698
+ <ul>
699
+ <li><strong>Image Classification</strong> (์˜ˆ: ๋™๋ฌผยท์‹๋ฌผยท์˜๋ฅ˜ ๋ถ„๋ฅ˜)</li>
700
+ <li><strong>Object Detection</strong> (์‚ฌ์ง„ ์† ์‚ฌ๋ฌผ ๋ฐ•์Šค๋กœ ์žก๊ธฐ)</li>
701
+ <li><strong>Automatic Speech Recognition</strong> (์Œ์„ฑ โ†’ ํ…์ŠคํŠธ, Whisper ๋“ฑ)</li>
702
+ <li><strong>Translation</strong> (ํ•œโ†”์˜, ํ•œโ†”์ผ)</li>
703
+ <li><strong>Text-to-Image</strong> (Stable Diffusion ๊ณ„์—ด)</li>
704
+ </ul>
705
+ </li>
706
+ <li>ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์—์„œ <strong>๋‹ค์šด๋กœ๋“œ ์ˆ˜๊ฐ€ ๋งŽ์€ ๋ชจ๋ธ 1๊ฐœ</strong>๋ฅผ ๊ณจ๋ผ ๋ชจ๋ธ ์นด๋“œ๋ฅผ ์ •๋…ํ•œ๋‹ค</li>
707
+ <li>๋ชจ๋ธ ํŽ˜์ด์ง€ ์šฐ์ธก์˜ <strong>Inference API ์œ„์ ฏ</strong>์— ์ง์ ‘ ์ž…๋ ฅ์„ ๋„ฃ๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•œ๋‹ค</li>
708
+ <li>์•„๋ž˜ 5๊ฐ€์ง€๋ฅผ ์ •๋ฆฌํ•ด ์˜† ์‚ฌ๋žŒ๊ณผ 1๋ถ„์”ฉ ๋ฐœํ‘œํ•œ๋‹ค</li>
709
+ </ol>
710
+
711
+ <h3>๐Ÿ“‹ ๋ฐœํ‘œ ์นด๋“œ (์ •๋ฆฌ ์–‘์‹)</h3>
712
+ <table>
713
+ <tr><th>ํ•ญ๋ชฉ</th><th>์ ์„ ๋‚ด์šฉ</th></tr>
714
+ <tr><td>๋ชจ๋ธ ์ด๋ฆ„</td><td>์˜ˆ: <code>openai/whisper-large-v3</code></td></tr>
715
+ <tr><td>๋ฌด์—‡์„ ํ•˜๋Š” ๋ชจ๋ธ?</td><td>ํ•œ ์ค„ ์„ค๋ช…</td></tr>
716
+ <tr><td>ํ•™์Šต ๋ฐ์ดํ„ฐ</td><td>๋ชจ๋ธ ์นด๋“œ์˜ "Training data" ์„น์…˜ ์š”์•ฝ</td></tr>
717
+ <tr><td>์œ„์ ฏ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ</td><td>๋‚ด๊ฐ€ ๋„ฃ์€ ์ž…๋ ฅ โ†’ ์ถœ๋ ฅ</td></tr>
718
+ <tr><td>์ด๊ฑธ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ์•ฑ ์•„์ด๋””์–ด</td><td>1์ค„</td></tr>
719
+ </table>
720
+
721
+ <div class="why-box">
722
+ <div class="label">๊ต์ˆ˜์˜ ์˜๋„</div>
723
+ <p>์ด ํ™œ๋™์˜ ์ง„์งœ ๋ชฉ์ ์€ "๋ชจ๋ธ์„ ํ•˜๋‚˜ ์™ธ์šฐ๋Š” ๊ฒƒ"์ด ์•„๋‹ˆ๋ผ
724
+ <strong>"ํ•„์š”ํ•  ๋•Œ HF์—์„œ ์ ํ•ฉํ•œ ๋ชจ๋ธ์„ ๊ฒ€์ƒ‰ยทํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ๊ฐ"</strong>์„ ํ‚ค์šฐ๋Š” ๊ฒƒ์ด๋‹ค.
725
+ ์•ž์œผ๋กœ ์–ด๋–ค AI ํ”„๋กœ์ ํŠธ๋“  ์ฒซ ๋‹จ๊ณ„๋Š” ํ•ญ์ƒ "HF์— ๋น„์Šทํ•œ ๋ชจ๋ธ์ด ์ด๋ฏธ ์žˆ๋Š”๊ฐ€?" ๊ฒ€์ƒ‰์ด๋‹ค.</p>
726
+ </div>
727
+ </section>
728
+
729
+ <!-- SECTION 7 -->
730
+ <section class="class-section s2">
731
+ <div class="section-label">SECTION 7 ยท LAB B (20๋ถ„)</div>
732
+ <h2 class="section-title">Lab B. ํ”„๋กฌํ”„ํŠธ ๊นจ๋œจ๋ฆฌ๊ธฐ โ€” ๊ตฌ์กฐํ™”๋œ ์ถœ๋ ฅ์˜ ์ค‘์š”์„ฑ</h2>
733
+
734
+ <p>"LLM์—๊ฒŒ JSON์„ ๋‹ฌ๋ผ๊ณ  ํ•˜๋ฉด JSON์„ ์ค€๋‹ค"๋Š” ๊ฑด <strong>๊ฑฐ์ง“๋ง</strong>์ด๋‹ค.
735
+ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์•ฝํ•˜๊ฒŒ ์งœ๋ฉด ์–ด๋–ป๊ฒŒ ๋ฐ•์‚ด๋‚˜๋Š”์ง€ ์ง์ ‘ ๋ณด๊ณ , ์–ด๋–ป๊ฒŒ ๊ฐ•ํ™”ํ•˜๋Š”์ง€ ๋ฐฐ์›Œ๋ณธ๋‹ค.</p>
736
+
737
+ <h3>๐Ÿ”ฌ ์‹คํ—˜ 1. ์•ฝํ•œ ํ”„๋กฌํ”„ํŠธ๋กœ ๋Œ๋ ค๋ณด๊ธฐ</h3>
738
+ <p>app.py์˜ <code>SYSTEM_PROMPT</code>๋ฅผ <strong>์ผ๋ถ€๋Ÿฌ ์•„๋ž˜์ฒ˜๋Ÿผ ๋‹จ์ˆœํ•˜๊ฒŒ</strong> ๋ฐ”๊พผ๋‹ค:</p>
739
+ <pre><span class="kw">SYSTEM_PROMPT</span> = <span class="str">"์Œ์‹ ์นผ๋กœ๋ฆฌ๋ฅผ ์•Œ๋ ค์ค˜."</span></pre>
740
+ <p>๊ทธ๋ฆฌ๊ณ  ์Œ์‹ ์‚ฌ์ง„ 5์žฅ์„ ์ฐจ๋ก€๋กœ ๋„ฃ์–ด๋ณด๋ฉด์„œ ๋‹ค์Œ์„ ๊ด€์ฐฐํ•œ๋‹ค:</p>
741
+ <ul>
742
+ <li>JSON์ด ์•„์˜ˆ ์•ˆ ๋‚˜์˜ค๋Š” ๊ฒฝ์šฐ</li>
743
+ <li>JSON ์•ž๋’ค์— <em>"Sure! Here's the answer:"</em> ๊ฐ™์€ ์žก๋‹ด์ด ๋ถ™๋Š” ๊ฒฝ์šฐ</li>
744
+ <li>ํ‚ค ์ด๋ฆ„์ด <code>calories</code>, <code>kcal</code>, <code>calorie_count</code>๋กœ ๋งค๋ฒˆ ๋‹ค๋ฅธ ๊ฒฝ์šฐ</li>
745
+ <li>ํ•œ๊ตญ์–ด๋กœ ๋‹ตํ•  ๋•Œ์™€ ์˜์–ด๋กœ ๋‹ตํ•  ๋•Œ ํ˜•์‹์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ</li>
746
+ </ul>
747
+ <p>โ†’ ์ด๊ฒƒ์ด ๋ฐ”๋กœ <strong>์•ฑ์ด ์ฃฝ๋Š” ์ง„์งœ ์ด์œ </strong>๋‹ค. ๋ชจ๋ธ์ด "ํ‹€๋ฆฐ ๋‹ต"์„ ์ค˜์„œ๊ฐ€ ์•„๋‹ˆ๋ผ "์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ" ๋‹ตํ•˜๊ธฐ ๋•Œ๋ฌธ.</p>
748
+
749
+ <h3>๐Ÿ›ก๏ธ ์‹คํ—˜ 2. ํ”„๋กฌํ”„ํŠธ ๊ฐ•ํ™” 4๋‹จ๊ณ„</h3>
750
+ <p>์•„๋ž˜ 4๊ฐ€์ง€ ๊ธฐ๋ฒ•์„ <strong>ํ•˜๋‚˜์”ฉ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ</strong> ๊ฒฐ๊ณผ๊ฐ€ ์–ผ๋งˆ๋‚˜ ์•ˆ์ •๋˜๋Š”์ง€ ๋ณธ๋‹ค.</p>
751
+
752
+ <table>
753
+ <tr><th>๋‹จ๊ณ„</th><th>๊ธฐ๋ฒ•</th><th>์˜ˆ์‹œ ๋ฌธ๊ตฌ</th></tr>
754
+ <tr><td>1</td><td><strong>์—ญํ•  ๋ถ€์—ฌ</strong></td><td>"๋„ˆ๋Š” ํ•œ๊ตญ ์˜์–‘์‚ฌ AI๋‹ค."</td></tr>
755
+ <tr><td>2</td><td><strong>์Šคํ‚ค๋งˆ ๋ช…์‹œ</strong></td><td>JSON ํ‚ค ์ด๋ฆ„๊ณผ ํƒ€์ž…์„ ๋ชจ๋‘ ์ ๊ธฐ</td></tr>
756
+ <tr><td>3</td><td><strong>์˜ˆ์‹œ ์ œ๊ณต (few-shot)</strong></td><td>"์ž…๋ ฅ: pizza โ†’ ์ถœ๋ ฅ: {...}"</td></tr>
757
+ <tr><td>4</td><td><strong>๊ธˆ์ง€์‚ฌํ•ญ ๋ช…์‹œ</strong></td><td>"JSON ์™ธ ์–ด๋–ค ํ…์ŠคํŠธ๋„ ์ถœ๋ ฅ ๊ธˆ์ง€. ๋งˆํฌ๋‹ค์šด ์ฝ”๋“œ๋ธ”๋ก ๊ธˆ์ง€."</td></tr>
758
+ </table>
759
+
760
+ <h3>๐Ÿ’ช ์ฑŒ๋ฆฐ์ง€: ๋ณธ์ธ๋งŒ์˜ "๋ฐฉํƒ„ ํ”„๋กฌํ”„ํŠธ" ๋งŒ๋“ค๊ธฐ</h3>
761
+ <div class="todo-box">
762
+ <div><span class="num">!</span><strong>๋ฏธ์…˜</strong> โ€” ๊ฐ™์€ ์‚ฌ์ง„ 10์žฅ์„ ์—ฐ์†์œผ๋กœ ๋„ฃ์—ˆ์„ ๋•Œ
763
+ <strong>10๋ฒˆ ๋ชจ๋‘ ๊ฐ™์€ ํ˜•์‹์˜ JSON</strong>์ด ๋‚˜์˜ค๊ฒŒ ๋งŒ๋“ค์–ด๋ผ.
764
+ ์„ฑ๊ณตํ•˜๋ฉด ์œ„ 4๋‹จ๊ณ„ ์™ธ์— ๋ณธ์ธ์ด ์ถ”๊ฐ€ํ•œ ํŠธ๋ฆญ์„ 1์ค„๋กœ ์ ์–ด ์˜† ์‚ฌ๋žŒ์—๊ฒŒ ๊ณต์œ .</div>
765
+ </div>
766
+
767
+ <div class="why-box">
768
+ <div class="label">์‹ค๋ฌด์—์„œ ๋” ๊ฐ•๋ ฅํ•œ ๋ฐฉ๋ฒ•</div>
769
+ <p>ํ”„๋กฌํ”„ํŠธ๋กœ ๊ฐ•์ œํ•˜๋Š” ๊ฑด ์ž„์‹œ ๋ฐฉํŽธ์ด๋‹ค. ์‹ค์„œ๋น„์Šค์—์„œ๋Š”
770
+ <strong>JSON Schema mode</strong>(OpenAI), <strong>Tool calling</strong>,
771
+ <strong>Pydantic + Instructor</strong> ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์จ์„œ
772
+ ๋ชจ๋ธ์ด <em>๊ตฌ์กฐ ์ž์ฒด๋ฅผ ์–ด๊ธธ ์ˆ˜ ์—†๊ฒŒ</em> ๋งŒ๋“ ๋‹ค. ์ด๊ฑด ๋‹ค์Œ ํ•™๊ธฐ์˜ ์ฃผ์ œ.</p>
773
+ </div>
774
+ </section>
775
+
776
+ <!-- SECTION 8 -->
777
+ <section class="class-section s3">
778
+ <div class="section-label">SECTION 8 ยท LAB C (20๋ถ„)</div>
779
+ <h2 class="section-title">Lab C. ๋ชจ๋ธ ๋ฐ”๊ฟ”์น˜๊ธฐ ์ฑŒ๋ฆฐ์ง€</h2>
780
+
781
+ <p>"<code>nateraw/food</code>๊ฐ€ ์ •๋ง ์ตœ์„ ์ธ๊ฐ€?"
782
+ โ€” ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค(Inference API)๋ฅผ ์“ฐ๋ฉด ๋ชจ๋ธ์€ ํ•œ ์ค„๋งŒ ๋ฐ”๊ฟ”๋„ ๊ต์ฒด๋œ๋‹ค.
783
+ ์ด ์œ ์—ฐํ•จ์ด HF์˜ ๊ฐ€์žฅ ํฐ ๊ฐ•์ ์ด๋‹ค.</p>
784
+
785
+ <h3>๐ŸŽฏ ์ฑŒ๋ฆฐ์ง€ ๊ทœ์น™</h3>
786
+ <ol class="step-list">
787
+ <li><code>model_config.py</code>์˜ <code>VISION_MODEL</code> ํ•œ ์ค„๋งŒ ๋ฐ”๊ฟ”์„œ
788
+ ๋‹ค๋ฅธ ์Œ์‹ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ๋ชจ๋ธ๋กœ ๊ต์ฒด</li>
789
+ <li>๊ฐ™์€ ์Œ์‹ ์‚ฌ์ง„ 5์žฅ์„ ๋‘ ๋ชจ๋ธ์— ๋ชจ๋‘ ๋Œ๋ ค์„œ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ‘œ๋กœ ์ •๋ฆฌ</li>
790
+ <li>"์–ด๋А ๋ชจ๋ธ์ด ๋” ์ข‹์•˜๋Š”๊ฐ€" + ๊ทธ ์ด์œ ๋ฅผ 1์ค„๋กœ ์ž‘์„ฑ</li>
791
+ </ol>
792
+
793
+ <h3>๐Ÿ”„ ํ›„๋ณด ๋ชจ๋ธ (HF์—์„œ "food classification" ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ)</h3>
794
+ <table>
795
+ <tr><th>๋ชจ๋ธ</th><th>ํŠน์ง•</th><th>ํ•œ ์ค„ ํ‰</th></tr>
796
+ <tr>
797
+ <td><code>nateraw/food</code></td>
798
+ <td>ViT, Food-101 (101์ข…)</td>
799
+ <td>์ด๋ฒˆ ์ฃผ์ฐจ ๊ธฐ๋ณธ๊ฐ’</td>
800
+ </tr>
801
+ <tr>
802
+ <td><code>Kaludi/food-category-classification-v2.0</code></td>
803
+ <td>๋Œ€๋ถ„๋ฅ˜(Bread, Dessert ๋“ฑ 11์ข…)</td>
804
+ <td>์„ธ๋ฐ€ํ•˜์ง€ ์•Š์ง€๋งŒ ๋น ๋ฆ„</td>
805
+ </tr>
806
+ <tr>
807
+ <td><code>prithivMLmods/Food-101-93M</code></td>
808
+ <td>SigLIP ๊ธฐ๋ฐ˜, ๋” ํฐ ๋ชจ๋ธ</td>
809
+ <td>์ •ํ™•๋„โ†‘ but cold startโ†‘</td>
810
+ </tr>
811
+ <tr>
812
+ <td>๋ณธ์ธ์ด ๊ฒ€์ƒ‰ํ•œ ๋ชจ๋ธ</td>
813
+ <td>โ€”</td>
814
+ <td>๊ฐ€์‚ฐ์  โญ</td>
815
+ </tr>
816
+ </table>
817
+
818
+ <h3>๐Ÿ“Š ๋น„๊ต ํ‘œ ์–‘์‹</h3>
819
+ <table>
820
+ <tr><th>์‚ฌ์ง„</th><th>๋ชจ๋ธ A top-1</th><th>๋ชจ๋ธ B top-1</th><th>์‹ค์ œ ์ •๋‹ต</th><th>์Šน์ž</th></tr>
821
+ <tr><td>์‚ฌ์ง„ 1</td><td>?</td><td>?</td><td>?</td><td>?</td></tr>
822
+ <tr><td>์‚ฌ์ง„ 2</td><td>?</td><td>?</td><td>?</td><td>?</td></tr>
823
+ <tr><td colspan="5">โ€ฆ 5์žฅ๊นŒ์ง€</td></tr>
824
+ </table>
825
+
826
+ <h3>๐Ÿค” ๋ฐœํ‘œ ์งˆ๋ฌธ</h3>
827
+ <ul>
828
+ <li>ํ•œ์‹(๊น€์น˜์ฐŒ๊ฐœยท๋น„๋น”๋ฐฅ) ์‚ฌ์ง„์€ ์–ด๋А ๋ชจ๋ธ์ด ๋” ์ž˜ ๋งž์ท„๋Š”๊ฐ€? <em>์™œ ๊ทธ๋Ÿด๊นŒ?</em></li>
829
+ <li>๋ชจ๋ธ์„ ๋ฐ”๊ฟจ๋”๋‹ˆ LLM์ด ๋งŒ๋“ค์–ด๋‚ด๋Š” ์นผ๋กœ๋ฆฌ ์ถ”์ •๊ฐ’๋„ ๋‹ฌ๋ผ์กŒ๋Š”๊ฐ€?</li>
830
+ <li>"์ข‹์€ ๋ชจ๋ธ"์˜ ๊ธฐ์ค€์€ ์ •ํ™•๋„๋ฟ์ธ๊ฐ€? (์†๋„ยทํฌ๊ธฐยท๋ผ์ด์„ ์Šค๋„ ๊ณ ๋ ค)</li>
831
+ </ul>
832
+
833
+ <div class="why-box">
834
+ <div class="label">ํ•ต์‹ฌ ๊ตํ›ˆ</div>
835
+ <p>์‹ค์ œ AI ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ๋ชจ๋ธ 1๊ฐœ๋กœ ๋๋‚ด์ง€ ์•Š๋Š”๋‹ค.
836
+ <strong>์—ฌ๋Ÿฌ ํ›„๋ณด๋ฅผ ๊ฐ™์€ ๋ฐ์ดํ„ฐ์— ๋Œ๋ ค๋ณด๊ณ  ๋น„๊ต(=๋ฒค์น˜๋งˆํ‚น)</strong>ํ•œ ๋’ค ๊ณ ๋ฅธ๋‹ค.
837
+ ์˜ค๋Š˜ ํ•œ ์ผ์ด ๋ฐ”๋กœ ๊ทธ ๋ฏธ๋‹ˆ ๋ฒ„์ „์ด๋‹ค.
838
+ ๊ทธ๋ฆฌ๊ณ  HF์˜ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค ๋•๋ถ„์— ๋น„๊ต๊ฐ€ "ํ•œ ์ค„ ์ˆ˜์ •"์œผ๋กœ ๋๋‚œ๋‹ค๋Š” ๊ฒŒ ํ•ต์‹ฌ.</p>
839
+ </div>
840
+ </section>
841
+
842
+
843
+ <!-- SECTION 9 -->
844
+ <section class="class-section s5" id="section-deploy">
845
+ <div class="section-label">SECTION 9 ยท DEPLOY</div>
846
+ <h2 class="section-title">HuggingFace Space ๋ฐฐํฌ โ€” A to Z</h2>
847
+
848
+ <p>๋กœ์ปฌ์—์„œ ๋™์ž‘์„ ํ™•์ธํ–ˆ๋‹ค๋ฉด ์ด์ œ ์„ธ์ƒ์— ๊ณต๊ฐœํ•  ์ฐจ๋ก€๋‹ค.
849
+ HF Space๋Š” <strong>"git push ํ•œ ๋ฒˆ์œผ๋กœ ๊ณต๊ฐœ URL"</strong>์„ ์ฃผ๋Š” ๋ฌด๋ฃŒ ํ˜ธ์ŠคํŒ…์ด๋‹ค.
850
+ ๋ฐฉ๋ฒ•์€ 3๊ฐ€์ง€๊ฐ€ ์žˆ๋Š”๋ฐ ์ฒซ ๋ฐฐํฌ๋Š” <strong>์›น ๋“œ๋ž˜๊ทธ</strong>๊ฐ€ ๊ฐ€์žฅ ์‰ฝ๋‹ค.</p>
851
+
852
+ <div class="why-box">
853
+ <div class="label">์ค€๋น„๋ฌผ ์ฒดํฌ</div>
854
+ <p>โœ“ HF ๊ณ„์ • &nbsp; โœ“ Read ํ† ํฐ(<code>hf_xxxx...</code>) &nbsp;
855
+ โœ“ ๋กœ์ปฌ์—์„œ ๋Œ์•„๊ฐ€๋Š” ์™„์„ฑ๋œ <code>app.py</code> &nbsp;
856
+ โœ“ ๋ฐฐํฌํ•  ํŒŒ์ผ 4๊ฐœ: <code>app.py</code>, <code>model_config.py</code>, <code>requirements.txt</code>, <code>README.md</code></p>
857
+ </div>
858
+
859
+ <h3>๐Ÿ—๏ธ Step 1. Space ์ƒ์„ฑํ•˜๊ธฐ</h3>
860
+ <p><a href="https://huggingface.co/new-space">huggingface.co/new-space</a> ์ ‘์† โ†’ ์•„๋ž˜ ํผ์„ ์œ„์—์„œ ์•„๋ž˜๋กœ ์ฑ„์šด๋‹ค. โ‘ ~โ‘ฅ ๋ฒˆํ˜ธ๊ฐ€ ์ด๋ฏธ์ง€์™€ ํ‘œ์— ๋งค์นญ๋œ๋‹ค.</p>
861
+ <img src="images/06_new_space.png" alt="Create a new Space ํผ" style="width:100%;max-width:720px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
862
+ <table>
863
+ <tr><th>๋ฒˆํ˜ธ</th><th>ํ•ญ๋ชฉ</th><th>๊ฐ’</th></tr>
864
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;">1</span></td><td><strong>Owner / Space name</strong></td><td>Owner๋Š” ๋ณธ์ธ ์œ ์ €๋ช… ์ž๋™ ์„ ํƒ / Space name์— <code>calorie-counter</code> ์ž…๋ ฅ</td></tr>
865
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#f97316;color:white;text-align:center;font-weight:bold;">2</span></td><td><strong>License</strong></td><td><code>apache-2.0</code> ์„ ํƒ</td></tr>
866
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;">3</span></td><td><strong>Select the Space SDK</strong></td><td><strong>Gradio</strong> โš ๏ธ (Docker/Static ์•„๋‹˜) โ†’ ํ…œํ”Œ๋ฆฟ์€ <em>Blank</em></td></tr>
867
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;">4</span></td><td><strong>Space hardware</strong></td><td><code>CPU Basic ยท Free</code> (๊ธฐ๋ณธ๊ฐ’)</td></tr>
868
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#8b5cf6;color:white;text-align:center;font-weight:bold;">5</span></td><td><strong>Visibility</strong></td><td><code>Public</code> ์„ ํƒ (๋‚จ์—๊ฒŒ URL ๊ณต์œ ํ•˜๋ ค๋ฉด ํ•„์ˆ˜)</td></tr>
869
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ec4899;color:white;text-align:center;font-weight:bold;">6</span></td><td><strong>Create Space</strong></td><td>๋งจ ์•„๋ž˜ ๋ฒ„ํŠผ ํด๋ฆญ โ†’ ๋นˆ Space ์ƒ์„ฑ ์™„๋ฃŒ</td></tr>
870
+ </table>
871
+
872
+ <h3>๐Ÿ”‘ Step 2. HF_TOKEN Secret ๋“ฑ๋ก โš ๏ธ (์ด๊ฑฐ ๋นผ๋จน์œผ๋ฉด ๋ฐฐํฌ ํ›„ ์—๋Ÿฌ)</h3>
873
+ <p>์šฐ๋ฆฌ ์•ฑ์€ Inference API๋ฅผ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ Space ์•ˆ์—์„œ๋„ <code>HF_TOKEN</code>์ด ํ•„์š”ํ•˜๋‹ค.
874
+ <strong>์ฝ”๋“œ์— ์ ์œผ๋ฉด ์ ˆ๋Œ€ ์•ˆ ๋˜๊ณ </strong>, Secret์œผ๋กœ ๋“ฑ๋กํ•ด์•ผ ํ•œ๋‹ค.</p>
875
+ <p>๋ฐฉ๊ธˆ ๋งŒ๋“  Space ํŽ˜์ด์ง€ ์ƒ๋‹จ <strong>Settings</strong> ํƒญ โ†’ ์•„๋ž˜๋กœ ์Šคํฌ๋กคํ•˜๋ฉด <strong>Variables and secrets</strong> ์„น์…˜์ด ๋ณด์ธ๋‹ค.</p>
876
+ <img src="images/07_secrets.png" alt="Settings โ†’ Variables and secrets" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
877
+ <table>
878
+ <tr><th>๋ฒˆํ˜ธ</th><th>์œ„์น˜</th><th>ํ•  ์ผ</th></tr>
879
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;">1</span></td><td><strong>Variables and secrets ์„น์…˜</strong></td><td>Variables(๊ณต๊ฐœ ํ‰๋ฌธ)์™€ Secrets(์•”ํ˜ธํ™”) ๋‘ ์นธ์ด ์žˆ๋‹ค. ํ† ํฐ์€ <strong>Secrets</strong>์— ๋„ฃ๋Š”๋‹ค</td></tr>
880
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;">2</span></td><td><strong>New secret</strong> ๋ฒ„ํŠผ (์šฐ์ธก ์ƒ๋‹จ)</td><td>ํด๋ฆญ โ†’ ํŒ์—…์—์„œ Name: <code>HF_TOKEN</code> / Value: ๋ณธ์ธ ํ† ํฐ <code>hf_xxxx...</code> โ†’ Save</td></tr>
881
+ </table>
882
+ <div class="why-box">
883
+ <div class="label">Secret vs Variable ์ฐจ์ด</div>
884
+ <p><strong>Secret</strong> โ€” ๊ฐ’์ด ์•”ํ˜ธํ™”๋˜์–ด ๋‹ค์‹œ๋Š” ์กฐํšŒ ๋ถˆ๊ฐ€. ํ† ํฐ/๋น„๋ฐ€๋ฒˆํ˜ธ์šฉ. ๋Ÿฐํƒ€์ž„์— ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์ฃผ์ž….<br>
885
+ <strong>Variable</strong> โ€” ํ‰๋ฌธ. ๋ชจ๋ธ ์ด๋ฆ„ยทURL ๊ฐ™์€ ๊ณต๊ฐœ ๊ฐ€๋Šฅํ•œ ์„ค์ •๊ฐ’์šฉ.</p>
886
+ </div>
887
+
888
+ <h3>๐Ÿ“ค Step 3-A. ํŒŒ์ผ ์—…๋กœ๋“œ โ€” ๋ฐฉ๋ฒ• โ‘  ์›น ๋“œ๋ž˜๊ทธ (๊ฐ€์žฅ ์‰ฌ์›€)</h3>
889
+ <img src="images/08_files.png" alt="Space Files ํƒญ โ€” Contribute ๋“œ๋กญ๋‹ค์šด" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
890
+ <table>
891
+ <tr><th>๋ฒˆํ˜ธ</th><th>์œ„์น˜</th><th>ํ•  ์ผ</th></tr>
892
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;">1</span></td><td><strong>Files</strong> ํƒญ (์ƒ๋‹จ ์šฐ์ธก)</td><td>Space ํŽ˜์ด์ง€ ์ƒ๋‹จ์˜ App/Files/Community/Settings ์ค‘ Files ํด๋ฆญ</td></tr>
893
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;">2</span></td><td><strong>+ Contribute</strong> ๋“œ๋กญ๋‹ค์šด (์šฐ์ธก ์ƒ๋‹จ)</td><td>ํด๋ฆญ โ†’ <em>Upload files</em> ์„ ํƒ โ†’ ํƒ์ƒ‰๊ธฐ์—์„œ <code>app.py</code>ยท<code>model_config.py</code>ยท<code>requirements.txt</code>ยท<code>README.md</code> 4๊ฐœ ๋“œ๋ž˜๊ทธ โ†’ Commit ๋ฉ”์‹œ์ง€ <code>init</code> โ†’ <strong>Commit changes to main</strong></td></tr>
894
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;">3</span></td><td><strong>ํŒŒ์ผ ๋ชฉ๋ก</strong> (๋ณธ๋ฌธ)</td><td>์—…๋กœ๋“œ ์„ฑ๊ณต ์‹œ ์—ฌ๊ธฐ์— ํŒŒ์ผ์ด ์ญ‰ ๋‚˜์—ด๋œ๋‹ค. ์ดํ›„์—” ํŒŒ์ผ ํด๋ฆญ โ†’ ์—ฐํ•„ ์•„์ด์ฝ˜์œผ๋กœ ๋ฐ”๋กœ ์ˆ˜์ • ๊ฐ€๋Šฅ</td></tr>
895
+ </table>
896
+ <p>์ปค๋ฐ‹ ํ›„ ์ž๋™์œผ๋กœ <strong>App</strong> ํƒญ์œผ๋กœ ์ด๋™ โ†’ ๋นŒ๋“œ ๋กœ๊ทธ๊ฐ€ ์‹ค์‹œ๊ฐ„ ํ‘œ์‹œ๋จ (2~4๋ถ„).</p>
897
+
898
+ <h3>๐Ÿ’ป Step 3-B. ํŒŒ์ผ ์—…๋กœ๋“œ โ€” ๋ฐฉ๋ฒ• โ‘ก git push (ํ‘œ์ค€ ๋ฐฉ์‹)</h3>
899
+ <p>์‹ค๋ฌด์—์„œ๋Š” ํ•ญ์ƒ ์ด ๋ฐฉ๋ฒ•์„ ์“ด๋‹ค. Space๊ฐ€ <strong>์ง„์งœ git ์ €์žฅ์†Œ</strong>๋ผ๋Š” ๊ฑธ ๋А๋‚„ ์ˆ˜ ์žˆ๋‹ค.</p>
900
+
901
+ <h4>โš ๏ธ ๋จผ์ €: <strong>Write ๊ถŒํ•œ ํ† ํฐ</strong> ๋ฐœ๊ธ‰ (git push ์ „์šฉ)</h4>
902
+ <p>์•ž์„œ Step 2์—์„œ ๋งŒ๋“  <strong>Read ํ† ํฐ</strong>์€ Inference API ํ˜ธ์ถœ์šฉ์ด๋ผ <code>git push</code>๊ฐ€ <em>not authorized</em>๋กœ ๊ฑฐ์ ˆ๋œ๋‹ค. push์šฉ <strong>Write ํ† ํฐ์„ ๋”ฐ๋กœ ํ•˜๋‚˜ ๋”</strong> ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.</p>
903
+ <p><a href="https://huggingface.co/settings/tokens/new?tokenType=write">huggingface.co/settings/tokens/new?tokenType=write</a> ์ ‘์†:</p>
904
+ <img src="images/10_write_token.png" alt="Create new Access Token โ€” Write ํƒ€์ž…" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
905
+ <table>
906
+ <tr><th>๋ฒˆํ˜ธ</th><th>ํ•ญ๋ชฉ</th><th>๊ฐ’</th></tr>
907
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;">1</span></td><td><strong>Token type</strong></td><td><strong>Write</strong> ์„ ํƒ (๊ธฐ๋ณธ์€ Fine-grained). โš ๏ธ ์ƒ์„ฑ ํ›„ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€ โ€” "This cannot be changed after token creation."</td></tr>
908
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;">2</span></td><td><strong>Token name</strong></td><td>์ž์œ ๋กญ๊ฒŒ (์˜ˆ: <code>week06-push</code>). ๊ธฐ์กด Read ํ† ํฐ๊ณผ ๊ตฌ๋ถ„๋˜๋Š” ์ด๋ฆ„์œผ๋กœ</td></tr>
909
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;">3</span></td><td><strong>Create token</strong></td><td>ํด๋ฆญ โ†’ <code>hf_xxxx...</code> ๋ณต์‚ฌ. <strong>๋‹ค์‹œ๋Š” ๋ชป ๋ณธ๋‹ค</strong></td></tr>
910
+ </table>
911
+ <div class="why-box">
912
+ <div class="label">Read vs Write ํ† ํฐ ์–ธ์ œ ๋ญ ์“ฐ๋‚˜</div>
913
+ <p><strong>Read</strong> โ€” Inference API ํ˜ธ์ถœ / ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ (<code>.env</code>ยทSpace Secrets์— ๋„ฃ๋Š” ๊ทธ ํ† ํฐ)<br>
914
+ <strong>Write</strong> โ€” <code>git push</code>, Space ์ƒ์„ฑยท์ˆ˜์ •, ํŒŒ์ผ ์—…๋กœ๋“œ ๋“ฑ <em>์“ฐ๊ธฐ ์ž‘์—…</em><br>
915
+ ๐Ÿ‘‰ ์šฉ๋„๋ณ„๋กœ ๋ถ„๋ฆฌํ•ด๋‘๋ฉด Write ํ† ํฐ๋งŒ ์œ ์ถœ๋ผ๋„ API ํ˜ธ์ถœ์€ ์•ˆ ์ „ํ•ด์ง„๋‹ค. ๋ณด์•ˆ โ†‘</p>
916
+ </div>
917
+ <div class="why-box">
918
+ <div class="label">๐Ÿ” git push ์‹œ ์ด์ „ ์ž๊ฒฉ์ฆ๋ช… ์บ์‹œ๊ฐ€ ๋‚จ์•„์žˆ๋‹ค๋ฉด (macOS)</div>
919
+ <p>์˜ˆ์ „์— email/๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ์ž˜๋ชป ์ž…๋ ฅํ–ˆ๋‹ค๋ฉด ํ‚ค์ฒด์ธ์— ์บ์‹œ๋ผ์„œ ๊ณ„์† ์‹คํŒจํ•œ๋‹ค. ํ•œ ๋ฒˆ๋งŒ ๋น„์›Œ์ฃผ์ž:</p>
920
+ <pre>printf <span class="str">"protocol=https\nhost=huggingface.co\n\n"</span> | git credential-osxkeychain erase</pre>
921
+ <p>๊ทธ ๋‹ค์Œ <code>git push</code> โ†’ Username์€ <strong>HF ์œ ์ €๋ช…</strong>(์ด๋ฉ”์ผ โŒ) / Password๋Š” <strong>๋ฐฉ๊ธˆ ๋งŒ๋“  Write ํ† ํฐ</strong>. ์„ฑ๊ณตํ•˜๋ฉด ํ‚ค์ฒด์ธ์— ์ž๋™ ์ €์žฅ๋ผ ์ดํ›„์—” ์•ˆ ๋ฌผ์–ด๋ณธ๋‹ค.</p>
922
+ </div>
923
+ <pre><span class="comment"># ๐Ÿ“ ์‹œ์ž‘ ์ƒํƒœ: week06/ (zip ํ‘ผ ํด๋”) ์•ˆ์— ์™„์„ฑ ํŒŒ์ผ์ด ์ด๋ฏธ ์žˆ๋‹ค
924
+ # week06/
925
+ # โ”œโ”€โ”€ app.py โ† ๋‚ด๊ฐ€ ์ฑ„์›Œ๋„ฃ์€ ์™„์„ฑ๋ณธ
926
+ # โ”œโ”€โ”€ model_config.py
927
+ # โ”œโ”€โ”€ requirements.txt
928
+ # โ”œโ”€โ”€ README.md
929
+ # โ””โ”€โ”€ images/...
930
+
931
+ # 1) week06/ ์•ˆ์—์„œ Space ์ €์žฅ์†Œ๋ฅผ ๋‚ด๋ ค๋ฐ›๋Š”๋‹ค
932
+ # โ†’ calorie-counter/ ๋ผ๋Š” ํด๋”๊ฐ€ ์ƒˆ๋กœ ์ƒ๊ธด๋‹ค
933
+ git clone https://huggingface.co/spaces/&lt;๋ณธ์ธ์œ ์ €๋ช…&gt;/calorie-counter
934
+
935
+ # ์ด ์‹œ์ ์˜ ํด๋” ๊ตฌ์กฐ:
936
+ # week06/
937
+ # โ”œโ”€โ”€ app.py โ† ์›๋ณธ (์•„์ง ์—ฌ๊ธฐ ์žˆ์Œ)
938
+ # โ”œโ”€โ”€ ...
939
+ # โ””โ”€โ”€ calorie-counter/ โ† ๋ฐฉ๊ธˆ cloneํ•œ Space ์ €์žฅ์†Œ
940
+
941
+ # 2) cloneํ•œ ํด๋”๋กœ ์ด๋™
942
+ cd calorie-counter
943
+
944
+ # 3) ํ•œ ๋‹จ๊ณ„ ์œ„(../ = week06/)์˜ ํŒŒ์ผ 4๊ฐœ๋ฅผ ์—ฌ๊ธฐ๋กœ ๋ณต์‚ฌ
945
+ cp ../app.py .
946
+ cp ../model_config.py .
947
+ cp ../requirements.txt .
948
+ cp ../README.md .
949
+
950
+ # 4) ์ปค๋ฐ‹ & ํ‘ธ์‹œ โ€” ์ด ์ˆœ๊ฐ„ HF๊ฐ€ ์ž๋™์œผ๋กœ ๋นŒ๋“œ ์‹œ์ž‘
951
+ git add .
952
+ git commit -m <span class="str">"init: calorie counter with LangChain LCEL"</span>
953
+ git push
954
+ <span class="comment"># Username: ๋ณธ์ธ HF ์œ ์ €๋ช…
955
+ # Password: hf_xxxx... (๋น„๋ฐ€๋ฒˆํ˜ธ ์•„๋‹Œ ํ† ํฐ!)</span></pre>
956
+
957
+ <h3>๐Ÿ“„ Step 3-C. README.md์˜ YAML Frontmatter โ€” ํ•„์ˆ˜</h3>
958
+ <p>Space๋Š” README.md ๋งจ ์œ„์˜ <strong>YAML ๋ธ”๋ก</strong>์œผ๋กœ ์„ค์ •์„ ์ฝ๋Š”๋‹ค. ์ด ๋ธ”๋ก์ด ์—†์œผ๋ฉด ๋นŒ๋“œ๊ฐ€ ์‹คํŒจํ•œ๋‹ค.</p>
959
+ <pre><span class="str">---
960
+ title: HuggingFace Calorie Counter
961
+ emoji: ๐Ÿฑ
962
+ colorFrom: pink
963
+ colorTo: yellow
964
+ sdk: gradio
965
+ sdk_version: 5.9.1
966
+ python_version: "3.11"
967
+ app_file: app.py
968
+ pinned: false
969
+ license: apache-2.0
970
+ ---</span>
971
+
972
+ # 6์ฃผ์ฐจ: HuggingFace Space ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ
973
+ ...</pre>
974
+ <table>
975
+ <tr><th>ํ‚ค</th><th>์˜๋ฏธ</th></tr>
976
+ <tr><td><code>sdk</code></td><td>Space ๋Ÿฐํƒ€์ž„ โ€” ๋ฐ˜๋“œ์‹œ <code>gradio</code></td></tr>
977
+ <tr><td><code>sdk_version</code></td><td>Gradio ๋ฒ„์ „ โ€” ๋กœ์ปฌ๊ณผ ๋งž์ถ”๋ฉด ์•ˆ์ „</td></tr>
978
+ <tr><td><code>app_file</code></td><td>Space๊ฐ€ ์‹คํ–‰ํ•  ํŒŒ์ด์ฌ ํŒŒ์ผ โ€” <code>app.py</code></td></tr>
979
+ <tr><td><code>emoji</code>, <code>colorFrom/To</code></td><td>Space ์นด๋“œ ๊พธ๋ฏธ๊ธฐ (์„ ํƒ)</td></tr>
980
+ <tr><td><code>title</code></td><td>Space ํŽ˜์ด์ง€ ์ œ๋ชฉ</td></tr>
981
+ </table>
982
+
983
+ <h3>๐Ÿ” Step 4. ๋นŒ๋“œ ๋กœ๊ทธ ์ฝ๋Š” ๋ฒ•</h3>
984
+ <p>Space <strong>App</strong> ํƒญ์—์„œ ์ƒํƒœ ๋ฑƒ์ง€์™€ ๋กœ๊ทธ ํŒจ๋„์„ ํ•จ๊ป˜ ๋ณธ๋‹ค. ์•„๋ž˜๋Š” ์‹ค์ œ๋กœ ์—๋Ÿฌ๊ฐ€ ๋‚œ ์˜ˆ์‹œ ํ™”๋ฉด.</p>
985
+ <img src="images/09_app_logs.png" alt="Space App ํƒญ โ€” ์ƒํƒœ ๋ฑƒ์ง€ + ๋กœ๊ทธ ํŒจ๋„" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
986
+ <table>
987
+ <tr><th>๋ฒˆํ˜ธ</th><th>์˜์—ญ</th><th>์˜๋ฏธ / ๋ณด๋Š” ๋ฒ•</th></tr>
988
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#ef4444;color:white;text-align:center;font-weight:bold;">1</span></td><td><strong>์ƒํƒœ ๋ฑƒ์ง€</strong> (์ƒ๋‹จ, ์ œ๋ชฉ ์˜†)</td><td><code>Building</code>(๋นŒ๋“œ ์ค‘) โ†’ <code>Running</code>(์ดˆ๋ก, ์„ฑ๊ณต) โ†’ <code>Runtime error</code>(๋นจ๊ฐ•, ๋Ÿฐํƒ€์ž„ ์ฃฝ์Œ) โ†’ <code>Sleeping ๐Ÿ’ค</code>(48h ๋ฌด์ ‘์†). ์—ฌ๊ธฐ๋ถ€ํ„ฐ ๋จผ์ € ํ™•์ธ</td></tr>
989
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#f97316;color:white;text-align:center;font-weight:bold;">2</span></td><td><strong>App / Files / Community / Settings</strong> ํƒญ</td><td>App ํƒญ์ด ์ง€๊ธˆ ํ™œ์„ฑํ™”๋จ (๋ฐ‘์ค„). ๋‹ค๋ฅธ ํƒญ์œผ๋กœ ์–ธ์ œ๋“  ์ด๋™ ๊ฐ€๋Šฅ</td></tr>
990
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#0ea5e9;color:white;text-align:center;font-weight:bold;">3</span></td><td><strong>๋กœ๊ทธ ํƒญ ๋ฐ”</strong> (Logs / Build / Container)</td><td><em>Build</em>: <code>pip install</code> ๋‹จ๊ณ„(์˜์กด์„ฑ ๋ˆ„๋ฝ ์‹œ ์—ฌ๊ธฐ์„œ ์‹คํŒจ) / <em>Container</em>: ๋นŒ๋“œ ์„ฑ๊ณต ํ›„ ๋Ÿฐํƒ€์ž„ ๋กœ๊ทธ(Python tracebackยทprint ์ถœ๋ ฅ) / <em>Logs Endpoint</em>: ์›๋ณธ ๋กœ๊ทธ URL</td></tr>
991
+ <tr><td><span style="display:inline-block;width:24px;height:24px;border-radius:50%;background:#10b981;color:white;text-align:center;font-weight:bold;">4</span></td><td><strong>๋กœ๊ทธ ๋ณธ๋ฌธ</strong></td><td>Running์ผ ๋• ์—ฌ๊ธฐ์— Gradio UI๊ฐ€ ์ž„๋ฒ ๋“œ๋˜๊ณ , ์—๋Ÿฌ ์‹œ traceback์ด ๋‚˜์˜จ๋‹ค. ์œ„ ์˜ˆ์‹œ๋Š” <code>ModuleNotFoundError: No module named 'audioop'</code> โ€” ํŒŒ์ด์ฌ 3.13์—์„œ pydub ํ˜ธํ™˜ ๋ฌธ์ œ</td></tr>
992
+ </table>
993
+
994
+ <h3>๐ŸŽ‰ Step 5. ๋™์ž‘ ํ™•์ธ & ๋ฐฐํฌ๋œ URL</h3>
995
+ <p>Running์ด ๋˜๋ฉด ์ด๋Ÿฐ ํ™”๋ฉด์ด ๋œฌ๋‹ค. ์ดˆ๋ก <code>โ— Running</code> ๋ฑƒ์ง€๊ฐ€ ๋ณด์ด๋ฉด ์„ฑ๊ณต.</p>
996
+ <img src="images/11_running.png" alt="๋ฐฐํฌ ์„ฑ๊ณต: Running ์ƒํƒœ์˜ Gradio UI" style="width:100%;max-width:900px;border:1px solid #e5e7eb;border-radius:8px;margin:0.6rem 0;">
997
+ <div class="todo-box">
998
+ <div><span class="num">โœ“</span>์ƒ๋‹จ ์ƒํƒœ ๋ฑƒ์ง€๊ฐ€ <strong>Running</strong> (์ดˆ๋ก)์œผ๋กœ ๋ฐ”๋€œ</div>
999
+ <div><span class="num">โœ“</span>Gradio UI๊ฐ€ Space ํŽ˜์ด์ง€ ์•ˆ์— ์ž„๋ฒ ๋“œ๋˜์–ด ํ‘œ์‹œ๋จ</div>
1000
+ <div><span class="num">โœ“</span>์Œ์‹ ์‚ฌ์ง„ 1์žฅ ๋“œ๋ž˜๊ทธ โ†’ 30~60์ดˆ ํ›„ ๋ถ„๋ฅ˜ ๊ฒฐ๊ณผ + JSON ํ‘œ์‹œ</div>
1001
+ </div>
1002
+
1003
+ <h4>๐ŸŒ Space๊ฐ€ ๋ฐฐํฌ๋˜๋ฉด URL์ด 2๊ฐœ ์ƒ๊ธด๋‹ค</h4>
1004
+ <table>
1005
+ <tr><th>์ข…๋ฅ˜</th><th>ํ˜•์‹</th><th>์–ธ์ œ ์“ฐ๋‚˜</th></tr>
1006
+ <tr>
1007
+ <td><strong>โ‘  ํŽ˜์ด์ง€ URL</strong><br>(HF ํ—ˆ๋ธŒ ํŽ˜์ด์ง€)</td>
1008
+ <td><code>https://huggingface.co/spaces/&lt;์œ ์ €&gt;/&lt;์ŠคํŽ˜์ด์Šค๋ช…&gt;</code><br>์˜ˆ: <code>https://huggingface.co/spaces/jay-kim412/estimate_calories</code></td>
1009
+ <td>Space ํ”„๋กœํ•„(์ข‹์•„์š”ยทCommunityยทFiles ํƒญ) + ์•ฑ ์ž„๋ฒ ๋“œ๊ฐ€ ํ•จ๊ป˜ ๋ณด์ž„. ์นœ๊ตฌํ•œํ…Œ ๊ณต์œ ยท์ด๋ ฅ์„œ์— ๋ถ™์ผ ๋• ์ด๊ฑธ ์”€</td>
1010
+ </tr>
1011
+ <tr>
1012
+ <td><strong>โ‘ก ์ง์ ‘ ์•ฑ URL</strong><br>(Gradio ํ’€์Šคํฌ๋ฆฐ)</td>
1013
+ <td><code>https://&lt;์œ ์ €&gt;-&lt;์ŠคํŽ˜์ด์Šค๋ช…&gt;.hf.space</code><br>์˜ˆ: <code>https://jay-kim412-estimate-calories.hf.space</code></td>
1014
+ <td>HF UI ์—†์ด ์•ฑ๋งŒ ์ „์ฒดํ™”๋ฉด. iframe ์ž„๋ฒ ๋“œยท๋ชจ๋ฐ”์ผ ๊ณต์œ ์— ํŽธํ•จ. ์œ ์ €๋ช…ยท์ŠคํŽ˜์ด์Šค๋ช…์˜ <code>_</code>๋Š” ์ž๋™์œผ๋กœ <code>-</code>๋กœ ์น˜ํ™˜๋œ๋‹ค</td>
1015
+ </tr>
1016
+ </table>
1017
+ <div class="why-box">
1018
+ <div class="label">๐Ÿ’ก Custom domain์€?</div>
1019
+ <p>Settings ํŽ˜์ด์ง€์— <strong>Custom domain</strong> ํ•ญ๋ชฉ์ด ๋ณด์ด๋Š”๋ฐ, ๋ณธ์ธ ์†Œ์œ  ๋„๋ฉ”์ธ(<code>calorie.mydomain.com</code> ๋“ฑ)์„ Space์— ์—ฐ๊ฒฐํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. <strong>PRO ๊ณ„์ • ์œ ๋ฃŒ</strong> ์ „์šฉ์ด๋ผ ์ˆ˜์—…์—์„œ๋Š” ๋ฌด์‹œ. ๋ฌด๋ฃŒ ๊ณ„์ •์€ ์œ„ 2๊ฐœ URL๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค.</p>
1020
+ </div>
1021
+
1022
+ <h3>๐Ÿ› Step 6. ์ž์ฃผ ๊ฑธ๋ฆฌ๋Š” ํ•จ์ •๊ณผ ํ•ด๊ฒฐ๋ฒ•</h3>
1023
+ <table>
1024
+ <tr><th>์ฆ์ƒ</th><th>์›์ธ</th><th>ํ•ด๊ฒฐ</th></tr>
1025
+ <tr>
1026
+ <td>Build failed: <code>ModuleNotFoundError</code></td>
1027
+ <td>requirements.txt์— ๋ˆ„๋ฝ</td>
1028
+ <td>ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ์ถ”๊ฐ€ ํ›„ ์žฌํ‘ธ์‹œ</td>
1029
+ </tr>
1030
+ <tr>
1031
+ <td>Runtime: <code>HF_TOKEN ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค</code></td>
1032
+ <td>Secrets ๋ฏธ๋“ฑ๋ก</td>
1033
+ <td>Settings โ†’ Variables and secrets ์žฌํ™•์ธ</td>
1034
+ </tr>
1035
+ <tr>
1036
+ <td>์ฒซ ํ˜ธ์ถœ์—์„œ 503 Service Unavailable</td>
1037
+ <td>LLM cold start (๋ฌด๋ฃŒ ํ‹ฐ์–ด)</td>
1038
+ <td>30์ดˆ ๋Œ€๊ธฐ ํ›„ ๋‹ค์‹œ ์‹œ๋„. ๋ฐ˜๋ณต๋˜๋ฉด ๋‹ค๋ฅธ LLM์œผ๋กœ ๊ต์ฒด</td>
1039
+ </tr>
1040
+ <tr>
1041
+ <td><code>meta-llama/Meta-Llama-3-8B-Instruct</code> ์ ‘๊ทผ ๊ฑฐ๋ถ€</td>
1042
+ <td>Meta ๋ผ์ด์„ ์Šค ๋ฏธ๋™์˜</td>
1043
+ <td><a href="https://huggingface.co/meta-llama/Meta-Llama-3-8B-Instruct">๋ชจ๋ธ ํŽ˜์ด์ง€</a>์—์„œ ๋™์˜ ์ฒดํฌ ํ›„ ์Šน์ธ ๋Œ€๊ธฐ</td>
1044
+ </tr>
1045
+ <tr>
1046
+ <td>Space๊ฐ€ <code>Sleeping ๐Ÿ’ค</code> ์ƒํƒœ</td>
1047
+ <td>48์‹œ๊ฐ„ ํŠธ๋ž˜ํ”ฝ ์—†์œผ๋ฉด ์ž๋™ ํœด๋ฉด</td>
1048
+ <td>ํŽ˜์ด์ง€ ์ ‘์†๋งŒ ํ•ด๋„ ์ž๋™์œผ๋กœ ๊นจ์–ด๋‚จ (30์ดˆ)</td>
1049
+ </tr>
1050
+ <tr>
1051
+ <td>git push ์‹œ <em>Authentication failed</em></td>
1052
+ <td>๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ์‹œ๋„</td>
1053
+ <td>Password ์ž๋ฆฌ์— <strong>HF ํ† ํฐ</strong>(<code>hf_...</code>) ์ž…๋ ฅ</td>
1054
+ </tr>
1055
+ <tr>
1056
+ <td>๋นŒ๋“œ๋Š” ์„ฑ๊ณตํ–ˆ๋Š”๋ฐ UI๊ฐ€ ์•ˆ ๋œธ</td>
1057
+ <td><code>app_file</code> ์ง€์ • ์˜ค๋ฅ˜</td>
1058
+ <td>README.md frontmatter์— <code>app_file: app.py</code> ํ™•์ธ</td>
1059
+ </tr>
1060
+ </table>
1061
+
1062
+ <h3>๐Ÿ”„ Step 7. ์ฝ”๋“œ ์ˆ˜์ • ํ›„ ์žฌ๋ฐฐํฌ</h3>
1063
+ <p>Space๋Š” git์ด๋ฏ€๋กœ <strong>๊ทธ๋ƒฅ ๋‹ค์‹œ pushํ•˜๋ฉด ์ž๋™ ์žฌ๋นŒ๋“œ</strong>๋œ๋‹ค.</p>
1064
+ <pre><span class="comment"># ์›น ์—…๋กœ๋“œ ๋ฐฉ์‹์ด๋ฉด</span>
1065
+ <span class="comment"># โ†’ Files ํƒญ์—์„œ ํ•ด๋‹น ํŒŒ์ผ ํด๋ฆญ โ†’ ์—ฐํ•„ ์•„์ด์ฝ˜(Edit) โ†’ ์ˆ˜์ • ํ›„ Commit</span>
1066
+
1067
+ <span class="comment"># git ๋ฐฉ์‹์ด๋ฉด</span>
1068
+ git add app.py
1069
+ git commit -m <span class="str">"tweak: ํ”„๋กฌํ”„ํŠธ ๊ฐ•ํ™”"</span>
1070
+ git push
1071
+ <span class="comment"># โ†’ Space๊ฐ€ 1~2๋ถ„ ํ›„ ์ž๋™ ์žฌ์‹œ์ž‘</span></pre>
1072
+
1073
+ <h3>๐Ÿ’ฐ ๋น„์šฉ ์•ˆ๋‚ด (๋ฌด๋ฃŒ ํ‹ฐ์–ด ์ œํ•œ)</h3>
1074
+ <ul>
1075
+ <li><strong>Space ํ˜ธ์ŠคํŒ…</strong>: ๋ฌด๋ฃŒ (CPU basic ๋ฌด์ œํ•œ)</li>
1076
+ <li><strong>Inference API ํ˜ธ์ถœ</strong>: ๋ฌด๋ฃŒ ๊ณ„์ •์€ ์‹œ๊ฐ„๋‹น ์ œํ•œ์ด ์žˆ์Œ (์ •ํ™•ํ•œ ์ˆ˜์น˜๋Š” ์‹œ์ฆŒ๋ณ„ ๋ณ€๋™)</li>
1077
+ <li>48์‹œ๊ฐ„ ๋ฏธ์‚ฌ์šฉ โ†’ ์ž๋™ Sleep โ†’ ์ ‘์† ์‹œ ์ž๋™ ๊ธฐ์ƒ (cold start 30~60์ดˆ)</li>
1078
+ <li>ํ•ญ์ƒ ์ผœ๋‘๋ ค๋ฉด <strong>ZeroGPU</strong>(PRO ๊ณ„์ •) ๋˜๋Š” <strong>Inference Endpoints</strong> ์œ ๋ฃŒ ์ „ํ™˜</li>
1079
+ </ul>
1080
+
1081
+ <div class="why-box">
1082
+ <div class="label">๐Ÿ† ๋ฐฐํฌ ์™„๋ฃŒ ํ›„</div>
1083
+ <p>๊ณต๊ฐœ URL์„ GitHub ํ”„๋กœํ•„ยท์ด๋ ฅ์„œยท๋งํฌ๋“œ์ธ์— ๋ถ™์ด์ž.
1084
+ "HuggingFace์— ์ง์ ‘ ๋ฐฐํฌํ•œ AI ์•ฑ"์€
1085
+ ์ฑ„์šฉ ๋‹ด๋‹น์ž์™€ ๊ต์ˆ˜์—๊ฒŒ <strong>๋ง๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ•ํ•œ ์ฆ๋ช…</strong>์ด ๋œ๋‹ค.
1086
+ ์ด๋ฒˆ ํ•œ ๋ฒˆ์˜ ๋ฐฐํฌ ๊ฒฝํ—˜์ด ์•ž์œผ๋กœ ๋งŒ๋“ค ๋ชจ๋“  AI ๋ฐ๋ชจ์˜ ํ…œํ”Œ๋ฆฟ์ด ๋œ๋‹ค.</p>
1087
+ </div>
1088
+ </section>
1089
+
1090
+ <!-- MISSION -->
1091
+ <div class="mission">
1092
+ <h2>๐ŸŽฏ ์˜ค๋Š˜ ์ˆ˜์—… ๋ฏธ์…˜</h2>
1093
+ <ul>
1094
+ <li>app.py์˜ TODO 3๊ณณ์„ ๋ชจ๋‘ ์ฑ„์šด๋‹ค</li>
1095
+ <li>๋กœ์ปฌ์—์„œ ์Œ์‹ ์‚ฌ์ง„ 1์žฅ ์ด์ƒ์œผ๋กœ ๋™์ž‘ ํ™•์ธ</li>
1096
+ <li>HuggingFace Space์— ๋ฐฐํฌํ•ด ๊ณต๊ฐœ URL ๋ฐ›๊ธฐ</li>
1097
+ <li>title/emoji/SYSTEM_PROMPT ์ค‘ ํ•˜๋‚˜ ์ด์ƒ ๋ณธ์ธ๋งŒ์˜ ๋ฐฉ์‹์œผ๋กœ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆ</li>
1098
+ <li>๊ฒฐ๊ณผ๋ฌผ: <strong>Space URL + ๊ฒฐ๊ณผ ์Šคํฌ๋ฆฐ์ƒท 1์žฅ + 2~3์ค„ ํšŒ๊ณ </strong></li>
1099
+ </ul>
1100
+ </div>
1101
+
1102
+ <footer>
1103
+ 2026 AI์›น์œตํ•ฉ ยท Week 06 ยท HuggingFace ร— Spaces ยท ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ
1104
+ </footer>
1105
+ </div>
1106
+ </body>
1107
+ </html>
README.md CHANGED
@@ -1,14 +1,87 @@
1
  ---
2
- title: Calcal
3
- emoji: ๐Ÿš€
4
  colorFrom: pink
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.11.0
 
8
  app_file: app.py
9
  pinned: false
10
  license: apache-2.0
11
- short_description: Calorie Calculator
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: HuggingFace Calorie Counter
3
+ emoji: ๐Ÿฑ
4
  colorFrom: pink
5
+ colorTo: yellow
6
  sdk: gradio
7
+ sdk_version: 5.9.1
8
+ python_version: "3.11"
9
  app_file: app.py
10
  pinned: false
11
  license: apache-2.0
 
12
  ---
13
 
14
+ # 6์ฃผ์ฐจ: HuggingFace Space ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ
15
+
16
+ ์Œ์‹ ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•˜๋ฉด HuggingFace Inference API๋กœ ์Œ์‹์„ ์ธ์‹ํ•˜๊ณ ,
17
+ LLM์ด 1์ธ๋ถ„ ๊ธฐ์ค€ ์นผ๋กœ๋ฆฌ/ํƒ„๋‹จ์ง€๋ฅผ ์ถ”์ •ํ•˜๋Š” Gradio ์•ฑ์ด๋‹ค.
18
+ ์™„์„ฑ๋œ ์•ฑ์€ ๊ทธ๋Œ€๋กœ **HuggingFace Space** ์— ์˜ฌ๋ ค ๊ณต๊ฐœ URL์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
19
+
20
+ > ์ด ์ž๋ฃŒ์˜ ๊ธฐ์ˆ  ์ •๋ณด๋Š” 2026-04 ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค.
21
+
22
+ ## ํŒŒ์ผ ๊ตฌ์กฐ
23
+
24
+ ```
25
+ week06/
26
+ โ”œโ”€โ”€ app.py # Gradio ์•ฑ ๋ณธ์ฒด (TODO 4๊ณณ์„ ์ฑ„์›Œ ์™„์„ฑ)
27
+ โ”œโ”€โ”€ model_config.py # HF ๋ชจ๋ธ ์ด๋ฆ„ ์ƒ์ˆ˜ + InferenceClient ํŒฉํ† ๋ฆฌ
28
+ โ”œโ”€โ”€ requirements.txt # Space๊ฐ€ ์„ค์น˜ํ•  ์˜์กด์„ฑ
29
+ โ”œโ”€โ”€ .env.example # HF_TOKEN ํ…œํ”Œ๋ฆฟ
30
+ โ””โ”€โ”€ README.md # ์ด ํŒŒ์ผ (์•ž์˜ YAML์ด Space ์„ค์ •)
31
+ ```
32
+
33
+ ## ์‹คํ–‰ ๋ฐฉ๋ฒ• (๋กœ์ปฌ)
34
+
35
+ ```bash
36
+ # 1) ํ† ํฐ ๋ฐœ๊ธ‰: https://huggingface.co/settings/tokens (Read ๊ถŒํ•œ)
37
+ cp .env.example .env
38
+ # .env ํŒŒ์ผ์„ ์—ด์–ด HF_TOKEN=hf_... ๋กœ ์ˆ˜์ •
39
+
40
+ # 2) ์˜์กด์„ฑ ์„ค์น˜
41
+ uv pip install -r requirements.txt
42
+
43
+ # 3) ์‹คํ–‰
44
+ uv run python app.py
45
+ # ๋ธŒ๋ผ์šฐ์ €: http://127.0.0.1:7860
46
+ ```
47
+
48
+ ## TODO (app.py ์•ˆ)
49
+
50
+ 1. **`SYSTEM_PROMPT`** โ€” ์˜์–‘์‚ฌ ์—ญํ•  + JSON ์Šคํ‚ค๋งˆ ๊ฐ•์ œ (ChatPromptTemplate ์•ˆ์— ๋“ค์–ด๊ฐ€๋ฏ€๋กœ ์ค‘๊ด„ํ˜ธ๋Š” `{{ }}`๋กœ ์ด์Šค์ผ€์ดํ”„)
51
+ 2. **`_chain_lazy()` ์•ˆ LCEL ์ฒด์ธ ์กฐ๋ฆฝ** (4๋‹จ๊ณ„)
52
+ - 2-1. `HuggingFaceEndpoint` ์ƒ์„ฑ (`repo_id=LLM_MODEL`, `task="text-generation"`, ํ† ํฐ)
53
+ - 2-2. `ChatHuggingFace(llm=endpoint)` ๋กœ ๊ฐ์‹ธ๊ธฐ
54
+ - 2-3. `ChatPromptTemplate.from_messages([("system", SYSTEM_PROMPT), ("human", "...{labels_json}")])`
55
+ - 2-4. `_chain = prompt | llm | JsonOutputParser()` ํŒŒ์ดํ”„ ์—ฐ๊ฒฐ
56
+ 3. **`classify_food()`** โ€” `client.image_classification(tmp_path, model=VISION_MODEL)` ํ˜ธ์ถœ
57
+ 4. **`estimate_calories()`** โ€” `chain.invoke({"labels_json": labels_json})` ํ˜ธ์ถœ
58
+
59
+ ๋„ค ๊ณณ์„ ์ฑ„์šฐ๋ฉด ์•ฑ์ด ๋™์ž‘ํ•œ๋‹ค.
60
+
61
+ ## HuggingFace Space ๋ฐฐํฌ ๋ฐฉ๋ฒ•
62
+
63
+ 1. https://huggingface.co/new-space ์—์„œ **Gradio** SDK๋กœ Space ์ƒ์„ฑ
64
+ 2. Space์˜ **Settings > Variables and secrets** ์— `HF_TOKEN` ๋“ฑ๋ก
65
+ 3. ํŒŒ์ผ ์—…๋กœ๋“œ (์›น ๋“œ๋ž˜๊ทธ or `git push`)
66
+ ```bash
67
+ git clone https://huggingface.co/spaces/<๋ณธ์ธ>/<space-์ด๋ฆ„>
68
+ cd <space-์ด๋ฆ„>
69
+ cp ../week06/{app.py,model_config.py,requirements.txt,README.md} .
70
+ git add .
71
+ git commit -m "init"
72
+ git push
73
+ ```
74
+ 4. ๋ช‡ ๋ถ„ ํ›„ `https://huggingface.co/spaces/<๋ณธ์ธ>/<space-์ด๋ฆ„>` ์ ‘์†ํ•˜์—ฌ ๋™์ž‘ ํ™•์ธ
75
+
76
+ ## ๊ณผ์ œ
77
+
78
+ - [ ] Space URL ์ œ์ถœ
79
+ - [ ] title/emoji/ํ”„๋กฌํ”„ํŠธ ์ค‘ ํ•˜๋‚˜ ์ด์ƒ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆ
80
+ - [ ] ๊ฒฐ๊ณผ ์Šคํฌ๋ฆฐ์ƒท 1์žฅ + 2~3์ค„ ์„ค๋ช…
81
+
82
+ ## ์‚ฌ์šฉ ๋ชจ๋ธ
83
+
84
+ | ์—ญํ•  | ๋ชจ๋ธ |
85
+ |------|------|
86
+ | ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ | `nateraw/food` |
87
+ | ์นผ๋กœ๋ฆฌ ์ถ”์ • LLM | `meta-llama/Meta-Llama-3-8B-Instruct` |
__pycache__/model_config.cpython-313.pyc ADDED
Binary file (1.49 kB). View file
 
app.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 6์ฃผ์ฐจ ์‹ค์Šต: HuggingFace Space ์นผ๋กœ๋ฆฌ ์นด์šดํ„ฐ (LangChain LCEL ยท ํ•™์ƒ ๋ฒ„์ „)
3
+ =====================================================================
4
+ ์Œ์‹ ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•˜๋ฉด
5
+ 1) HF Inference API์˜ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ๋ชจ๋ธ๋กœ ์Œ์‹์„ ์ธ์‹ํ•˜๊ณ 
6
+ 2) ๊ทธ ๊ฒฐ๊ณผ๋ฅผ LangChain ChatHuggingFace LLM์— ๋„˜๊ฒจ ์นผ๋กœ๋ฆฌ/์˜์–‘์†Œ๋ฅผ ์ถ”์ •ํ•œ ๋’ค
7
+ 3) Gradio UI๋กœ ๋ณด์—ฌ์ค€๋‹ค.
8
+
9
+ ํ•ต์‹ฌ ๋ณ€๊ฒฝ: estimate_calories๋Š” LCEL ์ฒด์ธ(prompt | llm | parser)์œผ๋กœ ๊ตฌ์„ฑํ•œ๋‹ค.
10
+ ์ด ํŒŒ์ผ์„ ๊ทธ๋Œ€๋กœ HuggingFace Space(Gradio SDK)์— ์˜ฌ๋ฆฌ๋ฉด ๋ฐฐํฌ๋œ๋‹ค.
11
+
12
+ TODO ๋กœ ํ‘œ์‹œ๋œ ๋ถ€๋ถ„์„ ์ฑ„์›Œ ์™„์„ฑํ•œ ๋’ค,
13
+ 1) ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ•ด๋ณด๊ณ 
14
+ 2) HuggingFace Space์— ๋ฐฐํฌํ•œ๋‹ค.
15
+
16
+ ๋กœ์ปฌ ์‹คํ–‰:
17
+ uv run python app.py
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import tempfile
25
+ from typing import Any
26
+
27
+ import gradio as gr
28
+ from gradio_client import utils as _gc_utils # noqa: E402
29
+
30
+ # --- workaround: gradio_client์˜ JSON Schema walker๊ฐ€ bool ์Šคํ‚ค๋งˆ๋ฅผ ๋งŒ๋‚˜๋ฉด
31
+ # ํ„ฐ์ง€๋Š” ๋ฒ„๊ทธ(#10178) ์šฐํšŒ. Label/JSON ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒ์„ฑํ•˜๋Š”
32
+ # additionalProperties: true ์Šคํ‚ค๋งˆ์—์„œ ๋ฐœ์ƒํ•œ๋‹ค.
33
+ _orig_get_type = _gc_utils.get_type
34
+ def _safe_get_type(schema):
35
+ if isinstance(schema, bool):
36
+ return "Any"
37
+ return _orig_get_type(schema)
38
+ _gc_utils.get_type = _safe_get_type
39
+
40
+ _orig_j2p = _gc_utils._json_schema_to_python_type
41
+ def _safe_j2p(schema, defs=None):
42
+ if isinstance(schema, bool):
43
+ return "Any"
44
+ return _orig_j2p(schema, defs)
45
+ _gc_utils._json_schema_to_python_type = _safe_j2p
46
+
47
+ from dotenv import load_dotenv
48
+ from huggingface_hub import InferenceClient
49
+ from langchain_core.output_parsers import JsonOutputParser
50
+ from langchain_core.prompts import ChatPromptTemplate
51
+ from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint
52
+ from PIL import Image
53
+
54
+ from model_config import LLM_MODEL, VISION_MODEL, get_token
55
+
56
+ load_dotenv()
57
+
58
+ TOP_K = 3
59
+
60
+ # ---------------------------------------------------------------------------
61
+ # TODO 1. ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
62
+ # ---------------------------------------------------------------------------
63
+ # LLM ์ด '์˜์–‘์‚ฌ AI' ์—ญํ• ์„ ํ•˜๊ณ , 1์ธ๋ถ„ ๊ธฐ์ค€ ์นผ๋กœ๋ฆฌ/ํƒ„๋‹จ์ง€๋ฅผ JSON ์œผ๋กœ ์ถœ๋ ฅํ•˜๋„๋ก
64
+ # ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ผ.
65
+ # - ๋ฐ˜๋“œ์‹œ ์•„๋ž˜ JSON ์Šคํ‚ค๋งˆ๋งŒ ์ถœ๋ ฅํ•˜๋ผ๊ณ  ๊ฐ•์ œํ•  ๊ฒƒ
66
+ # {"food": str, "confidence": float, "calories_kcal": int,
67
+ # "carbs_g": int, "protein_g": int, "fat_g": int, "note": str}
68
+ # - ChatPromptTemplate ์— ๋“ค์–ด๊ฐ€๋ฏ€๋กœ JSON ์˜ˆ์‹œ์˜ ์ค‘๊ด„ํ˜ธ๋Š” {{ }} ๋กœ ์ด์Šค์ผ€์ดํ”„ํ•  ๊ฒƒ
69
+ SYSTEM_PROMPT = """ ๋„ˆ๋Š” ํ•œ๊ตญ ์˜์–‘์‚ฌ AI๋‹ค.
70
+ ์‚ฌ์šฉ์ž๊ฐ€ ์Œ์‹ ๋ถ„๋ฅ˜ ๊ฒฐ๊ณผ(top-k labels)๋ฅผ ์ฃผ๋ฉด,
71
+ ๊ฐ€์žฅ ๊ฐ€๋Šฅ์„ฑ ๋†’์€ ์Œ์‹ 1๊ฐœ์˜ 1์ธ๋ถ„ ๊ธฐ์ค€ ์˜์–‘์ •๋ณด๋ฅผ ์ถ”์ •ํ•ด
72
+ ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ JSON ์Šคํ‚ค๋งˆ๋งŒ ์ถœ๋ ฅํ•˜๋ผ. ๋‹ค๋ฅธ ํ…์ŠคํŠธ/๋งˆํฌ๋‹ค์šด ๊ธˆ์ง€.
73
+
74
+ {{"food": "์Œ์‹๋ช…", "confidence": 0.0~1.0,
75
+ "calories_kcal": ์ •์ˆ˜, "carbs_g": ์ •์ˆ˜,
76
+ "protein_g": ์ •์ˆ˜, "fat_g": ์ •์ˆ˜,
77
+ "note": "์ถ”์ • ๊ทผ๊ฑฐ ํ•œ ์ค„"}}"
78
+
79
+ """
80
+ # -----------------------------------------------------------------------------
81
+ # ํด๋ผ์ด์–ธํŠธ / ์ฒด์ธ lazy init
82
+ # -----------------------------------------------------------------------------
83
+ _vision_client: InferenceClient | None = None
84
+ _chain = None
85
+
86
+
87
+ def _vision_lazy() -> InferenceClient:
88
+ global _vision_client
89
+ if _vision_client is None:
90
+ _vision_client = InferenceClient(token=get_token())
91
+ return _vision_client
92
+
93
+
94
+ def _chain_lazy():
95
+ """LCEL ์ฒด์ธ: prompt | ChatHuggingFace | JsonOutputParser"""
96
+ global _chain
97
+ if _chain is None:
98
+ # 3-1. HF Inference Endpoint ์ƒ์„ฑ
99
+ endpoint = HuggingFaceEndpoint(
100
+ repo_id=LLM_MODEL,
101
+ task="text-generation",
102
+ max_new_tokens=300,
103
+ temperature=0.2,
104
+ huggingfacehub_api_token=get_token(),
105
+ )
106
+
107
+ # 3-2. ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ฐ์‹ธ๊ธฐ
108
+ llm = ChatHuggingFace(llm=endpoint)
109
+
110
+ # 3-3. ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ
111
+ prompt = ChatPromptTemplate.from_messages([
112
+ ("system", SYSTEM_PROMPT),
113
+ ("human", "๋‹ค์Œ์€ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜๊ธฐ์˜ top-k ๊ฒฐ๊ณผ๋‹ค:\n{labels_json}"),
114
+ ])
115
+
116
+ # 3-4. LCEL ํŒŒ์ดํ”„๋ผ์ธ โ€” ์ด ํ•œ ์ค„์ด ํ•ต์‹ฌ!
117
+ _chain = prompt | llm | JsonOutputParser()
118
+
119
+ return _chain
120
+
121
+
122
+ # -----------------------------------------------------------------------------
123
+ # Step 1: ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ (LangChain ์ถ”์ƒํ™” ์—†์Œ โ€” InferenceClient ์ง์ ‘ ์‚ฌ์šฉ)
124
+ # -----------------------------------------------------------------------------
125
+ def classify_food(image: Image.Image) -> list[dict[str, Any]]:
126
+ """HF ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ๋ชจ๋ธ์— PIL ์ด๋ฏธ์ง€๋ฅผ ๋„˜๊ฒจ top-k ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š”๋‹ค."""
127
+ client = _vision_lazy()
128
+
129
+ # PIL ์ด๋ฏธ์ง€๋ฅผ JPEG ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ (hf-inference ๋ผ์šฐํ„ฐ๊ฐ€ Content-Type ์„ ์š”๊ตฌ).
130
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
131
+ image.convert("RGB").save(tmp, format="JPEG")
132
+ tmp_path = tmp.name
133
+
134
+ try:
135
+ raw = client.image_classification(tmp_path, model=VISION_MODEL)
136
+ finally:
137
+ os.unlink(tmp_path)
138
+
139
+ results: list[dict[str, Any]] = []
140
+ for item in raw[:TOP_K]:
141
+ if isinstance(item, dict):
142
+ results.append({"label": item["label"], "score": float(item["score"])})
143
+ else:
144
+ results.append({"label": item.label, "score": float(item.score)})
145
+ return results
146
+
147
+
148
+ # -----------------------------------------------------------------------------
149
+ # Step 2: ์นผ๋กœ๋ฆฌ/์˜์–‘์†Œ ์ถ”์ • (LCEL ์ฒด์ธ)
150
+ # -----------------------------------------------------------------------------
151
+ def estimate_calories(labels: list[dict[str, Any]]) -> dict[str, Any]:
152
+ chain = _chain_lazy()
153
+ labels_json = json.dumps(labels, ensure_ascii=False)
154
+ try:
155
+ chain = _chain_lazy()
156
+ labels_json = json.dumps(labels, ensure_ascii=False)
157
+ return chain.invoke({"labels_json": labels_json})
158
+ except Exception as e:
159
+ return {
160
+ "food": labels[0]["label"] if labels else "unknown",
161
+ "confidence": labels[0]["score"] if labels else 0.0,
162
+ "calories_kcal": 0,
163
+ "carbs_g": 0,
164
+ "protein_g": 0,
165
+ "fat_g": 0,
166
+ "note": f"์ฒด์ธ ์‹คํ–‰ ์‹คํŒจ: {type(e).__name__}: {str(e)[:120]}",
167
+ }
168
+
169
+
170
+ # -----------------------------------------------------------------------------
171
+ # Step 3: Gradio ์ฝœ๋ฐฑ
172
+ # -----------------------------------------------------------------------------
173
+ def analyze(image):
174
+ if image is None:
175
+ return {}, {"error": "์ด๋ฏธ์ง€๋ฅผ ๋จผ์ € ์—…๋กœ๋“œํ•ด ์ฃผ์„ธ์š”."}
176
+ labels = classify_food(image)
177
+ label_view = {item["label"]: item["score"] for item in labels}
178
+ nutrition = estimate_calories(labels)
179
+ return label_view, nutrition
180
+
181
+
182
+ # -----------------------------------------------------------------------------
183
+ # Step 4: UI
184
+ # -----------------------------------------------------------------------------
185
+ def build_ui() -> gr.Interface:
186
+ return gr.Interface(
187
+ fn=analyze,
188
+ inputs=gr.Image(type="pil", label="์Œ์‹ ์‚ฌ์ง„ ์—…๋กœ๋“œ"),
189
+ outputs=[
190
+ gr.Label(num_top_classes=TOP_K, label="์Œ์‹ ๋ถ„๋ฅ˜ ๊ฒฐ๊ณผ"),
191
+ gr.JSON(label="์นผ๋กœ๋ฆฌ & ์˜์–‘์†Œ ์ถ”์ •"),
192
+ ],
193
+ title="๐Ÿฑ HuggingFace Calorie Counter (LangChain LCEL)",
194
+ description=(
195
+ "์Œ์‹ ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•˜๋ฉด HF Inference API๋กœ ์Œ์‹์„ ์ธ์‹ํ•˜๊ณ , "
196
+ "LangChain LCEL ์ฒด์ธ์ด 1์ธ๋ถ„ ๊ธฐ์ค€ ์นผ๋กœ๋ฆฌ/์˜์–‘์†Œ๋ฅผ ์ถ”์ •ํ•ฉ๋‹ˆ๋‹ค. "
197
+ "๊ฒฐ๊ณผ๋Š” ์ฐธ๊ณ ์šฉ์ž…๋‹ˆ๋‹ค."
198
+ ),
199
+ flagging_mode="never",
200
+ )
201
+
202
+
203
+ # ๋ชจ๋“ˆ ๋ ˆ๋ฒจ demo (Space/HF ๋Ÿฐํƒ€์ž„ ํ˜ธํ™˜)
204
+ demo = build_ui()
205
+
206
+ if __name__ == "__main__":
207
+ # HF Space์—์„œ๋Š” SPACE_ID ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋ผ ์žˆ์–ด 0.0.0.0 ๋ฐ”์ธ๋”ฉ์ด ํ•„์š”ํ•˜๋‹ค.
208
+ # ๋กœ์ปฌ์—์„œ๋Š” 127.0.0.1.
209
+ is_space = bool(os.getenv("SPACE_ID"))
210
+ demo.launch(
211
+ server_name="0.0.0.0" if is_space else "127.0.0.1",
212
+ server_port=int(os.getenv("PORT", 7860)),
213
+ show_api=False,
214
+ ssr_mode=False,
215
+ )
calcal/.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
calcal/README.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Calcal
3
+ emoji: ๐Ÿš€
4
+ colorFrom: pink
5
+ colorTo: blue
6
+ sdk: gradio
7
+ sdk_version: 6.11.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: apache-2.0
11
+ short_description: Calorie Calculator
12
+ ---
13
+
14
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
images/01_main.png ADDED

Git LFS Details

  • SHA256: b5565fde54ad1d0e546d2530f3c0d709812f0c48e05c250d409e484688f7d2b5
  • Pointer size: 131 Bytes
  • Size of remote file: 389 kB
images/02_models.png ADDED

Git LFS Details

  • SHA256: 113bb91f4a923869ac109c483938a641b29a41c28f90e7fff44b8654461b77c7
  • Pointer size: 131 Bytes
  • Size of remote file: 359 kB
images/03_model_card.png ADDED

Git LFS Details

  • SHA256: ca0c611fa9a2345e91458056d91b533a3ad1ba602b384855f6633bbae2d1539f
  • Pointer size: 131 Bytes
  • Size of remote file: 165 kB
images/04_spaces.png ADDED

Git LFS Details

  • SHA256: 866bfc9ce13e0bd59f65f933dd4d2d3509ba82d1b2becac7bbfb5953f72dabb6
  • Pointer size: 131 Bytes
  • Size of remote file: 494 kB
images/05_tokens.png ADDED

Git LFS Details

  • SHA256: 4c6d98759fd3c950ab224c34920470454e8e6ebbdec39640e3438b4d0b852c6b
  • Pointer size: 131 Bytes
  • Size of remote file: 286 kB
images/06_new_space.png ADDED

Git LFS Details

  • SHA256: 580f5130fdad527c2c22e7ff916c0aa4c5f64e37918c6d45b9bbf7ee62cc114b
  • Pointer size: 131 Bytes
  • Size of remote file: 191 kB
images/07_secrets.png ADDED
images/08_files.png ADDED
images/09_app_logs.png ADDED

Git LFS Details

  • SHA256: 469fbe99928057d8fc4fa5bf32efaaec508e9aed4f23d1f88b28f2fbe4b1a71b
  • Pointer size: 131 Bytes
  • Size of remote file: 198 kB
images/10_write_token.png ADDED

Git LFS Details

  • SHA256: d92a486e26ba41f1a9dc06b86a734905819811900b9d7c7d32d0cd27fe6f8f03
  • Pointer size: 131 Bytes
  • Size of remote file: 187 kB
images/11_running.png ADDED
model_config.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 6์ฃผ์ฐจ ๋ชจ๋ธ ์„ค์ • โ€” HuggingFace Inference API
3
+ ===========================================
4
+ ํ† ํฐ์€ .env ์˜ HF_TOKEN ๋˜๋Š” HUGGINGFACEHUB_API_TOKEN ์—์„œ ์ฝ๋Š”๋‹ค.
5
+ HF Space์— ๋ฐฐํฌํ•  ๋•Œ๋Š” Settings > Secrets ์— HF_TOKEN ์„ ๋“ฑ๋กํ•œ๋‹ค.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import os
11
+
12
+ from huggingface_hub import InferenceClient
13
+
14
+ # ์Œ์‹ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ (ViT, food-101 ํŒŒ์ธํŠœ๋‹)
15
+ VISION_MODEL = "nateraw/food"
16
+
17
+ # ์นผ๋กœ๋ฆฌ/์˜์–‘์†Œ ์ถ”์ •์šฉ ํ…์ŠคํŠธ LLM
18
+ LLM_MODEL = "meta-llama/Meta-Llama-3-8B-Instruct"
19
+
20
+
21
+ def get_token() -> str:
22
+ token = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACEHUB_API_TOKEN")
23
+ if not token:
24
+ raise SystemExit(
25
+ "HF_TOKEN(๋˜๋Š” HUGGINGFACEHUB_API_TOKEN) ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค.\n"
26
+ " 1) https://huggingface.co/settings/tokens ์—์„œ Read ํ† ํฐ ๋ฐœ๊ธ‰\n"
27
+ " 2) .env ์— HF_TOKEN=hf_xxx ์ถ”๊ฐ€ (๋กœ์ปฌ)\n"
28
+ " 3) HF Space: Settings > Secrets ์— HF_TOKEN ๋“ฑ๋ก"
29
+ )
30
+ return token
31
+
32
+
33
+ def get_client() -> InferenceClient:
34
+ """์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜์šฉ ํด๋ผ์ด์–ธํŠธ."""
35
+ return InferenceClient(token=get_token())
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio>=5.0,<6
2
+ huggingface_hub>=0.24,<1.0
3
+ langchain>=0.3
4
+ langchain-core>=0.3
5
+ langchain-huggingface>=0.1
6
+ pillow>=10.0
7
+ python-dotenv>=1.0