File size: 5,933 Bytes
99cc3fd be6c945 99cc3fd be6c945 1adf5f1 99cc3fd 85bf964 99cc3fd 1adf5f1 99cc3fd f39631c ba95cd5 1adf5f1 99cc3fd f39631c be6c945 f39631c 1adf5f1 f39631c 1adf5f1 f39631c be6c945 1adf5f1 f39631c 1adf5f1 f39631c 1adf5f1 f39631c 1adf5f1 f39631c 99cc3fd f39631c 99cc3fd f39631c 1adf5f1 f39631c 1adf5f1 f39631c be6c945 1adf5f1 be6c945 1adf5f1 be6c945 1adf5f1 be6c945 1adf5f1 be6c945 f39631c 1adf5f1 be6c945 1adf5f1 be6c945 1adf5f1 be6c945 1adf5f1 be6c945 1adf5f1 |
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
import streamlit as st
import torch
import os
import time
from threading import Thread
from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer
from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.schema import Document
# --- Hugging Face Token ---
HF_TOKEN = st.secrets["HF_TOKEN"]
# --- Page Config ---
st.set_page_config(page_title="DigiTwin RAG", page_icon="π", layout="centered")
st.title("π DigiTs the Twin")
# --- File Upload UI ---
with st.sidebar:
st.header("π Upload Knowledge Files")
uploaded_files = st.file_uploader("Upload PDFs or .txt files", accept_multiple_files=True, type=["pdf", "txt"])
if uploaded_files:
st.success(f"{len(uploaded_files)} file(s) uploaded")
# --- Load Model & Tokenizer ---
@st.cache_resource
def load_model():
tokenizer = AutoTokenizer.from_pretrained("amiguel/GM_Qwen1.8B_Finetune", trust_remote_code=True, token=HF_TOKEN)
model = AutoModelForCausalLM.from_pretrained(
"amiguel/GM_Qwen1.8B_Finetune",
device_map="auto",
torch_dtype=torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float32,
trust_remote_code=True,
token=HF_TOKEN
)
return model, tokenizer
model, tokenizer = load_model()
# --- System Prompt ---
SYSTEM_PROMPT = (
"You are DigiTwin, a digital expert and senior topside engineer specializing in inspection and maintenance "
"of offshore piping systems, structural elements, mechanical equipment, floating production units, pressure vessels "
"(with emphasis on Visual Internal Inspection - VII), and pressure safety devices (PSDs). Rely on uploaded documents "
"and context to provide practical, standards-driven, and technically accurate responses. Your guidance reflects deep "
"field experience, industry regulations, and proven methodologies in asset integrity and reliability engineering."
)
# --- Prompt Builder ---
def build_prompt(messages, context=""):
prompt = f"<|im_start|>system\n{SYSTEM_PROMPT}\n\nContext:\n{context}<|im_end|>\n"
for msg in messages:
role = msg["role"]
prompt += f"<|im_start|>{role}\n{msg['content']}<|im_end|>\n"
prompt += "<|im_start|>assistant\n"
return prompt
# --- Embed Uploaded Documents ---
@st.cache_resource
def embed_uploaded_files(files):
raw_docs = []
for f in files:
path = f"/tmp/{f.name}"
with open(path, "wb") as out_file:
out_file.write(f.read())
loader = PyPDFLoader(path) if f.name.endswith(".pdf") else TextLoader(path)
raw_docs.extend(loader.load())
splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64)
chunks = splitter.split_documents(raw_docs)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
db = FAISS.from_documents(chunks, embedding=embeddings)
return db
retriever = embed_uploaded_files(uploaded_files) if uploaded_files else None
# --- Streaming Generator ---
def generate_response(prompt_text):
streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
inputs = tokenizer(prompt_text, return_tensors="pt").to(model.device)
thread = Thread(target=model.generate, kwargs={
"input_ids": inputs["input_ids"],
"attention_mask": inputs["attention_mask"],
"max_new_tokens": 1024,
"temperature": 0.7,
"top_p": 0.9,
"repetition_penalty": 1.1,
"do_sample": True,
"streamer": streamer
})
thread.start()
return streamer
# --- Avatars ---
USER_AVATAR = "https://raw.githubusercontent.com/achilela/vila_fofoka_analysis/9904d9a0d445ab0488cf7395cb863cce7621d897/USER_AVATAR.png"
BOT_AVATAR = "https://raw.githubusercontent.com/achilela/vila_fofoka_analysis/991f4c6e4e1dc7a8e24876ca5aae5228bcdb4dba/Ataliba_Avatar.jpg"
# --- Initialize Chat Memory ---
if "messages" not in st.session_state:
st.session_state.messages = []
# --- Display Message History ---
for msg in st.session_state.messages:
with st.chat_message(msg["role"], avatar=USER_AVATAR if msg["role"] == "user" else BOT_AVATAR):
st.markdown(msg["content"])
# --- Chat Interface ---
if prompt := st.chat_input("Ask something based on uploaded documents..."):
st.chat_message("user", avatar=USER_AVATAR).markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})
context = ""
docs = []
if retriever:
docs = retriever.similarity_search(prompt, k=3)
context = "\n\n".join([doc.page_content for doc in docs])
# Limit to last 6 messages for memory
recent_messages = st.session_state.messages[-6:]
full_prompt = build_prompt(recent_messages, context)
with st.chat_message("assistant", avatar=BOT_AVATAR):
start = time.time()
container = st.empty()
answer = ""
for chunk in generate_response(full_prompt):
answer += chunk
container.markdown(answer + "β", unsafe_allow_html=True)
container.markdown(answer)
end = time.time()
st.session_state.messages.append({"role": "assistant", "content": answer})
input_tokens = len(tokenizer(full_prompt)["input_ids"])
output_tokens = len(tokenizer(answer)["input_ids"])
speed = output_tokens / (end - start)
with st.expander("π Debug Info"):
st.caption(
f"π Input Tokens: {input_tokens} | Output Tokens: {output_tokens} | "
f"π Speed: {speed:.1f} tokens/sec"
)
for i, doc in enumerate(docs):
st.markdown(f"**Chunk #{i+1}**")
st.code(doc.page_content.strip()[:500])
|