File size: 3,995 Bytes
4d068e8
 
 
 
f7f504f
4d068e8
f7f504f
4d068e8
 
 
 
 
 
 
 
 
 
 
 
f7f504f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4d068e8
 
f7f504f
 
 
4d068e8
f7f504f
4d068e8
 
f7f504f
 
4d068e8
 
f7f504f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4d068e8
f7f504f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import requests
import gradio as gr

# ---------------- RAG DOCUMENT SETUP ---------------- #

K8S_DOC_URLS = {
    "pods": "https://kubernetes.io/docs/concepts/workloads/pods/",
    "deployments": "https://kubernetes.io/docs/concepts/workloads/controllers/deployment/",
    "services": "https://kubernetes.io/docs/concepts/services-networking/service/",
    "namespaces": "https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/",
    "nodes": "https://kubernetes.io/docs/concepts/architecture/nodes/",
    "statefulsets": "https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/",
    "rbac": "https://kubernetes.io/docs/reference/access-authn-authz/rbac/",
    "persistent-volumes": "https://kubernetes.io/docs/concepts/storage/persistent-volumes/",
    "ingress": "https://kubernetes.io/docs/concepts/services-networking/ingress/",
    "autoscaling": "https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/"
}

def fetch_doc(url):
    try:
        response = requests.get(url, timeout=10)
        if response.status_code == 200:
            return response.text
    except:
        return ""
    return ""

DOCUMENTS = [
    {"doc": name, "url": url, "text": fetch_doc(url)}
    for name, url in K8S_DOC_URLS.items()
]

def search_docs(query, top_k=3):
    query = query.lower()
    matches = []
    for doc in DOCUMENTS:
        text = doc["text"].lower()
        if query in text:
            snippet_start = text.index(query)
            snippet_end = snippet_start + 350
            snippet = doc["text"][snippet_start:snippet_end].replace("\n", " ")
            matches.append((snippet, doc["url"], doc["doc"]))
    return matches[:top_k]


# --------------- LLM CALL (OpenRouter) ---------------- #

def call_llm(prompt):
    url = "https://openrouter.ai/api/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {os.getenv('OPENROUTER_API_KEY')}",
        "HTTP-Referer": "https://huggingface.co/",
        "X-Title": "Kubernetes RAG Assistant"
    }

    data = {
        "model": "meta-llama/llama-3.1-8b-instruct",
        "messages": [{"role": "user", "content": prompt}],
        "max_tokens": 350
    }

    res = requests.post(url, json=data, headers=headers)
    out = res.json()

    if "choices" in out:
        return out["choices"][0]["message"]["content"]
    print("DEBUG LLM Error:", out)
    return "⚠ Model error. Try again."


# ----------- RAG + Prompt Construction ---------------- #

def build_answer(query):
    results = search_docs(query)
    context = ""
    citations = []

    for i, (snippet, url, doc) in enumerate(results, start=1):
        label = f"[{i}]"
        context += f"{label}: {snippet}\n\n"
        citations.append(f"{label}{url}")

    prompt = f"""
    Use the context below to answer the question clearly.
    Add citations like [1], [2] at the end of sentences.

    Context:
    {context}

    Question: {query}
    """

    answer = call_llm(prompt)
    citations_text = "\n".join(citations) or "No sources found."

    return answer, citations_text


# ---------------------- UI --------------------------- #

custom_css = """
.source-box {
    font-size: 14px;
    background: #1b2733;
    padding: 10px;
    border-radius: 8px;
    color: #c9e2ff;
    border: 1px solid #4a90e2;
}
"""

with gr.Blocks(css=custom_css, theme="soft") as app:

    gr.HTML("""
    <h1 style='color:#326ce5; text-align:center;'>☸️ Kubernetes RAG Assistant</h1>
    <p style='text-align:center; font-size:17px; color:#ddd;'>Ask any Kubernetes question and get answers with docs citations 📌</p>
    """)

    question = gr.Textbox(label="Ask a Kubernetes Question:", placeholder="e.g., What is RBAC in Kubernetes?")

    answer = gr.Markdown(label="Answer")
    sources = gr.Markdown(label="Sources", elem_classes=["source-box"])

    submit = gr.Button("Ask ☸️")

    submit.click(build_answer, inputs=question, outputs=[answer, sources])

app.launch()