Skip to content

Commit aae969d

Browse files
fix login err
1 parent 243d4c2 commit aae969d

11 files changed

Lines changed: 428 additions & 44 deletions

File tree

README.MD

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
# Career Advisor Chatbot (Prototype)
2+
AI Young Guru 2026
23

34
## Quick Start
45
- `cd backend`
56
- `npm install`
67
- `npm run setup-db`
78
- `npm run dev`
89

9-
## Frontend
10-
- `cd frontend`
11-
- `npm install`
12-
- `npm run dev`
13-
14-
## One-Click Run (Windows)
15-
- Double click `run.bat`
16-
17-
## Single Command (Root)
18-
- `npm install`
19-
- `npm run setup`
20-
- `npm run dev`
21-
2210
## Single URL (Serve Frontend From Backend)
2311
- `npm run build` (one-time)
2412
- `npm run start`
@@ -49,3 +37,14 @@ Base URL: `http://localhost:3001`
4937
## Notes
5038
- Uses SQLite. Configure `DB_PATH` if needed.
5139
- Scenario and matcher are rule-based for prototype speed.
40+
41+
## LLM API MODEL
42+
GPT OSS 120B
43+
See: https://console.groq.com/playground?model=openai/gpt-oss-120b
44+
45+
-----------------------------------------------------------------------------------
46+
Credit
47+
Team LLMagik
48+
* Phạm Khôi Nguyên @thisIsAnVariableOfACoder
49+
* Đinh Quang Minh
50+
* Vũ Minh Hoàng

assets/index-B-t5DAid.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/index-BRRsefk5.js

Lines changed: 313 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/dist/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
}(window.location));
1717
</script>
1818
<script src="./runtime-config.js"></script>
19-
<script type="module" crossorigin src="./assets/index-COrLJwNo.js"></script>
20-
<link rel="stylesheet" crossorigin href="./assets/index--5gsf48C.css">
19+
<script type="module" crossorigin src="./assets/index-BRRsefk5.js"></script>
20+
<link rel="stylesheet" crossorigin href="./assets/index-B-t5DAid.css">
2121
</head>
2222
<body>
2323
<div id="root"></div>

frontend/dist/runtime-config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
window.__API_BASE__ = window.__API_BASE__ || '';
2+
window.__IS_OFFLINE__ = window.__IS_OFFLINE__ ?? (!window.__API_BASE__ && /(^|\.)github\.io$/i.test(window.location.hostname));

frontend/public/runtime-config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
window.__API_BASE__ = window.__API_BASE__ || '';
2+
window.__IS_OFFLINE__ = window.__IS_OFFLINE__ ?? (!window.__API_BASE__ && /(^|\.)github\.io$/i.test(window.location.hostname));

frontend/src/api.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,41 @@
11
import { API_BASE, IS_OFFLINE } from './config';
22
import { offlineApi } from './offlineStore';
33

4+
function buildUrl(path) {
5+
const normalizedPath = String(path || '').startsWith('/') ? path : `/${path}`;
6+
if (!API_BASE) return normalizedPath;
7+
return `${API_BASE}${normalizedPath}`;
8+
}
9+
410
async function request(path, options = {}) {
5-
const res = await fetch(`${API_BASE}${path}`, options);
6-
return res.json();
11+
try {
12+
const res = await fetch(buildUrl(path), options);
13+
const text = await res.text();
14+
let json = null;
15+
16+
if (text) {
17+
try {
18+
json = JSON.parse(text);
19+
} catch {
20+
json = null;
21+
}
22+
}
23+
24+
if (!res.ok) {
25+
return {
26+
success: false,
27+
error: json?.error || `Request failed (${res.status})`
28+
};
29+
}
30+
31+
if (json && typeof json === 'object') return json;
32+
return { success: true, data: null };
33+
} catch {
34+
return {
35+
success: false,
36+
error: 'Khong the ket noi may chu. Vui long kiem tra API hoac thu lai.'
37+
};
38+
}
739
}
840

941
export const api = {

frontend/src/config.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,20 @@
1-
export const API_BASE = 'http://localhost:3001';
2-
export const IS_OFFLINE = false;
1+
function normalizeBaseUrl(url) {
2+
return String(url || '').trim().replace(/\/+$/, '');
3+
}
4+
5+
const runtimeApiBase = normalizeBaseUrl(
6+
typeof window !== 'undefined' ? window.__API_BASE__ : ''
7+
);
8+
const envApiBase = normalizeBaseUrl(import.meta.env.VITE_API_BASE);
9+
const hostname = typeof window !== 'undefined' ? window.location.hostname : '';
10+
const isGithubPages = /(^|\.)github\.io$/i.test(hostname);
11+
12+
const fallbackApiBase = isGithubPages ? '' : 'http://localhost:3001';
13+
const configuredApiBase = runtimeApiBase || envApiBase || fallbackApiBase;
14+
15+
const runtimeOffline = typeof window !== 'undefined' ? window.__IS_OFFLINE__ : undefined;
16+
const envOffline = import.meta.env.VITE_OFFLINE_MODE === 'true';
17+
const autoOfflineForGithub = isGithubPages && !configuredApiBase;
18+
19+
export const API_BASE = configuredApiBase;
20+
export const IS_OFFLINE = Boolean(runtimeOffline ?? envOffline ?? autoOfflineForGithub);

frontend/src/pages/Auth.jsx

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useState } from 'react';
22
import { useAuth } from '../context/AuthContext';
33
import { IS_OFFLINE } from '../config';
44
import { api } from '../api';
@@ -10,27 +10,41 @@ export default function Auth() {
1010
const [password, setPassword] = useState('');
1111
const [userType, setUserType] = useState('high_school');
1212
const [error, setError] = useState('');
13+
const [submitting, setSubmitting] = useState(false);
1314

1415
async function handleSubmit(e) {
1516
e.preventDefault();
17+
if (submitting) return;
18+
1619
setError('');
17-
const body = mode === 'login'
18-
? { email, password }
19-
: { email, password, user_type: userType };
20-
const json = mode === 'login'
21-
? await api.login(body)
22-
: await api.register(body);
23-
if (!json?.success) {
24-
setError(json?.error || 'Đăng nhập thất bại');
25-
return;
20+
setSubmitting(true);
21+
22+
try {
23+
const body = mode === 'login'
24+
? { email, password }
25+
: { email, password, user_type: userType };
26+
27+
const json = mode === 'login'
28+
? await api.login(body)
29+
: await api.register(body);
30+
31+
if (!json?.success) {
32+
setError(json?.error || 'Dang nhap that bai');
33+
return;
34+
}
35+
36+
login(json.data);
37+
} catch {
38+
setError('Dang nhap that bai. Vui long thu lai.');
39+
} finally {
40+
setSubmitting(false);
2641
}
27-
login(json.data);
2842
}
2943

3044
if (user) {
3145
return (
3246
<div className="max-w-md mx-auto rounded-2xl border border-[#E8E2D8] bg-white p-6 shadow-sm">
33-
<div className="text-lg font-semibold">Bạn đã đăng nhập</div>
47+
<div className="text-lg font-semibold">Ban da dang nhap</div>
3448
<div className="text-sm text-[#5B5B57] mt-2">{user.email}</div>
3549
</div>
3650
);
@@ -39,12 +53,12 @@ export default function Auth() {
3953
return (
4054
<div className="max-w-md mx-auto rounded-2xl border border-[#E8E2D8] bg-white p-6 shadow-sm">
4155
<div className="flex gap-2 mb-4">
42-
<button className={`px-3 py-2 rounded-lg text-sm ${mode === 'login' ? 'bg-[var(--c-primary)] text-white' : 'border'}`} onClick={() => setMode('login')}>Đăng nhập</button>
43-
<button className={`px-3 py-2 rounded-lg text-sm ${mode === 'register' ? 'bg-[var(--c-primary)] text-white' : 'border'}`} onClick={() => setMode('register')}>Tạo tài khoản</button>
56+
<button className={`px-3 py-2 rounded-lg text-sm ${mode === 'login' ? 'bg-[var(--c-primary)] text-white' : 'border'}`} onClick={() => setMode('login')}>Dang nhap</button>
57+
<button className={`px-3 py-2 rounded-lg text-sm ${mode === 'register' ? 'bg-[var(--c-primary)] text-white' : 'border'}`} onClick={() => setMode('register')}>Tao tai khoan</button>
4458
</div>
4559
{IS_OFFLINE && (
4660
<div className="mb-3 text-xs text-[#B91C1C]">
47-
Đang chạy chế độ demo offline. Tài khoản được lưu cục bộ trên trình duyệt.
61+
Dang chay che do demo offline. Tai khoan duoc luu cuc bo tren trinh duyet.
4862
</div>
4963
)}
5064
<form onSubmit={handleSubmit} className="space-y-3">
@@ -53,22 +67,26 @@ export default function Auth() {
5367
<input id="email" className="mt-1 w-full rounded-lg border border-[#E2D8C8] px-3 py-2 text-sm" value={email} onChange={(e) => setEmail(e.target.value)} />
5468
</div>
5569
<div>
56-
<label className="text-xs text-[#5B5B57]" htmlFor="password">Mật khẩu</label>
70+
<label className="text-xs text-[#5B5B57]" htmlFor="password">Mat khau</label>
5771
<input id="password" type="password" className="mt-1 w-full rounded-lg border border-[#E2D8C8] px-3 py-2 text-sm" value={password} onChange={(e) => setPassword(e.target.value)} />
5872
</div>
5973
{mode === 'register' && (
6074
<div>
61-
<label className="text-xs text-[#5B5B57]" htmlFor="userType">Loại tài khoản</label>
75+
<label className="text-xs text-[#5B5B57]" htmlFor="userType">Loai tai khoan</label>
6276
<select id="userType" className="mt-1 w-full rounded-lg border border-[#E2D8C8] px-3 py-2 text-sm" value={userType} onChange={(e) => setUserType(e.target.value)}>
63-
<option value="high_school">Học sinh</option>
64-
<option value="university">Sinh viên</option>
65-
<option value="professional">Người đi làm</option>
77+
<option value="high_school">Hoc sinh</option>
78+
<option value="university">Sinh vien</option>
79+
<option value="professional">Nguoi di lam</option>
6680
</select>
67-
<div className="mt-2 text-[11px] text-[#5B5B57]">Tài khoản admin là cố định.</div>
81+
<div className="mt-2 text-[11px] text-[#5B5B57]">Tai khoan admin la co dinh.</div>
6882
</div>
6983
)}
70-
<button className="w-full rounded-lg bg-[var(--c-primary)] py-2 text-white hover:opacity-90 transition" type="submit">
71-
{mode === 'login' ? 'Đăng nhập' : 'Tạo tài khoản'}
84+
<button
85+
className="w-full rounded-lg bg-[var(--c-primary)] py-2 text-white hover:opacity-90 transition disabled:cursor-not-allowed disabled:opacity-60"
86+
type="submit"
87+
disabled={submitting}
88+
>
89+
{mode === 'login' ? 'Dang nhap' : 'Tao tai khoan'}
7290
</button>
7391
</form>
7492
{error && <div className="mt-3 text-xs text-[#D64545]">{error}</div>}

index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
}(window.location));
1717
</script>
1818
<script src="./runtime-config.js"></script>
19-
<script type="module" crossorigin src="./assets/index-COrLJwNo.js"></script>
20-
<link rel="stylesheet" crossorigin href="./assets/index--5gsf48C.css">
19+
<script type="module" crossorigin src="./assets/index-BRRsefk5.js"></script>
20+
<link rel="stylesheet" crossorigin href="./assets/index-B-t5DAid.css">
2121
</head>
2222
<body>
2323
<div id="root"></div>

0 commit comments

Comments
 (0)