File size: 6,599 Bytes
c875fdf
 
 
 
 
 
 
 
 
 
 
 
 
babc68d
c875fdf
 
 
 
69046d4
 
c875fdf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
01ec921
c875fdf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2b904e4
c875fdf
 
 
 
 
 
 
 
 
 
 
 
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
from tools import RetrievalTool
from dotenv import load_dotenv
from langchain_core.prompts import PromptTemplate
from langchain_groq import ChatGroq
from pydantic import BaseModel, Field
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import pandas as pd
import uvicorn
import re
import os


load_dotenv()

app = FastAPI()

origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

os.environ["ASTRA_DB_API_ENDPOINT"] = os.getenv("ASTRA_DB_API_ENDPOINT")
os.environ["ASTRA_DB_APPLICATION_TOKEN"] = os.getenv("ASTRA_DB_APPLICATION_TOKEN")
os.environ["ASTRA_DB_NAMESPACE"] = os.getenv("ASTRA_DB_NAMESPACE")
os.environ["HF_TOKEN"] = os.getenv("HF_TOKEN")
os.environ["GROQ_API_KEY"] = os.getenv("GROQ_API_KEY")
os.environ["CALENDARIFIC_API_KEY"] = os.getenv("CALENDARIFIC_API_KEY")

retrieval_tool = RetrievalTool()

class ScheduleRecommendationModel(BaseModel):
    programme_schedule: str = Field(description="The entire list of recommended programs..")
    reasoning: str = Field(description="The reasoning behind the recommendation.")

template = """
You are a smart TV schedule assistant.

Your job is to generate a clean, formatted program schedule for a specific day.

Constraints:
- Do NOT include any explanation, notes, or Markdown.
- Do NOT repeat any program on the same day.
- Format must be exactly: HH:MM - HH:MM : ProgramName
- Use the provided channel start time as the beginning of the schedule.
- Prime time is from 18:00 to 22:00 — prioritize the highest-rated programs here.
- If the date is a holiday (e.g., Christmas), ensure 2 to 3 holiday-themed programs (based on keywords like "Christmas", "Santa", or "Carol" in the synopsis) are included in the schedule.
- If it's a weekend, favor family-friendly or entertainment-heavy content.
- If it's a weekday, prefer shorter or lighter content during the day and prioritize core genre in prime time.
- Do not schedule past 23:59.

Inputs:
- Genre: {genre}
- DayType: {day_type}  # Either "weekday" or "weekend"
- Holiday: {holiday_event}  # Either "Christmas", "New year" or None
- Start Time: {start_time}
- Available Programs:
{program_list}

Now generate the full day schedule starting from {start_time} using the above constraints.
"""
summary_template = """
You are a smart TV reasoning summary assistant.

Your task is to clearly explain the thought process behind a given TV schedule recommendation.

The summary should help the user understand why specific programs were selected, why they appear at certain times, and how the genre, ratings, time of day, day type (weekday/weekend), and special events (e.g., holidays like Christmas) influenced the schedule.

✳️ Instructions:

Do not add any information that is not already present in the reasoning.Do not repeat phrases. Do not speculate or guess. Only use the facts from the reasoning text..

The summary must reflect the actual reasoning provided by the model.

Write in a natural, human-readable tone, suitable for a user reading a TV planner explanation.

Keep it concise but detailed enough to convey scheduling logic (approx. 8-10 lines).

Highlight how prime-time slots (18:00–22:00) were used for high-rated programs.

If applicable, explain how holiday content or weekend scheduling influenced the selection.
Use the reasoning provided to you and summarize it in a clear and concise manner.
{reasoning}
"""
prompt = PromptTemplate.from_template(template)
summary_prompt = PromptTemplate.from_template(summary_template)
llm = ChatGroq(model_name = "deepseek-r1-distill-llama-70b", api_key = os.environ["GROQ_API_KEY"])
summary_llm = ChatGroq(model_name = "gemma2-9b-it", api_key = os.environ["GROQ_API_KEY"])

chain = prompt | llm 
summary_chain = summary_prompt | summary_llm

def get_dynamic_schedule(program_df:str, genre:str, start_time:str, day_type:str, holiday_event:str):   
    try:
        response = chain.invoke({"program_list": program_df,
                                 "genre": genre,                               
                                "day_type": day_type,
                                "holiday_event": holiday_event,
                                "start_time": start_time})   
        
        text_data = response.content
        think_match = re.search(r'<think>(.*?)</think>', text_data, re.DOTALL)
        if think_match:
            reasoning = think_match.group(1).strip()
            reasoning_answer = summarize_reasoning(reasoning)
            final_answer = text_data.split("</think>")[-1].strip()
            return ScheduleRecommendationModel(programme_schedule=final_answer, reasoning=reasoning_answer)

        # if text_data and "</think>" in text_data:
        #     result = re.split(r'</think>', text_data, maxsplit=1)[-1].strip()
        #     return result
        
        return ScheduleRecommendationModel(programme_schedule=response, reasoning="Error while generating reasoning.")
        
    except Exception as e:
        return f"Error: {str(e)}"

def get_weekday_or_weekend(date:str):
    try:
        schedule_date = pd.to_datetime(date)
        if schedule_date.weekday() < 5:  # Monday to Friday
            return "weekday"
        else:  # Saturday and Sunday
            return "weekend"
    except ValueError:
        raise ValueError("Invalid date format. Please use YYYY-MM-DD.")

def get_schedule_recommendation(genre:str, date:str, start_time:str):
    program_list, holidayEvent = retrieval_tool.get_relevant_programmes(genre, date)    
    
    day_of_week = get_weekday_or_weekend(date)
    schedule_recommendation = get_dynamic_schedule(program_list, genre, start_time, day_of_week, holidayEvent)
    print("Schedule Recommendation:", schedule_recommendation)
    return schedule_recommendation


def summarize_reasoning(reasoning:str):
    if reasoning:
        response = summary_chain.invoke({"reasoning": reasoning})
        return response.content        
    return "Error while generating reasoning."

@app.get("/api/v1/getScheduleRecommendation")
async def extract_details(genre:str, date:str, start_time:str):
    try:     
        return get_schedule_recommendation(genre, date, start_time)
    except HTTPException as e:
        return JSONResponse(status_code=500, content={"error": str(e)})

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

# if __name__ == "__main__":    
#     get_schedule_recommendation('comedy', '2023-12-25', '09:00')