File size: 4,057 Bytes
2be4cba
6e78e68
2be4cba
6e78e68
 
 
 
2be4cba
6e78e68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
from huggingface_hub import InferenceClient

from openai import OpenAI
import chromadb
from sentence_transformers import SentenceTransformer
import os

"""
For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
"""
client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")

# Use a basic sentence transformer finetuned for text similarity tasks
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

def embedding_func(text):
    return model.encode(text, convert_to_numpy=True)  

# Initialize ChromaDB (runs locally)
chroma_client = chromadb.PersistentClient(path="./chroma_db")  

# Create or load a collection with metadata support
collection = chroma_client.get_or_create_collection(
    name="oura_chunks",
    metadata={"hnsw:space": "cosine"}  
)

def query_openai(query, context):
    client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

    # Add instructions to the system message
    system_message = {"role": "system", 
        "content": "You are an expert assistant answering questions about the Oura Ring app.\n"
        "Use only the provided context for your responses.\n"
        "If you do not find relevant information, clearly state that the question is out of scope.\n"
        "Always cite the most relevant article, section, and link that are directly found in the provided context.\n"
        "Do not provide links that are not found in the provided context."}
    
    # Add the user's input
    user_message = {"role": "user", "content": query}

    # Submit system message for response
    completion = client.chat.completions.create(
        model="gpt-4",  
        messages=[
            system_message,  
            {"role": "assistant", "content": context},  
            user_message  
        ],
    )
    
    # Output the chatbot's response
    return completion.choices[0].message.content

# Query ChromaDB for relevant chunks
def retrieve_relevant_chunks(query, n_results=5):
    query_embedding = embedding_func(query).tolist()  
    results = collection.query(
        query_embeddings=[query_embedding], 
        n_results=n_results
    )
    return results

# Perform RAG (Retrieve + Generate) with OpenAI
def perform_rag(query, provider="openai"):
    # Retrieve relevant chunks from ChromaDB
    results = retrieve_relevant_chunks(query, n_results=5)
    
    # Combine the retrieved chunks for LLM input
    relevant_chunks = []
    for document, metadata, distance in zip(results["documents"][0],results["metadatas"][0],results["distances"][0]):
        # Apply relatively lenient filter to return most relevant chunks
        if distance > 0.75:
            continue
        # Structure chunks to include all relevant metadata
        relevant_chunks.append(f'\nArticle Title: {metadata["article_title"]}\nSection Title: {metadata["section_title"]}\nArticle Link: {metadata["link"]}\nRelevance Score: {100*round(1 - distance, 2)}\nArticle Content: {document}\n')
    if len(relevant_chunks) < 1:
        context = f'\nArticle Title: No Relevant Article\nSection Title: No Relevant Article\nArticle Link: No Relevant Article\nRelevance Score: No Relevant Article\nArticle Content: No Relevant Article\n'
    else:
        context = "\n".join(relevant_chunks)  

    # Query OpenAI gpt-4 for a response
    answer = query_openai(query, context)
    
    return answer

def ask_oura_assistant(message, history):
    response = perform_rag(message, "openai")  
    history.append((message, response))  
    return history

with gr.Blocks(theme="soft") as demo:
    gr.Markdown("### Ask me anything about the Oura Ring app!")
    gr.Markdown("# Oura Ring App Assistant")
    
    msg = gr.Textbox(label="Your question", placeholder="Type your question here...")
    submit_btn = gr.Button("Ask")
    
    chatbot = gr.Chatbot()
    
    submit_btn.click(ask_oura_assistant, inputs=[msg, chatbot], outputs=chatbot)


if __name__ == "__main__":
    demo.launch(share=True)