# -*- coding: utf-8 -*-
"""SERVER Agent-Lab — Web UI cho phòng Lab: nhập ảnh gỗ mộc + mẫu màu + yêu cầu → agent trả 2 phương án quy trình & công thức.

Chạy:  python server_lab.py            (cổng 8098, chỉ 127.0.0.1; truy cập ngoài qua Tailscale /lab)
Có 2 lớp bảo vệ: bind 127.0.0.1 + MẬT KHẨU dùng chung (đổi trong mat_khau.txt, mặc định sinh tự động).
Chạy được cả ở gốc (http://127.0.0.1:8098/) và dưới tiền tố (/lab/... qua Tailscale).
"""
import cgi, hashlib, hmac, html, io, json, mimetypes, os, re, secrets, shutil, sqlite3, sys, time, urllib.parse
from http.cookies import SimpleCookie
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

GOC = r'C:\Claw 2\Nghien cuu\Agent-Lab'
DB = os.path.join(GOC, 'lab.db')
VIEC = os.path.join(GOC, 'viec')
D_DB = r'C:\Claw 2\Nghien cuu\Du-an-D-Ho-so-vat-lieu\CSDLD.db'
CONG = 8098
MK_FILE = os.path.join(GOC, 'mat_khau.txt')
BI_MAT_FILE = os.path.join(GOC, 'bi_mat.txt')
os.makedirs(VIEC, exist_ok=True)


def _doc(p, mac_dinh=''):
    try:
        return open(p, encoding='utf-8').read().strip()
    except Exception:
        return mac_dinh


def mat_khau():
    mk = _doc(MK_FILE)
    if not mk:
        mk = 'lab-' + secrets.token_hex(3)
        open(MK_FILE, 'w', encoding='utf-8').write(mk)
    return mk


def bi_mat():
    b = _doc(BI_MAT_FILE)
    if not b:
        b = secrets.token_hex(16)
        open(BI_MAT_FILE, 'w', encoding='utf-8').write(b)
    return b


def ma_phien():
    return hmac.new(bi_mat().encode(), mat_khau().encode(), hashlib.sha256).hexdigest()[:32]


def db():
    """Mở DB qua worker_lab.noi_db() để luôn có schema + tự nâng cấp cột mới."""
    import importlib.util
    spec = importlib.util.spec_from_file_location('worker_lab_x', os.path.join(GOC, 'worker_lab.py'))
    m = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(m)
    return m.noi_db()


def ds_loai_go():
    try:
        c = sqlite3.connect('file:' + D_DB + '?mode=ro', uri=True).cursor()
        return [r[0] for r in c.execute('SELECT ten_vn FROM loai_go ORDER BY id').fetchall()]
    except Exception:
        return []


def ds_yeu_cau():
    try:
        c = sqlite3.connect('file:' + D_DB + '?mode=ro', uri=True).cursor()
        return [r[0] for r in c.execute('SELECT yeu_cau FROM yeu_cau_chat_luong ORDER BY id').fetchall()]
    except Exception:
        return []


def md_sang_html(md, tien_to=''):
    def inline(s):
        s = html.escape(s)
        s = re.sub(r'\*\*(.+?)\*\*', r'<b>\1</b>', s)
        s = re.sub(r'(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)', r'<i>\1</i>', s)
        s = re.sub(r'`(.+?)`', r'<code>\1</code>', s)
        s = re.sub(r'!\[(.*?)\]\((.+?)\)', r'<img alt="\1" src="tep?id=IDVIEC&d=\2">', s)
        return s

    ra, trong_bang, trong_ds, dau = [], False, False, True
    for l in md.split('\n'):
        if re.match(r'^\s*\|', l):
            o = [x.strip() for x in l.strip().strip('|').split('|')]
            if all(re.fullmatch(r':?-{2,}:?', x or '-') for x in o) and len(o) > 1:
                continue
            if not trong_bang:
                ra.append('<table class="b">')
                trong_bang, dau = True, True
            the = 'th' if dau else 'td'
            ra.append('<tr>' + ''.join('<%s>%s</%s>' % (the, inline(x), the) for x in o) + '</tr>')
            dau = False
            continue
        if trong_bang:
            ra.append('</table>')
            trong_bang = False
        m = re.match(r'^(#{1,6})\s+(.*)$', l)
        if m:
            n = len(m.group(1))
            ra.append('<h%d>%s</h%d>' % (n, inline(m.group(2)), n))
            continue
        if re.match(r'^\s*[-*]\s+', l):
            if not trong_ds:
                ra.append('<ul>')
                trong_ds = True
            ra.append('<li>%s</li>' % inline(re.sub(r'^\s*[-*]\s+', '', l)))
            continue
        if trong_ds:
            ra.append('</ul>')
            trong_ds = False
        if l.strip() in ('---', '***'):
            ra.append('<hr>')
        elif l.strip() == '':
            ra.append('')
        else:
            ra.append('<p>%s</p>' % inline(l))
    if trong_bang:
        ra.append('</table>')
    if trong_ds:
        ra.append('</ul>')
    return '\n'.join(ra)


CSS = """
:root{--nen:#f5f6f8;--the:#fff;--vien:#dfe3e8;--chu:#1c2733;--nhan:#0b6b3a}
*{box-sizing:border-box}body{margin:0;font:15px/1.55 'Segoe UI',Arial,sans-serif;background:var(--nen);color:var(--chu)}
header{background:#0b3d2c;color:#fff;padding:14px 20px}header b{font-size:17px}header span{opacity:.85;font-size:13px;margin-left:10px}
main{max-width:1000px;margin:18px auto;padding:0 14px}
.the{background:var(--the);border:1px solid var(--vien);border-radius:10px;padding:16px 18px;margin-bottom:16px}
label{display:block;font-weight:600;margin:10px 0 4px}
input[type=text],input[type=password],select,textarea{width:100%;padding:8px 10px;border:1px solid var(--vien);border-radius:7px;font:inherit;background:#fff}
textarea{min-height:70px}input[type=file]{padding:6px 0}
.bo{display:flex;gap:12px;flex-wrap:wrap}.bo>div{flex:1 1 300px}
button{background:var(--nhan);color:#fff;border:0;border-radius:8px;padding:11px 20px;font:inherit;font-weight:600;cursor:pointer;margin-top:14px}
button:disabled{opacity:.55;cursor:default}
small{color:#5d6b7a}
table.b{border-collapse:collapse;width:100%;margin:10px 0;font-size:14px}table.b td,table.b th{border:1px solid var(--vien);padding:6px 8px;text-align:left;vertical-align:top}
table.b th{background:#eef1f4}
.trang{display:inline-block;padding:2px 9px;border-radius:20px;font-size:12px;font-weight:700}
.cho{background:#fff3cd;color:#7a5b00}.chay{background:#cfe4ff;color:#0a3d75}.xong{background:#d6f4e0;color:#0b5c2e}.loi{background:#ffd9d9;color:#8a1414}
img{max-width:100%}
.bangviec{width:100%;border-collapse:collapse;font-size:14px}.bangviec td,.bangviec th{border-bottom:1px solid var(--vien);padding:7px 6px;text-align:left}
a{color:#0b6b3a}
"""


def trang_dang_nhap(tien_to='', loi=''):
    return '''<!doctype html><html lang="vi"><meta charset="utf-8"><title>Agent-Lab · Đăng nhập</title>
<base href="./"><script>document.addEventListener("DOMContentLoaded",function(){var B=(location.pathname.indexOf("/lab")===0)?"/lab/":"/";var b=document.querySelector("base");if(b&&b.getAttribute("href")!==B)b.href=B;});</script>
<style>%s</style><header><b>AGENT-LAB</b><span>Đề nghị quy trình sơn &amp; công thức pha màu</span></header>
<main><div class="the" style="max-width:420px">
<h3 style="margin-top:0">Đăng nhập</h3>
%s
<form method="post" action="dang-nhap">
<label>Mật khẩu dùng chung của phòng Lab</label>
<input type="password" name="mat_khau" autofocus required>
<button type="submit">Vào hệ thống</button>
</form>
<p><small>Liên hệ anh Minh (phòng Kỹ thuật) để lấy mật khẩu.</small></p>
</div></main></html>''' % (CSS, ('<p style="color:#8a1414"><b>%s</b></p>' % html.escape(loi)) if loi else '')


def trang_dau(tien_to=''):
    lo = ''.join('<option value="%s">' % html.escape(x) for x in ds_loai_go())
    yc = ''.join('<option value="%s">' % html.escape(x) for x in ds_yeu_cau())
    gus = ['5–10 GU (mờ)', '25–35 GU (satin)', '60–80 GU (bóng)', '> 90 GU (bóng cao)']
    return '''<!doctype html><html lang="vi"><meta charset="utf-8"><title>Agent-Lab · Đề nghị quy trình &amp; công thức sơn</title>
<base href="./"><script>document.addEventListener("DOMContentLoaded",function(){var B=(location.pathname.indexOf("/lab")===0)?"/lab/":"/";var b=document.querySelector("base");if(b&&b.getAttribute("href")!==B)b.href=B;});</script>
<style>%s</style>
<header><b>AGENT-LAB</b><span>Đề nghị quy trình sơn &amp; công thức pha màu — kính gửi bộ phận kỹ thuật</span></header>
<main>
<div class="the">
<p><b>Cách dùng:</b> chụp <b>ảnh gỗ mộc</b> và <b>ảnh mẫu màu cần đạt</b> trong cùng một buổi, đủ sáng, có <b>thẻ chuẩn màu</b> trong khung nếu có; điền đủ các ô bên dưới rồi bấm Gửi. Agent sẽ trả về tối đa <b>2 phương án</b> quy trình + công thức pha màu cho từng công đoạn (khoảng 4–6 phút), kèm file Word để in.</p>
<p><small>Kết quả là <b>đề nghị</b> của phòng Lab — vẫn phải làm <b>thẻ mẫu xác nhận</b> trước khi áp cho chuyền. · <a href="danh-sach">Danh sách việc</a></small></p>
</div>
<form class="the" id="f" onsubmit="return gui(event)">
<div class="bo">
  <div><label>Người gửi / bộ phận</label><input type="text" name="nguoi_gui" required placeholder="VD: Lab – Hùng"></div>
  <div><label>Loại gỗ / nền</label><input type="text" name="loai_go" list="dslo" required placeholder="VD: Cao su ghép thanh">
    <datalist id="dslo">%s</datalist></div>
</div>
<div class="bo">
  <div><label>Đặc tính gỗ (quan sát được)</label><textarea name="dac_tinh" placeholder="VD: phôi mới chà #240, mạch hở, có vệt dầu ở mặt, thớ xoáy"></textarea></div>
  <div><label>Yêu cầu chất lượng của khách</label><input type="text" name="yeu_cau" list="dsyc" placeholder="VD: chống ẩm tủ bếp + chống ố vàng">
    <datalist id="dsyc">%s</datalist></div>
</div>
<div class="bo">
  <div><label>Độ bóng yêu cầu</label><select name="do_bong">%s</select></div>
  <div><label>Ghi chú thêm (tùy chọn)</label><input type="text" name="ghi_chu" placeholder="VD: khách cần giữ vân tự nhiên, không sơn bóng"></div>
</div>
<div class="bo">
  <div><label>Email nhận kết quả (nếu điền: agent tự gửi file Word vào email này khi xong)</label>
    <input type="text" name="email" placeholder="VD: lab@btchem.vn — để trống nếu chỉ xem trên web"></div>
</div>
<div class="bo">
  <div><label>Ảnh GỖ MỘC (bắt buộc) *</label><input type="file" name="anh_moc" accept="image/*" required></div>
  <div><label>Ảnh MẪU MÀU cần đạt (bắt buộc) *</label><input type="file" name="anh_mau" accept="image/*" required></div>
</div>
<button id="nut" type="submit">Gửi cho agent</button>
<p id="tb"><small>Thiếu ảnh gỗ mộc thì agent sẽ ghi rõ “THIẾU ẢNH GỖ MỘC — đề nghị cung cấp” và tự đưa giả định theo loài gỗ.</small></p>
</form>
<div class="the" id="ket" style="display:none"></div>
</main>
<script>
const B='';
function gui(e){e.preventDefault();const f=document.getElementById('f'),nut=document.getElementById('nut');
 nut.disabled=true;nut.textContent='Đang gửi…';const fd=new FormData(f);
 fetch(B+'gui',{method:'POST',body:fd}).then(r=>r.json()).then(d=>{
   if(!d.id){document.getElementById('tb').innerHTML='<b style="color:#8a1414">Lỗi: '+JSON.stringify(d)+'</b>';nut.disabled=false;nut.textContent='Gửi cho agent';return;}
   nut.textContent='Đã gửi — agent đang chạy (việc #'+d.id+')';theoDoi(d.id);}).catch(err=>{document.getElementById('tb').textContent='Lỗi mạng: '+err;nut.disabled=false;});
 return false;}
function theoDoi(id){fetch(B+'trang-thai?id='+id).then(r=>r.json()).then(d=>{
  const t=document.getElementById('nut');
  let mail='';
  if(d.email){mail = d.email_luc ? ' · Đã gửi email tới <b>'+d.email+'</b>'
                    : (d.email_loi ? ' · <span style="color:#8a1414">Lỗi gửi email: '+d.email_loi+'</span>'
                                   : ' · sẽ gửi email tới <b>'+d.email+'</b> khi xong');}
  if(d.trang_thai=='cho'||d.trang_thai=='dang_chay'||d.trang_thai=='moi'){t.textContent='Agent đang chạy… ('+d.trang_thai+')';setTimeout(()=>theoDoi(id),6000);}
  else if(d.trang_thai=='xong'){t.textContent='XONG — xem kết quả bên dưới';document.getElementById('ket').style.display='block';
    document.getElementById('ket').innerHTML='<p><b>Việc #'+id+' đã xong.</b> <a href="'+B+'ket-qua?id='+id+'">Xem kết quả chi tiết</a> · <a href="'+B+'tai-docx?id='+id+'">Tải file Word</a>'+mail+'</p>';ketQua(id);}
  else{t.textContent='Việc #'+id+' lỗi';document.getElementById('ket').style.display='block';
    document.getElementById('ket').innerHTML='<p style="color:#8a1414"><b>Việc #'+id+' lỗi:</b> '+(d.loi||'')+'</p>';}});}
function ketQua(id){fetch(B+'ket-qua?id='+id+'&than=1').then(r=>r.text()).then(h=>{document.getElementById('ket').innerHTML=h+'<p><a href="'+B+'tai-docx?id='+id+'">⬇ Tải file Word</a> · <a href="./">Gửi việc mới</a> · <a href="'+B+'danh-sach">Danh sách việc</a></p>';});}
</script></html>''' % (CSS, lo, yc, ''.join('<option>%s</option>' % x for x in gus))


class H(BaseHTTPRequestHandler):
    server_version = 'AgentLab/1.1'

    def log_message(self, fmt, *a):
        pass

    def _tach(self):
        """Tách tiền tố /lab nếu truy cập qua Tailscale; trả (tiền_tố, đường_dẫn)."""
        u = urllib.parse.urlparse(self.path)
        duong = u.path
        if duong.startswith('/lab'):
            return '/lab', (duong[4:] or '/')
        return '', duong

    def _cho_phep(self):
        c = SimpleCookie(self.headers.get('Cookie') or '')
        m = c.get('alab')
        return bool(m and hmac.compare_digest(m.value, ma_phien()))

    def _gui(self, ma, nd, loai='text/html; charset=utf-8'):
        self.send_response(ma)
        self.send_header('Content-Type', loai)
        self.send_header('Content-Length', str(len(nd)))
        self.send_header('Cache-Control', 'no-store, must-revalidate')
        self.send_header('Pragma', 'no-cache')
        self.end_headers()
        self.wfile.write(nd)

    def _json(self, obj):
        self._gui(200, json.dumps(obj, ensure_ascii=False).encode('utf-8'), 'application/json; charset=utf-8')

    def do_GET(self):
        tien_to, duong = self._tach()
        q = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
        if not self._cho_phep():
            return self._gui(200, trang_dang_nhap(tien_to).encode('utf-8'))
        if duong in ('/', ''):
            self._gui(200, trang_dau(tien_to).encode('utf-8'))
        elif duong == '/thoat':
            self.send_response(302)
            self.send_header('Set-Cookie', 'alab=; Path=/; Max-Age=0')
            self.send_header('Location', tien_to + '/')
            self.end_headers()
        elif duong == '/trang-thai':
            con = db()
            r = con.execute('SELECT trang_thai,loi,email,email_luc,email_loi FROM viec WHERE id=?', (q.get('id', ['0'])[0],)).fetchone()
            if not r:
                self._json({'trang_thai': 'khong-thay', 'loi': ''})
            else:
                self._json({'trang_thai': r[0], 'loi': (r[1] or '')[:400], 'email': r[2] or '',
                            'email_luc': r[3] or '', 'email_loi': (r[4] or '')[:300]})
        elif duong == '/ket-qua':
            con = db()
            r = con.execute('SELECT trang_thai,ket_qua,phan_tich,docx FROM viec WHERE id=?', (q.get('id', ['0'])[0],)).fetchone()
            if not r:
                return self._gui(404, b'<h3>Khong thay viec</h3>')
            if r[0] != 'xong':
                return self._gui(200, ('<p>Việc đang ở trạng thái: <b>%s</b></p>' % r[0]).encode('utf-8'))
            md = open(r[1], encoding='utf-8').read() if r[1] and os.path.exists(r[1]) else '(không có kết quả)'
            body = md_sang_html(md, tien_to).replace('IDVIEC', q.get('id', ['0'])[0])
            dau = ('<style>%s</style><header><b>AGENT-LAB · KẾT QUẢ VIỆC #%s</b>'
                   '<span><a style="color:#cfe8d8" href="./">gửi việc mới</a> · <a style="color:#cfe8d8" href="danh-sach">danh sách</a></span></header>'
                   '<main><div class="the">' % (CSS, q.get('id', ['0'])[0])) if 'than=1' not in q else \
                  ('<style>%s</style><div class="the">' % CSS)
            self._gui(200, (dau + body + '</div></main>').encode('utf-8'))
        elif duong == '/tep':
            con = db()
            r = con.execute('SELECT thu_muc FROM viec WHERE id=?', (q.get('id', ['0'])[0],)).fetchone()
            if not r:
                return self._gui(404, b'x')
            duong_tep = os.path.normpath(os.path.join(r[0], q.get('d', [''])[0]))
            if not duong_tep.startswith(os.path.normpath(r[0])) or not os.path.exists(duong_tep):
                return self._gui(404, b'x')
            loai = mimetypes.guess_type(duong_tep)[0] or 'application/octet-stream'
            self._gui(200, open(duong_tep, 'rb').read(), loai)
        elif duong == '/tai-docx':
            con = db()
            r = con.execute('SELECT docx FROM viec WHERE id=?', (q.get('id', ['0'])[0],)).fetchone()
            if not r or not r[0] or not os.path.exists(r[0]):
                return self._gui(404, b'Khong co file')
            nd = open(r[0], 'rb').read()
            self.send_response(200)
            self.send_header('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
            self.send_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(r[0]))
            self.send_header('Content-Length', str(len(nd)))
            self.end_headers()
            self.wfile.write(nd)
        elif duong == '/danh-sach':
            con = db()
            hang = ''.join(
                '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td><span class="trang %s">%s</span></td><td>%s</td><td>%s</td></tr>'
                % (r[0], r[1][:16], html.escape(r[2] or ''), html.escape(r[3] or ''), r[4], r[4],
                   ('<a href="ket-qua?id=%s">xem</a>' % r[0]) if r[4] == 'xong' else '',
                   ('<a href="tai-docx?id=%s">Word</a>' % r[0]) if r[4] == 'xong' else '')
                for r in con.execute('SELECT id,tao_luc,nguoi_gui,loai_go,trang_thai,ket_thuc,giay FROM viec ORDER BY id DESC LIMIT 100'))
            self._gui(200, ('<style>%s</style><header><b>AGENT-LAB · DANH SÁCH VIỆC</b></header><main><div class="the">'
                            '<base href="./"><script>document.addEventListener("DOMContentLoaded",function(){var B=(location.pathname.indexOf("/lab")===0)?"/lab/":"/";var b=document.querySelector("base");if(b&&b.getAttribute("href")!==B)b.href=B;});</script>'
                            '<table class="bangviec"><tr><th>#</th><th>Lúc</th><th>Người gửi</th><th>Nền gỗ</th><th>Trạng thái</th><th></th><th></th></tr>%s</table>'
                            '<p><a href="./">← Gửi việc mới</a> · <a href="thoat">Thoát</a></p></div></main>'
                            % (CSS, hang)).encode('utf-8'))
        else:
            self._gui(404, b'Khong co')

    def do_POST(self):
        tien_to, duong = self._tach()
        if duong == '/dang-nhap':
            dai = int(self.headers.get('Content-Length') or 0)
            fs = cgi.FieldStorage(fp=io.BytesIO(self.rfile.read(dai)), headers=self.headers,
                                  environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('Content-Type', '')})
            if fs.getvalue('mat_khau', '') == mat_khau():
                self.send_response(302)
                self.send_header('Set-Cookie', 'alab=%s; Path=/; Max-Age=43200; HttpOnly; SameSite=Lax' % ma_phien())
                self.send_header('Location', './')
                self.end_headers()
                return
            return self._gui(200, trang_dang_nhap(tien_to, 'Sai mật khẩu — thử lại.').encode('utf-8'))
        if not self._cho_phep():
            return self._gui(403, b'Chua dang nhap')
        if duong == '/gui':
            dai = int(self.headers.get('Content-Length') or 0)
            if dai > 60 * 1024 * 1024:
                return self._json({'loi': 'ảnh quá lớn (>60MB)'})
            fs = cgi.FieldStorage(fp=io.BytesIO(self.rfile.read(dai)), headers=self.headers,
                                  environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('Content-Type', '')})
            con = db()
            cur = con.execute("INSERT INTO viec (tao_luc,trang_thai,nguoi_gui,loai_go,dac_tinh,yeu_cau,do_bong,ghi_chu,email) VALUES (?,?,?,?,?,?,?,?,?)",
                              (time.strftime('%Y-%m-%d %H:%M:%S'), 'cho', fs.getvalue('nguoi_gui', ''), fs.getvalue('loai_go', ''),
                               fs.getvalue('dac_tinh', ''), fs.getvalue('yeu_cau', ''), fs.getvalue('do_bong', ''),
                               fs.getvalue('ghi_chu', ''), (fs.getvalue('email', '') or '').strip()))
            vid = cur.lastrowid
            # cảnh báo nếu dữ liệu vào đã bị lỗi ký tự (thường do công cụ gửi sai bảng mã)
            for cot, gt in (('nguoi_gui', fs.getvalue('nguoi_gui', '')), ('loai_go', fs.getvalue('loai_go', '')),
                            ('dac_tinh', fs.getvalue('dac_tinh', '')), ('yeu_cau', fs.getvalue('yeu_cau', '')),
                            ('ghi_chu', fs.getvalue('ghi_chu', ''))):
                if '\ufffd' in gt:
                    print('  ⚠️  [CẢNH BÁO KÝ TỰ] việc #%d · ô %s có ký tự lỗi U+FFFD — công cụ gửi có thể dùng sai bảng mã '
                          '(dùng trình duyệt hoặc _gui_viec.py)' % (vid, cot))
            d = os.path.join(VIEC, 'V%04d_%s' % (vid, time.strftime('%d%m')))
            os.makedirs(os.path.join(d, 'anh_goc'), exist_ok=True)
            duong_anh = {}
            for ten in ('anh_moc', 'anh_mau'):
                if ten in fs and fs[ten].filename:
                    p = os.path.join(d, 'anh_goc', os.path.basename(fs[ten].filename))
                    open(p, 'wb').write(fs[ten].file.read())
                    duong_anh[ten] = p
            con.execute('UPDATE viec SET thu_muc=?, anh_moc=?, anh_mau=? WHERE id=?',
                        (d, duong_anh.get('anh_moc'), duong_anh.get('anh_mau'), vid))
            con.commit()
            print('[%s] việc #%d từ %s | %s' % (time.strftime('%H:%M:%S'), vid, fs.getvalue('nguoi_gui', ''), fs.getvalue('loai_go', '')))
            return self._json({'id': vid})
        if duong == '/phan-hoi':
            dai = int(self.headers.get('Content-Length') or 0)
            fs = cgi.FieldStorage(fp=io.BytesIO(self.rfile.read(dai)), headers=self.headers,
                                  environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('Content-Type', '')})
            con = db()
            con.execute('INSERT INTO phan_hoi (viec_id,ket_qua_thu,ghi_chu,luc) VALUES (?,?,?,?)',
                        (fs.getvalue('viec_id', ''), fs.getvalue('ket_qua_thu', ''), fs.getvalue('ghi_chu', ''), time.strftime('%Y-%m-%d %H:%M:%S')))
            con.commit()
            return self._json({'ok': 1})
        self._gui(404, b'Khong co')


if __name__ == '__main__':
    print('Agent-Lab Web UI: http://127.0.0.1:%d  (mật khẩu: %s)' % (CONG, mat_khau()))
    ThreadingHTTPServer(('127.0.0.1', CONG), H).serve_forever()
