import streamlit as st import streamlit.components.v1 as components import os import html import re import torch from datasets import load_dataset from langchain_ollama import OllamaLLM from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS from langchain.chains import RetrievalQA from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.docstore.document import Document from langchain_openai import ChatOpenAI from langchain_together import Together from langchain.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate # ๐น Load and inject custom CSS def load_css(file_name): with open(file_name) as f: st.markdown(f'', unsafe_allow_html=True) load_css("styles.css") # ๐น System prompt system_prompt = """ You are Adrega AI, a helpful assistant trained to answer questions based on internal company documentation. Instructions: - Be concise and professional and keep response length under 512 tokens if possible. - Use markdown formatting when helpful. - Never show the thought process or reasoning steps. - If the user asks about a specific operation in the product, explain step by step how to do it. - If the user greets you (e.g. โHiโ, โHelloโ), respond with a friendly greeting and offer help. Do not reference documentation unless a question is asked. - Reference the Help page from the hamburger menu when needed. - The Field Reference module is not a physical module, but a description of fields in Adrega. Prioritize it when describing fields. - Do not make assumptions. Use the manual as reference. """ # ๐น Chat prompt template chat_prompt = ChatPromptTemplate.from_messages([ SystemMessagePromptTemplate.from_template(system_prompt), HumanMessagePromptTemplate.from_template(""" Context: {context} Question: {question} """) ]) # ๐น Provider selection #provider_options = ["Together", "HuggingFace", "Adrega"] provider_options = ["Adrega", "Together"] selected_provider = st.selectbox("Provider", provider_options) # ๐น Load and process dataset once if "initialized" not in st.session_state: dataset = load_dataset("andreska/Adrega61Docs", split="train") def read_dataset(dataset): return "\n\n".join([ f"Title: {item['title']}\nModule: {item['module']}\nContent: {item['content']}" for item in dataset ]) raw_text = read_dataset(dataset) text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100) docs = text_splitter.split_documents([Document(page_content=raw_text)]) # Smart device detection for HuggingFace Spaces device = 'cuda' if torch.cuda.is_available() else 'cpu' embedding_model = HuggingFaceEmbeddings( model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={'device': device} ) db = FAISS.from_documents(docs, embedding_model) st.session_state.db = db st.session_state.docs = docs st.session_state.initialized = True # ๐น Provider-specific LLM setup def get_llm(provider): # Validate provider input against allowed options allowed_providers = ["Adrega", "Together", "HuggingFace"] if provider not in allowed_providers: provider = "Adrega" # Default fallback if provider == "Together": return Together( # Alternative models available for testing #model="meta-llama/Llama-3.2-11B-Vision-Free", model="deepseek-ai/DeepSeek-R1-Distilled", #model="flux-ai/FLUX.1-schnell-Free", max_tokens=2048 ) elif provider == "HuggingFace": return ChatOpenAI( base_url="https://router.huggingface.co/v1", api_key=os.environ["HF_API_KEY"], model="HuggingFaceTB/SmolLM3-3B:hf-inference", ) else: # Adrega return OllamaLLM( base_url=os.environ["ADREGA_URL"], #model="phi3:mini", # Alternative lightweight model model="llama3:latest", streaming=False, ) # ๐น Build the LLM and retriever llm = get_llm(selected_provider) retriever = st.session_state.db.as_retriever(search_kwargs={"k": 5}) # ๐น UI Styling st.markdown(""" """, unsafe_allow_html=True) # ๐น Initialize chat history if "chat_history" not in st.session_state: st.session_state.chat_history = [{"role": "assistant", "content": "Hi! I am your Adrega AI assistant. How can I help you today?"}] # ๐น Build limited context from history def build_context(history, max_chars=10000): context = [] total_chars = 0 for msg in reversed(history): if msg["role"] == "user": entry = f"You: {msg['content']}\n" else: entry = f"Adrega AI: {msg['content']}\n" total_chars += len(entry) if total_chars > max_chars: break context.insert(0, entry) return "\n".join(context) def render_chat(): html_content = """