Spaces:
Sleeping
Sleeping
Download app.py from Vanshcc/GIT_DOC_RAG: direct link, hf CLI and curl.
- Browser
- Download file 15.6 kB
-
https://huggingface.co/spaces/Vanshcc/GIT_DOC_RAG/resolve/main/app.py
- Command line
-
hf download hf://spaces/Vanshcc/GIT_DOC_RAG/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Vanshcc/GIT_DOC_RAG/resolve/main/app.py
15.6 kB
| import streamlit as st | |
| import json | |
| import torch | |
| import numpy as np | |
| import pandas as pd | |
| from sentence_transformers import SentenceTransformer | |
| import lancedb | |
| import os | |
| import requests | |
| from groq import Groq | |
| from dotenv import load_dotenv | |
| # Load environment variables | |
| load_dotenv() | |
| # =============================== | |
| # PAGE CONFIG & PREMIUM TECH UI | |
| # =============================== | |
| st.set_page_config(page_title="Git Intelligence System", page_icon="π»", layout="wide") | |
| st.markdown(""" | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); | |
| /* ADVANCED TECH THEME */ | |
| html, body, [class*="css"] { | |
| font-family: 'Space Grotesk', sans-serif; | |
| } | |
| .stApp { | |
| background: #020617; | |
| color: #f8fafc; | |
| overflow-x: hidden; | |
| } | |
| /* π¦ ANIMATED GRID BACKGROUND */ | |
| .stApp::before { | |
| content: ""; | |
| position: fixed; | |
| top: 0; left: 0; | |
| width: 200%; height: 200%; | |
| background-image: | |
| linear-gradient(rgba(56, 189, 248, 0.03) 1px, transparent 1px), | |
| linear-gradient(90deg, rgba(56, 189, 248, 0.03) 1px, transparent 1px); | |
| background-size: 50px 50px; | |
| transform: perspective(500px) rotateX(60deg) translateY(-50%); | |
| animation: gridMove 20s linear infinite; | |
| z-index: -1; | |
| opacity: 0.5; | |
| } | |
| @keyframes gridMove { | |
| 0% { transform: perspective(500px) rotateX(60deg) translateY(-50%) translateZ(0); } | |
| 100% { transform: perspective(500px) rotateX(60deg) translateY(-50%) translateZ(50px); } | |
| } | |
| /* π SCANLINE EFFECT */ | |
| .stApp::after { | |
| content: ""; | |
| position: fixed; | |
| top: 0; left: 0; | |
| width: 100%; height: 2px; | |
| background: rgba(56, 189, 248, 0.1); | |
| opacity: 0.2; | |
| z-index: 1000; | |
| pointer-events: none; | |
| animation: scanline 8s linear infinite; | |
| } | |
| @keyframes scanline { | |
| 0% { top: -5%; } | |
| 100% { top: 105%; } | |
| } | |
| /* π ULTRA GLASS CARDS */ | |
| .answer-box, .glass-card { | |
| background: rgba(15, 23, 42, 0.6); | |
| backdrop-filter: blur(20px) saturate(180%); | |
| -webkit-backdrop-filter: blur(20px) saturate(180%); | |
| border: 1px solid rgba(56, 189, 248, 0.15); | |
| border-radius: 20px; | |
| padding: 2.5rem; | |
| box-shadow: | |
| 0 20px 50px rgba(0, 0, 0, 0.4), | |
| inset 0 0 20px rgba(56, 189, 248, 0.05); | |
| margin-bottom: 2.5rem; | |
| transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| } | |
| .glass-card:hover { | |
| border-color: rgba(56, 189, 248, 0.5); | |
| transform: translateY(-5px) scale(1.01); | |
| box-shadow: 0 30px 60px rgba(0, 0, 0, 0.6), 0 0 20px rgba(56, 189, 248, 0.2); | |
| } | |
| /* β‘ HEADERS & TYPOGRAPHY */ | |
| .main-title { | |
| font-weight: 800; | |
| font-size: 4.5rem; | |
| background: linear-gradient(to right, #7dd3fc, #38bdf8, #10b981); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| text-align: center; | |
| margin-bottom: 0.5rem; | |
| filter: drop-shadow(0 0 15px rgba(56, 189, 248, 0.3)); | |
| letter-spacing: -2px; | |
| } | |
| .sub-title { | |
| text-align: center; | |
| color: #94a3b8; | |
| font-size: 1.1rem; | |
| margin-bottom: 4rem; | |
| font-family: 'JetBrains Mono', monospace; | |
| letter-spacing: 3px; | |
| text-transform: uppercase; | |
| opacity: 0.8; | |
| } | |
| /* πΉοΈ STATUS INDICATOR */ | |
| .status-container { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| gap: 10px; | |
| margin-bottom: 2rem; | |
| } | |
| .status-dot { | |
| width: 8px; height: 8px; | |
| background: #10b981; | |
| border-radius: 50%; | |
| box-shadow: 0 0 10px #10b981; | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { transform: scale(1); opacity: 1; } | |
| 50% { transform: scale(1.5); opacity: 0.5; } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| /* β¨οΈ TERMINAL INPUT FORCE */ | |
| div[data-testid="stChatInput"] { | |
| padding-bottom: 20px !important; | |
| } | |
| div[data-testid="stChatInput"] textarea { | |
| background: rgba(7, 10, 25, 0.95) !important; | |
| border: 2px solid rgba(56, 189, 248, 0.3) !important; | |
| border-radius: 16px !important; | |
| color: #f0f9ff !important; | |
| font-family: 'JetBrains Mono', monospace !important; | |
| font-size: 1rem !important; | |
| box-shadow: 0 0 30px rgba(56, 189, 248, 0.1) !important; | |
| } | |
| /* π·οΈ SOURCE LABELS */ | |
| .source-pill { | |
| display: inline-block; | |
| background: rgba(56, 189, 248, 0.08); | |
| border: 1px solid rgba(56, 189, 248, 0.3); | |
| color: #7dd3fc !important; | |
| padding: 0.4rem 1rem; | |
| border-radius: 10px; | |
| font-size: 0.75rem; | |
| margin-right: 0.6rem; | |
| margin-bottom: 0.6rem; | |
| font-family: 'JetBrains Mono', monospace; | |
| transition: all 0.2s ease; | |
| } | |
| .source-pill:hover { | |
| background: rgba(56, 189, 248, 0.2); | |
| border-color: #38bdf8; | |
| transform: scale(1.05); | |
| } | |
| .token-pill { | |
| display: inline-block; | |
| background: rgba(30, 41, 59, 0.8); | |
| border: 1px solid rgba(148, 163, 184, 0.2); | |
| color: #94a3b8 !important; | |
| padding: 0.25rem 0.75rem; | |
| border-radius: 8px; | |
| font-size: 0.7rem; | |
| margin-left: 0.4rem; | |
| font-family: 'JetBrains Mono', monospace; | |
| } | |
| /* SCROLLBAR CUSTOMIZATION */ | |
| ::-webkit-scrollbar { width: 10px; } | |
| ::-webkit-scrollbar-track { background: #020617; } | |
| ::-webkit-scrollbar-thumb { | |
| background: linear-gradient(to bottom, #334155, #1e293b); | |
| border-radius: 10px; | |
| border: 2px solid #020617; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { background: #475569; } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # =============================== | |
| # RESOURCE LOADING | |
| # =============================== | |
| def load_resources(): | |
| device = 'cuda' if torch.cuda.is_available() else 'cpu' | |
| model = SentenceTransformer("BAAI/bge-m3", device=device) | |
| # Add FlashRank reranker as in Ramayana app | |
| from flashrank import Ranker, RerankRequest | |
| ranker = Ranker(model_name="ms-marco-MiniLM-L-12-v2") | |
| db = lancedb.connect("./.lancedb") | |
| tbl = db.open_table("git_knowledge") | |
| with open('alias_map.json', 'r', encoding='utf-8') as f: | |
| alias_map = json.load(f) | |
| return model, ranker, tbl, alias_map | |
| try: | |
| model, ranker, tbl, alias_map = load_resources() | |
| except Exception as e: | |
| st.error(f"Failed to load resources: {e}") | |
| st.stop() | |
| # =============================== | |
| # LLM LOGIC | |
| # =============================== | |
| def get_answer_from_llm(query, context): | |
| system_prompt = """You are a STERN and HIGHLY PRECISE Technical Document Analyst. | |
| Your objective is to answer questions using ONLY the provided Context Chunks. | |
| STRICT ANTI-HALLUCINATION PROTOCOLS: | |
| 1. ABSOLUTE GROUNDING: Every claim you make MUST be directly supported by the provided text. | |
| 2. NO EXTERNAL KNOWLEDGE: Do NOT use your internal training data to explain commands, syntax, or concepts. If the information is not in the context, you MUST say: "The provided documentation does not contain information regarding [Topic]." | |
| 3. LIST vs. DESCRIPTION: If the context merely lists a command (e.g., in a 'git --help' style table) but does not provide details or syntax, you MUST state: "The documentation mentions [Command] but provides no instructions or explanations." | |
| 4. CITE EVERYTHING: When providing an answer, explicitly mention which 'Source' provided the data. | |
| 5. NEGATIVE CONSTRAINT: Do NOT be 'helpful' by providing external tutorials. Your helpfulness is measured by how accurately you report ONLY what is in the document.""" | |
| messages = [ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": f"Context Chunks:\n{context}\n\nQuestion: {query}"} | |
| ] | |
| input_tokens = len(str(messages)) // 4 | |
| g_key = os.getenv("GROQ_API_KEY") | |
| if g_key: | |
| try: | |
| client = Groq(api_key=g_key) | |
| # Try different models | |
| for m in ["llama-3.3-70b-versatile", "mixtral-8x7b-32768"]: | |
| try: | |
| res = client.chat.completions.create(model=m, messages=messages, temperature=0.1) | |
| ans = res.choices[0].message.content | |
| return ans, m, input_tokens, len(ans) // 4 | |
| except Exception: | |
| continue | |
| except Exception: | |
| pass | |
| s_key = os.getenv("SAMBANOVA_API_KEY") | |
| if s_key and s_key != "your_key_here": | |
| try: | |
| url = "https://api.sambanova.ai/v1/chat/completions" | |
| headers = {"Authorization": f"Bearer {s_key}", "Content-Type": "application/json"} | |
| data = { | |
| "model": "Meta-Llama-3.3-70B-Instruct", | |
| "messages": messages, | |
| "temperature": 0.1, | |
| "stream": False | |
| } | |
| res = requests.post(url, headers=headers, json=data, timeout=12) | |
| if res.status_code == 200: | |
| ans = res.json()['choices'][0]['message']['content'] | |
| return ans, "SambaNova (Llama-3.3)", input_tokens, len(ans) // 4 | |
| except Exception: | |
| pass | |
| return "LLM integration failed. Please check API keys.", "None", 0, 0 | |
| # =============================== | |
| # MAIN UI | |
| # =============================== | |
| st.markdown('<h1 class="main-title">Git Documentation AI</h1>', unsafe_allow_html=True) | |
| st.markdown('<div class="status-container"><div class="status-dot"></div><div style="color: #10b981; font-family: JetBrains Mono; font-size: 0.8rem;">SYSTEM CORE: ONLINE</div></div>', unsafe_allow_html=True) | |
| st.markdown('<p class="sub-title">> git query --intelligent-search --ultra-premium</p>', unsafe_allow_html=True) | |
| if "messages" not in st.session_state: | |
| st.session_state.messages = [] | |
| # =============================== | |
| # SIDEBAR | |
| # =============================== | |
| with st.sidebar: | |
| st.markdown('<div class="metadata-section" style="background: rgba(15,23,42,0.6); padding: 1.5rem; border-radius: 12px; border: 1px solid rgba(56, 189, 248, 0.2);">', unsafe_allow_html=True) | |
| st.markdown("### π οΈ Git Archive Specs") | |
| st.write(f"**Storage:** LanceDB Vector") | |
| st.write(f"**Embedding:** BGE-M3") | |
| st.write(f"**Reranker:** FlashRank") | |
| st.markdown("---") | |
| st.markdown("### π¦ Knowledge Base") | |
| try: | |
| count = len(tbl.to_pandas()) | |
| st.write(f"**Total Chunks:** {count}") | |
| st.write(f"**Source:** Git Documentation") | |
| except: | |
| st.write("**Chunks:** 16") | |
| with st.expander("π System Internals"): | |
| st.markdown(""" | |
| - **Pipeline**: Pypdf Extraction | |
| - **Search**: Hybrid (Vector + Rerank) | |
| - **LLM**: Groq Professional | |
| """) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Display Messages | |
| for msg in st.session_state.messages: | |
| if msg["role"] == "user": | |
| st.markdown(f'<div style="text-align: right; color: #38bdf8; font-family: JetBrains Mono; margin: 1rem;">$ {msg["content"]}</div>', unsafe_allow_html=True) | |
| else: | |
| st.markdown(msg["content"], unsafe_allow_html=True) | |
| # Landing Page Content | |
| if not st.session_state.messages: | |
| st.markdown(""" | |
| <div class="glass-card"> | |
| <h3 style="color: #38bdf8; margin-top: 0; font-family: Space Grotesk;">System Initialized</h3> | |
| <p style="color: #e2e8f0; font-size: 1.1rem;">Expert RAG system for official Git Documentation with FlashRank Optimization.</p> | |
| <ul style="color: #94a3b8; line-height: 2;"> | |
| <li><b>Command Execution</b>: "How do I rebase my feature branch?"</li> | |
| <li><b>Conceptual Clarity</b>: "Explain the Git object model."</li> | |
| <li><b>Workflow Optimization</b>: "Best practices for merge conflicts."</li> | |
| </ul> | |
| <div style="margin-top: 2rem; display: flex; gap: 10px;"> | |
| <code style="background: rgba(56, 189, 248, 0.1); padding: 5px 15px; border-radius: 6px; color: #38bdf8; border: 1px solid rgba(56, 189, 248, 0.2);">v2.0.4-stable</code> | |
| <code style="background: rgba(16, 185, 129, 0.1); padding: 5px 15px; border-radius: 6px; color: #10b981; border: 1px solid rgba(16, 185, 129, 0.2);">RAG-ACTIVE</code> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Chat Input | |
| if user_query := st.chat_input("Enter your Git question..."): | |
| # Store user message | |
| st.session_state.messages.append({"role": "user", "content": user_query}) | |
| st.rerun() | |
| # Processing the latest user message | |
| if st.session_state.messages and st.session_state.messages[-1]["role"] == "user": | |
| query = st.session_state.messages[-1]["content"] | |
| with st.spinner("Searching documentation..."): | |
| # 1. Expand aliases | |
| processed_query = query.lower() | |
| mapping = alias_map.get("alias_map", {}) | |
| for k, v in mapping.items(): | |
| processed_query = processed_query.replace(k, v) | |
| # 2. Vector Search (Initial Fetch) | |
| q_vec = model.encode(processed_query) | |
| initial_results = tbl.search(q_vec).limit(15).to_list() | |
| # 3. Rerank with FlashRank | |
| from flashrank import RerankRequest | |
| passages = [{"id": i, "text": r['text'], "meta": r} for i, r in enumerate(initial_results)] | |
| rerank_request = RerankRequest(query=processed_query, passages=passages) | |
| reranked_results = ranker.rerank(rerank_request)[:5] | |
| # 4. Build Context | |
| context_str = "\n---\n".join([f"Source: {r['meta']['title']}\nContent: {r['meta']['text']}" for r in reranked_results]) | |
| # 5. Get Answer | |
| answer, model_name, in_t, out_t = get_answer_from_llm(query, context_str) | |
| # 6. Format Output | |
| sources_html = "".join([f'<span class="source-pill">{r["meta"]["title"]}</span>' for r in reranked_results]) | |
| formatted_answer = f""" | |
| <div class="answer-box"> | |
| <h3 style="color: #10b981; margin-top: 0;">Response</h3> | |
| <div style="color: #f8fafc; line-height: 1.6;">{answer}</div> | |
| <div style="margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid rgba(255,255,255,0.1); display: flex; justify-content: space-between; align-items: flex-end;"> | |
| <div> | |
| <div style="font-size: 0.7rem; color: #64748b; margin-bottom: 0.5rem;">CITED SOURCES:</div> | |
| {sources_html} | |
| </div> | |
| <div style="text-align: right;"> | |
| <span class="token-pill">in:{in_t}</span> | |
| <span class="token-pill">out:{out_t}</span> | |
| <span class="token-pill">{model_name}</span> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| st.session_state.messages.append({"role": "assistant", "content": formatted_answer}) | |
| st.rerun() | |