cuongpm-cs commited on
Commit
ca9145f
·
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 +714 -0
  8. Web/mind-reframe/.gitignore +24 -0
  9. Web/mind-reframe/README.md +73 -0
  10. Web/mind-reframe/dist/assets/index-Bpbr8g8G.js +0 -0
  11. Web/mind-reframe/dist/assets/index-CILzSiom.js +0 -0
  12. Web/mind-reframe/dist/assets/index-Cm8lmTTn.css +1 -0
  13. Web/mind-reframe/dist/assets/index-D75GAFpb.js +0 -0
  14. Web/mind-reframe/dist/assets/index-DNBzG3Ln.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 (26.4 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,714 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ class FeedbackRequest(BaseModel):
82
+ session_id: str
83
+ situation: str
84
+ thought: str
85
+ current_reframe: str
86
+
87
+ class ImproveRequest(BaseModel):
88
+ session_id: str
89
+ situation: str
90
+ thought: str
91
+ current_reframe: str
92
+ history_response: list
93
+ feedback: str
94
+
95
+ API_base = 'http://localhost:1812/api/v1/'
96
+
97
+ sessions_store: Dict[str, dict] = {}
98
+
99
+ SESSION_EXPIRY_MINUTES = 60
100
+
101
+ class FeedbackData(BaseModel):
102
+ session_id: str
103
+ timestamp: str
104
+ input: dict
105
+ output: dict
106
+ ratings: dict
107
+
108
+ @app.post("/api/feedback")
109
+ async def save_feedback(data: FeedbackData):
110
+ try:
111
+ # Chuyển đổi sang dict
112
+ record = data.dict()
113
+
114
+ # Ghi vào file dataset_feedback.jsonl
115
+ # Mode 'a' (append) để ghi nối tiếp, không ghi đè
116
+ with open("dataset_feedback.jsonl", "a", encoding="utf-8") as f:
117
+ # Ghi mỗi feedback trên 1 dòng (JSONL format)
118
+ f.write(json.dumps(record, ensure_ascii=False) + "\n")
119
+
120
+ return {"status": "success", "message": "Feedback saved"}
121
+ except Exception as e:
122
+ print(f"Error saving file: {e}")
123
+ raise HTTPException(status_code=500, detail="Internal Server Error")
124
+
125
+ @app.post("/api/session/init")
126
+ async def init_session():
127
+ """Initialize a new session"""
128
+ session_id = str(uuid.uuid4())
129
+ sessions_store[session_id] = {
130
+ 'session_id': session_id,
131
+ 'situation': None,
132
+ 'thought': None,
133
+ 'distortions': None,
134
+ 'analysis': None,
135
+ 'candidates': None,
136
+ 'selected_reframe': None,
137
+ 'created_at': datetime.now(),
138
+ 'updated_at': datetime.now()
139
+ }
140
+ return {"session_id": session_id}
141
+
142
+ def _check_has_distortion(text: str) -> bool:
143
+ """Kiểm tra xem có distortion hay không"""
144
+ if not text or len(text.strip()) < 10:
145
+ return False
146
+
147
+ # if '[' in text and ']' in text:
148
+ # return True
149
+
150
+ positive_indicators = [
151
+ "all-or-nothing", "mind reading", "catastrophizing",
152
+ "overgeneralization", "mental filter", "labeling",
153
+ "emotional reasoning", "should statements",
154
+ "jumping to conclusions", "fortune telling",
155
+ "personalization", "disqualifying"
156
+ ]
157
+
158
+ text_lower = text.lower()
159
+ if any(indicator in text_lower for indicator in positive_indicators):
160
+ return True
161
+
162
+ negative_indicators = [
163
+ "không có distortion",
164
+ "không phát hiện distortion",
165
+ "no distortion",
166
+ "không tìm thấy distortion"
167
+ ]
168
+
169
+ return not any(indicator in text_lower for indicator in negative_indicators)
170
+
171
+
172
+ def _extract_distortion_types(text: str) -> list:
173
+ """
174
+ Extract các loại distortion từ response
175
+ Hỗ trợ format: [Type1, Type2, Type3] hoặc text tự do
176
+ """
177
+ import re
178
+
179
+ bracket_match = re.search(r'\[(.*?)\]', text)
180
+ if bracket_match:
181
+ content = bracket_match.group(1)
182
+ distortions = [d.strip() for d in content.split(',')]
183
+ normalized = []
184
+ for d in distortions:
185
+ d_normalized = d.strip().title()
186
+ if 'all-or-nothing' in d.lower():
187
+ d_normalized = 'All-or-Nothing Thinking'
188
+ elif 'mind reading' in d.lower():
189
+ d_normalized = 'Mind Reading'
190
+ elif 'catastrophizing' in d.lower():
191
+ d_normalized = 'Catastrophizing'
192
+ elif 'overgeneralization' in d.lower():
193
+ d_normalized = 'Overgeneralization'
194
+ elif 'mental filter' in d.lower():
195
+ d_normalized = 'Mental Filter'
196
+ elif 'jumping to conclusions' in d.lower():
197
+ d_normalized = 'Jumping to Conclusions'
198
+ elif 'fortune telling' in d.lower():
199
+ d_normalized = 'Fortune Telling'
200
+ elif 'emotional reasoning' in d.lower():
201
+ d_normalized = 'Emotional Reasoning'
202
+ elif 'should statements' in d.lower():
203
+ d_normalized = 'Should Statements'
204
+ elif 'labeling' in d.lower():
205
+ d_normalized = 'Labeling'
206
+ elif 'personalization' in d.lower():
207
+ d_normalized = 'Personalization'
208
+ elif 'disqualifying the positive' in d.lower():
209
+ d_normalized = 'Disqualifying the Positive'
210
+ elif 'magnification' in d.lower():
211
+ d_normalized = 'Magnification'
212
+ elif 'minimization' in d.lower():
213
+ d_normalized = 'Minimization'
214
+ elif 'blame' in d.lower():
215
+ d_normalized = 'Blame'
216
+
217
+ normalized.append(d_normalized)
218
+
219
+ return normalized if normalized else ["Unknown Distortion"]
220
+
221
+ common_distortions = {
222
+ "all-or-nothing": "All-or-Nothing Thinking",
223
+ "overgeneralization": "Overgeneralization",
224
+ "mental filter": "Mental Filter",
225
+ "disqualifying the positive": "Disqualifying the Positive",
226
+ "jumping to conclusions": "Jumping to Conclusions",
227
+ "mind reading": "Mind Reading",
228
+ "fortune telling": "Fortune Telling",
229
+ "magnification": "Magnification",
230
+ "catastrophizing": "Catastrophizing",
231
+ "minimization": "Minimization",
232
+ "emotional reasoning": "Emotional Reasoning",
233
+ "should statements": "Should Statements",
234
+ "labeling": "Labeling",
235
+ "personalization": "Personalization",
236
+ "blame": "Blame"
237
+ }
238
+
239
+ found_distortions = []
240
+ text_lower = text.lower()
241
+
242
+ for key, distortion_name in common_distortions.items():
243
+ if key in text_lower:
244
+ found_distortions.append(distortion_name)
245
+
246
+ seen = set()
247
+ unique_distortions = []
248
+ for d in found_distortions:
249
+ if d not in seen:
250
+ seen.add(d)
251
+ unique_distortions.append(d)
252
+
253
+ return unique_distortions if unique_distortions else ["Unknown Distortion"]
254
+
255
+
256
+ def _extract_explanation(text: str) -> str:
257
+ """
258
+ Extract phần giải thích từ response
259
+ Bỏ qua phần danh sách distortions trong []
260
+ """
261
+ import re
262
+
263
+ text_cleaned = re.sub(r'^\s*\[.*?\]\s*', '', text).strip()
264
+
265
+ if text_cleaned:
266
+ explanation = text_cleaned.strip()
267
+
268
+ prefixes_to_remove = [
269
+ "explanation:",
270
+ "giải thích:",
271
+ "phân tích:"
272
+ # "the speaker"
273
+ ]
274
+
275
+ explanation_lower = explanation.lower()
276
+ for prefix in prefixes_to_remove:
277
+ if explanation_lower.startswith(prefix):
278
+ explanation = explanation[len(prefix):].strip()
279
+ if explanation:
280
+ explanation = explanation[0].upper() + explanation[1:]
281
+ break
282
+
283
+ return explanation
284
+
285
+ return text.strip()
286
+
287
+ @app.post("/api/detect")
288
+ async def detect_distortion(request: DetectionRequest):
289
+ try:
290
+ update_session(request.session_id, {
291
+ 'situation': request.situation,
292
+ 'thought': request.thought
293
+ })
294
+
295
+ async with httpx.AsyncClient(timeout=30.0) as client:
296
+ dot_analysis = await client.post(
297
+ f"{API_base}prompts/templates/execute",
298
+ json={
299
+ "provider": "groq",
300
+ "template_name": "dot.analysis",
301
+ "model": "openai/gpt-oss-20b",
302
+ "variables": {
303
+ "situation": request.situation,
304
+ "thought": request.thought
305
+ }
306
+ },
307
+ headers={
308
+ "accept": "application/json",
309
+ "Content-Type": "application/json"
310
+ }
311
+ )
312
+
313
+ dot_analysis.raise_for_status()
314
+ result_analysis = dot_analysis.json()
315
+ analysis_response = result_analysis.get("result", "") or result_analysis.get("content", "") # Fix: đổi result thành result_analysis
316
+
317
+ # Bước 2: Gọi dot.detection với kết quả từ dot.analysis
318
+ dot_detection = await client.post(
319
+ f"{API_base}prompts/templates/execute",
320
+ json={
321
+ "provider": "groq",
322
+ "template_name": "dot.detection",
323
+ "model": "openai/gpt-oss-20b",
324
+ "variables": {
325
+ "situation": request.situation,
326
+ "thought": request.thought,
327
+ "dot_analysis": analysis_response
328
+ }
329
+ },
330
+ headers={
331
+ "accept": "application/json",
332
+ "Content-Type": "application/json"
333
+ }
334
+ )
335
+
336
+ dot_detection.raise_for_status()
337
+ result_detection = dot_detection.json() # Fix: đổi tên biến để rõ ràng
338
+
339
+ ai_response = result_detection.get("result", "") or result_detection.get("content", "") # Fix: dùng result_detection
340
+
341
+ has_distortion = _check_has_distortion(ai_response)
342
+ distortion_types = _extract_distortion_types(ai_response)
343
+ explanation = _extract_explanation(ai_response)
344
+
345
+ update_session(request.session_id, {
346
+ 'distortions': distortion_types if distortion_types else []
347
+ })
348
+
349
+ return {
350
+ "session_id": request.session_id,
351
+ "has_distortion": has_distortion,
352
+ "distortion_types": distortion_types,
353
+ "explanation": explanation,
354
+ "raw_response": ai_response
355
+ }
356
+
357
+ except httpx.HTTPError as e:
358
+ raise HTTPException(
359
+ status_code=500,
360
+ detail=f"Lỗi khi gọi API phân tích: {str(e)}"
361
+ )
362
+ except Exception as e:
363
+ raise HTTPException(
364
+ status_code=500,
365
+ detail=f"Lỗi không xác định: {str(e)}"
366
+ )
367
+
368
+ def _parse_json_response(text: str) -> dict:
369
+ """Parse JSON từ AI response, xử lý markdown và whitespace"""
370
+ import json
371
+ import re
372
+
373
+ try:
374
+ # Clean text
375
+ text = text.strip()
376
+
377
+ # Remove markdown code blocks
378
+ if text.startswith("```json"):
379
+ text = text[7:]
380
+ elif text.startswith("```"):
381
+ text = text[3:]
382
+
383
+ if text.endswith("```"):
384
+ text = text[:-3]
385
+
386
+ text = text.strip()
387
+
388
+ # Parse JSON
389
+ return json.loads(text)
390
+
391
+ except json.JSONDecodeError as e:
392
+ # Fallback: try to extract JSON from text
393
+ json_match = re.search(r'\{.*\}', text, re.DOTALL)
394
+ if json_match:
395
+ try:
396
+ return json.loads(json_match.group())
397
+ except:
398
+ pass
399
+
400
+ raise ValueError(f"Không thể parse JSON response: {e}\nText: {text[:200]}")
401
+
402
+ @app.post("/api/analyze")
403
+ async def analyze_thought(request: AnalyzeRequest):
404
+ try:
405
+ async with httpx.AsyncClient(timeout=30.0) as client:
406
+ thera_rcm = await client.post(
407
+ f"{API_base}prompts/templates/execute",
408
+ json={
409
+ "provider": "groq",
410
+ "template_name": "dot.thera_rcm",
411
+ "model": "openai/gpt-oss-20b",
412
+ "variables": {
413
+ "situation": request.situation,
414
+ "thought": request.thought,
415
+ "distortions_type": request.distortions
416
+ }
417
+ },
418
+ headers={
419
+ "accept": "application/json",
420
+ "Content-Type": "application/json"
421
+ }
422
+ )
423
+ thera_rcm.raise_for_status()
424
+ result = thera_rcm.json()
425
+ print(request.situation)
426
+ print(request.thought)
427
+ print(request.distortions)
428
+
429
+ ai_text = result.get("result", "") or result.get("content", "")
430
+ parsed_result = _parse_json_response(ai_text)
431
+
432
+ # Validate và add defaults nếu thiếu fields
433
+ if "emotional_impact" not in parsed_result:
434
+ parsed_result["emotional_impact"] = "Tác động cảm xúc đáng kể"
435
+
436
+ if "underlying_beliefs" not in parsed_result or not parsed_result["underlying_beliefs"]:
437
+ parsed_result["underlying_beliefs"] = ["Niềm tin cốt lõi cần được khám phá thêm"]
438
+
439
+ if "triggers" not in parsed_result or not parsed_result["triggers"]:
440
+ parsed_result["triggers"] = ["Các tình huống tương tự"]
441
+
442
+ if "recommended_therapies" not in parsed_result or not parsed_result["recommended_therapies"]:
443
+ # Default therapies based on common distortions
444
+ parsed_result["recommended_therapies"] = ["CBT", "ACT"]
445
+ parsed_result["session_id"] = request.session_id
446
+ return parsed_result
447
+
448
+ except json.JSONDecodeError as e:
449
+ # Fallback response nếu parse JSON thất bại
450
+ return {
451
+ "session_id": request.session_id,
452
+ "emotional_impact": "Lo âu và căng thẳng đáng kể do các suy nghĩ tiêu cực",
453
+ "underlying_beliefs": [
454
+ "Tôi cần được chấp nhận bởi người khác",
455
+ "Tôi phải tránh thất bại bằng mọi giá",
456
+ "Nếu có vấn đề xảy ra, đó là lỗi của tôi"
457
+ ],
458
+ "triggers": [
459
+ "Tình huống liên quan đến mối quan hệ",
460
+ "Áp lực và kỳ vọng",
461
+ "Sự không chắc chắn"
462
+ ],
463
+ "recommended_therapies": ["CBT", "ACT", "DBT"]
464
+ }
465
+
466
+ except httpx.HTTPError as e:
467
+ raise HTTPException(
468
+ status_code=500,
469
+ detail=f"Lỗi khi gọi API phân tích: {str(e)}"
470
+ )
471
+ except Exception as e:
472
+ raise HTTPException(
473
+ status_code=500,
474
+ detail=f"Lỗi không xác định: {str(e)}"
475
+ )
476
+
477
+ # @app.post("/api/reframe")
478
+ # async def generate_reframe(request: ReframeRequest):
479
+ # reframe_candidates = []
480
+ # for therapy in request.recommended_therapies:
481
+ # async with httpx.AsyncClient(timeout=30.0) as client:
482
+ # response = await client.post(
483
+ # f"{API_base}prompts/templates/execute",
484
+ # json={
485
+ # "provider": "groq",
486
+ # "template_name": f"reframe.{therapy.lower()}",
487
+ # "model": "openai/gpt-oss-20b",
488
+ # "variables": {
489
+ # "situation": request.situation,
490
+ # "thought": request.thought,
491
+ # }
492
+ # },
493
+ # headers={
494
+ # "accept": "application/json",
495
+ # "Content-Type": "application/json"
496
+ # }
497
+ # )
498
+ # response.raise_for_status()
499
+ # result = response.json()
500
+
501
+ # reframe = result.get("reframing response", "")
502
+ # # parsed_result = _parse_json_response(ai_text)
503
+ # reframe_candidates.append({
504
+ # "therapy": f"{therapy}",
505
+ # "reframe": f"{reframe}",
506
+ # "rationale": "demo",
507
+ # "evaluation": {"empathy": 5, "logic": 4, "helpfulness": 5}
508
+ # })
509
+ # return reframe_candidates
510
+
511
+ @app.post("/api/reframe")
512
+ async def generate_reframe(request: ReframeRequest):
513
+ async def fetch_reframe(therapy: str) -> Dict[str, Any]:
514
+ """Fetch reframe for a single therapy type"""
515
+ async with httpx.AsyncClient(timeout=30.0) as client:
516
+ response = await client.post(
517
+ f"{API_base}prompts/templates/execute",
518
+ json={
519
+ "provider": "groq",
520
+ "template_name": f"reframe.{therapy.lower()}",
521
+ "model": "openai/gpt-oss-20b",
522
+ "variables": {
523
+ "situation": request.situation,
524
+ "thought": request.thought,
525
+ }
526
+ },
527
+ headers={
528
+ "accept": "application/json",
529
+ "Content-Type": "application/json"
530
+ }
531
+ )
532
+ response.raise_for_status()
533
+ result = response.json()
534
+
535
+ # Parse JSON string trong trường 'content'
536
+ import json
537
+ content_str = result.get("content", "{}")
538
+ content_json = json.loads(content_str)
539
+
540
+ # Thử cả 2 key có thể có
541
+ reframe = content_json.get("reframing response") or content_json.get("reframing_response", "")
542
+ wtw = content_json.get("why_this_works") or content_json.get("why this works", "")
543
+
544
+ feedback = await client.post(
545
+ f"{API_base}prompts/templates/execute",
546
+ json={
547
+ "provider": "groq",
548
+ "template_name": f"dot.thera_supervisor",
549
+ "model": "openai/gpt-oss-20b",
550
+ "variables": {
551
+ "situation": request.situation,
552
+ "thought": request.thought,
553
+ "reframe_response": reframe
554
+ }
555
+ },
556
+ headers={
557
+ "accept": "application/json",
558
+ "Content-Type": "application/json"
559
+ }
560
+ )
561
+ feedback.raise_for_status()
562
+ feedback = feedback.json()
563
+ print(feedback)
564
+ feedback_str = feedback.get("content", "{}")
565
+ feedback_json = json.loads(feedback_str)
566
+ return {
567
+ "therapy": therapy,
568
+ "reframe": reframe,
569
+ "rationale": wtw,
570
+ "evaluation": feedback_json
571
+ }
572
+
573
+ reframe_candidates = await asyncio.gather(
574
+ *[fetch_reframe(therapy) for therapy in request.recommended_therapies],
575
+ return_exceptions=True
576
+ )
577
+ successful_results = [
578
+ result for result in reframe_candidates
579
+ if not isinstance(result, Exception)
580
+ ]
581
+ return {
582
+ "session_id": request.session_id,
583
+ "candidates": successful_results
584
+ }
585
+
586
+ @app.post("/api/instruction_feedback")
587
+ async def generate_instruction_feedback(request: FeedbackRequest):
588
+ try:
589
+ async with httpx.AsyncClient(timeout=30.0) as client:
590
+ ai_feedback = await client.post(
591
+ f"{API_base}prompts/templates/execute",
592
+ json={
593
+ "provider": "groq",
594
+ "template_name": "reframe.thera_supervisor_full",
595
+ "model": "openai/gpt-oss-20b",
596
+ "variables": {
597
+ "situation": request.situation,
598
+ "thought": request.thought,
599
+ "reframe_response": request.current_reframe
600
+ }
601
+ },
602
+ headers={
603
+ "accept": "application/json",
604
+ "Content-Type": "application/json"
605
+ }
606
+ )
607
+
608
+ ai_feedback.raise_for_status()
609
+ ai_feedback = ai_feedback.json()
610
+ ai_feedback = ai_feedback.get("result", "") or ai_feedback.get("content", "")
611
+
612
+
613
+ return {
614
+ "session_id": request.session_id,
615
+ "ai_feedback": ai_feedback,
616
+ }
617
+
618
+ except httpx.HTTPError as e:
619
+ raise HTTPException(
620
+ status_code=500,
621
+ detail=f"Lỗi khi gọi API phân tích: {str(e)}"
622
+ )
623
+ except Exception as e:
624
+ raise HTTPException(
625
+ status_code=500,
626
+ detail=f"Lỗi không xác định: {str(e)}"
627
+ )
628
+
629
+ @app.post("/api/improve")
630
+ async def generate_improve_reframe(request: ImproveRequest):
631
+ try:
632
+ async with httpx.AsyncClient(timeout=30.0) as client:
633
+ response = await client.post(
634
+ f"{API_base}prompts/templates/execute",
635
+ json={
636
+ "provider": "groq",
637
+ "template_name": "reframe.cbtwfeedback",
638
+ "model": "openai/gpt-oss-20b",
639
+ "variables": {
640
+ "situation": request.situation,
641
+ "thought": request.thought,
642
+ "history_response": request.history_response,
643
+ "old_response": request.current_reframe,
644
+ "feedback": request.feedback
645
+ }
646
+ },
647
+ headers={
648
+ "accept": "application/json",
649
+ "Content-Type": "application/json"
650
+ }
651
+ )
652
+
653
+ response.raise_for_status()
654
+ result = response.json()
655
+ import json
656
+ content_str = result.get("content", "{}")
657
+ content_json = json.loads(content_str)
658
+
659
+ reframe = content_json.get("reframing response") or content_json.get("reframing_response", "")
660
+
661
+ ai_feedback = await client.post(
662
+ f"{API_base}prompts/templates/execute",
663
+ json={
664
+ "provider": "groq",
665
+ "template_name": "reframe.thera_supervisor_full",
666
+ "model": "openai/gpt-oss-20b",
667
+ "variables": {
668
+ "situation": request.situation,
669
+ "thought": request.thought,
670
+ "reframe_response": reframe
671
+ }
672
+ },
673
+ headers={
674
+ "accept": "application/json",
675
+ "Content-Type": "application/json"
676
+ }
677
+ )
678
+
679
+ ai_feedback.raise_for_status()
680
+ ai_feedback = ai_feedback.json()
681
+ ai_feedback = ai_feedback.get("result", "") or ai_feedback.get("content", "")
682
+
683
+
684
+ return {
685
+ "session_id": request.session_id,
686
+ "new_reframe": reframe,
687
+ "ai_feedback": ai_feedback
688
+ }
689
+
690
+ except httpx.HTTPError as e:
691
+ raise HTTPException(
692
+ status_code=500,
693
+ detail=f"Lỗi khi gọi API phân tích: {str(e)}"
694
+ )
695
+ except Exception as e:
696
+ raise HTTPException(
697
+ status_code=500,
698
+ detail=f"Lỗi không xác định: {str(e)}"
699
+ )
700
+
701
+ @app.post("/api/save")
702
+ async def save_selection(data: dict):
703
+ print(f"User saved reframe: {data}")
704
+ return {"status": "success"}
705
+
706
+
707
+ app.mount("/assets", StaticFiles(directory="../mind-reframe/dist/assets"), name="assets")
708
+
709
+ @app.get("/{full_path:path}")
710
+ async def serve_react_app(full_path: str):
711
+ if full_path.startswith("api/"):
712
+ return {"error": "Not Found"}
713
+
714
+ 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-Bpbr8g8G.js ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/dist/assets/index-CILzSiom.js ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/dist/assets/index-Cm8lmTTn.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-0\.5{margin-top:.125rem}.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-\[3rem\]{min-height:3rem}.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-not-allowed{cursor:not-allowed}.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-end{justify-content:flex-end}.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-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.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}.overflow-x-auto{overflow-x:auto}.whitespace-nowrap{white-space:nowrap}.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-md{border-radius:.375rem}.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-200{--tw-border-opacity:1;border-color:rgb(199 210 254/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-200{--tw-border-opacity:1;border-color:rgb(233 213 255/var(--tw-border-opacity,1))}.border-purple-200\/50{border-color:#e9d5ff80}.border-purple-500{--tw-border-opacity:1;border-color:rgb(168 85 247/var(--tw-border-opacity,1))}.border-purple-600{--tw-border-opacity:1;border-color:rgb(147 51 234/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-200{--tw-bg-opacity:1;background-color:rgb(233 213 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\/60{background-color:#fff9}.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-5{padding-left:1.25rem;padding-right:1.25rem}.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-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.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-2{padding-bottom:.5rem}.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-6{padding-top:1.5rem}.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-purple-800{--tw-text-opacity:1;color:rgb(107 33 168/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}.duration-500{transition-duration:.5s}.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\:border-purple-400:hover{--tw-border-opacity:1;border-color:rgb(192 132 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\:bg-purple-50:hover{--tw-bg-opacity:1;background-color:rgb(250 245 255/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-D75GAFpb.js ADDED
The diff for this file is too large to render. See raw diff
 
Web/mind-reframe/dist/assets/index-DNBzG3Ln.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-CILzSiom.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-Cm8lmTTn.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 (222 Bytes). View file
 
ai-core/app/__pycache__/config.cpython-313.pyc ADDED
Binary file (2.25 kB). View file
 
ai-core/app/__pycache__/main.cpython-313.pyc ADDED
Binary file (6.8 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 (226 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 (229 Bytes). View file
 
ai-core/app/api/v1/__pycache__/router.cpython-313.pyc ADDED
Binary file (983 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 (239 Bytes). View file
 
ai-core/app/api/v1/endpoints/__pycache__/cache.cpython-313.pyc ADDED
Binary file (3.54 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/chat.cpython-313.pyc ADDED
Binary file (3.54 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/completion.cpython-313.pyc ADDED
Binary file (1.55 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/health.cpython-313.pyc ADDED
Binary file (1.46 kB). View file
 
ai-core/app/api/v1/endpoints/__pycache__/prompts.cpython-313.pyc ADDED
Binary file (5.79 kB). View file