kootaeng2 commited on
Commit
fd1e3ee
ยท
1 Parent(s): c98f885

Feat: Implement user login and registration system

Browse files
src/app.py CHANGED
@@ -1,24 +1,56 @@
1
- # app.py (์ˆ˜์ • ํ›„ ์ตœ์ข… ๋ฒ„์ „)
2
 
3
- from flask import Flask, render_template, request, jsonify
4
- # 'ํ˜„์žฌ ํด๋”์— ์žˆ๋Š”' ์ด๋ผ๋Š” ์˜๋ฏธ๋กœ ํŒŒ์ผ ์ด๋ฆ„ ์•ž์— ์ (.)์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
 
 
 
 
 
 
 
 
5
  from .emotion_engine import load_emotion_classifier, predict_emotion
6
  from .recommender import Recommender
7
- import random
8
 
 
 
 
9
  app = Flask(__name__)
10
 
11
- # --- (์ดํ•˜ ๋‚˜๋จธ์ง€ ์ฝ”๋“œ๋Š” ๋ชจ๋‘ ๋™์ผ) ---
12
- print("AI ์ฑ—๋ด‡ ์„œ๋ฒ„๋ฅผ ์ค€๋น„ ์ค‘์ž…๋‹ˆ๋‹ค...")
13
- # ...
 
 
 
14
 
15
- app = Flask(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
 
 
 
 
 
 
 
17
  print("AI ์ฑ—๋ด‡ ์„œ๋ฒ„๋ฅผ ์ค€๋น„ ์ค‘์ž…๋‹ˆ๋‹ค...")
18
- # ์„œ๋ฒ„๊ฐ€ ์‹œ์ž‘๋  ๋•Œ AI ์—”์ง„๊ณผ ์ถ”์ฒœ๊ธฐ๋ฅผ ๊ฐ๊ฐ ํ•œ ๋ฒˆ์”ฉ๋งŒ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
19
  emotion_classifier = load_emotion_classifier()
20
  recommender = Recommender()
21
- # ์›นํŽ˜์ด์ง€์— ๊ฐ์ •๋ณ„ ์ด๋ชจ์ง€๋ฅผ ๋ณด๋‚ด์ฃผ๊ธฐ ์œ„ํ•œ ๋”•์…”๋„ˆ๋ฆฌ์ž…๋‹ˆ๋‹ค.
22
  emotion_emoji_map = {
23
  '๊ธฐ์จ': '๐Ÿ˜„', 'ํ–‰๋ณต': '๐Ÿ˜Š', '์‚ฌ๋ž‘': 'โค๏ธ',
24
  '๋ถˆ์•ˆ': '๐Ÿ˜Ÿ', '์Šฌํ””': '๐Ÿ˜ข', '์ƒ์ฒ˜': '๐Ÿ’”',
@@ -28,32 +60,80 @@ emotion_emoji_map = {
28
  }
29
  print("โœ… AI ์ฑ—๋ด‡ ์„œ๋ฒ„๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  @app.route("/")
32
  def home():
33
- """์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฒ˜์Œ ์ ‘์†ํ–ˆ์„ ๋•Œ ๋ณด์—ฌ์ค„ ๋ฉ”์ธ ํŽ˜์ด์ง€๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค."""
34
- # templates ํด๋” ์•ˆ์— ์žˆ๋Š” emotion_homepage.html ํŒŒ์ผ์„ ํ™”๋ฉด์— ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
35
- return render_template("emotion_homepage.html")
 
 
 
36
 
37
  @app.route("/api/recommend", methods=["POST"])
38
  def api_recommend():
39
- """์›นํŽ˜์ด์ง€์˜ '์ถ”์ฒœ ๋ฐ›๊ธฐ' ๋ฒ„ํŠผ ํด๋ฆญ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค."""
40
- # 1. ์›นํŽ˜์ด์ง€๋กœ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์ผ๊ธฐ ๋‚ด์šฉ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.
 
 
 
41
  user_diary = request.json.get("diary")
42
  if not user_diary:
43
  return jsonify({"error": "์ผ๊ธฐ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค."}), 400
44
 
45
- # 2. emotion_engine์„ ์‚ฌ์šฉํ•ด ๊ฐ์ •์„ ์˜ˆ์ธกํ•ฉ๋‹ˆ๋‹ค.
46
  predicted_emotion = predict_emotion(emotion_classifier, user_diary)
47
 
48
- # 3. recommender๋ฅผ ์‚ฌ์šฉํ•ด '์ˆ˜์šฉ'๊ณผ '์ „ํ™˜' ์ถ”์ฒœ์„ ๋ชจ๋‘ ๋ฐ›์Šต๋‹ˆ๋‹ค.
49
  accept_recs = recommender.recommend(predicted_emotion, "์ˆ˜์šฉ")
50
  change_recs = recommender.recommend(predicted_emotion, "์ „ํ™˜")
51
 
52
- # 4. ๊ฐ ์ถ”์ฒœ ๋ชฉ๋ก์—์„œ ๋žœ๋ค์œผ๋กœ ํ•˜๋‚˜์”ฉ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. (๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„)
53
  accept_choice = random.choice(accept_recs) if accept_recs else "์ถ”์ฒœ ์—†์Œ"
54
  change_choice = random.choice(change_recs) if change_recs else "์ถ”์ฒœ ์—†์Œ"
55
 
56
- # 5. ์›นํŽ˜์ด์ง€์— ๋ณด์—ฌ์ค„ ์ตœ์ข… ํ…์ŠคํŠธ๋ฅผ ์กฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.
57
  recommendation_text = (
58
  f"<b>[ ์ด ๊ฐ์ •์„ ๋” ๊นŠ์ด ๋А๋ผ๊ณ  ์‹ถ๋‹ค๋ฉด... (์ˆ˜์šฉ) ]</b><br>"
59
  f"โ€ข {accept_choice}<br><br>"
@@ -61,7 +141,6 @@ def api_recommend():
61
  f"โ€ข {change_choice}"
62
  )
63
 
64
- # 6. ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ JSON ํ˜•ํƒœ๋กœ ์›นํŽ˜์ด์ง€์— ๋Œ๋ ค์ค๋‹ˆ๋‹ค.
65
  response_data = {
66
  "emotion": predicted_emotion,
67
  "emoji": emotion_emoji_map.get(predicted_emotion, '๐Ÿค”'),
@@ -69,5 +148,10 @@ def api_recommend():
69
  }
70
  return jsonify(response_data)
71
 
 
 
 
72
  if __name__ == "__main__":
 
 
73
  app.run(debug=True)
 
1
+ # src/app.py (์ตœ์ข… ํ†ตํ•ฉ ๋ฒ„์ „)
2
 
3
+ # ---------------------------------
4
+ # 1. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ๋ชจ๋“ˆ ์ž„ํฌํŠธ
5
+ # ---------------------------------
6
+ import os
7
+ import random
8
+ from flask import Flask, render_template, request, jsonify, session, redirect, url_for
9
+ from flask_sqlalchemy import SQLAlchemy
10
+ from werkzeug.security import generate_password_hash, check_password_hash
11
+
12
+ # 'ํ˜„์žฌ ํด๋”์— ์žˆ๋Š”' ๋ชจ๋“ˆ๋“ค์„ ์ƒ๋Œ€ ๊ฒฝ๋กœ๋กœ ์ž„ํฌํŠธ
13
  from .emotion_engine import load_emotion_classifier, predict_emotion
14
  from .recommender import Recommender
 
15
 
16
+ # ---------------------------------
17
+ # 2. Flask ์•ฑ ์ดˆ๊ธฐํ™” ๋ฐ ๊ธฐ๋ณธ ์„ค์ •
18
+ # ---------------------------------
19
  app = Flask(__name__)
20
 
21
+ # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ •
22
+ basedir = os.path.abspath(os.path.dirname(__file__))
23
+ app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'database.db')
24
+ app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
25
+ # ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์‹œํฌ๋ฆฟ ํ‚ค (โš ๏ธ ์‹ค์ œ ๋ฐฐํฌ ์‹œ์—๋Š” ๋” ๋ณต์žกํ•œ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”!)
26
+ app.config['SECRET_KEY'] = 'dev-secret-key-for-flask-session'
27
 
28
+ # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ์ฒด ์ƒ์„ฑ
29
+ db = SQLAlchemy(app)
30
+
31
+ # ---------------------------------
32
+ # 3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชจ๋ธ ์ •์˜
33
+ # ---------------------------------
34
+ class User(db.Model):
35
+ """์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ์„ ์œ„ํ•œ ๋ชจ๋ธ"""
36
+ id = db.Column(db.Integer, primary_key=True)
37
+ username = db.Column(db.String(80), unique=True, nullable=False)
38
+ password_hash = db.Column(db.String(128), nullable=False)
39
+
40
+ def set_password(self, password):
41
+ """๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•ด์‹ฑํ•˜์—ฌ ์ €์žฅ"""
42
+ self.password_hash = generate_password_hash(password)
43
 
44
+ def check_password(self, password):
45
+ """ํ•ด์‹œ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ์ž…๋ ฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋น„๊ต"""
46
+ return check_password_hash(self.password_hash, password)
47
+
48
+ # ---------------------------------
49
+ # 4. AI ์—”์ง„ ๋ฐ ์ถ”์ฒœ๊ธฐ ์ดˆ๊ธฐ ๋กœ๋”ฉ
50
+ # ---------------------------------
51
  print("AI ์ฑ—๋ด‡ ์„œ๋ฒ„๋ฅผ ์ค€๋น„ ์ค‘์ž…๋‹ˆ๋‹ค...")
 
52
  emotion_classifier = load_emotion_classifier()
53
  recommender = Recommender()
 
54
  emotion_emoji_map = {
55
  '๊ธฐ์จ': '๐Ÿ˜„', 'ํ–‰๋ณต': '๐Ÿ˜Š', '์‚ฌ๋ž‘': 'โค๏ธ',
56
  '๋ถˆ์•ˆ': '๐Ÿ˜Ÿ', '์Šฌํ””': '๐Ÿ˜ข', '์ƒ์ฒ˜': '๐Ÿ’”',
 
60
  }
61
  print("โœ… AI ์ฑ—๋ด‡ ์„œ๋ฒ„๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
62
 
63
+ # ---------------------------------
64
+ # 5. ๋ผ์šฐํŠธ(Routes) ์ •์˜
65
+ # ---------------------------------
66
+
67
+ # --- ์‚ฌ์šฉ์ž ์ธ์ฆ ๊ด€๋ จ ๋ผ์šฐํŠธ ---
68
+ @app.route('/signup', methods=['GET', 'POST'])
69
+ def signup():
70
+ if request.method == 'POST':
71
+ username = request.form['username']
72
+ password = request.form['password']
73
+
74
+ if User.query.filter_by(username=username).first():
75
+ return "์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„์ž…๋‹ˆ๋‹ค."
76
+
77
+ new_user = User(username=username)
78
+ new_user.set_password(password)
79
+ db.session.add(new_user)
80
+ db.session.commit()
81
+
82
+ return redirect(url_for('login'))
83
+
84
+ return render_template('signup.html')
85
+
86
+ @app.route('/login', methods=['GET', 'POST'])
87
+ def login():
88
+ if request.method == 'POST':
89
+ username = request.form['username']
90
+ password = request.form['password']
91
+ user = User.query.filter_by(username=username).first()
92
+
93
+ if user and user.check_password(password):
94
+ session['user_id'] = user.id
95
+ session['username'] = user.username
96
+ return redirect(url_for('home'))
97
+ else:
98
+ return "๋กœ๊ทธ์ธ ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค."
99
+
100
+ return render_template('login.html')
101
+
102
+ @app.route('/logout')
103
+ def logout():
104
+ session.pop('user_id', None)
105
+ session.pop('username', None)
106
+ return redirect(url_for('login'))
107
+
108
+ # --- ๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ผ์šฐํŠธ ---
109
  @app.route("/")
110
  def home():
111
+ """๋ฉ”์ธ ํŽ˜์ด์ง€. ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™."""
112
+ if 'user_id' not in session:
113
+ return redirect(url_for('login'))
114
+
115
+ # ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„์„ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ „๋‹ฌ
116
+ return render_template("emotion_homepage.html", username=session.get('username'))
117
 
118
  @app.route("/api/recommend", methods=["POST"])
119
  def api_recommend():
120
+ """์ผ๊ธฐ ๋ถ„์„ ๋ฐ ์ฝ˜ํ…์ธ  ์ถ”์ฒœ API."""
121
+ # API ์š”์ฒญ๋„ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๋งŒ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ฒดํฌ
122
+ if 'user_id' not in session:
123
+ return jsonify({"error": "๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค."}), 401
124
+
125
  user_diary = request.json.get("diary")
126
  if not user_diary:
127
  return jsonify({"error": "์ผ๊ธฐ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค."}), 400
128
 
 
129
  predicted_emotion = predict_emotion(emotion_classifier, user_diary)
130
 
 
131
  accept_recs = recommender.recommend(predicted_emotion, "์ˆ˜์šฉ")
132
  change_recs = recommender.recommend(predicted_emotion, "์ „ํ™˜")
133
 
 
134
  accept_choice = random.choice(accept_recs) if accept_recs else "์ถ”์ฒœ ์—†์Œ"
135
  change_choice = random.choice(change_recs) if change_recs else "์ถ”์ฒœ ์—†์Œ"
136
 
 
137
  recommendation_text = (
138
  f"<b>[ ์ด ๊ฐ์ •์„ ๋” ๊นŠ์ด ๋А๋ผ๊ณ  ์‹ถ๋‹ค๋ฉด... (์ˆ˜์šฉ) ]</b><br>"
139
  f"โ€ข {accept_choice}<br><br>"
 
141
  f"โ€ข {change_choice}"
142
  )
143
 
 
144
  response_data = {
145
  "emotion": predicted_emotion,
146
  "emoji": emotion_emoji_map.get(predicted_emotion, '๐Ÿค”'),
 
148
  }
149
  return jsonify(response_data)
150
 
151
+ # ---------------------------------
152
+ # 6. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰
153
+ # ---------------------------------
154
  if __name__ == "__main__":
155
+ with app.app_context():
156
+ db.create_all() # (์„ ํƒ์‚ฌํ•ญ) ์•ฑ ์‹คํ–‰ ์‹œ DB๊ฐ€ ์—†์œผ๋ฉด ์ž๋™์œผ๋กœ ์ƒ์„ฑ.
157
  app.run(debug=True)
src/database.db ADDED
Binary file (12.3 kB). View file
 
src/templates/login.html ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>๋กœ๊ทธ์ธ</title>
6
+ </head>
7
+ <body>
8
+ <h1>๋กœ๊ทธ์ธ</h1>
9
+ <form method="post">
10
+ <label for="username">์‚ฌ์šฉ์ž ์ด๋ฆ„:</label>
11
+ <input type="text" id="username" name="username" required>
12
+ <br><br>
13
+ <label for="password">๋น„๋ฐ€๋ฒˆํ˜ธ:</label>
14
+ <input type="password" id="password" name="password" required>
15
+ <br><br>
16
+ <button type="submit">๋กœ๊ทธ์ธ</button>
17
+ </form>
18
+ <p>๊ณ„์ •์ด ์—†์œผ์‹ ๊ฐ€์š”? <a href="/signup">ํšŒ์›๊ฐ€์ž…</a></p>
19
+ </body>
20
+ </html>
src/templates/signup.html ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>ํšŒ์›๊ฐ€์ž…</title>
6
+ </head>
7
+ <body>
8
+ <h1>ํšŒ์›๊ฐ€์ž…</h1>
9
+ <form method="post">
10
+ <label for="username">์‚ฌ์šฉ์ž ์ด๋ฆ„:</label>
11
+ <input type="text" id="username" name="username" required>
12
+ <br><br>
13
+ <label for="password">๋น„๋ฐ€๋ฒˆํ˜ธ:</label>
14
+ <input type="password" id="password" name="password" required>
15
+ <br><br>
16
+ <button type="submit">ํšŒ์›๊ฐ€์ž…</button>
17
+ </form>
18
+ <p>์ด๋ฏธ ๊ณ„์ •์ด ์žˆ์œผ์‹ ๊ฐ€์š”? <a href="/login">๋กœ๊ทธ์ธ</a></p>
19
+ </body>
20
+ </html>