sciagent code + Gitea Actions CI/CD
CI/CD / backend (push) Failing after 2m8s
CI/CD / frontend (push) Failing after 1m40s
CI/CD / deploy (push) Has been skipped

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Thinh Lam
2026-06-30 09:38:30 +07:00
commit 688fac73e9
1167 changed files with 158244 additions and 0 deletions
+327
View File
@@ -0,0 +1,327 @@
# -*- coding: utf-8 -*-
"""
Seed 10 medical initiatives across all workflow states.
Each initiative represents a realistic medical/healthcare innovation.
Covers: Draft, Submitted, UnitReview, CouncilReview, Approved (ready for report), Finalized.
"""
import requests
import json
import sys
API = 'https://api.ski-ump.com.vn/api'
ADMIN_EMAIL = 'admin@dhyd.local'
ADMIN_PASSWORD = 'Admin@123456'
def login(email, password):
r = requests.post(f'{API}/auth/login',
json={'email': email, 'password': password},
headers={'Content-Type': 'application/json; charset=utf-8'})
r.raise_for_status()
data = r.json()
return data['accessToken'], data['userId']
def get_units(token):
r = requests.get(f'{API}/admin/units', headers={'Authorization': f'Bearer {token}'})
r.raise_for_status()
return r.json()
def register_user(email, password, full_name, role, admin_token):
"""Register + assign role"""
# Register
r = requests.post(f'{API}/auth/register',
json={'email': email, 'password': password, 'fullName': full_name},
headers={'Authorization': f'Bearer {admin_token}', 'Content-Type': 'application/json; charset=utf-8'})
if r.status_code == 200 or r.status_code == 201 or r.status_code == 204:
data = r.json() if r.text else {}
user_id = data.get('userId') or data.get('id')
if user_id and role != 'Viewer':
# Assign role
r2 = requests.post(f'{API}/admin/users/{user_id}/roles/{role}',
headers={'Authorization': f'Bearer {admin_token}'})
print(f' → Assigned role {role}: {r2.status_code}')
print(f'[OK] Created user {email} ({role})')
return user_id
elif r.status_code == 400 and 'already' in r.text.lower():
print(f'[SKIP] User {email} already exists')
return None
else:
print(f'[FAIL] {email}: {r.status_code} {r.text[:200]}')
return None
def create_initiative(token, data):
r = requests.post(f'{API}/initiatives',
json=data,
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'})
if r.status_code not in (200, 201):
print(f'[FAIL] Create initiative: {r.status_code} {r.text[:300]}')
return None
result = r.json()
print(f'[OK] Created initiative: {result.get("code","?")} - {data["title"][:50]}')
return result.get('id')
def change_status(token, initiative_id, target_status, comment):
r = requests.post(f'{API}/initiatives/{initiative_id}/status',
json={'targetStatus': target_status, 'comment': comment},
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'})
if r.status_code not in (200, 204):
print(f'[FAIL] Status change to {target_status}: {r.status_code} {r.text[:200]}')
return False
return True
def submit(token, initiative_id):
r = requests.post(f'{API}/initiatives/{initiative_id}/submit',
json='Nộp tự động từ seed script',
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'})
return r.status_code in (200, 204)
def approve(token, initiative_id):
r = requests.post(f'{API}/initiatives/{initiative_id}/approve',
json='Phê duyệt từ seed script',
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'})
return r.status_code in (200, 204)
def reject(token, initiative_id):
r = requests.post(f'{API}/initiatives/{initiative_id}/reject',
json='Từ chối test',
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'})
return r.status_code in (200, 204)
# Medical initiatives sample data
INITIATIVES = [
{
'title': 'Ứng dụng Trí tuệ nhân tạo trong chẩn đoán hình ảnh X-quang phổi',
'shortSummary': 'Phát triển mô hình AI hỗ trợ bác sĩ chẩn đoán bệnh lý phổi qua ảnh X-quang',
'description': 'Đề xuất xây dựng hệ thống AI dựa trên Deep Learning (CNN) để phân tích ảnh X-quang phổi, phát hiện sớm các bệnh lý như viêm phổi, lao, ung thư phổi. Hệ thống hỗ trợ bác sĩ giảm thời gian chẩn đoán và tăng độ chính xác lên 92%.',
'objectives': 'Xây dựng mô hình AI đạt độ chính xác > 90% cho 5 bệnh lý phổi phổ biến. Triển khai thí điểm tại Bệnh viện Đại học Y Dược.',
'scopeOfApplication': 'Khoa Chẩn đoán hình ảnh, Khoa Nội tổng hợp, Khoa Lao và bệnh phổi',
'expectedOutcomes': 'Giảm 40% thời gian chẩn đoán. Tăng 15% độ chính xác phát hiện sớm. Công bố 2 bài báo khoa học quốc tế.',
'category': 6, # Technology
'group': 1,
'unit_code': 'KY',
'estimatedBudget': 500000000,
'target_status': 3, # Xét cấp trường
},
{
'title': 'Chương trình đào tạo lâm sàng tích hợp thực tại ảo (VR) cho sinh viên Y',
'shortSummary': 'Ứng dụng công nghệ VR trong giảng dạy lâm sàng, mô phỏng ca bệnh và quy trình phẫu thuật',
'description': 'Xây dựng chương trình đào tạo kết hợp VR giúp sinh viên thực hành các kỹ năng lâm sàng trong môi trường ảo an toàn, giảm áp lực lên bệnh viện thực hành, tăng khả năng xử lý tình huống khẩn cấp.',
'objectives': 'Thiết lập 3 phòng lab VR. Xây dựng 20 ca bệnh mô phỏng. Triển khai cho 500 sinh viên Y khoa năm 3-6.',
'scopeOfApplication': 'Khoa Y, sinh viên hệ chính quy và liên thông',
'expectedOutcomes': 'Cải thiện 30% điểm thi lâm sàng. Giảm 50% lỗi kỹ thuật ở sinh viên mới ra trường.',
'category': 1, # Education
'group': 1,
'unit_code': 'PDT',
'estimatedBudget': 2000000000,
'target_status': 4, # Đã duyệt
},
{
'title': 'Phát triển quy trình bào chế thuốc kháng viêm từ dược liệu Việt Nam',
'shortSummary': 'Nghiên cứu chiết xuất hoạt chất kháng viêm từ Nghệ vàng, Ngải cứu, Trà xanh',
'description': 'Phát triển quy trình chuẩn hóa chiết xuất Curcumin, Artemisinin và Catechin theo GMP-WHO để sản xuất thuốc kháng viêm bản địa, thay thế các thuốc nhập khẩu.',
'objectives': 'Xây dựng 3 quy trình chuẩn (curcumin >95%, artemisinin >98%, EGCG >40%). Đăng ký 2 bằng sáng chế.',
'scopeOfApplication': 'Khoa Dược, Công ty Dược phẩm Đại học Y Dược',
'expectedOutcomes': 'Sản xuất 10.000 đơn vị sản phẩm/năm. Giảm 60% chi phí so với thuốc nhập.',
'category': 2, # Research
'group': 2,
'unit_code': 'KD',
'estimatedBudget': 1500000000,
'target_status': 7, # Finalized (đã hoàn tất)
},
{
'title': 'Mô hình chăm sóc bệnh nhân cao tuổi tại nhà (Home Care) với ứng dụng IoT',
'shortSummary': 'Hệ thống theo dõi sức khỏe người già tại nhà qua thiết bị IoT kết nối bác sĩ',
'description': 'Triển khai mô hình chăm sóc tại nhà sử dụng vòng đeo tay, máy đo huyết áp, đường huyết thông minh kết nối với app điều dưỡng. Bác sĩ nhận cảnh báo theo dõi real-time.',
'objectives': 'Phủ 500 hộ gia đình trong 2 năm. Giảm 30% lượt nhập viện cấp cứu ở người > 65 tuổi.',
'scopeOfApplication': 'Khoa Điều Dưỡng, Trung tâm Y tế cộng đồng',
'expectedOutcomes': 'Cứu sống 15-20 ca mỗi năm nhờ phát hiện sớm. Giảm 25% chi phí điều trị.',
'category': 3, # Social Impact
'group': 1,
'unit_code': 'KDD',
'estimatedBudget': 800000000,
'target_status': 2, # Xét cấp khoa
},
{
'title': 'Ứng dụng liệu pháp tế bào gốc trong điều trị viêm khớp mạn tính',
'shortSummary': 'Nghiên cứu lâm sàng sử dụng tế bào gốc trung mô điều trị thoái hóa khớp',
'description': 'Thử nghiệm lâm sàng pha II sử dụng tế bào gốc trung mô (MSC) tách từ mô mỡ tự thân để điều trị thoái hóa khớp gối độ 2-3, tránh phẫu thuật thay khớp nhân tạo.',
'objectives': 'Đạt tỷ lệ cải thiện > 70% sau 6 tháng. Giảm điểm đau VAS từ 7-8 xuống 2-3.',
'scopeOfApplication': 'Khoa Y, Khoa Cơ xương khớp, Bệnh viện ĐHYD',
'expectedOutcomes': 'Công bố 3 bài báo. Ứng dụng rộng sau khi xong pha III.',
'category': 2, # Research
'group': 2,
'unit_code': 'KY',
'estimatedBudget': 3000000000,
'target_status': 3, # Xét cấp trường
},
{
'title': 'Hệ thống số hóa hồ sơ bệnh án nha khoa với chuẩn HL7 FHIR',
'shortSummary': 'Xây dựng hồ sơ bệnh án nha khoa điện tử tích hợp chụp 3D CBCT và X-quang',
'description': 'Chuyển đổi toàn bộ hồ sơ bệnh án giấy sang điện tử, tích hợp ảnh chụp 3D, theo chuẩn HL7 FHIR để trao đổi dữ liệu giữa các bệnh viện.',
'objectives': 'Số hóa 100% hồ sơ trong 18 tháng. Trích xuất được insights từ dữ liệu.',
'scopeOfApplication': 'Khoa Răng Hàm Mặt',
'expectedOutcomes': 'Giảm 70% thời gian tra cứu. Tăng chất lượng chẩn đoán.',
'category': 6, # Technology
'group': 1,
'unit_code': 'KRHM',
'estimatedBudget': 1200000000,
'target_status': 1, # Đã nộp
},
{
'title': 'Nghiên cứu dịch tễ học bệnh đái tháo đường type 2 tại TP.HCM',
'shortSummary': 'Khảo sát tỷ lệ và yếu tố nguy cơ ĐTĐ tại 10 quận huyện TP.HCM',
'description': 'Nghiên cứu cắt ngang trên 5000 người từ 30-70 tuổi tại TP.HCM để xác định tỷ lệ mắc, yếu tố nguy cơ (di truyền, lối sống, béo phì), đề xuất chính sách y tế dự phòng.',
'objectives': 'Có dữ liệu đại diện quần thể TP.HCM. Xây dựng mô hình dự đoán nguy cơ.',
'scopeOfApplication': 'Khoa Y, Sở Y tế TP.HCM',
'expectedOutcomes': 'Xuất bản 5 bài báo ISI. Đề xuất chương trình tầm soát quốc gia.',
'category': 2, # Research
'group': 2,
'unit_code': 'KY',
'estimatedBudget': 2500000000,
'target_status': 0, # Nháp (chưa nộp)
},
{
'title': 'Phương pháp châm cứu điện kết hợp vật lý trị liệu điều trị đau lưng mạn',
'shortSummary': 'Kết hợp y học cổ truyền và hiện đại điều trị đau lưng mạn tính',
'description': 'Phương pháp kết hợp châm cứu điện tại các huyệt Thận du, Đại trường du với bài tập kéo giãn và tăng cường cơ lưng. Nghiên cứu đối chứng ngẫu nhiên 200 bệnh nhân.',
'objectives': 'Giảm ≥50% điểm đau sau 4 tuần. Cải thiện chất lượng cuộc sống (SF-36).',
'scopeOfApplication': 'Khoa Y Học Cổ Truyền, Khoa Phục hồi chức năng',
'expectedOutcomes': 'Xây dựng phác đồ chuẩn. Đào tạo 50 bác sĩ YHCT.',
'category': 2, # Research
'group': 1,
'unit_code': 'KYHCT',
'estimatedBudget': 600000000,
'target_status': 4, # Đã duyệt
},
{
'title': 'Cải tiến quy trình quản lý nghiên cứu khoa học cấp trường qua cổng điện tử',
'shortSummary': 'Xây dựng cổng thông tin quản lý nghiên cứu khoa học từ đề xuất đến nghiệm thu',
'description': 'Phát triển web app cho phép giảng viên nộp đề xuất, theo dõi tiến độ, báo cáo định kỳ, nghiệm thu online. Tích hợp AI kiểm tra trùng lặp đề tài.',
'objectives': 'Số hóa 100% quy trình. Giảm 80% thời gian xử lý giấy tờ.',
'scopeOfApplication': 'Phòng Khoa học Công nghệ, toàn trường',
'expectedOutcomes': 'Tăng 30% số đề tài được phê duyệt. Tiết kiệm 2000 giờ nhân sự/năm.',
'category': 5, # Management
'group': 1,
'unit_code': 'PKHCN',
'estimatedBudget': 400000000,
'target_status': 5, # Từ chối
},
{
'title': 'Chương trình đánh giá năng lực giảng viên theo chuẩn quốc tế (AACSB)',
'shortSummary': 'Xây dựng framework đánh giá giảng viên dựa trên chuẩn AACSB và ABET',
'description': 'Thiết kế hệ thống đánh giá toàn diện năng lực giảng viên: giảng dạy, nghiên cứu, cộng đồng. Tích hợp phần mềm thu thập phản hồi sinh viên, đồng nghiệp.',
'objectives': 'Đánh giá 100% giảng viên trong 3 năm. Công bố Chương trình đạt chuẩn quốc tế.',
'scopeOfApplication': 'Phòng Tổ chức Cán bộ, toàn trường',
'expectedOutcomes': 'Nâng cao chất lượng giảng viên. Đạt chứng nhận kiểm định ngành 2027.',
'category': 5, # Management
'group': 1,
'unit_code': 'PTCCB',
'estimatedBudget': 700000000,
'target_status': 2, # Xét cấp khoa
},
]
def advance_to_status(token, initiative_id, target):
"""Move initiative from Draft (0) step-by-step to target status"""
# State machine: 0 -> 1 -> 2 -> 3 -> 4 ; or 0 -> 1 -> 5 (reject)
if target == 0:
return True # already Draft
if not submit(token, initiative_id):
print(f' [FAIL] submit')
return False
if target == 1:
return True
if not change_status(token, initiative_id, 2, 'Chuyển sang xét cấp khoa'):
return False
if target == 2:
return True
if target == 5:
return reject(token, initiative_id)
if not change_status(token, initiative_id, 3, 'Chuyển sang xét cấp trường'):
return False
if target == 3:
return True
if not approve(token, initiative_id):
return False
if target == 4:
return True
# Move to finalized via report phase (4 -> 6 -> 7)
if target == 7:
if not change_status(token, initiative_id, 6, 'Báo cáo đang duyệt'):
return False
if not change_status(token, initiative_id, 7, 'Hoàn tất'):
return False
return True
def main():
print('=== DYD Sample Data Seeder ===')
print('Logging in as admin...')
admin_token, admin_id = login(ADMIN_EMAIL, ADMIN_PASSWORD)
print(f'Admin: {admin_id[:8]}...')
# Create test users
print('\n=== Creating test users ===')
test_users = [
('reviewer1@dhyd.local', 'Review@2026', 'Trần Thị Bình - Trưởng khoa Y', 'Editor'),
('reviewer2@dhyd.local', 'Review@2026', 'Nguyễn Văn An - Trưởng khoa Dược', 'Editor'),
('gv1@dhyd.local', 'User@123456', 'TS. Lê Hoàng Minh - Giảng viên Khoa Y', 'Viewer'),
('gv2@dhyd.local', 'User@123456', 'ThS. Phạm Thu Hà - Giảng viên Khoa Dược', 'Viewer'),
('gv3@dhyd.local', 'User@123456', 'BS. Võ Thanh Tùng - Giảng viên Khoa Điều Dưỡng', 'Viewer'),
]
for email, pwd, name, role in test_users:
register_user(email, pwd, name, role, admin_token)
# Get units
print('\n=== Loading units ===')
units = get_units(admin_token)
unit_by_code = {u['code']: u for u in units}
for u in units:
print(f' {u["code"]}: {u["name"]}')
# Create + advance each initiative
print(f'\n=== Creating {len(INITIATIVES)} initiatives ===')
for idx, init in enumerate(INITIATIVES, 1):
unit = unit_by_code.get(init['unit_code'])
if not unit:
print(f'[SKIP] Unit {init["unit_code"]} not found')
continue
print(f'\n[{idx}/{len(INITIATIVES)}] {init["title"][:60]}...')
payload = {
'title': init['title'],
'shortSummary': init['shortSummary'],
'description': init['description'],
'objectives': init['objectives'],
'scopeOfApplication': init['scopeOfApplication'],
'expectedOutcomes': init['expectedOutcomes'],
'category': init['category'],
'group': init['group'],
'owningUnitId': unit['id'],
'estimatedBudget': init['estimatedBudget'],
'authors': [{
'authorId': '00000000-0000-0000-0000-000000000000',
'fullName': 'Admin Test',
'email': 'admin@dhyd.local',
'position': 'Quản trị viên',
'academicTitle': 'Tiến sĩ',
'contributionPercentage': 100,
'isLeadAuthor': True,
'contributionDescription': 'Chủ nhiệm đề tài',
}],
}
initiative_id = create_initiative(admin_token, payload)
if initiative_id:
target = init['target_status']
if target != 0:
success = advance_to_status(admin_token, initiative_id, target)
status_name = {0:'Nháp',1:'Đã nộp',2:'Xét cấp khoa',3:'Xét cấp trường',4:'Đã duyệt',5:'Từ chối',6:'Đang báo cáo',7:'Hoàn tất'}[target]
print(f' → Target status: {status_name} ({target}) — {"OK" if success else "FAIL"}')
print('\n✅ Seed complete!')
if __name__ == '__main__':
try:
main()
except Exception as e:
print(f'ERROR: {e}')
sys.exit(1)