Kavin Arasu commited on
Commit
68694b3
1 Parent(s): 5e6dcea

First Model Version

Browse files
app/api/Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.8
2
+
3
+ COPY requirements.txt .
4
+
5
+ RUN pip install -r requirements.txt
6
+
7
+ COPY . .
8
+
9
+ EXPOSE 3000
10
+
11
+ CMD ["flask", "run", "--host=0.0.0.0", "--port=3000"]
app/api/app.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, jsonify
2
+ from model import model
3
+
4
+ app = Flask(__name__)
5
+
6
+ @app.route("/", methods = ['GET'])
7
+ def hello_word():
8
+ return render_template("index.html")
9
+
10
+ @app.route("/generate", methods = ['GET'])
11
+ def generate():
12
+ name = model.generate_name()
13
+ return jsonify(name=name)
14
+
15
+ if __name__ == "__main__":
16
+ app.run(port = 3000, debug = True)
app/api/docker-compose.yml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: "3.7"
2
+
3
+ services:
4
+ mlapp:
5
+ container_name: mlapp
6
+ image: iamkavinarasu/mlapp
7
+ ports:
8
+ - "3000:3000"
9
+ build:
10
+ context: .
11
+ dockerfile: Dockerfile
app/api/model/__pycache__/model.cpython-310.pyc ADDED
Binary file (789 Bytes). View file
 
app/api/model/bigrams.pkl ADDED
Binary file (3.59 kB). View file
 
app/api/model/model.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ from pathlib import Path
3
+ import torch
4
+
5
+ BASE_DIR = Path(__file__).resolve(strict=True).parent
6
+
7
+ with open(f"{BASE_DIR}/bigrams.pkl", "rb") as file:
8
+ P,char_to_int,int_to_char = pickle.load(file)
9
+
10
+ generator = torch.Generator().manual_seed(2147483647)
11
+
12
+ def generate_name():
13
+ name = []
14
+ ix = 0
15
+ while True:
16
+ probs = P[ix]
17
+ ix = torch.multinomial(probs, num_samples = 1, replacement = True, generator = generator).item()
18
+ name.append(int_to_char[ix])
19
+ if ix == 0:
20
+ break
21
+ name = ''.join(name)
22
+ return name
app/api/requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ click==8.1.3
2
+ Flask==2.2.2
3
+ itsdangerous==2.1.2
4
+ Jinja2==3.1.2
5
+ MarkupSafe==2.1.2
6
+ six==1.16.0
7
+ torch==1.13.1
8
+ typing_extensions==4.5.0
9
+ Werkzeug==2.2.3
app/api/static/css/styles.css ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ margin: auto;
3
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif;
4
+ overflow: auto;
5
+ background: linear-gradient(315deg, rgba(101,0,94,1) 3%, rgba(60,132,206,1) 38%, rgba(48,238,226,1) 68%, rgba(255,25,25,1) 98%);
6
+ animation: gradient 15s ease infinite;
7
+ background-size: 400% 400%;
8
+ background-attachment: fixed;
9
+ }
10
+
11
+ @keyframes gradient {
12
+ 0% {
13
+ background-position: 0% 0%;
14
+ }
15
+ 50% {
16
+ background-position: 100% 100%;
17
+ }
18
+ 100% {
19
+ background-position: 0% 0%;
20
+ }
21
+ }
22
+
23
+ .wave {
24
+ background: rgb(255 255 255 / 25%);
25
+ border-radius: 1000% 1000% 0 0;
26
+ position: fixed;
27
+ width: 200%;
28
+ height: 12em;
29
+ animation: wave 10s -3s linear infinite;
30
+ transform: translate3d(0, 0, 0);
31
+ opacity: 0.8;
32
+ bottom: 0;
33
+ left: 0;
34
+ z-index: -1;
35
+ }
36
+
37
+ .wave:nth-of-type(2) {
38
+ bottom: -1.25em;
39
+ animation: wave 18s linear reverse infinite;
40
+ opacity: 0.8;
41
+ }
42
+
43
+ .wave:nth-of-type(3) {
44
+ bottom: -2.5em;
45
+ animation: wave 20s -1s reverse infinite;
46
+ opacity: 0.9;
47
+ }
48
+
49
+ @keyframes wave {
50
+ 2% {
51
+ transform: translateX(1);
52
+ }
53
+
54
+ 25% {
55
+ transform: translateX(-25%);
56
+ }
57
+
58
+ 50% {
59
+ transform: translateX(-50%);
60
+ }
61
+
62
+ 75% {
63
+ transform: translateX(-25%);
64
+ }
65
+
66
+ 100% {
67
+ transform: translateX(1);
68
+ }
69
+ }
70
+
71
+ * {
72
+ margin: 0;
73
+ padding: 0;
74
+ box-sizing: border-box;
75
+ font-family:'Courier New', Courier, monospace;
76
+ }
77
+ body {
78
+ width: 100%;
79
+ height: 100vh;
80
+ display: flex;
81
+ justify-content: center;
82
+ align-items: center;
83
+ }
84
+ button {
85
+ border: 0;
86
+ outline: 0;
87
+ }
88
+ .container {
89
+ margin: 40px 0;
90
+ width: 400px;
91
+ height: 600px;
92
+ padding: 10px 25px;
93
+ background: #0a0e31;
94
+ border-radius: 10px;
95
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.45), 0 4px 8px rgba(0, 0, 0, 0.35), 0 8px 12px rgba(0, 0, 0, 0.15);
96
+ font-family: "Montserrat";
97
+ }
98
+ .container .title {
99
+ font-size: 1.75rem;
100
+ margin: 10px -5px;
101
+ margin-bottom: 30px;
102
+ color: #fff;
103
+ }
104
+ .result {
105
+ position: relative;
106
+ width: 100%;
107
+ height: 65px;
108
+ overflow: hidden;
109
+ }
110
+ .result__info {
111
+ position: absolute;
112
+ bottom: 4px;
113
+ color: #fff;
114
+ font-size: 0.8rem;
115
+ transition: all 150ms ease-in-out;
116
+ transform: translateY(200%);
117
+ opacity: 0;
118
+ }
119
+ .result__info.right {
120
+ right: 8px;
121
+ }
122
+ .result__info.left {
123
+ left: 8px;
124
+ }
125
+ .result__viewbox {
126
+ width: 100%;
127
+ height: 100%;
128
+ background: rgba(255, 255, 255, 0.08);
129
+ border-radius: 8px;
130
+ color: #fff;
131
+ text-align: center;
132
+ line-height: 65px;
133
+ }
134
+ .result #copy-btn {
135
+ position: absolute;
136
+ top: var(--y);
137
+ left: var(--x);
138
+ width: 38px;
139
+ height: 38px;
140
+ background: #fff;
141
+ border-radius: 50%;
142
+ opacity: 0;
143
+ transform: translate(-50%, -50%) scale(0);
144
+ transition: all 350ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
145
+ cursor: pointer;
146
+ z-index: 2;
147
+ }
148
+ .result #copy-btn:active {
149
+ box-shadow: 0 0 0 200px rgba(255, 255, 255, 0.08);
150
+ }
151
+ .result:hover #copy-btn {
152
+ opacity: 1;
153
+ transform: translate(-50%, -50%) scale(1.35);
154
+ }
155
+ .field-title {
156
+ position: absolute;
157
+ top: -10px;
158
+ left: 8px;
159
+ transform: translateY(-50%);
160
+ font-weight: 800;
161
+ color: rgba(255, 255, 255, 0.5);
162
+ text-transform: uppercase;
163
+ font-size: 0.65rem;
164
+ pointer-events: none;
165
+ user-select: none;
166
+ }
167
+ .options {
168
+ width: 100%;
169
+ height: auto;
170
+ margin: 50px 0;
171
+ }
172
+ .range__slider {
173
+ position: relative;
174
+ width: 100%;
175
+ height: calc(65px - 10px);
176
+ display: flex;
177
+ justify-content: center;
178
+ align-items: center;
179
+ background: rgba(255, 255, 255, 0.08);
180
+ border-radius: 8px;
181
+ margin: 30px 0;
182
+ }
183
+ .range__slider::before, .range__slider::after {
184
+ position: absolute;
185
+ color: #fff;
186
+ font-size: 0.9rem;
187
+ font-weight: bold;
188
+ }
189
+ .range__slider::before {
190
+ content: attr(data-min);
191
+ left: 10px;
192
+ }
193
+ .range__slider::after {
194
+ content: attr(data-max);
195
+ right: 10px;
196
+ }
197
+ .range__slider .length__title::after {
198
+ content: attr(data-length);
199
+ position: absolute;
200
+ right: -16px;
201
+ font-variant-numeric: tabular-nums;
202
+ color: #fff;
203
+ }
204
+ #slider {
205
+ -webkit-appearance: none;
206
+ width: calc(100% - (70px));
207
+ height: 2px;
208
+ border-radius: 5px;
209
+ background: rgba(255, 255, 255, 0.314);
210
+ outline: none;
211
+ padding: 0;
212
+ margin: 0;
213
+ cursor: pointer;
214
+ }
215
+ #slider::-webkit-slider-thumb {
216
+ -webkit-appearance: none;
217
+ width: 20px;
218
+ height: 20px;
219
+ border-radius: 50%;
220
+ background: #fff;
221
+ cursor: pointer;
222
+ transition: all 0.15s ease-in-out;
223
+ }
224
+ #slider::-webkit-slider-thumb:hover {
225
+ background: #d4d4d4;
226
+ transform: scale(1.2);
227
+ }
228
+ #slider::-moz-range-thumb {
229
+ width: 20px;
230
+ height: 20px;
231
+ border: 0;
232
+ border-radius: 50%;
233
+ background: #fff;
234
+ cursor: pointer;
235
+ transition: background 0.15s ease-in-out;
236
+ }
237
+ #slider::-moz-range-thumb:hover {
238
+ background: #d4d4d4;
239
+ }
240
+ .settings {
241
+ position: relative;
242
+ height: auto;
243
+ widows: 100%;
244
+ display: flex;
245
+ flex-direction: column;
246
+ }
247
+ .settings .setting {
248
+ position: relative;
249
+ width: 100%;
250
+ height: calc(65px - 10px);
251
+ background: rgba(255, 255, 255, 0.08);
252
+ border-radius: 8px;
253
+ display: flex;
254
+ align-items: center;
255
+ padding: 10px 25px;
256
+ color: #fff;
257
+ margin-bottom: 8px;
258
+ }
259
+ .settings .setting input {
260
+ opacity: 0;
261
+ position: absolute;
262
+ }
263
+ .settings .setting input + label {
264
+ user-select: none;
265
+ }
266
+ .settings .setting input + label::before, .settings .setting input + label::after {
267
+ content: "";
268
+ position: absolute;
269
+ transition: 150ms cubic-bezier(0.24, 0, 0.5, 1);
270
+ transform: translateY(-50%);
271
+ top: 50%;
272
+ right: 10px;
273
+ cursor: pointer;
274
+ }
275
+ .settings .setting input + label::before {
276
+ height: 30px;
277
+ width: 50px;
278
+ border-radius: 30px;
279
+ background: rgba(214, 214, 214, 0.434);
280
+ }
281
+ .settings .setting input + label::after {
282
+ height: 24px;
283
+ width: 24px;
284
+ border-radius: 60px;
285
+ right: 32px;
286
+ background: #fff;
287
+ }
288
+ .settings .setting input:checked + label:before {
289
+ background: #5d68e2;
290
+ transition: all 150ms cubic-bezier(0, 0, 0, 0.1);
291
+ }
292
+ .settings .setting input:checked + label:after {
293
+ right: 14px;
294
+ }
295
+ .settings .setting input:focus + label:before {
296
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.75);
297
+ }
298
+ .settings .setting input:disabled + label:before, .settings .setting input:disabled + label:after {
299
+ cursor: not-allowed;
300
+ }
301
+ .settings .setting input:disabled + label:before {
302
+ background: #4f4f6a;
303
+ }
304
+ .settings .setting input:disabled + label:after {
305
+ background: #909090;
306
+ }
307
+ .btn.generate {
308
+ user-select: none;
309
+ position: relative;
310
+ width: 100%;
311
+ height: 50px;
312
+ margin: 10px 0;
313
+ border-radius: 8px;
314
+ color: #fff;
315
+ border: none;
316
+ background-image: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
317
+ letter-spacing: 1px;
318
+ font-weight: bold;
319
+ text-transform: uppercase;
320
+ cursor: pointer;
321
+ transition: all 150ms ease;
322
+ }
323
+ .btn.generate:active {
324
+ transform: translateY(-3%);
325
+ box-shadow: 0 4px 8px rgba(255, 255, 255, 0.08);
326
+ }
327
+ .support {
328
+ position: fixed;
329
+ right: 10px;
330
+ bottom: 10px;
331
+ padding: 10px;
332
+ display: flex;
333
+ }
334
+ a {
335
+ margin: 0 20px;
336
+ color: #fff;
337
+ font-size: 2rem;
338
+ transition: all 400ms ease;
339
+ }
340
+ a:hover {
341
+ color: #222;
342
+ }
343
+ .github-corner svg {
344
+ position: absolute;
345
+ right: 0;
346
+ top: 0;
347
+ mix-blend-mode: darken;
348
+ color: #eee;
349
+ fill: #353535;
350
+ clip-path: polygon(0 0, 100% 0, 100% 100%);
351
+ }
352
+ .github-corner:hover .octo-arm {
353
+ animation: octocat-wave 0.56s;
354
+ }
355
+ @keyframes octocat-wave {
356
+ 0%, 100% {
357
+ transform: rotate(0);
358
+ }
359
+ 20%, 60% {
360
+ transform: rotate(-20deg);
361
+ }
362
+ 40%, 80% {
363
+ transform: rotate(10deg);
364
+ }
365
+ }
app/api/static/js/index.js ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Clear the concole on every refresh
2
+ // console.clear();
3
+ // set the body to full height
4
+ // document.body.style.height = `${innerHeight}px`
5
+
6
+ // Range Slider Properties.
7
+ // Fill : The trailing color that you see when you drag the slider.
8
+ // background : Default Range Slider Background
9
+ const sliderProps = {
10
+ fill: "#0B1EDF",
11
+ background: "rgba(255, 255, 255, 0.214)",
12
+ };
13
+
14
+ // Selecting the Range Slider container which will effect the LENGTH property of the password.
15
+ const slider = document.querySelector(".range__slider");
16
+
17
+ // Text which will show the value of the range slider.
18
+ const sliderValue = document.querySelector(".length__title");
19
+
20
+ // Using Event Listener to apply the fill and also change the value of the text.
21
+ slider.querySelector("input").addEventListener("input", event => {
22
+ sliderValue.setAttribute("data-length", event.target.value);
23
+ applyFill(event.target);
24
+ });
25
+ // Selecting the range input and passing it in the applyFill func.
26
+ applyFill(slider.querySelector("input"));
27
+ // This function is responsible to create the trailing color and setting the fill.
28
+ function applyFill(slider) {
29
+ const percentage = (100 * (slider.value - slider.min)) / (slider.max - slider.min);
30
+ const bg = `linear-gradient(90deg, ${sliderProps.fill} ${percentage}%, ${sliderProps.background} ${percentage +
31
+ 0.1}%)`;
32
+ slider.style.background = bg;
33
+ sliderValue.setAttribute("data-length", slider.value);
34
+ }
35
+
36
+ // Selecting all the DOM Elements that are necessary -->
37
+
38
+ // The Viewbox where the result will be shown
39
+ const resultEl = document.getElementById("result");
40
+ // The input slider, will use to change the length of the password
41
+ const lengthEl = document.getElementById("slider");
42
+
43
+ // Button to generate the password
44
+ const generateBtn = document.getElementById("generate");
45
+ // Button to copy the text
46
+ const copyBtn = document.getElementById("copy-btn");
47
+ // Result viewbox container
48
+ const resultContainer = document.querySelector(".result");
49
+ // Text info showed after generate button is clicked
50
+ const copyInfo = document.querySelector(".result__info.right");
51
+ // Text appear after copy button is clicked
52
+ const copiedInfo = document.querySelector(".result__info.left");
53
+
54
+ // if this variable is trye only then the copyBtn will appear, i.e. when the user first click generate the copyBth will interact.
55
+ let generatedPassword = false;
56
+
57
+ // Update Css Props of the COPY button
58
+ // Getting the bounds of the result viewbox container
59
+ let resultContainerBound = {
60
+ left: resultContainer.getBoundingClientRect().left,
61
+ top: resultContainer.getBoundingClientRect().top,
62
+ };
63
+ // This will update the position of the copy button based on mouse Position
64
+ resultContainer.addEventListener("mousemove", e => {
65
+ resultContainerBound = {
66
+ left: resultContainer.getBoundingClientRect().left,
67
+ top: resultContainer.getBoundingClientRect().top,
68
+ };
69
+ if(generatedPassword){
70
+ copyBtn.style.opacity = '1';
71
+ copyBtn.style.pointerEvents = 'all';
72
+ copyBtn.style.setProperty("--x", `${e.x - resultContainerBound.left}px`);
73
+ copyBtn.style.setProperty("--y", `${e.y - resultContainerBound.top}px`);
74
+ }else{
75
+ copyBtn.style.opacity = '0';
76
+ copyBtn.style.pointerEvents = 'none';
77
+ }
78
+ });
79
+ window.addEventListener("resize", e => {
80
+ resultContainerBound = {
81
+ left: resultContainer.getBoundingClientRect().left,
82
+ top: resultContainer.getBoundingClientRect().top,
83
+ };
84
+ });
85
+
86
+ // Copy Password in clipboard
87
+ copyBtn.addEventListener("click", () => {
88
+ const textarea = document.createElement("textarea");
89
+ const password = resultEl.innerText;
90
+ if (!password || password == "CLICK GENERATE") {
91
+ return;
92
+ }
93
+ textarea.value = password;
94
+ document.body.appendChild(textarea);
95
+ textarea.select();
96
+ document.execCommand("copy");
97
+ textarea.remove();
98
+
99
+ copyInfo.style.transform = "translateY(200%)";
100
+ copyInfo.style.opacity = "0";
101
+ copiedInfo.style.transform = "translateY(0%)";
102
+ copiedInfo.style.opacity = "0.75";
103
+ });
104
+
105
+ function generateName(){
106
+ fetch('/generate')
107
+ .then(response => response.json())
108
+ .then(data => {
109
+ resultEl.innerText = data.name;
110
+ })
111
+ .catch(error => console.error(error));
112
+ }
113
+
114
+ // When Generate is clicked Password id generated.
115
+ generateBtn.addEventListener("click", () => {
116
+
117
+ const length = +lengthEl.value;
118
+ generatedPassword = true;
119
+ copyInfo.style.transform = "translateY(0%)";
120
+ copyInfo.style.opacity = "0.75";
121
+ copiedInfo.style.transform = "translateY(200%)";
122
+ copiedInfo.style.opacity = "0";
123
+ });
app/api/templates/index.html ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Name Generator</title>
8
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" integrity="sha512-SzlrxWUlpfuzQ+pcUCosxcglQRNAq/DZjVsC0lE40xsADsfeQoEypE+enwcOiGjk/bSuGGKHEyjSoQ1zVisanQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
10
+ </head>
11
+ <body>
12
+ <div>
13
+ <div class="wave"></div>
14
+ <div class="wave"></div>
15
+ <div class="wave"></div>
16
+
17
+ <div class="container">
18
+ <h2 class="title">Name Generator</h2>
19
+ <div class="result">
20
+ <div class="result__title field-title">Generated Name</div>
21
+ <div class="result__info right">click to copy</div>
22
+ <div class="result__info left">copied</div>
23
+ <div class="result__viewbox" id="result">CLICK GENERATE</div>
24
+ <button id="copy-btn" style="--x: 0; --y: 0"><i class="far fa-copy"></i></button>
25
+ </div>
26
+ <div class="length range__slider" data-min="4" data-max="32">
27
+ <div class="length__title field-title" data-length='0'>length:</div>
28
+ <input id="slider" type="range" min="4" max="32" value="16" />
29
+ </div>
30
+
31
+ <button onclick="generateName()" class="btn generate" id="generate">Generate Name</button>
32
+ </div>
33
+ </div>
34
+ <script src="{{url_for('static', filename='js/index.js')}}" type="text/javascript"></script>
35
+ </body>
36
+ </html>
ml-dev/train.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import pickle
3
+
4
+ # Character which represents the start and end of a word
5
+ TOKEN = '.'
6
+
7
+ # Reading the names into a list
8
+ words = open('data/names.txt','r').read().splitlines()
9
+
10
+ # Building a vocabulary out of all of the characters we have
11
+ vocab = sorted(list(set(''.join(words)) | {TOKEN}))
12
+
13
+ # Building a Bigram table which will hold the counts for each of the bigram
14
+ n = len(vocab)
15
+ N = torch.zeros((n,n), dtype = torch.int32)
16
+
17
+ # Defining a mapping for characters to and from integers
18
+ char_to_int = {char:i for i,char in enumerate(vocab)}
19
+ int_to_char = {value:key for key,value in char_to_int.items()}
20
+
21
+ # Populating the Bigram table (N) with counts
22
+ for word in words:
23
+ chars = [TOKEN] + list(word) + [TOKEN]
24
+ for ch1,ch2 in zip(chars,chars[1:]):
25
+ ix1 = char_to_int[ch1]
26
+ ix2 = char_to_int[ch2]
27
+ N[ix1,ix2] += 1
28
+
29
+ # Normalise the counts to represent probabilities
30
+ P = N.float()
31
+ P /= P.sum(1, keepdim = True)
32
+
33
+ # Open a file and use dump()
34
+ with open('model/bigrams.pkl', 'wb') as file:
35
+ pickle.dump([P,char_to_int,int_to_char], file)