File size: 3,886 Bytes
531a034
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61241ce
531a034
 
 
 
61241ce
531a034
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61241ce
531a034
 
 
 
 
61241ce
 
531a034
 
 
 
 
 
 
 
 
61241ce
 
 
 
 
 
 
 
 
 
 
531a034
 
 
 
 
 
 
 
 
 
 
 
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
import os
from tqdm import tqdm
from dotenv import load_dotenv
import chromadb
from openai import OpenAI
from langchain_openai import OpenAIEmbeddings

# Initialize environment variables
load_dotenv(override=True)
os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')
os.environ['HF_TOKEN'] = os.getenv('HF_TOKEN', 'your-key-if-not-using-env')

# Initialize OpenAI client
openai = OpenAI()

# Initialize vectorizer
vectorizer = OpenAIEmbeddings(
    model="text-embedding-ada-002",
    openai_api_key=os.getenv('OPENAI_API_KEY')
)


def find_similars(collection, description):
    """
    Find similar faculty members based on the given description.
    
    Args:
        collection: The ChromaDB collection to search in
        description (str): The description to search for similar faculty members
        
    Returns:
        tuple: (documents, names, links) containing the similar faculty members' information
    """
    results = collection.query(
        query_embeddings=vectorizer.embed_query(description),
        n_results=10
    )
    documents = results['documents'][0][:]
    name = [m['name'] for m in results['metadatas'][0][:]]
    link = [m['url'] for m in results['metadatas'][0][:]]
    return documents, name, link

def make_context(similars):
    """
    Create a context string from similar faculty members.
    
    Args:
        similars (tuple): The output from find_similars function
        
    Returns:
        str: Formatted context string
    """
    message = "To provide some context, here are some faculty members that might be relevant to your description.\n\n"
    documents, names, links = similars
    for similar, name, link in zip(documents, names, links):
        message += f'''Potentially related faculty:
{name}

        website: {link}

        {similar}\n\n'''
    return message

def messages_for(description, similars):
    """
    Create a message object for the OpenAI API.
    
    Args:
        description (str): The user's description
        similars (tuple): The output from find_similars function
        
    Returns:
        dict: Message object for OpenAI API
    """
    user_prompt = f"Here is my description: {description}\n\n"
    user_prompt += make_context(similars)
    return {"role": "user", "content": user_prompt}

def gpt_4o_mini_rag(description, history, collection):
    """
    Generate a response using GPT-4o-mini model with RAG.
    
    Args:
        description (str): The user's description
        history (list): Chat history as list of tuples (user_message, assistant_message)
        collection: The ChromaDB collection to search in
        
    Yields:
        str: Generated response chunks
    """
    system_message = {
        "role": "system",
        "content": "You are a academic advisor. You estimate the relevance of faculty members to a given description. Suggest relevant faculty members. Don't forget to include a link to the faculty member's profile. You should give explanation for your choice in markdown format."
    }
    
    # Format chat history into proper message format
    formatted_history = []
    for user_msg, assistant_msg in history:
        formatted_history.append({"role": "user", "content": user_msg})
        formatted_history.append({"role": "assistant", "content": assistant_msg})
    
    similars = find_similars(collection=collection, description=description)
    current_message = messages_for(description, similars)
    
    # Combine all messages in the correct order
    messages = [system_message] + formatted_history + [current_message]
    
    stream = openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        seed=42,
        stream=True
    )
    
    response = ""
    for chunk in stream:
        response += chunk.choices[0].delta.content or ''
        yield response