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