File size: 5,376 Bytes
26b4abe
0ab8e73
 
 
 
 
 
 
 
b6e2d2c
 
 
 
 
 
 
 
0ab8e73
7598214
b6e2d2c
 
0ab8e73
b6e2d2c
26b4abe
18c7f43
26b4abe
0ab8e73
b6e2d2c
 
 
7598214
b6e2d2c
7598214
b6e2d2c
0ab8e73
 
7598214
 
 
0ab8e73
b6e2d2c
 
0ab8e73
7598214
0ab8e73
b6e2d2c
 
7598214
0ab8e73
7598214
 
9a1b219
7598214
9a1b219
 
7598214
 
0ab8e73
7598214
0ab8e73
9a1b219
b6e2d2c
9a1b219
0ab8e73
b6e2d2c
0ab8e73
 
9a1b219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5a3dd7f
9a1b219
18c7f43
9b537e1
5a3dd7f
 
9a1b219
 
 
18c7f43
 
 
 
b6e2d2c
26b4abe
b6e2d2c
 
18c7f43
9a1b219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0ab8e73
 
9a1b219
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
# app.py — Insurance Q&A (RAG) with system prompt + simple config
import os
import gradio as gr
from pinecone import Pinecone, ServerlessSpec
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext, Settings
from llama_index.vector_stores.pinecone import PineconeVectorStore
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI

# --- System Prompt (polite + answer-from-document constraint) ---
SYSTEM_PROMPT = """You are Aisha, a polite and professional Insurance assistant.
Answer ONLY using the information found in the indexed insurance document(s).
If the answer is not in the document(s), say: "I couldn’t find that in the document."
Keep responses concise, helpful, and courteous.
"""

# ===== Minimal CONFIG (only necessary keys) =====
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
OPENAI_API_KEY   = os.getenv("OPENAI_API_KEY")
if not PINECONE_API_KEY or not OPENAI_API_KEY:
    raise RuntimeError("Missing PINECONE_API_KEY or OPENAI_API_KEY (set them in Space → Settings → Variables).")

DATA_DIR = "data"                         # Put insurance docs here (e.g., data/insurance.pdf)
LOGO_PATH = os.path.join(DATA_DIR, "dds_logo.png")  # Mandatory logo
if not os.path.exists(LOGO_PATH):
    raise RuntimeError("Logo not found: data/dds_logo.png.png (commit it to your Space repo).")

EMBED_MODEL = "text-embedding-3-small"    # 1536-dim
LLM_MODEL   = "gpt-4o-mini"
TOP_K       = 4                            # internal similarity_top_k

# ===== LlamaIndex / Pinecone (simple, fixed serverless: aws/us-east-1) =====
Settings.embed_model = OpenAIEmbedding(model=EMBED_MODEL, api_key=OPENAI_API_KEY)
Settings.llm = OpenAI(model=LLM_MODEL, api_key=OPENAI_API_KEY, system_prompt=SYSTEM_PROMPT)

pc = Pinecone(api_key=PINECONE_API_KEY)
def ensure_index(name: str, dim: int = 1536):
    names = [i["name"] for i in pc.list_indexes()]
    if name not in names:
        pc.create_index(
            name=name, dimension=dim, metric="cosine",
            spec=ServerlessSpec(cloud="aws", region="us-east-1"),
        )
    return pc.Index(name)

# Fixed index name for simplicity
pinecone_index = ensure_index("dds-insurance-index", dim=1536)
vector_store = PineconeVectorStore(pinecone_index=pinecone_index)

def bootstrap_index():
    if not os.path.isdir(DATA_DIR):
        raise RuntimeError("No 'data/' directory found. Commit your documents to data/ in the Space repo.")
    docs = SimpleDirectoryReader(DATA_DIR).load_data()
    if not docs:
        raise RuntimeError("No documents found in data/. Add e.g., data/insurance.pdf")
    storage_ctx = StorageContext.from_defaults(vector_store=vector_store)
    VectorStoreIndex.from_documents(docs, storage_context=storage_ctx, show_progress=True)

bootstrap_index()

def answer(query: str) -> str:
    if not query.strip():
        return "Please enter a question (or select one from the FAQ list)."
    index = VectorStoreIndex.from_vector_store(vector_store)
    resp = index.as_query_engine(similarity_top_k=TOP_K).query(query)
    return str(resp)

FAQS = [
    "",
    "What benefits are covered under the policy?",
    "How do I file a claim and what documents are required?",
    "What are the exclusions and limitations?",
    "Is pre-authorization needed for hospitalization?",
    "What is the reimbursement timeline?",
    "How are outpatient vs inpatient services handled?",
    "How can I check my network hospitals/clinics?",
    "What is the co-pay or deductible policy?",
]

def use_faq(selected_faq: str, free_text: str):
    prompt = (selected_faq or "").strip() or (free_text or "").strip()
    if not prompt:
        return "", "Please select a FAQ or type your question."
    return prompt, answer(prompt)

# ===== UI =====
CSS = """
.header { display:flex; flex-direction:column; align-items:center; gap:6px; }
.logo img { width:300px; height:300px; object-fit:contain; }  /* fixed 300x300 */
.title { text-align:center; font-weight:700; font-size:1.4rem; margin:6px 0 0 0; }
.subnote { text-align:center; margin-top:-2px; opacity:0.8; }
"""

with gr.Blocks(css=CSS, theme=gr.themes.Soft()) as demo:
    with gr.Row():
        with gr.Column():
            gr.Markdown("<div class='header'>")
            gr.Image(value=LOGO_PATH, show_label=False, elem_classes=["logo"])
            gr.Markdown(
                "<h1 class='title'>DDS Insurance Q&A — RAG Assistant</h1>"
                "<p class='subnote'>Answers strictly from your insurance document(s)</p>"
            )
            gr.Markdown("</div>")

    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("### Ask from Frequently Asked Questions")
            faq = gr.Dropdown(choices=FAQS, value=FAQS[0], label="Select a common question")

            gr.Markdown("### Or type your question")
            user_q = gr.Textbox(
                label="Your question",
                placeholder="e.g., What is covered under outpatient benefits?",
                lines=2
            )
            ask_btn = gr.Button("Ask", variant="primary")

        with gr.Column(scale=1):
            chosen_prompt = gr.Textbox(label="Query sent", interactive=False)
            answer_box = gr.Markdown()

    ask_btn.click(use_faq, inputs=[faq, user_q], outputs=[chosen_prompt, answer_box])

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