cuongpm-cs commited on
Commit
f171e60
·
0 Parent(s):

Initial commit

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +35 -0
  2. Dockerfile +16 -0
  3. README.md +11 -0
  4. Web/backend/.env +0 -0
  5. Web/backend/__pycache__/main.cpython-313.pyc +0 -0
  6. Web/backend/dataset_feedback.jsonl +50 -0
  7. Web/backend/main.py +587 -0
  8. Web/mind-reframe/.gitignore +24 -0
  9. Web/mind-reframe/README.md +73 -0
  10. Web/mind-reframe/dist/assets/index-B3ZeeytQ.css +1 -0
  11. Web/mind-reframe/dist/assets/index-BoHQMix6.js +0 -0
  12. Web/mind-reframe/dist/assets/index-Ces_8vm5.js +0 -0
  13. Web/mind-reframe/dist/assets/index-DSeqsUYm.css +1 -0
  14. Web/mind-reframe/dist/assets/index-ebY5FnGP.js +0 -0
  15. Web/mind-reframe/dist/index.html +14 -0
  16. Web/mind-reframe/dist/vite.svg +1 -0
  17. Web/mind-reframe/eslint.config.js +23 -0
  18. Web/mind-reframe/index.html +13 -0
  19. Web/mind-reframe/package-lock.json +0 -0
  20. Web/mind-reframe/package.json +37 -0
  21. Web/mind-reframe/postcss.config.js +6 -0
  22. Web/mind-reframe/public/vite.svg +1 -0
  23. Web/mind-reframe/src/App.css +42 -0
  24. Web/mind-reframe/src/App.tsx +0 -0
  25. Web/mind-reframe/src/assets/react.svg +0 -0
  26. Web/mind-reframe/src/index.css +3 -0
  27. Web/mind-reframe/src/main.tsx +10 -0
  28. Web/mind-reframe/tailwind.config.js +11 -0
  29. Web/mind-reframe/tsconfig.app.json +28 -0
  30. Web/mind-reframe/tsconfig.json +7 -0
  31. Web/mind-reframe/tsconfig.node.json +26 -0
  32. Web/mind-reframe/vite.config.ts +13 -0
  33. ai-core/.env +37 -0
  34. ai-core/README.md +66 -0
  35. ai-core/app/__init__.py +0 -0
  36. ai-core/app/__pycache__/__init__.cpython-313.pyc +0 -0
  37. ai-core/app/__pycache__/config.cpython-313.pyc +0 -0
  38. ai-core/app/__pycache__/main.cpython-313.pyc +0 -0
  39. ai-core/app/api/__init__.py +0 -0
  40. ai-core/app/api/__pycache__/__init__.cpython-313.pyc +0 -0
  41. ai-core/app/api/v1/__init__.py +0 -0
  42. ai-core/app/api/v1/__pycache__/__init__.cpython-313.pyc +0 -0
  43. ai-core/app/api/v1/__pycache__/router.cpython-313.pyc +0 -0
  44. ai-core/app/api/v1/endpoints/__init__.py +0 -0
  45. ai-core/app/api/v1/endpoints/__pycache__/__init__.cpython-313.pyc +0 -0
  46. ai-core/app/api/v1/endpoints/__pycache__/cache.cpython-313.pyc +0 -0
  47. ai-core/app/api/v1/endpoints/__pycache__/chat.cpython-313.pyc +0 -0
  48. ai-core/app/api/v1/endpoints/__pycache__/completion.cpython-313.pyc +0 -0
  49. ai-core/app/api/v1/endpoints/__pycache__/health.cpython-313.pyc +0 -0
  50. ai-core/app/api/v1/endpoints/__pycache__/prompts.cpython-313.pyc +0 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10.11
2
+
3
+ RUN apt-get update && apt-get install -y supervisor && rm -rf /var/lib/apt/lists/*
4
+
5
+ WORKDIR /app
6
+
7
+ RUN useradd -m -u 1000 user
8
+ USER user
9
+ ENV PATH="/home/user/.local/bin:$PATH"
10
+
11
+ COPY --chown=user ./requirements.txt requirements.txt
12
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
13
+
14
+ COPY --chown=user . /app
15
+
16
+ CMD ["supervisord", "-c", "/app/supervisord.conf"]
README.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Mind Reframe
3
+ emoji: 🦀
4
+ colorFrom: indigo
5
+ colorTo: purple
6
+ sdk: docker
7
+ pinned: false
8
+ license: apache-2.0
9
+ ---
10
+
11
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
Web/backend/.env ADDED
File without changes
Web/backend/__pycache__/main.cpython-313.pyc ADDED
Binary file (21.7 kB). View file
 
Web/backend/dataset_feedback.jsonl ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"session_id": "06df2526-3b92-433f-bc81-fa147d4959ab", "timestamp": "2026-01-22T03:28:36.626Z", "input": {"situation": "My wife didn't look up from her phone or answer me when I came to talk to her.", "thought": "Am I not worth her time?"}, "output": {"therapy_type": "ACT", "reframe": "I’m having the thought that I’m not worth her time. I can accept this feeling and choose to connect with her when she’s ready."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 4, "learning": 3}}
2
+ {"session_id": "5f601d8b-cdd3-4bd5-a933-a37fbeac5d9b", "timestamp": "2026-01-22T05:03:31.166Z", "input": {"situation": "My wife didn't look up from her phone or answer me when I came to talk to her.", "thought": "Am I not worth her time?"}, "output": {"therapy_type": "ACT", "reframe": "I’m having the thought that I’m not worth her time. I can accept this feeling and choose to connect with her when she’s ready."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 4}}
3
+ {"session_id": "f6ee1997-0394-40d1-b4f6-6014e5da4224", "timestamp": "2026-01-22T14:10:09.768Z", "input": {"situation": "My wife didn't look up from her phone or answer me when I came to talk to her.", "thought": "Am I not worth her time?"}, "output": {"therapy_type": "CBT", "reframe": "She might be preoccupied with something on her phone; it doesn't mean I'm not important to her."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 4}}
4
+ {"session_id": "efaa369d-f0ff-4da9-a047-b5cba0f11fc6", "timestamp": "2026-01-22T14:29:18.149Z", "input": {"situation": "tôi bị điểm thấp hơn so với năng lực", "thought": "không được chú ý, trọng dụng \n"}, "output": {"therapy_type": "ACT", "reframe": "I'm noticing the thought that I'm not valued, and I can accept this feeling while focusing on my growth and what truly matters to me."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 4, "learning": 3}}
5
+ {"session_id": "c7527b9b-e6b9-4242-97de-521c2d239a18", "timestamp": "2026-01-26T08:58:36.761Z", "input": {"situation": "I called an old friend, but she wasn't home and didn't return my call.\n", "thought": "Maybe she doesn't want to talk to me anymore.\n"}, "output": {"therapy_type": "CBT", "reframe": "She might just be busy or away; it doesn't mean she doesn't want to talk to me."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 4, "learning": 3}}
6
+ {"session_id": "c7527b9b-e6b9-4242-97de-521c2d239a18", "timestamp": "2026-01-26T08:59:51.077Z", "input": {"situation": "I am walking down the street in a new red jeans and a stranger looked at the jeans\n", "thought": "I should have never worn these jeans and stick to blue ones\n"}, "output": {"therapy_type": "REBT", "reframe": "Wearing these jeans is my choice, and it's okay if others have different opinions. I can feel good about my style regardless of their reactions."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 3, "learning": 4}}
7
+ {"session_id": "c7527b9b-e6b9-4242-97de-521c2d239a18", "timestamp": "2026-01-26T09:01:57.083Z", "input": {"situation": "Having problems coming up with words to write essay.\n", "thought": "I will get a bad grade.\n"}, "output": {"therapy_type": "REBT", "reframe": "I can do my best on this essay, and a single grade doesn't define my worth or abilities."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 3, "learning": 3}}
8
+ {"session_id": "2503ab8d-ce18-4a02-843d-cae122866ff2", "timestamp": "2026-01-27T00:56:54.243Z", "input": {"situation": "I sent an email to my boss in the morning and haven't received a reply by 5 PM.", "thought": "He must be angry with me; I'm probably going to get fired."}, "output": {"therapy_type": "Schema Therapy", "reframe": "My boss may be busy or dealing with other priorities; I’ll follow up tomorrow if I don’t hear back."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 4, "learning": 3}}
9
+ {"session_id": "2503ab8d-ce18-4a02-843d-cae122866ff2", "timestamp": "2026-01-27T01:00:12.590Z", "input": {"situation": "I made a small typo in a presentation slide during the team meeting.", "thought": "I am so incompetent. Everyone noticed and thinks I’m an idiot."}, "output": {"therapy_type": "CFT", "reframe": "I made a small mistake, and that's okay. Everyone makes errors, and I can learn and grow from this experience."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 4, "learning": 3}}
10
+ {"session_id": "2503ab8d-ce18-4a02-843d-cae122866ff2", "timestamp": "2026-01-27T01:03:31.027Z", "input": {"situation": "My colleague got the promotion that I also applied for.", "thought": "I’ll never be successful. I’m always going to be stuck at the bottom."}, "output": {"therapy_type": "MI", "reframe": "I can learn from this experience and find new opportunities to grow. I have strengths that can lead me to success."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 4, "learning": 4}}
11
+ {"session_id": "2503ab8d-ce18-4a02-843d-cae122866ff2", "timestamp": "2026-01-27T01:32:01.576Z", "input": {"situation": "I finished my project two days early, but I feel like I could have done more.", "thought": "It doesn't count because it wasn't perfect. I’m a fraud."}, "output": {"therapy_type": "MBCT", "reframe": "I acknowledge my feelings of inadequacy, but I recognize that completing my project early is an achievement, and I am doing my best."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 3, "learning": 4}}
12
+ {"session_id": "2503ab8d-ce18-4a02-843d-cae122866ff2", "timestamp": "2026-01-27T02:17:43.127Z", "input": {"situation": "My manager gave me constructive feedback on how to improve my report.", "thought": "She thinks my work is terrible. I can’t do anything right."}, "output": {"therapy_type": "CBT", "reframe": "My manager's feedback is meant to help me improve, not to criticize my worth. I can learn and grow from this experience."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 4, "learning": 4}}
13
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:15:34.527Z", "input": {"situation": "My manager gave me constructive feedback on how to improve my report.", "thought": "She thinks my work is terrible. I can’t do anything right."}, "output": {"therapy_type": "MBCT", "reframe": "I appreciate my manager's feedback as a chance to grow. It's okay to make mistakes; they don't define my worth or abilities."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 2, "learning": 3}}
14
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:16:16.437Z", "input": {"situation": "A client cancelled our meeting at the last minute.", "thought": "They must hate working with me. I drove them away."}, "output": {"therapy_type": "CBT", "reframe": "They may have had a valid reason to cancel, and it doesn't reflect their feelings about me or our work together."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 3, "learning": 3}}
15
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:17:04.356Z", "input": {"situation": "I struggled to solve a bug in the code for a few hours.", "thought": "I’m not cut out for this job. A real engineer would have fixed it instantly."}, "output": {"therapy_type": "Narrative Therapy", "reframe": "I am a dedicated problem-solver who takes the time to understand challenges, and that persistence is a strength that will help me grow as an engineer."}, "ratings": {"belief": 2, "helpfulness": 3, "recall": 4, "learning": 3}}
16
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:18:08.382Z", "input": {"situation": "I received praise for my part of the group project.", "thought": "They are just being nice. I didn't actually do anything special."}, "output": {"therapy_type": "Schema Therapy", "reframe": "Your contributions were valuable, and it's okay to accept praise. You deserve recognition for your hard work and effort."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 4, "learning": 2}}
17
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:18:52.522Z", "input": {"situation": "I have a lot of tasks to finish by the end of the week.", "thought": "There is no way I can handle this. I am going to fail completely."}, "output": {"therapy_type": "REBT", "reframe": "I can manage my tasks by prioritizing and taking them one step at a time, and it's okay if I don't complete everything perfectly."}, "ratings": {"belief": 3, "helpfulness": 4, "recall": 2, "learning": 3}}
18
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:19:43.466Z", "input": {"situation": "I voiced an opinion in a meeting and no one commented on it immediately.", "thought": "I should have kept my mouth shut. My ideas are stupid."}, "output": {"therapy_type": "DBT", "reframe": "I feel disappointed that my idea went unnoticed, but I can share it again later or seek feedback. My thoughts are valid, and I can improve my communication."}, "ratings": {"belief": 2, "helpfulness": 3, "recall": 4, "learning": 4}}
19
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:21:36.579Z", "input": {"situation": "A friend read my message but didn't reply for a few hours.", "thought": "They are ignoring me. I must have annoyed them."}, "output": {"therapy_type": "CBT", "reframe": "They might be busy or distracted; it doesn't mean I've annoyed them. I'll give them time to respond."}, "ratings": {"belief": 3, "helpfulness": 4, "recall": 4, "learning": 4}}
20
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:22:31.988Z", "input": {"situation": "I wasn't invited to a coworker's weekend gathering.", "thought": "Nobody likes me. I am an outcast."}, "output": {"therapy_type": "CBT", "reframe": "Not being invited doesn't mean I'm unlikable; there could be many reasons for it that have nothing to do with me."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 3, "learning": 4}}
21
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:23:52.004Z", "input": {"situation": "My partner seems quiet and tired after coming home from work.", "thought": "They are losing interest in me. Our relationship is falling apart."}, "output": {"therapy_type": "SFBT", "reframe": "My partner may be tired from work, and I can support them while also nurturing our connection."}, "ratings": {"belief": 2, "helpfulness": 3, "recall": 3, "learning": 3}}
22
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:24:41.663Z", "input": {"situation": "I waved at an acquaintance on the street, but they didn't wave back.", "thought": "They pretended not to see me because they think I'm weird."}, "output": {"therapy_type": "CBT", "reframe": "They might not have seen me or were distracted; it doesn't mean they think I'm weird."}, "ratings": {"belief": 2, "helpfulness": 4, "recall": 4, "learning": 4}}
23
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:25:34.717Z", "input": {"situation": "I stumbled over my words while telling a joke at a party.", "thought": "I ruined the mood. Everyone thinks I'm awkward and boring."}, "output": {"therapy_type": "DBT", "reframe": "I felt embarrassed when I stumbled, but that doesn’t define me. I can learn from this and share more jokes in the future."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 3, "learning": 4}}
24
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:27:03.965Z", "input": {"situation": "My friend had to cancel our dinner plans due to a headache.", "thought": "That’s just an excuse. They just don’t want to spend time with me."}, "output": {"therapy_type": "Narrative Therapy", "reframe": "I recognize that my friend's headache is a real issue, and it doesn't define our friendship or their desire to spend time with me."}, "ratings": {"belief": 2, "helpfulness": 2, "recall": 4, "learning": 4}}
25
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:27:54.138Z", "input": {"situation": "I gained a little weight over the holidays.", "thought": "I am disgusting. No one will ever find me attractive again."}, "output": {"therapy_type": "REBT", "reframe": "I can accept my body as it is now and focus on healthy choices without tying my worth to my appearance."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 3, "learning": 3}}
26
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:30:01.157Z", "input": {"situation": "I asked someone on a date and they politely declined.", "thought": "I am unlovable. I will be alone forever."}, "output": {"therapy_type": "MBCT", "reframe": "I acknowledge this feeling of unlovability, but it’s just a thought, not my truth. I am worthy of love and connection, even in this moment."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 4}}
27
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:30:40.738Z", "input": {"situation": "People were laughing at a nearby table in the restaurant.", "thought": "They are definitely laughing at me and my outfit."}, "output": {"therapy_type": "CBT", "reframe": "They might be laughing about something unrelated; I can't know their thoughts, and I feel good in my outfit."}, "ratings": {"belief": 3, "helpfulness": 4, "recall": 3, "learning": 4}}
28
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:31:37.239Z", "input": {"situation": "My parents asked why I haven't visited lately.", "thought": "I am a terrible son/daughter. I always let everyone down."}, "output": {"therapy_type": "CBT", "reframe": "I care about my family, and while I haven't visited lately, it doesn't mean I'm a bad son/daughter. I can make time for them soon."}, "ratings": {"belief": 3, "helpfulness": 4, "recall": 4, "learning": 3}}
29
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:32:33.113Z", "input": {"situation": "I got a B+ on an exam I studied hard for.", "thought": "If I don’t get an A, I am a total failure."}, "output": {"therapy_type": "CBT", "reframe": "Getting a B+ shows my hard work paid off, and I can still learn and improve for next time."}, "ratings": {"belief": 2, "helpfulness": 3, "recall": 3, "learning": 4}}
30
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:33:21.554Z", "input": {"situation": "I didn't understand the lecture material as quickly as my classmate.", "thought": "I am stupid. Everyone else is smarter than me."}, "output": {"therapy_type": "MBCT", "reframe": "I notice this thought of being stupid, but I am learning at my own pace, and that is okay."}, "ratings": {"belief": 3, "helpfulness": 2, "recall": 2, "learning": 4}}
31
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:34:05.671Z", "input": {"situation": "The professor marked a few corrections on my essay.", "thought": "This proves I can't write. I shouldn't even be in this university."}, "output": {"therapy_type": "DBT", "reframe": "I feel discouraged by the corrections, but this feedback helps me grow as a writer. I can improve and succeed in this university."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 4, "learning": 3}}
32
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:34:43.986Z", "input": {"situation": "I have a deadline for a thesis coming up in two months.", "thought": "It’s going to be a disaster. I won’t finish in time."}, "output": {"therapy_type": "SFBT", "reframe": "I have two months to focus on my thesis, and I can take small steps each week to make steady progress."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 3, "learning": 4}}
33
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:35:30.119Z", "input": {"situation": "I asked a question in class and the teacher asked me to clarify.", "thought": "That was a dumb question. The whole class is judging me."}, "output": {"therapy_type": "REBT", "reframe": "Asking questions is a part of learning; it's okay to seek clarification, and not everyone is judging me."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 2, "learning": 2}}
34
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:39:31.721Z", "input": {"situation": "I missed one day of studying due to illness.", "thought": "My entire study schedule is ruined. I'm going to fail the course."}, "output": {"therapy_type": "CBT", "reframe": "Missing one day of studying is not the end; I can adjust my schedule and still succeed in the course."}, "ratings": {"belief": 3, "helpfulness": 4, "recall": 4, "learning": 4}}
35
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:40:14.523Z", "input": {"situation": "My peer review feedback was mostly positive but had one suggestion.", "thought": "They only put the positive stuff to be polite. The suggestion is the truth: my work sucks."}, "output": {"therapy_type": "REBT", "reframe": "The feedback is mostly positive, and the suggestion is an opportunity for growth; my work has strengths and areas to improve."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 3, "learning": 3}}
36
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:41:05.754Z", "input": {"situation": "I feel nervous about the upcoming presentation.", "thought": "My anxiety shows I am weak and incapable."}, "output": {"therapy_type": "Schema Therapy", "reframe": "Feeling anxious is a normal response to challenges; it doesn't define my worth or abilities."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 3}}
37
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:41:49.471Z", "input": {"situation": "I saw my classmates discussing a topic I haven't started reviewing yet.", "thought": "I am so far behind. There is no point in even trying now."}, "output": {"therapy_type": "CFT", "reframe": "It's okay to feel behind; I can start now and take small steps. I am capable of learning at my own pace."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 3, "learning": 2}}
38
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:42:31.325Z", "input": {"situation": "I got rejected from one internship program.", "thought": "No company will ever hire me. My career is over before it started."}, "output": {"therapy_type": "MI", "reframe": "I can learn from this experience and keep trying; my journey is just beginning, and I have strengths to build on."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 2}}
39
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:43:25.958Z", "input": {"situation": "The bus arrived late, making me late for an appointment.", "thought": "Why do bad things always happen to me? The universe is against me."}, "output": {"therapy_type": "CBT", "reframe": "Sometimes things go wrong, but it doesn't mean the universe is against me. I can adapt and find solutions."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 3}}
40
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:44:10.470Z", "input": {"situation": "I burned the dinner I was cooking.", "thought": "I can’t do anything right. I’m useless."}, "output": {"therapy_type": "REBT", "reframe": "I can make mistakes, and that doesn’t define my worth or abilities. I can learn and improve from this experience."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 3, "learning": 3}}
41
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:44:52.027Z", "input": {"situation": "I dropped a glass and it shattered.", "thought": "I am such a clumsy idiot. I ruin everything I touch."}, "output": {"therapy_type": "DBT", "reframe": "I feel frustrated and clumsy right now, but accidents happen. I can learn from this and be more careful next time."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 4}}
42
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:45:30.498Z", "input": {"situation": "I woke up feeling a bit tired today.", "thought": "This day is going to be terrible. Nothing will go right."}, "output": {"therapy_type": "CBT", "reframe": "I may feel tired now, but I can still take small steps to make today better and see how it unfolds."}, "ratings": {"belief": 3, "helpfulness": 4, "recall": 4, "learning": 4}}
43
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:46:16.439Z", "input": {"situation": "My car wouldn't start this morning.", "thought": "This is a catastrophe. Now my whole week is destroyed."}, "output": {"therapy_type": "Schema Therapy", "reframe": "This is inconvenient, but I can find solutions and adjust my plans. It's not the end of the week."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 3, "learning": 3}}
44
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:47:02.940Z", "input": {"situation": "I tried a new hobby and wasn't good at it immediately.", "thought": "If I'm not good at it right away, I shouldn't bother. I have no talent."}, "output": {"therapy_type": "REBT", "reframe": "It's okay not to be good at something right away; I can improve with practice and enjoy the process of learning."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 3, "learning": 3}}
45
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:47:46.582Z", "input": {"situation": "I realized I forgot to pay a utility bill on time.", "thought": "I am so irresponsible. I can't manage my own life."}, "output": {"therapy_type": "REBT", "reframe": "I made a mistake by forgetting the bill, but that doesn't define my ability to manage my life. I can learn from this."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 4}}
46
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:48:26.536Z", "input": {"situation": "It started raining when I didn't bring an umbrella.", "thought": "Just my luck. Everything always goes wrong for me."}, "output": {"therapy_type": "CBT", "reframe": "Sometimes things don't go as planned, but this is just a minor inconvenience, not a reflection of my overall luck."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 3}}
47
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:57:34.922Z", "input": {"situation": "I have a mild headache.", "thought": "What if it's a brain tumor? Something is seriously wrong with me."}, "output": {"therapy_type": "CBT", "reframe": "I have a mild headache, but it’s more likely due to stress or dehydration than something serious. I’ll take care of myself and monitor how I feel."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 3, "learning": 4}}
48
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:58:17.883Z", "input": {"situation": "I felt awkward during a brief elevator ride with a neighbor.", "thought": "They must think I'm a social weirdo."}, "output": {"therapy_type": "CBT", "reframe": "It's normal to feel awkward sometimes; they probably didn't think much of it, just like I often don't in similar situations."}, "ratings": {"belief": 4, "helpfulness": 3, "recall": 4, "learning": 4}}
49
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:58:54.699Z", "input": {"situation": "I successfully fixed a difficult problem, but it took longer than expected.", "thought": "It shouldn't have taken that long. I'm slow and inefficient."}, "output": {"therapy_type": "CBT", "reframe": "It took longer than expected, but I successfully solved a difficult problem, which shows my persistence and problem-solving skills."}, "ratings": {"belief": 3, "helpfulness": 3, "recall": 3, "learning": 3}}
50
+ {"session_id": "7ea9d141-d906-4b4f-873b-ad587d578138", "timestamp": "2026-01-27T14:59:29.565Z", "input": {"situation": "My partner bought me a gift, but it wasn't what I wanted.", "thought": "They don't know me at all. We are completely incompatible."}, "output": {"therapy_type": "REBT", "reframe": "My partner cares about me, and while this gift isn't what I wanted, it doesn't mean we're incompatible."}, "ratings": {"belief": 4, "helpfulness": 4, "recall": 4, "learning": 4}}
Web/backend/main.py ADDED
@@ -0,0 +1,587 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # File: main.py
2
+ from fastapi import FastAPI
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from pydantic import BaseModel
5
+ import uuid
6
+ from fastapi.staticfiles import StaticFiles
7
+ from fastapi.responses import FileResponse
8
+ import os
9
+ import httpx
10
+ from fastapi import HTTPException
11
+ from typing import Dict, Optional, Any
12
+ from datetime import datetime, timedelta
13
+ import json
14
+
15
+ import asyncio
16
+
17
+ app = FastAPI()
18
+
19
+ app.add_middleware(
20
+ CORSMiddleware,
21
+ allow_origins=["*"],
22
+ allow_credentials=True,
23
+ allow_methods=["*"],
24
+ allow_headers=["*"],
25
+ )
26
+
27
+ class SessionInit(BaseModel):
28
+ pass
29
+
30
+ class SessionData(BaseModel):
31
+ session_id: str
32
+ situation: str
33
+ thought: str
34
+ distortions: Optional[list] = None
35
+ analysis: Optional[dict] = None
36
+ candidates: Optional[list] = None
37
+ selected_reframe: Optional[dict] = None
38
+ created_at: datetime
39
+ updated_at: datetime
40
+
41
+ def clean_expired_sessions():
42
+ """Remove sessions older than SESSION_EXPIRY_MINUTES"""
43
+ now = datetime.now()
44
+ expired = [
45
+ sid for sid, data in sessions_store.items()
46
+ if (now - data['updated_at']).seconds > SESSION_EXPIRY_MINUTES * 60
47
+ ]
48
+ for sid in expired:
49
+ del sessions_store[sid]
50
+
51
+ def get_session(session_id: str) -> Optional[dict]:
52
+ """Get session data by ID"""
53
+ clean_expired_sessions()
54
+ return sessions_store.get(session_id)
55
+
56
+ def update_session(session_id: str, data: dict):
57
+ """Update session data"""
58
+ if session_id in sessions_store:
59
+ sessions_store[session_id].update(data)
60
+ sessions_store[session_id]['updated_at'] = datetime.now()
61
+ else:
62
+ raise HTTPException(status_code=404, detail="Session not found")
63
+
64
+ class DetectionRequest(BaseModel):
65
+ session_id: str
66
+ situation: str
67
+ thought: str
68
+
69
+ class AnalyzeRequest(BaseModel):
70
+ session_id: str
71
+ situation: str
72
+ thought: str
73
+ distortions: list
74
+
75
+ class ReframeRequest(BaseModel):
76
+ session_id: str
77
+ situation: str
78
+ thought: str
79
+ recommended_therapies: list
80
+
81
+
82
+ API_base = 'http://localhost:1812/api/v1/'
83
+
84
+ sessions_store: Dict[str, dict] = {}
85
+
86
+ SESSION_EXPIRY_MINUTES = 60
87
+
88
+ class FeedbackData(BaseModel):
89
+ session_id: str
90
+ timestamp: str
91
+ input: dict
92
+ output: dict
93
+ ratings: dict
94
+
95
+ @app.post("/api/feedback")
96
+ async def save_feedback(data: FeedbackData):
97
+ try:
98
+ # Chuyển đổi sang dict
99
+ record = data.dict()
100
+
101
+ # Ghi vào file dataset_feedback.jsonl
102
+ # Mode 'a' (append) để ghi nối tiếp, không ghi đè
103
+ with open("dataset_feedback.jsonl", "a", encoding="utf-8") as f:
104
+ # Ghi mỗi feedback trên 1 dòng (JSONL format)
105
+ f.write(json.dumps(record, ensure_ascii=False) + "\n")
106
+
107
+ return {"status": "success", "message": "Feedback saved"}
108
+ except Exception as e:
109
+ print(f"Error saving file: {e}")
110
+ raise HTTPException(status_code=500, detail="Internal Server Error")
111
+
112
+ @app.post("/api/session/init")
113
+ async def init_session():
114
+ """Initialize a new session"""
115
+ session_id = str(uuid.uuid4())
116
+ sessions_store[session_id] = {
117
+ 'session_id': session_id,
118
+ 'situation': None,
119
+ 'thought': None,
120
+ 'distortions': None,
121
+ 'analysis': None,
122
+ 'candidates': None,
123
+ 'selected_reframe': None,
124
+ 'created_at': datetime.now(),
125
+ 'updated_at': datetime.now()
126
+ }
127
+ return {"session_id": session_id}
128
+
129
+ def _check_has_distortion(text: str) -> bool:
130
+ """Kiểm tra xem có distortion hay không"""
131
+ if not text or len(text.strip()) < 10:
132
+ return False
133
+
134
+ # if '[' in text and ']' in text:
135
+ # return True
136
+
137
+ positive_indicators = [
138
+ "all-or-nothing", "mind reading", "catastrophizing",
139
+ "overgeneralization", "mental filter", "labeling",
140
+ "emotional reasoning", "should statements",
141
+ "jumping to conclusions", "fortune telling",
142
+ "personalization", "disqualifying"
143
+ ]
144
+
145
+ text_lower = text.lower()
146
+ if any(indicator in text_lower for indicator in positive_indicators):
147
+ return True
148
+
149
+ negative_indicators = [
150
+ "không có distortion",
151
+ "không phát hiện distortion",
152
+ "no distortion",
153
+ "không tìm thấy distortion"
154
+ ]
155
+
156
+ return not any(indicator in text_lower for indicator in negative_indicators)
157
+
158
+
159
+ def _extract_distortion_types(text: str) -> list:
160
+ """
161
+ Extract các loại distortion từ response
162
+ Hỗ trợ format: [Type1, Type2, Type3] hoặc text tự do
163
+ """
164
+ import re
165
+
166
+ bracket_match = re.search(r'\[(.*?)\]', text)
167
+ if bracket_match:
168
+ content = bracket_match.group(1)
169
+ distortions = [d.strip() for d in content.split(',')]
170
+ normalized = []
171
+ for d in distortions:
172
+ d_normalized = d.strip().title()
173
+ if 'all-or-nothing' in d.lower():
174
+ d_normalized = 'All-or-Nothing Thinking'
175
+ elif 'mind reading' in d.lower():
176
+ d_normalized = 'Mind Reading'
177
+ elif 'catastrophizing' in d.lower():
178
+ d_normalized = 'Catastrophizing'
179
+ elif 'overgeneralization' in d.lower():
180
+ d_normalized = 'Overgeneralization'
181
+ elif 'mental filter' in d.lower():
182
+ d_normalized = 'Mental Filter'
183
+ elif 'jumping to conclusions' in d.lower():
184
+ d_normalized = 'Jumping to Conclusions'
185
+ elif 'fortune telling' in d.lower():
186
+ d_normalized = 'Fortune Telling'
187
+ elif 'emotional reasoning' in d.lower():
188
+ d_normalized = 'Emotional Reasoning'
189
+ elif 'should statements' in d.lower():
190
+ d_normalized = 'Should Statements'
191
+ elif 'labeling' in d.lower():
192
+ d_normalized = 'Labeling'
193
+ elif 'personalization' in d.lower():
194
+ d_normalized = 'Personalization'
195
+ elif 'disqualifying the positive' in d.lower():
196
+ d_normalized = 'Disqualifying the Positive'
197
+ elif 'magnification' in d.lower():
198
+ d_normalized = 'Magnification'
199
+ elif 'minimization' in d.lower():
200
+ d_normalized = 'Minimization'
201
+ elif 'blame' in d.lower():
202
+ d_normalized = 'Blame'
203
+
204
+ normalized.append(d_normalized)
205
+
206
+ return normalized if normalized else ["Unknown Distortion"]
207
+
208
+ common_distortions = {
209
+ "all-or-nothing": "All-or-Nothing Thinking",
210
+ "overgeneralization": "Overgeneralization",
211
+ "mental filter": "Mental Filter",
212
+ "disqualifying the positive": "Disqualifying the Positive",
213
+ "jumping to conclusions": "Jumping to Conclusions",
214
+ "mind reading": "Mind Reading",
215
+ "fortune telling": "Fortune Telling",
216
+ "magnification": "Magnification",
217
+ "catastrophizing": "Catastrophizing",
218
+ "minimization": "Minimization",
219
+ "emotional reasoning": "Emotional Reasoning",
220
+ "should statements": "Should Statements",
221
+ "labeling": "Labeling",
222
+ "personalization": "Personalization",
223
+ "blame": "Blame"
224
+ }
225
+
226
+ found_distortions = []
227
+ text_lower = text.lower()
228
+
229
+ for key, distortion_name in common_distortions.items():
230
+ if key in text_lower:
231
+ found_distortions.append(distortion_name)
232
+
233
+ seen = set()
234
+ unique_distortions = []
235
+ for d in found_distortions:
236
+ if d not in seen:
237
+ seen.add(d)
238
+ unique_distortions.append(d)
239
+
240
+ return unique_distortions if unique_distortions else ["Unknown Distortion"]
241
+
242
+
243
+ def _extract_explanation(text: str) -> str:
244
+ """
245
+ Extract phần giải thích từ response
246
+ Bỏ qua phần danh sách distortions trong []
247
+ """
248
+ import re
249
+
250
+ text_cleaned = re.sub(r'^\s*\[.*?\]\s*', '', text).strip()
251
+
252
+ if text_cleaned:
253
+ explanation = text_cleaned.strip()
254
+
255
+ prefixes_to_remove = [
256
+ "explanation:",
257
+ "giải thích:",
258
+ "phân tích:"
259
+ # "the speaker"
260
+ ]
261
+
262
+ explanation_lower = explanation.lower()
263
+ for prefix in prefixes_to_remove:
264
+ if explanation_lower.startswith(prefix):
265
+ explanation = explanation[len(prefix):].strip()
266
+ if explanation:
267
+ explanation = explanation[0].upper() + explanation[1:]
268
+ break
269
+
270
+ return explanation
271
+
272
+ return text.strip()
273
+
274
+ @app.post("/api/detect")
275
+ async def detect_distortion(request: DetectionRequest):
276
+ try:
277
+ update_session(request.session_id, {
278
+ 'situation': request.situation,
279
+ 'thought': request.thought
280
+ })
281
+
282
+ async with httpx.AsyncClient(timeout=30.0) as client:
283
+ dot_analysis = await client.post(
284
+ f"{API_base}prompts/templates/execute",
285
+ json={
286
+ "provider": "groq",
287
+ "template_name": "dot.analysis",
288
+ "model": "openai/gpt-oss-20b",
289
+ "variables": {
290
+ "situation": request.situation,
291
+ "thought": request.thought
292
+ }
293
+ },
294
+ headers={
295
+ "accept": "application/json",
296
+ "Content-Type": "application/json"
297
+ }
298
+ )
299
+
300
+ dot_analysis.raise_for_status()
301
+ result_analysis = dot_analysis.json()
302
+ analysis_response = result_analysis.get("result", "") or result_analysis.get("content", "") # Fix: đổi result thành result_analysis
303
+
304
+ # Bước 2: Gọi dot.detection với kết quả từ dot.analysis
305
+ dot_detection = await client.post(
306
+ f"{API_base}prompts/templates/execute",
307
+ json={
308
+ "provider": "groq",
309
+ "template_name": "dot.detection",
310
+ "model": "openai/gpt-oss-20b",
311
+ "variables": {
312
+ "situation": request.situation,
313
+ "thought": request.thought,
314
+ "dot_analysis": analysis_response
315
+ }
316
+ },
317
+ headers={
318
+ "accept": "application/json",
319
+ "Content-Type": "application/json"
320
+ }
321
+ )
322
+
323
+ dot_detection.raise_for_status()
324
+ result_detection = dot_detection.json() # Fix: đổi tên biến để rõ ràng
325
+
326
+ ai_response = result_detection.get("result", "") or result_detection.get("content", "") # Fix: dùng result_detection
327
+
328
+ has_distortion = _check_has_distortion(ai_response)
329
+ distortion_types = _extract_distortion_types(ai_response)
330
+ explanation = _extract_explanation(ai_response)
331
+
332
+ update_session(request.session_id, {
333
+ 'distortions': distortion_types if distortion_types else []
334
+ })
335
+
336
+ return {
337
+ "session_id": request.session_id,
338
+ "has_distortion": has_distortion,
339
+ "distortion_types": distortion_types,
340
+ "explanation": explanation,
341
+ "raw_response": ai_response
342
+ }
343
+
344
+ except httpx.HTTPError as e:
345
+ raise HTTPException(
346
+ status_code=500,
347
+ detail=f"Lỗi khi gọi API phân tích: {str(e)}"
348
+ )
349
+ except Exception as e:
350
+ raise HTTPException(
351
+ status_code=500,
352
+ detail=f"Lỗi không xác định: {str(e)}"
353
+ )
354
+
355
+ def _parse_json_response(text: str) -> dict:
356
+ """Parse JSON từ AI response, xử lý markdown và whitespace"""
357
+ import json
358
+ import re
359
+
360
+ try:
361
+ # Clean text
362
+ text = text.strip()
363
+
364
+ # Remove markdown code blocks
365
+ if text.startswith("```json"):
366
+ text = text[7:]
367
+ elif text.startswith("```"):
368
+ text = text[3:]
369
+
370
+ if text.endswith("```"):
371
+ text = text[:-3]
372
+
373
+ text = text.strip()
374
+
375
+ # Parse JSON
376
+ return json.loads(text)
377
+
378
+ except json.JSONDecodeError as e:
379
+ # Fallback: try to extract JSON from text
380
+ json_match = re.search(r'\{.*\}', text, re.DOTALL)
381
+ if json_match:
382
+ try:
383
+ return json.loads(json_match.group())
384
+ except:
385
+ pass
386
+
387
+ raise ValueError(f"Không thể parse JSON response: {e}\nText: {text[:200]}")
388
+
389
+ @app.post("/api/analyze")
390
+ async def analyze_thought(request: AnalyzeRequest):
391
+ try:
392
+ async with httpx.AsyncClient(timeout=30.0) as client:
393
+ thera_rcm = await client.post(
394
+ f"{API_base}prompts/templates/execute",
395
+ json={
396
+ "provider": "groq",
397
+ "template_name": "dot.thera_rcm",
398
+ "model": "openai/gpt-oss-20b",
399
+ "variables": {
400
+ "situation": request.situation,
401
+ "thought": request.thought,
402
+ "distortions_type": request.distortions
403
+ }
404
+ },
405
+ headers={
406
+ "accept": "application/json",
407
+ "Content-Type": "application/json"
408
+ }
409
+ )
410
+ thera_rcm.raise_for_status()
411
+ result = thera_rcm.json()
412
+ print(request.situation)
413
+ print(request.thought)
414
+ print(request.distortions)
415
+
416
+ ai_text = result.get("result", "") or result.get("content", "")
417
+ parsed_result = _parse_json_response(ai_text)
418
+
419
+ # Validate và add defaults nếu thiếu fields
420
+ if "emotional_impact" not in parsed_result:
421
+ parsed_result["emotional_impact"] = "Tác động cảm xúc đáng kể"
422
+
423
+ if "underlying_beliefs" not in parsed_result or not parsed_result["underlying_beliefs"]:
424
+ parsed_result["underlying_beliefs"] = ["Niềm tin cốt lõi cần được khám phá thêm"]
425
+
426
+ if "triggers" not in parsed_result or not parsed_result["triggers"]:
427
+ parsed_result["triggers"] = ["Các tình huống tương tự"]
428
+
429
+ if "recommended_therapies" not in parsed_result or not parsed_result["recommended_therapies"]:
430
+ # Default therapies based on common distortions
431
+ parsed_result["recommended_therapies"] = ["CBT", "ACT"]
432
+ parsed_result["session_id"] = request.session_id
433
+ return parsed_result
434
+
435
+ except json.JSONDecodeError as e:
436
+ # Fallback response nếu parse JSON thất bại
437
+ return {
438
+ "session_id": request.session_id,
439
+ "emotional_impact": "Lo âu và căng thẳng đáng kể do các suy nghĩ tiêu cực",
440
+ "underlying_beliefs": [
441
+ "Tôi cần được chấp nhận bởi người khác",
442
+ "Tôi phải tránh thất bại bằng mọi giá",
443
+ "Nếu có vấn đề xảy ra, đó là lỗi của tôi"
444
+ ],
445
+ "triggers": [
446
+ "Tình huống liên quan đến mối quan hệ",
447
+ "Áp lực và kỳ vọng",
448
+ "Sự không chắc chắn"
449
+ ],
450
+ "recommended_therapies": ["CBT", "ACT", "DBT"]
451
+ }
452
+
453
+ except httpx.HTTPError as e:
454
+ raise HTTPException(
455
+ status_code=500,
456
+ detail=f"Lỗi khi gọi API phân tích: {str(e)}"
457
+ )
458
+ except Exception as e:
459
+ raise HTTPException(
460
+ status_code=500,
461
+ detail=f"Lỗi không xác định: {str(e)}"
462
+ )
463
+
464
+ # @app.post("/api/reframe")
465
+ # async def generate_reframe(request: ReframeRequest):
466
+ # reframe_candidates = []
467
+ # for therapy in request.recommended_therapies:
468
+ # async with httpx.AsyncClient(timeout=30.0) as client:
469
+ # response = await client.post(
470
+ # f"{API_base}prompts/templates/execute",
471
+ # json={
472
+ # "provider": "groq",
473
+ # "template_name": f"reframe.{therapy.lower()}",
474
+ # "model": "openai/gpt-oss-20b",
475
+ # "variables": {
476
+ # "situation": request.situation,
477
+ # "thought": request.thought,
478
+ # }
479
+ # },
480
+ # headers={
481
+ # "accept": "application/json",
482
+ # "Content-Type": "application/json"
483
+ # }
484
+ # )
485
+ # response.raise_for_status()
486
+ # result = response.json()
487
+
488
+ # reframe = result.get("reframing response", "")
489
+ # # parsed_result = _parse_json_response(ai_text)
490
+ # reframe_candidates.append({
491
+ # "therapy": f"{therapy}",
492
+ # "reframe": f"{reframe}",
493
+ # "rationale": "demo",
494
+ # "evaluation": {"empathy": 5, "logic": 4, "helpfulness": 5}
495
+ # })
496
+ # return reframe_candidates
497
+
498
+ @app.post("/api/reframe")
499
+ async def generate_reframe(request: ReframeRequest):
500
+ async def fetch_reframe(therapy: str) -> Dict[str, Any]:
501
+ """Fetch reframe for a single therapy type"""
502
+ async with httpx.AsyncClient(timeout=30.0) as client:
503
+ response = await client.post(
504
+ f"{API_base}prompts/templates/execute",
505
+ json={
506
+ "provider": "groq",
507
+ "template_name": f"reframe.{therapy.lower()}",
508
+ "model": "openai/gpt-oss-20b",
509
+ "variables": {
510
+ "situation": request.situation,
511
+ "thought": request.thought,
512
+ }
513
+ },
514
+ headers={
515
+ "accept": "application/json",
516
+ "Content-Type": "application/json"
517
+ }
518
+ )
519
+ response.raise_for_status()
520
+ result = response.json()
521
+
522
+ # Parse JSON string trong trường 'content'
523
+ import json
524
+ content_str = result.get("content", "{}")
525
+ content_json = json.loads(content_str)
526
+
527
+ # Thử cả 2 key có thể có
528
+ reframe = content_json.get("reframing response") or content_json.get("reframing_response", "")
529
+ wtw = content_json.get("why_this_works") or content_json.get("why this works", "")
530
+
531
+ feedback = await client.post(
532
+ f"{API_base}prompts/templates/execute",
533
+ json={
534
+ "provider": "groq",
535
+ "template_name": f"dot.thera_supervisor",
536
+ "model": "openai/gpt-oss-20b",
537
+ "variables": {
538
+ "situation": request.situation,
539
+ "thought": request.thought,
540
+ "reframe_response": reframe
541
+ }
542
+ },
543
+ headers={
544
+ "accept": "application/json",
545
+ "Content-Type": "application/json"
546
+ }
547
+ )
548
+ feedback.raise_for_status()
549
+ feedback = feedback.json()
550
+ print(feedback)
551
+ feedback_str = feedback.get("content", "{}")
552
+ feedback_json = json.loads(feedback_str)
553
+ return {
554
+ "therapy": therapy,
555
+ "reframe": reframe,
556
+ "rationale": wtw,
557
+ "evaluation": feedback_json
558
+ }
559
+
560
+ reframe_candidates = await asyncio.gather(
561
+ *[fetch_reframe(therapy) for therapy in request.recommended_therapies],
562
+ return_exceptions=True
563
+ )
564
+ print(reframe_candidates)
565
+ successful_results = [
566
+ result for result in reframe_candidates
567
+ if not isinstance(result, Exception)
568
+ ]
569
+ return {
570
+ "session_id": request.session_id,
571
+ "candidates": successful_results
572
+ }
573
+
574
+ @app.post("/api/save")
575
+ async def save_selection(data: dict):
576
+ print(f"User saved reframe: {data}")
577
+ return {"status": "success"}
578
+
579
+
580
+ app.mount("/assets", StaticFiles(directory="../mind-reframe/dist/assets"), name="assets")
581
+
582
+ @app.get("/{full_path:path}")
583
+ async def serve_react_app(full_path: str):
584
+ if full_path.startswith("api/"):
585
+ return {"error": "Not Found"}
586
+
587
+ return FileResponse("../mind-reframe/dist/index.html")
Web/mind-reframe/.gitignore ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode/*
17
+ !.vscode/extensions.json
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
Web/mind-reframe/README.md ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # React + TypeScript + Vite
2
+
3
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
+
5
+ Currently, two official plugins are available:
6
+
7
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9
+
10
+ ## React Compiler
11
+
12
+ The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
13
+
14
+ ## Expanding the ESLint configuration
15
+
16
+ If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
17
+
18
+ ```js
19
+ export default defineConfig([
20
+ globalIgnores(['dist']),
21
+ {
22
+ files: ['**/*.{ts,tsx}'],
23
+ extends: [
24
+ // Other configs...
25
+
26
+ // Remove tseslint.configs.recommended and replace with this
27
+ tseslint.configs.recommendedTypeChecked,
28
+ // Alternatively, use this for stricter rules
29
+ tseslint.configs.strictTypeChecked,
30
+ // Optionally, add this for stylistic rules
31
+ tseslint.configs.stylisticTypeChecked,
32
+
33
+ // Other configs...
34
+ ],
35
+ languageOptions: {
36
+ parserOptions: {
37
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
38
+ tsconfigRootDir: import.meta.dirname,
39
+ },
40
+ // other options...
41
+ },
42
+ },
43
+ ])
44
+ ```
45
+
46
+ You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
47
+
48
+ ```js
49
+ // eslint.config.js
50
+ import reactX from 'eslint-plugin-react-x'
51
+ import reactDom from 'eslint-plugin-react-dom'
52
+
53
+ export default defineConfig([
54
+ globalIgnores(['dist']),
55
+ {
56
+ files: ['**/*.{ts,tsx}'],
57
+ extends: [
58
+ // Other configs...
59
+ // Enable lint rules for React
60
+ reactX.configs['recommended-typescript'],
61
+ // Enable lint rules for React DOM
62
+ reactDom.configs.recommended,
63
+ ],
64
+ languageOptions: {
65
+ parserOptions: {
66
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
67
+ tsconfigRootDir: import.meta.dirname,
68
+ },
69
+ // other options...
70
+ },
71
+ },
72
+ ])
73
+ ```
Web/mind-reframe/dist/assets/index-B3ZeeytQ.css ADDED
@@ -0,0 +1 @@
 
 
1
+ *,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.-bottom-1\/2{bottom:-50%}.-left-1\/2{left:-50%}.-right-1\/2{right:-50%}.-right-2{right:-.5rem}.-top-1\/2{top:-50%}.-top-2{top:-.5rem}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.z-50{z-index:50}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mb-1{margin-bottom:.25rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-2{margin-left:.5rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-md{max-width:28rem}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:2s cubic-bezier(.4,0,.6,1) infinite pulse}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:1s linear infinite spin}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem * var(--tw-space-x-reverse));margin-left:calc(2rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-4{border-left-width:4px}.border-t{border-top-width:1px}.border-blue-100{--tw-border-opacity:1;border-color:rgb(219 234 254/var(--tw-border-opacity,1))}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-800{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}.border-green-100{--tw-border-opacity:1;border-color:rgb(220 252 231/var(--tw-border-opacity,1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-green-300{--tw-border-opacity:1;border-color:rgb(134 239 172/var(--tw-border-opacity,1))}.border-green-500{--tw-border-opacity:1;border-color:rgb(34 197 94/var(--tw-border-opacity,1))}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity,1))}.border-indigo-600{--tw-border-opacity:1;border-color:rgb(79 70 229/var(--tw-border-opacity,1))}.border-pink-500{--tw-border-opacity:1;border-color:rgb(236 72 153/var(--tw-border-opacity,1))}.border-purple-500{--tw-border-opacity:1;border-color:rgb(168 85 247/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.border-yellow-300{--tw-border-opacity:1;border-color:rgb(253 224 71/var(--tw-border-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(187 247 208/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity,1))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity,1))}.bg-pink-100{--tw-bg-opacity:1;background-color:rgb(252 231 243/var(--tw-bg-opacity,1))}.bg-pink-200{--tw-bg-opacity:1;background-color:rgb(251 207 232/var(--tw-bg-opacity,1))}.bg-pink-600{--tw-bg-opacity:1;background-color:rgb(219 39 119/var(--tw-bg-opacity,1))}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(243 232 255/var(--tw-bg-opacity,1))}.bg-purple-600{--tw-bg-opacity:1;background-color:rgb(147 51 234/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/50{background-color:#ffffff80}.bg-white\/80{background-color:#fffc}.bg-white\/90{background-color:#ffffffe6}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity,1))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity,1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right, var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right, var(--tw-gradient-stops))}.bg-gradient-to-tr{background-image:linear-gradient(to top right, var(--tw-gradient-stops))}.from-blue-50{--tw-gradient-from:#eff6ff var(--tw-gradient-from-position);--tw-gradient-to:#eff6ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-gray-50{--tw-gradient-from:#f9fafb var(--tw-gradient-from-position);--tw-gradient-to:#f9fafb00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-green-50{--tw-gradient-from:#f0fdf4 var(--tw-gradient-from-position);--tw-gradient-to:#f0fdf400 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-green-600{--tw-gradient-from:#16a34a var(--tw-gradient-from-position);--tw-gradient-to:#16a34a00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-200\/30{--tw-gradient-from:#c7d2fe4d var(--tw-gradient-from-position);--tw-gradient-to:#c7d2fe00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-50{--tw-gradient-from:#eef2ff var(--tw-gradient-from-position);--tw-gradient-to:#eef2ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-500{--tw-gradient-from:#6366f1 var(--tw-gradient-from-position);--tw-gradient-to:#6366f100 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-600{--tw-gradient-from:#4f46e5 var(--tw-gradient-from-position);--tw-gradient-to:#4f46e500 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-pink-50{--tw-gradient-from:#fdf2f8 var(--tw-gradient-from-position);--tw-gradient-to:#fdf2f800 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-200\/30{--tw-gradient-from:#e9d5ff4d var(--tw-gradient-from-position);--tw-gradient-to:#e9d5ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-50{--tw-gradient-from:#faf5ff var(--tw-gradient-from-position);--tw-gradient-to:#faf5ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-yellow-50{--tw-gradient-from:#fefce8 var(--tw-gradient-from-position);--tw-gradient-to:#fefce800 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.via-purple-50{--tw-gradient-to:#faf5ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), #faf5ff var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-white{--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), #fff var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-amber-50{--tw-gradient-to:#fffbeb var(--tw-gradient-to-position)}.to-blue-100{--tw-gradient-to:#dbeafe var(--tw-gradient-to-position)}.to-emerald-50{--tw-gradient-to:#ecfdf5 var(--tw-gradient-to-position)}.to-emerald-600{--tw-gradient-to:#059669 var(--tw-gradient-to-position)}.to-gray-100{--tw-gradient-to:#f3f4f6 var(--tw-gradient-to-position)}.to-green-100{--tw-gradient-to:#dcfce7 var(--tw-gradient-to-position)}.to-indigo-100{--tw-gradient-to:#e0e7ff var(--tw-gradient-to-position)}.to-pink-100{--tw-gradient-to:#fce7f3 var(--tw-gradient-to-position)}.to-pink-50{--tw-gradient-to:#fdf2f8 var(--tw-gradient-to-position)}.to-purple-100{--tw-gradient-to:#f3e8ff var(--tw-gradient-to-position)}.to-purple-50{--tw-gradient-to:#faf5ff var(--tw-gradient-to-position)}.to-purple-500{--tw-gradient-to:#a855f7 var(--tw-gradient-to-position)}.to-purple-600{--tw-gradient-to:#9333ea var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.fill-yellow-400{fill:#facc15}.fill-yellow-500{fill:#eab308}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-12{padding-bottom:3rem}.pb-20{padding-bottom:5rem}.pb-4{padding-bottom:1rem}.pt-16{padding-top:4rem}.pt-20{padding-top:5rem}.pt-24{padding-top:6rem}.pt-4{padding-top:1rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-blue-800{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity,1))}.text-green-800{--tw-text-opacity:1;color:rgb(22 101 52/var(--tw-text-opacity,1))}.text-green-900{--tw-text-opacity:1;color:rgb(20 83 45/var(--tw-text-opacity,1))}.text-indigo-100{--tw-text-opacity:1;color:rgb(224 231 255/var(--tw-text-opacity,1))}.text-indigo-400{--tw-text-opacity:1;color:rgb(129 140 248/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-indigo-700{--tw-text-opacity:1;color:rgb(67 56 202/var(--tw-text-opacity,1))}.text-indigo-900{--tw-text-opacity:1;color:rgb(49 46 129/var(--tw-text-opacity,1))}.text-pink-600{--tw-text-opacity:1;color:rgb(219 39 119/var(--tw-text-opacity,1))}.text-pink-900{--tw-text-opacity:1;color:rgb(131 24 67/var(--tw-text-opacity,1))}.text-purple-600{--tw-text-opacity:1;color:rgb(147 51 234/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-transparent{color:#0000}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-yellow-400{--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity,1))}.text-yellow-500{--tw-text-opacity:1;color:rgb(234 179 8/var(--tw-text-opacity,1))}.text-yellow-600{--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity,1))}.text-yellow-900{--tw-text-opacity:1;color:rgb(113 63 18/var(--tw-text-opacity,1))}.opacity-20{opacity:.2}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.blur-2xl{--tw-blur:blur(40px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-3xl{--tw-blur:blur(64px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-property:all;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.placeholder\:text-gray-400::placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-\[1\.02\]:hover{--tw-scale-x:1.02;--tw-scale-y:1.02;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-indigo-200:hover{--tw-border-opacity:1;border-color:rgb(199 210 254/var(--tw-border-opacity,1))}.hover\:border-indigo-300:hover{--tw-border-opacity:1;border-color:rgb(165 180 252/var(--tw-border-opacity,1))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity,1))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:bg-indigo-100:hover{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity,1))}.hover\:bg-indigo-50:hover{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.hover\:bg-indigo-700:hover{--tw-bg-opacity:1;background-color:rgb(67 56 202/var(--tw-bg-opacity,1))}.hover\:from-green-700:hover{--tw-gradient-from:#15803d var(--tw-gradient-from-position);--tw-gradient-to:#15803d00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.hover\:from-indigo-700:hover{--tw-gradient-from:#4338ca var(--tw-gradient-from-position);--tw-gradient-to:#4338ca00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.hover\:to-emerald-700:hover{--tw-gradient-to:#047857 var(--tw-gradient-to-position)}.hover\:to-purple-700:hover{--tw-gradient-to:#7e22ce var(--tw-gradient-to-position)}.hover\:text-blue-800:hover{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity,1))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.hover\:text-indigo-600:hover{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.hover\:text-indigo-800:hover{--tw-text-opacity:1;color:rgb(55 48 163/var(--tw-text-opacity,1))}.hover\:text-yellow-200:hover{--tw-text-opacity:1;color:rgb(254 240 138/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity,1))}.focus\:outline-none:focus{outline-offset:2px;outline:2px solid #0000}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.focus\:ring-indigo-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(199 210 254/var(--tw-ring-opacity,1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:from-gray-400:disabled{--tw-gradient-from:#9ca3af var(--tw-gradient-from-position);--tw-gradient-to:#9ca3af00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.disabled\:to-gray-400:disabled{--tw-gradient-to:#9ca3af var(--tw-gradient-to-position)}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:640px){.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}}
Web/mind-reframe/dist/assets/index-BoHQMix6.js ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/dist/assets/index-Ces_8vm5.js ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/dist/assets/index-DSeqsUYm.css ADDED
@@ -0,0 +1 @@
 
 
1
+ *,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.-bottom-1\/2{bottom:-50%}.-left-1\/2{left:-50%}.-right-1\/2{right:-50%}.-right-2{right:-.5rem}.-top-1\/2{top:-50%}.-top-2{top:-.5rem}.top-0{top:0}.z-50{z-index:50}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mb-1{margin-bottom:.25rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-2{margin-left:.5rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-md{max-width:28rem}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:2s cubic-bezier(.4,0,.6,1) infinite pulse}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:1s linear infinite spin}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem * var(--tw-space-x-reverse));margin-left:calc(2rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-4{border-left-width:4px}.border-t{border-top-width:1px}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-800{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}.border-green-100{--tw-border-opacity:1;border-color:rgb(220 252 231/var(--tw-border-opacity,1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-green-300{--tw-border-opacity:1;border-color:rgb(134 239 172/var(--tw-border-opacity,1))}.border-green-500{--tw-border-opacity:1;border-color:rgb(34 197 94/var(--tw-border-opacity,1))}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity,1))}.border-indigo-600{--tw-border-opacity:1;border-color:rgb(79 70 229/var(--tw-border-opacity,1))}.border-pink-500{--tw-border-opacity:1;border-color:rgb(236 72 153/var(--tw-border-opacity,1))}.border-purple-500{--tw-border-opacity:1;border-color:rgb(168 85 247/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.border-yellow-300{--tw-border-opacity:1;border-color:rgb(253 224 71/var(--tw-border-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(187 247 208/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity,1))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity,1))}.bg-pink-100{--tw-bg-opacity:1;background-color:rgb(252 231 243/var(--tw-bg-opacity,1))}.bg-pink-200{--tw-bg-opacity:1;background-color:rgb(251 207 232/var(--tw-bg-opacity,1))}.bg-pink-600{--tw-bg-opacity:1;background-color:rgb(219 39 119/var(--tw-bg-opacity,1))}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(243 232 255/var(--tw-bg-opacity,1))}.bg-purple-600{--tw-bg-opacity:1;background-color:rgb(147 51 234/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/50{background-color:#ffffff80}.bg-white\/80{background-color:#fffc}.bg-white\/90{background-color:#ffffffe6}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity,1))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity,1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right, var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right, var(--tw-gradient-stops))}.bg-gradient-to-tr{background-image:linear-gradient(to top right, var(--tw-gradient-stops))}.from-blue-50{--tw-gradient-from:#eff6ff var(--tw-gradient-from-position);--tw-gradient-to:#eff6ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-gray-50{--tw-gradient-from:#f9fafb var(--tw-gradient-from-position);--tw-gradient-to:#f9fafb00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-green-50{--tw-gradient-from:#f0fdf4 var(--tw-gradient-from-position);--tw-gradient-to:#f0fdf400 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-green-600{--tw-gradient-from:#16a34a var(--tw-gradient-from-position);--tw-gradient-to:#16a34a00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-200\/30{--tw-gradient-from:#c7d2fe4d var(--tw-gradient-from-position);--tw-gradient-to:#c7d2fe00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-50{--tw-gradient-from:#eef2ff var(--tw-gradient-from-position);--tw-gradient-to:#eef2ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-500{--tw-gradient-from:#6366f1 var(--tw-gradient-from-position);--tw-gradient-to:#6366f100 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-indigo-600{--tw-gradient-from:#4f46e5 var(--tw-gradient-from-position);--tw-gradient-to:#4f46e500 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-pink-50{--tw-gradient-from:#fdf2f8 var(--tw-gradient-from-position);--tw-gradient-to:#fdf2f800 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-200\/30{--tw-gradient-from:#e9d5ff4d var(--tw-gradient-from-position);--tw-gradient-to:#e9d5ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-50{--tw-gradient-from:#faf5ff var(--tw-gradient-from-position);--tw-gradient-to:#faf5ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-yellow-50{--tw-gradient-from:#fefce8 var(--tw-gradient-from-position);--tw-gradient-to:#fefce800 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.via-purple-50{--tw-gradient-to:#faf5ff00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), #faf5ff var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-white{--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), #fff var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-amber-50{--tw-gradient-to:#fffbeb var(--tw-gradient-to-position)}.to-blue-100{--tw-gradient-to:#dbeafe var(--tw-gradient-to-position)}.to-emerald-50{--tw-gradient-to:#ecfdf5 var(--tw-gradient-to-position)}.to-emerald-600{--tw-gradient-to:#059669 var(--tw-gradient-to-position)}.to-gray-100{--tw-gradient-to:#f3f4f6 var(--tw-gradient-to-position)}.to-green-100{--tw-gradient-to:#dcfce7 var(--tw-gradient-to-position)}.to-indigo-100{--tw-gradient-to:#e0e7ff var(--tw-gradient-to-position)}.to-pink-100{--tw-gradient-to:#fce7f3 var(--tw-gradient-to-position)}.to-pink-50{--tw-gradient-to:#fdf2f8 var(--tw-gradient-to-position)}.to-purple-100{--tw-gradient-to:#f3e8ff var(--tw-gradient-to-position)}.to-purple-50{--tw-gradient-to:#faf5ff var(--tw-gradient-to-position)}.to-purple-500{--tw-gradient-to:#a855f7 var(--tw-gradient-to-position)}.to-purple-600{--tw-gradient-to:#9333ea var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.fill-yellow-400{fill:#facc15}.fill-yellow-500{fill:#eab308}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-12{padding-bottom:3rem}.pb-20{padding-bottom:5rem}.pb-4{padding-bottom:1rem}.pt-16{padding-top:4rem}.pt-20{padding-top:5rem}.pt-24{padding-top:6rem}.pt-4{padding-top:1rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity,1))}.text-green-800{--tw-text-opacity:1;color:rgb(22 101 52/var(--tw-text-opacity,1))}.text-green-900{--tw-text-opacity:1;color:rgb(20 83 45/var(--tw-text-opacity,1))}.text-indigo-100{--tw-text-opacity:1;color:rgb(224 231 255/var(--tw-text-opacity,1))}.text-indigo-400{--tw-text-opacity:1;color:rgb(129 140 248/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-indigo-700{--tw-text-opacity:1;color:rgb(67 56 202/var(--tw-text-opacity,1))}.text-indigo-900{--tw-text-opacity:1;color:rgb(49 46 129/var(--tw-text-opacity,1))}.text-pink-600{--tw-text-opacity:1;color:rgb(219 39 119/var(--tw-text-opacity,1))}.text-pink-900{--tw-text-opacity:1;color:rgb(131 24 67/var(--tw-text-opacity,1))}.text-purple-600{--tw-text-opacity:1;color:rgb(147 51 234/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-transparent{color:#0000}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-yellow-400{--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity,1))}.text-yellow-500{--tw-text-opacity:1;color:rgb(234 179 8/var(--tw-text-opacity,1))}.text-yellow-600{--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity,1))}.text-yellow-900{--tw-text-opacity:1;color:rgb(113 63 18/var(--tw-text-opacity,1))}.opacity-20{opacity:.2}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.blur-2xl{--tw-blur:blur(40px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-3xl{--tw-blur:blur(64px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-property:all;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-indigo-200:hover{--tw-border-opacity:1;border-color:rgb(199 210 254/var(--tw-border-opacity,1))}.hover\:border-indigo-300:hover{--tw-border-opacity:1;border-color:rgb(165 180 252/var(--tw-border-opacity,1))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity,1))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:bg-indigo-100:hover{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity,1))}.hover\:bg-indigo-50:hover{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.hover\:bg-indigo-700:hover{--tw-bg-opacity:1;background-color:rgb(67 56 202/var(--tw-bg-opacity,1))}.hover\:from-green-700:hover{--tw-gradient-from:#15803d var(--tw-gradient-from-position);--tw-gradient-to:#15803d00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.hover\:from-indigo-700:hover{--tw-gradient-from:#4338ca var(--tw-gradient-from-position);--tw-gradient-to:#4338ca00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.hover\:to-emerald-700:hover{--tw-gradient-to:#047857 var(--tw-gradient-to-position)}.hover\:to-purple-700:hover{--tw-gradient-to:#7e22ce var(--tw-gradient-to-position)}.hover\:text-indigo-600:hover{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.hover\:text-yellow-200:hover{--tw-text-opacity:1;color:rgb(254 240 138/var(--tw-text-opacity,1))}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity,1))}.focus\:outline-none:focus{outline-offset:2px;outline:2px solid #0000}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.focus\:ring-indigo-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(199 210 254/var(--tw-ring-opacity,1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:from-gray-400:disabled{--tw-gradient-from:#9ca3af var(--tw-gradient-from-position);--tw-gradient-to:#9ca3af00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.disabled\:to-gray-400:disabled{--tw-gradient-to:#9ca3af var(--tw-gradient-to-position)}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:640px){.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}}
Web/mind-reframe/dist/assets/index-ebY5FnGP.js ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/dist/index.html ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>mind-reframe</title>
8
+ <script type="module" crossorigin src="/assets/index-Ces_8vm5.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-B3ZeeytQ.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
Web/mind-reframe/dist/vite.svg ADDED
Web/mind-reframe/eslint.config.js ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+ import { defineConfig, globalIgnores } from 'eslint/config'
7
+
8
+ export default defineConfig([
9
+ globalIgnores(['dist']),
10
+ {
11
+ files: ['**/*.{ts,tsx}'],
12
+ extends: [
13
+ js.configs.recommended,
14
+ tseslint.configs.recommended,
15
+ reactHooks.configs.flat.recommended,
16
+ reactRefresh.configs.vite,
17
+ ],
18
+ languageOptions: {
19
+ ecmaVersion: 2020,
20
+ globals: globals.browser,
21
+ },
22
+ },
23
+ ])
Web/mind-reframe/index.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>mind-reframe</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
Web/mind-reframe/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/package.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "mind-reframe",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "lucide-react": "^0.562.0",
14
+ "react": "^19.2.0",
15
+ "react-dom": "^19.2.0"
16
+ },
17
+ "devDependencies": {
18
+ "@eslint/js": "^9.39.1",
19
+ "@types/node": "^24.10.1",
20
+ "@types/react": "^19.2.5",
21
+ "@types/react-dom": "^19.2.3",
22
+ "@vitejs/plugin-react": "^5.1.1",
23
+ "autoprefixer": "^10.4.23",
24
+ "eslint": "^9.39.1",
25
+ "eslint-plugin-react-hooks": "^7.0.1",
26
+ "eslint-plugin-react-refresh": "^0.4.24",
27
+ "globals": "^16.5.0",
28
+ "postcss": "^8.5.6",
29
+ "tailwindcss": "^3.4.17",
30
+ "typescript": "~5.9.3",
31
+ "typescript-eslint": "^8.46.4",
32
+ "vite": "npm:rolldown-vite@7.2.5"
33
+ },
34
+ "overrides": {
35
+ "vite": "npm:rolldown-vite@7.2.5"
36
+ }
37
+ }
Web/mind-reframe/postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
Web/mind-reframe/public/vite.svg ADDED
Web/mind-reframe/src/App.css ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+
21
+ @keyframes logo-spin {
22
+ from {
23
+ transform: rotate(0deg);
24
+ }
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ @media (prefers-reduced-motion: no-preference) {
31
+ a:nth-of-type(2) .logo {
32
+ animation: logo-spin infinite 20s linear;
33
+ }
34
+ }
35
+
36
+ .card {
37
+ padding: 2em;
38
+ }
39
+
40
+ .read-the-docs {
41
+ color: #888;
42
+ }
Web/mind-reframe/src/App.tsx ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/src/assets/react.svg ADDED
Web/mind-reframe/src/index.css ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
Web/mind-reframe/src/main.tsx ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
Web/mind-reframe/tailwind.config.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: [
4
+ "./index.html",
5
+ "./src/**/*.{js,ts,jsx,tsx}",
6
+ ],
7
+ theme: {
8
+ extend: {},
9
+ },
10
+ plugins: [],
11
+ }
Web/mind-reframe/tsconfig.app.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "types": ["vite/client"],
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true
26
+ },
27
+ "include": ["src"]
28
+ }
Web/mind-reframe/tsconfig.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
Web/mind-reframe/tsconfig.node.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
Web/mind-reframe/vite.config.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ // https://vitejs.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ server: {
8
+ // Thêm đoạn này vào để cho phép ngrok truy cập
9
+ allowedHosts: true,
10
+ // Hoặc nếu 'true' bị báo lỗi đỏ (ở bản cũ), dùng dòng dưới:
11
+ // host: true,
12
+ },
13
+ })
ai-core/.env ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GROQ_BASE_URL="https://api.groq.com/openai/v1"
2
+
3
+ # App Settings
4
+ APP_NAME=AI-Core API
5
+ APP_VERSION=1.0.0
6
+ DEBUG=True
7
+
8
+ # Server
9
+ HOST=0.0.0.0
10
+ PORT=1812
11
+
12
+ # Rate Limiting
13
+ RATE_LIMIT_ENABLED=True
14
+ RATE_LIMIT_PER_MINUTE=60
15
+ RATE_LIMIT_PER_HOUR=1000
16
+
17
+ # Authentication
18
+ AUTH_ENABLED=False
19
+ SECRET_KEY=your-super-secret-key-change-in-production
20
+ API_KEYS=["demo-key-123","test-key-456","prod-key-789"]
21
+
22
+ # Caching
23
+ CACHE_ENABLED=True
24
+ CACHE_TYPE=memory
25
+ CACHE_TTL=3600
26
+ CACHE_MAX_SIZE=1000
27
+
28
+ # Redis (nếu dùng Redis)
29
+ # CACHE_TYPE=redis
30
+ # REDIS_HOST=localhost
31
+ # REDIS_PORT=6379
32
+ # REDIS_DB=0
33
+ # REDIS_PASSWORD=
34
+
35
+ # Response Compression
36
+ COMPRESSION_ENABLED=True
37
+ COMPRESSION_MIN_SIZE=500
ai-core/README.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ReframeBench: Technical Implementation of Multi-Therapy Cognitive Restructuring
2
+
3
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
4
+ [![LangChain](https://img.shields.io/badge/LangChain-0.1.0-green.svg)](https://www.langchain.com/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ > **Core Technical Documentation** for "ReframeBench: A Benchmark for Multi-Therapy Cognitive Restructuring with LLMs". [cite_start]This repository implements a novel multi-agent reasoning pipeline that operationalizes 12 distinct psychotherapeutic frameworks[cite: 235, 236, 237, 238, 239, 240, 242, 243, 244, 246].
8
+
9
+ ## 🧠 Methodology: Therapy-Oriented Prompt Engineering
10
+
11
+ The core innovation of ReframeBench is the transition from generic instruction following to **Persona-based In-Context Learning**. We formalize the cognitive restructuring task not merely as text rewriting, but as a conditional generation problem constrained by specific therapeutic theoretical frameworks.
12
+
13
+ ### Mathematical Formulation
14
+ [cite_start]We define the generation function $R_{i,m}$ for a specific therapy modality $m$ as follows[cite: 50, 51]:
15
+
16
+ $$R_{i,m} = \text{LLM}(S_i, T_i, \mathcal{I}_{role} \oplus \mathcal{I}_{mechanism} \oplus \mathcal{I}_{safety})$$
17
+
18
+ [cite_start]Where $S_i$ is the situation, $T_i$ is the negative thought[cite: 49], and the prompt $P_m$ is composed of three strictly defined components:
19
+
20
+ 1. **$\mathcal{I}_{role}$ (Role Definition):** Establishes the expert persona to prime the model's latent space (e.g., *"You are an expert ACT therapist..."*).
21
+ 2. **$\mathcal{I}_{mechanism}$ (Theoretical Constraints):** The critical differentiator that enforces specific therapeutic techniques:
22
+ * [cite_start]**CBT:** Focuses on *Evidence* and *Logic* (Disputation)[cite: 235].
23
+ * [cite_start]**ACT:** Focuses on *Cognitive Defusion* and *Values* (Acceptance)[cite: 236].
24
+ * [cite_start]**DBT:** Focuses on *Dialectics* (Balancing Acceptance and Change)[cite: 244].
25
+ 3. **$\mathcal{I}_{safety}$ (Clinical Guardrails):** Hard constraints to prevent hallucinations and unsafe medical advice (e.g., crisis resource redirection).
26
+
27
+ ---
28
+
29
+ ## ⚙️ Architecture: Multi-Agent Reasoning Pipeline
30
+
31
+ We implement a sophisticated reasoning pipeline that moves beyond simple zero-shot prompting. [cite_start]The architecture comprises three distinct stages, modeled after clinical workflows[cite: 234]:
32
+
33
+ ### Step 1: Cognitive Distortion Detection (Zero-shot Classification)
34
+ Before reframing, the system analyzes the input thought ($T_i$) to identify specific cognitive traps (e.g., Catastrophizing, Polarization).
35
+ * **Goal:** To enable targeted intervention strategies.
36
+ * **Output:** Structured JSON list of distortions.
37
+
38
+ ### Step 2: Parallel Multi-Therapy Generation
39
+ [cite_start]The system utilizes parallel threads to generate candidate reframes from $N$ different therapeutic modules simultaneously[cite: 247].
40
+ * [cite_start]**Reframer Agent:** Acts as the generator $G$ using the therapy-specific prompts defined above[cite: 245].
41
+ * **Diversity:** High temperature settings ($T \approx 0.7$) are used to ensure linguistic diversity while maintaining theoretical adherence.
42
+
43
+ ### Step 3: Supervisor-Critique (LLM-as-a-Judge)
44
+ [cite_start]A specialized **Therapeutic Quality Evaluator** agent assesses the generated candidates[cite: 251].
45
+ * **Mechanism:** It acts as a clinical supervisor, scoring reframes on a scale of 1-5 based on **Empathy**, **Actionability**, and **Safety**.
46
+ * **Selection Logic:**
47
+ $$R_{final} = \operatorname*{argmax}_{R \in \{R_{CBT}, R_{ACT}, ...\}} (\text{Score}_{supervisor}(R))$$
48
+
49
+ ---
50
+
51
+ ## ⛓️ Advanced Technique: Implicit Chain-of-Thought (CoT)
52
+
53
+ To prevent the model from generating superficial advice, we employ **Implicit Chain-of-Thought** prompting. We instruct the model to perform a "hidden" analysis phase before outputting the final response.
54
+
55
+ **Prompt Template Structure:**
56
+ ```text
57
+ Phase 1: Analysis (Internal Monologue)
58
+ - Identify the underlying emotion.
59
+ - Identify the specific cognitive trap.
60
+ - Select the appropriate technique from the [Therapy Name] manual.
61
+
62
+ Phase 2: Drafting (Final Output)
63
+ - Draft the response applying the technique.
64
+ - Ensure the tone is validating and non-judgmental.
65
+
66
+ Output ONLY Phase 2.
ai-core/app/__init__.py ADDED
File without changes
ai-core/app/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (160 Bytes). View file
 
ai-core/app/__pycache__/config.cpython-313.pyc ADDED
Binary file (2.13 kB). View file
 
ai-core/app/__pycache__/main.cpython-313.pyc ADDED
Binary file (6.74 kB). View file
 
ai-core/app/api/__init__.py ADDED
File without changes
ai-core/app/api/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (164 Bytes). View file
 
ai-core/app/api/v1/__init__.py ADDED
File without changes
ai-core/app/api/v1/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (167 Bytes). View file
 
ai-core/app/api/v1/__pycache__/router.cpython-313.pyc ADDED
Binary file (921 Bytes). View file
 
ai-core/app/api/v1/endpoints/__init__.py ADDED
File without changes
ai-core/app/api/v1/endpoints/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (177 Bytes). View file
 
ai-core/app/api/v1/endpoints/__pycache__/cache.cpython-313.pyc ADDED
Binary file (3.48 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/chat.cpython-313.pyc ADDED
Binary file (3.48 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/completion.cpython-313.pyc ADDED
Binary file (1.49 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/health.cpython-313.pyc ADDED
Binary file (1.4 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/prompts.cpython-313.pyc ADDED
Binary file (5.73 kB). View file