File size: 22,852 Bytes
55dd1f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4bda5f9
55dd1f8
 
 
 
 
 
 
 
 
 
e806ae8
 
55dd1f8
 
 
 
 
e806ae8
55dd1f8
 
 
 
 
a4f2d89
 
 
 
 
 
55dd1f8
 
e806ae8
55dd1f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3bb4d47
55dd1f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3bb4d47
55dd1f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3bb4d47
55dd1f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e806ae8
 
55dd1f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4390144
55dd1f8
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# from itertools import islice
# import itertools
# import json
# import re
# from groq import Groq
# from config import direcindirecprompt
# from utils import groq_calls,write_to_file, get_file_data, get_mongo_collection
# from sklearn.feature_extraction.text import TfidfVectorizer
# from sklearn.metrics.pairwise import cosine_similarity
# import numpy as np
# from datetime import datetime

# '''
# The architecture is like this

# '''
# collection = get_mongo_collection()

# def main():
#     # user_journal = get_file_data("journal.txt")
#     # example = get_file_data("example.json")


#     # prompt= direcindirecprompt
#     direcindirecgroq_response = groq_calls(direcindirecprompt)
#     # parsed_json = json.loads(direcindirecgroq_response)
#     # print(parsed_json)
#     # write_to_file("overall_specific_problempair.json",direcindirecgroq_response)

#     guideprompt = f'''
#     So, I am giving a set of direct-indirect problem pair, here it is: {direcindirecgroq_response}
#     Now, these are some of the issues the user is facing in his daily life. Assume that you're a very skilled psychologist and help solve the problems faced
#     by the users in their daily life by recommending them a set of guidelines of what they could follow or practice in their daily life to keep themselves calm
#     These guidelines should not be very long, some short recommendations which can be followed even when the person is seated on his chair in office
#     or any where else. Basically the guidelines should be accessible/doable any time.
#     Give 1-2 guidelines for each of the problem that the user is facing as in the problem pair procided to you

#     Here are some examples of how guidelines could look like
#     -Take short breaks for deep breathing, walk in the present, and journal three things you're grateful for daily to shift perspective.
#     -Dedicate even 10 minutes to a hobby or enjoyable activity to recharge. 
#     -Reduce news consumption and screen time, especially before bed, to avoid overwhelm.

#     Above are some examples only, but remember whatever you suggest should be relevant to the problems the user is facing
#     Final output should be in JSON format only
#     final output should start and end like this
#     {{
#         problem1:["Set dedicated focus blocks (e.g., 90‑min) and log only the block end to satisfy reporting.","Use a private tracker to note progress, then share a concise daily summary with the manager."]
#     }} 
#     '''

#     guidegroq_response = groq_calls(guideprompt)
#     # with open("test.json", "w") as f:
#     #     f.write(guidegroq_response)




#     with open("structured_output_updated.json","r") as f:
#         task_dataset = json.load(f)
        


#     result = {}
#     # task_dataset = test
#     yogabranches = list(task_dataset["Yoga"]["branches"].keys())
#     for branch in yogabranches: 
#         if branch == "Asana":
#             postures = list(task_dataset["Yoga"]["branches"][branch].keys())
#             # print(postures)
#             result[f"{branch}s"] = {}
#             for posture in postures:
#                 lst = list(task_dataset["Yoga"]["branches"][branch][posture].keys())
#                 for pose in lst:
#                     # # poses.append(task_dataset["Yoga"]["branches"][branch][posture][pose])
#                     # print(task_dataset["Yoga"]["branches"][branch][posture][pose])
#                     sliced_items = list(task_dataset["Yoga"]["branches"][branch][posture][pose].values())[:2]
#                     result[f"{branch}s"][pose] = list(itertools.chain.from_iterable(sliced_items))
#         else:
#             postures = list(task_dataset["Yoga"]["branches"][branch].keys())
#             # print(postures)
#             result[f"{branch}s"] = {}
#             for posture in postures:
#                 lst = list(task_dataset["Yoga"]["branches"][branch][posture].values())[:2]
#                 result[f"{branch}s"][posture] = list(itertools.chain.from_iterable(lst))

#     # with open("overall_specific_problempair.json","r",encoding = "utf-8") as f:
#     #     user_problem = json.load(f)
    
#     user_problem = json.loads(direcindirecgroq_response)

#     cosineprompt = f'''
#   So i am giving you the iverall problems that are being faced by the user. Here it is: {user_problem.keys()}
#   Now I want you to generate a 2-3 line summary/description for each of the problems. It shuold indicate what effect it has on the user's body and mind.
#   So basically I want to perform a cosine similarity between this description that you give and a task dataset that has multiple tasks and they have their own descriptions of what they are able to cure
#   So, If you write a good description for each overall problem, then I can match it with the task dataset descriptions to find the best matching tasks for the user.
#   Here are examples of what is present in the task dataset descriptions:
#   "Nadi Shodhana (Alternate Nostril Breathing)": {{
#             "Stress": [
#               "Balances left/right brain hemispheres for nervous system equilibrium",
#               "Reduces cortisol by 27% through symmetrical breathing patterns",
#               "Creates instant mental clarity during decision fatigue"
#             ],
#             "Emotions": [
#               "Harmonizes emotional extremes by balancing solar/moon energies",
#               "Resets emotional reactivity through prefrontal cortex activation",
#               "Integrates logical and intuitive aspects of awareness"
#             ],
#             }}
#   "Bakasana (Crow Pose)": {{
#               "Focus": [
#                 "Develops laser-like concentration to prevent falling",
#                 "Trains mind-body coordination in challenging position",
#                 "Builds mental discipline through fear management"
#               ],
#               "Strength": [
#                 "Develops core and wrist strength simultaneously",
#                 "Tones abdominal muscles through active engagement",
#                 "Builds functional arm strength for daily activities"
#               ],
#               }}
#   So, you see there is a certain way the descriptions are written for the task and hence you need to generate the descriptions for the overall problems in a similar way so that cosine similarity precisely extracts onyl those tasks which are highly relevant to the overall problems being faced by the user.
#   Also, follow the following format strictly:
#   {{
#   "Overall Problem 1": ["Description"]
#   "Overall Problem 2": ["Description"]
#   }}

#   Remember to output not anything else what is said, also don't use very complicated words. You can use some technical words but keep it simple and precise otherwise if those words are present in the task dataset then cosine similaity will be very less.
#   also, replace "Overall Problem 1" with the problem name for which description is being written
#   '''
    
#     cosinegroq_response = groq_calls(cosineprompt)
#     # with open("test.json","w") as f:
#     #     f.write(cosinegroq_response)
#     parsed_json = json.loads(cosinegroq_response)
#     # write_to_file("overall_problemdesc.json",cosinegroq_response)

#     user_problem = parsed_json
#     user_problem_text = " ".join(sum(user_problem.values(), [])) 
#     tasks = {}
#     for branch in result.keys():
#         for pose in result[branch].keys():
#             documents = []
#             # print(result[branch][pose])
#             desc = ", ".join(result[branch][pose])
#             # print(desc)
#             documents.append(desc)
#             documents.append(user_problem_text)
            
#             # documents[0] ='Micromanagement  scrutiny, raising heart rate and restlessness. leading to tight muscles and frequent headaches. Language barriers and frustration, making communication difficult. Shallow breathing and lowering confidence and increasing social anxiety. Social exclusion triggers. It reduces heart rate variability and raises cortisol, leaving the body stressed. Burnout produces persistent fatigue, headaches, and muscle aches. Focus and decision‑making suffer, while sleep quality drops and inflammation markers rise. Discrimination induces emotional distress and self‑doubt, making the mind hypervigilant and anxious. stressing the body.'
#             vectorizer = TfidfVectorizer(stop_words='english')
#             tfidf_matrix = vectorizer.fit_transform(documents)
#             similarities = cosine_similarity(tfidf_matrix[-1], tfidf_matrix[:-1]).flatten()
#             tasks[f"{branch}({pose})"]= similarities
#             # print(f"{branch} --> ", f"{pose} --> ", similarities)
    
#     print(documents)
#     sorted_tasks = dict(sorted(tasks.items(), key=lambda item: item[1], reverse=True))
#     print(list(sorted_tasks.items())[:5])

#     username = "sameer" #in production extract the username 

#     if collection is not None:
#             chat_document = {
#                 "user_id": username,
#                 "timestamp": datetime.now(),
#                 "problemdesc": direcindirecgroq_response,
#                 "guidelines":guidegroq_response,
#                 "tasks": list(sorted_tasks.keys())[:5]

#             }
            
#             try:
#                 collection.insert_one(chat_document)
#                 print("Saved to DB")
#             except Exception as e:
#                 print(f"Failed to save to DB: {e}")

# if __name__ == "__main__":
#     main()






from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional, List, Dict, Any
from itertools import islice
import itertools
import json
import re
from datetime import datetime

# ML and Math imports
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

# Custom modules (assuming these exist in your project structure)
from groq import Groq
# from config import direcindirecprompt
from utils import groq_calls, write_to_file, get_file_data, get_mongo_collection
import uvicorn

# Initialize FastAPI app
app = FastAPI(title="Journal Task Planner")

# Initialize DB connection globally (or within dependency)
try:
    collection = get_mongo_collection()
except Exception as e:
    print(f"Warning: Database connection failed on startup: {e}")
    collection = None

# --- Pydantic Models for Request/Response ---
class AnalysisRequest(BaseModel):
    user_id: str
    username: str   # Default as per your code
    user_journal: str
    # Add other fields here if you need to pass user_journal dynamically later

class AnalysisResponse(BaseModel):
    status: str
    user_id: str
    username: str
    guidelines: Dict[str, Any]
    recommended_tasks: List[str]
    timestamp: datetime


@app.post("/cron_Journal_task_planner")
async def cron_test():
    return "Hello Cron Tester"


@app.post("/analyze-tasks", response_model=AnalysisResponse)
def generate_analysis(request: AnalysisRequest):

    example = get_file_data("example.json")
    direcindirecprompt = f'''
            I'll be giving you a journal entry written by a user. Your task is to extract out problems being faced by the user in the following format:
            {{
            "Overall Problem 1": ["Specific reason1 - reason why it was created", "Specific reason2  - reason why it was created"],
            "Overall Problem 2": ["Specific reason1 - reason why it was created"],
            }}
            I'll give you an example how this overall - specific problem pair looks like. Here you'll see that the heading (single word is the overall problem), then we have the reasons why it was created
            here is the overall - specific problem pair: {example}
            Obviusly a single overall problem can have multiple specific reasons why it was created. Put it in the exact format as shown above.
            Also, multiple overall problems can share a common specific reason why it was created. In that case, just repeat the specific reason under all of them.
            Here is the user text you have to analyse: {request.user_journal}
            Output strictly in the format given to you no extra symbols or words or anything
        '''


    # 1. Direct/Indirect Problem Identification
    try:
        # Assuming direcindirecprompt is imported from config
        
        direcindirecgroq_response = groq_calls(direcindirecprompt)
        print(direcindirecgroq_response)
        # If the response acts as a JSON source, we try to parse it to ensure validity
        # parsed_check = json.loads(direcindirecgroq_response) 
    except Exception as e:
        raise HTTPException(status_code=502, detail=f"Groq API Error (Problem Identification): {str(e)}")

    # 2. Guidelines Generation
    try:
        guideprompt = f'''
        So, I am giving a set of direct-indirect problem pair, here it is: {direcindirecgroq_response}
        Now, these are some of the issues the user is facing in his daily life. Assume that you're a very skilled psychologist and help solve the problems faced
        by the users in their daily life by recommending them a set of guidelines of what they could follow or practice in their daily life to keep themselves calm
        These guidelines should not be very long, some short recommendations which can be followed even when the person is seated on his chair in office
        or any where else. Basically the guidelines should be accessible/doable any time.
        Give 1-2 guidelines for each of the problem that the user is facing as in the problem pair procided to you

        Here are some examples of how guidelines could look like
        -Take short breaks for deep breathing, walk in the present, and journal three things you're grateful for daily to shift perspective.
        -Dedicate even 10 minutes to a hobby or enjoyable activity to recharge. 
        -Reduce news consumption and screen time, especially before bed, to avoid overwhelm.

        Above are some examples only, but remember whatever you suggest should be relevant to the problems the user is facing
        Final output should be in JSON format only
        final output should start and end like this
        {{
            "problem1": ["Set dedicated focus blocks...", "Use a private tracker..."]
        }} 
        '''
        guidegroq_response = groq_calls(guideprompt)
        print(guidegroq_response)
    except Exception as e:
        raise HTTPException(status_code=502, detail=f"Groq API Error (Guideline Generation): {str(e)}")

    # 3. Load Task Dataset
    try:
        with open("structured_output_updated.json", "r") as f:
            task_dataset = json.load(f)
    except FileNotFoundError:
        raise HTTPException(status_code=500, detail="Server Error: 'structured_output_updated.json' file not found.")
    except json.JSONDecodeError:
        raise HTTPException(status_code=500, detail="Server Error: Failed to decode task dataset JSON.")

    # 4. Process Yoga Branches (Business Logic)
    try:
        result = {}
        yogabranches = list(task_dataset["Yoga"]["branches"].keys())
        
        for branch in yogabranches: 
            if branch == "Asana":
                postures = list(task_dataset["Yoga"]["branches"][branch].keys())
                result[f"{branch}s"] = {}
                for posture in postures:
                    # Depending on structure, sometimes keys are poses
                    lst = list(task_dataset["Yoga"]["branches"][branch][posture].keys())
                    for pose in lst:
                        sliced_items = list(task_dataset["Yoga"]["branches"][branch][posture][pose].values())[:2]
                        result[f"{branch}s"][pose] = list(itertools.chain.from_iterable(sliced_items))
            else:
                postures = list(task_dataset["Yoga"]["branches"][branch].keys())
                result[f"{branch}s"] = {}
                for posture in postures:
                    lst = list(task_dataset["Yoga"]["branches"][branch][posture].values())[:2]
                    result[f"{branch}s"][posture] = list(itertools.chain.from_iterable(lst))
    except KeyError as e:
        raise HTTPException(status_code=500, detail=f"Data Processing Error: Key {str(e)} missing in dataset.")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Data Processing Error: {str(e)}")

    # 5. Cosine Similarity Preparation
    try:
        # We parse the response from Step 1 to get keys for the next prompt
        user_problem_raw = json.loads(direcindirecgroq_response)
        
        cosineprompt = f'''
        So i am giving you the iverall problems that are being faced by the user. Here it is: {user_problem_raw.keys()}
        Now I want you to generate a 2-3 line summary/description for each of the problems. It shuold indicate what effect it has on the user's body and mind.
        So basically I want to perform a cosine similarity between this description that you give and a task dataset that has multiple tasks and they have their own descriptions of what they are able to cure
        So, If you write a good description for each overall problem, then I can match it with the task dataset descriptions to find the best matching tasks for the user.
        Here are examples of what is present in the task dataset descriptions:
        "Nadi Shodhana (Alternate Nostril Breathing)": {{
                  "Stress": [
                    "Balances left/right brain hemispheres for nervous system equilibrium",
                    "Reduces cortisol by 27% through symmetrical breathing patterns",
                    "Creates instant mental clarity during decision fatigue"
                  ],
                  "Emotions": [
                    "Harmonizes emotional extremes by balancing solar/moon energies",
                    "Resets emotional reactivity through prefrontal cortex activation",
                    "Integrates logical and intuitive aspects of awareness"
                  ],
                  }}
        "Bakasana (Crow Pose)": {{
                    "Focus": [
                      "Develops laser-like concentration to prevent falling",
                      "Trains mind-body coordination in challenging position",
                      "Builds mental discipline through fear management"
                    ],
                    "Strength": [
                      "Develops core and wrist strength simultaneously",
                      "Tones abdominal muscles through active engagement",
                      "Builds functional arm strength for daily activities"
                    ],
                    }}
        So, you see there is a certain way the descriptions are written for the task and hence you need to generate the descriptions for the overall problems in a similar way so that cosine similarity precisely extracts onyl those tasks which are highly relevant to the overall problems being faced by the user.
        Also, follow the following format strictly:
        {{
        "Overall Problem 1": ["Description"]
        "Overall Problem 2": ["Description"]
        }}

        Remember to output not anything else what is said, also don't use very complicated words. You can use some technical words but keep it simple and precise otherwise if those words are present in the task dataset then cosine similaity will be very less.
        also, replace "Overall Problem 1" with the problem name for which description is being written
        '''
        
        cosinegroq_response = groq_calls(cosineprompt)
        print(cosinegroq_response)
        parsed_cosine_json = json.loads(cosinegroq_response)
        
        user_problem = parsed_cosine_json
        user_problem_text = " ".join(sum(user_problem.values(), []))
        
    except json.JSONDecodeError:
         raise HTTPException(status_code=500, detail="Failed to parse JSON from Groq response (Cosine Prompt).")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error preparing Cosine Similarity data: {str(e)}")

    # 6. Calculate Cosine Similarity
    try:
        tasks = {}
        for branch in result.keys():
            for pose in result[branch].keys():
                documents = []
                desc = ", ".join(result[branch][pose])
                documents.append(desc)
                documents.append(user_problem_text)
                
                vectorizer = TfidfVectorizer(stop_words='english')
                tfidf_matrix = vectorizer.fit_transform(documents)
                
                # Compare the last doc (user problem) with the first doc (task desc)
                similarities = cosine_similarity(tfidf_matrix[-1], tfidf_matrix[:-1]).flatten()
                tasks[f"{branch}({pose})"] = similarities[0] # Take the float value
        
        # Sort and take top 5
        sorted_tasks = dict(sorted(tasks.items(), key=lambda item: item[1], reverse=True))
        top_tasks = list(sorted_tasks.keys())[:5]
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Math/Vectorization Error: {str(e)}")

    # 7. Database Insertion
    chat_document = None
    try:
        # Try to parse guidelines string to JSON object for cleaner DB storage/Response
        try:
            guidelines_obj = json.loads(guidegroq_response)
        except:
            guidelines_obj = {"raw_text": guidegroq_response}

        chat_document = {
            "user_id": request.user_id,
            "username": request.username,
            "timestamp": datetime.now(),
            "problemdesc": direcindirecgroq_response, # Storing raw response string as per original code
            "guidelines": guidegroq_response,       # Storing raw response string as per original code
            "tasks": top_tasks
        }

        if collection is not None:
            collection.insert_one(chat_document)
            print("Saved to DB")
        else:
            print("Skipped DB save (Collection not available)")
            
    except Exception as e:
        # We log the DB error but might not want to fail the whole request if the calculation succeeded
        print(f"Failed to save to DB: {e}")
        # Note: Depending on requirements, you might want to raise HTTPException here or just proceed.

    # 8. Return Response
    return AnalysisResponse(
        status="success",
        user_id=request.user_id,
        username=request.username,
        guidelines=guidelines_obj,
        recommended_tasks=top_tasks,
        timestamp=chat_document["timestamp"] if chat_document else datetime.now()
    )

if __name__ == "__main__":
    # Run the app with uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)