|
import streamlit as st |
|
import datetime |
|
import pandas as pd |
|
from typing import List |
|
from langchain_embeddings import Embeddings |
|
from langchain.vectorstores import FAISS |
|
from langchain.prompts import ChatPromptTemplate |
|
from langchain.chat_models import ChatOpenAI |
|
from langchain.chains import ChatChain |
|
from langchain.text_splitter import RecursiveCharacterTextSplitter |
|
from langchain.schema import Document |
|
|
|
|
|
st.set_page_config(page_title="رزمیار ارتش", page_icon="🪖", layout="wide") |
|
|
|
|
|
st.markdown(""" |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap'); |
|
|
|
html, body, [class*="css"] { |
|
font-family: 'Vazirmatn', Tahoma, sans-serif; |
|
direction: rtl; |
|
text-align: right; |
|
} |
|
|
|
.stApp { |
|
background: linear-gradient(to left, #4b5e40, #2e3b2e); |
|
color: #ffffff; |
|
} |
|
/* استایلهای دیگر در اینجا قرار دارند */ |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
if "authenticated" not in st.session_state: |
|
st.session_state.authenticated = False |
|
|
|
if not st.session_state.authenticated: |
|
st.markdown("<h3 style='text-align: center; color: #b8860b;'>ورود به رزمیار ارتش</h3>", unsafe_allow_html=True) |
|
username = st.text_input("نام کاربری:", placeholder="شناسه نظامی خود را وارد کنید") |
|
password = st.text_input("رمز عبور:", type="password", placeholder="رمز عبور نظامی") |
|
if st.button("ورود"): |
|
if username == "admin" and password == "123": |
|
st.session_state.authenticated = True |
|
st.rerun() |
|
else: |
|
st.error("نام کاربری یا رمز عبور اشتباه است.") |
|
st.stop() |
|
|
|
|
|
with st.sidebar: |
|
st.image("log.png", use_container_width=True) |
|
|
|
menu_items = [ |
|
("گزارش عملیاتی", "https://cdn-icons-png.flaticon.com/512/3596/3596165.png"), |
|
("تاریخچه ماموریتها", "https://cdn-icons-png.flaticon.com/512/709/709496.png"), |
|
("تحلیل دادههای نظامی", "https://cdn-icons-png.flaticon.com/512/1828/1828932.png"), |
|
("مدیریت منابع", "https://cdn-icons-png.flaticon.com/512/681/681494.png"), |
|
("دستیار فرماندهی", "https://cdn-icons-png.flaticon.com/512/3601/3601646.png"), |
|
("تنظیمات امنیتی", "https://cdn-icons-png.flaticon.com/512/2099/2099058.png"), |
|
("پشتیبانی فنی", "https://cdn-icons-png.flaticon.com/512/597/597177.png"), |
|
] |
|
|
|
for idx, (text, icon) in enumerate(menu_items): |
|
st.markdown(f""" |
|
<div class="menu-item"> |
|
<img src="{icon}" /> |
|
{text} |
|
</div> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
st.markdown(""" |
|
<div class="header-text"> |
|
<h1>رزمیار ارتش</h1> |
|
<div class="subtitle">دستیار هوشمند ارتش</div> |
|
</div> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
st.markdown(f""" |
|
<div class="chat-message"> |
|
<span style="font-size: 24px;">🪖</span> |
|
<span>به رزمیار ارتش خوش آمدید.</span> |
|
</div> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
class TogetherEmbeddings(Embeddings): |
|
def __init__(self, model_name: str, api_key: str): |
|
self.model_name = model_name |
|
self.client = Together(api_key=api_key) |
|
|
|
def embed_documents(self, texts: List[str]) -> List[List[float]]: |
|
batch_size = 100 |
|
embeddings = [] |
|
for i in range(0, len(texts), batch_size): |
|
batch = texts[i:i + batch_size] |
|
response = self.client.embeddings.create(model=self.model_name, input=batch) |
|
embeddings.extend([item.embedding for item in response.data]) |
|
return embeddings |
|
|
|
def embed_query(self, text: str) -> List[float]: |
|
return self.embed_documents([text])[0] |
|
|
|
|
|
|
|
@st.cache_resource |
|
def build_vectorstore_from_csv(csv_file_path: str): |
|
df = pd.read_csv(csv_file_path) |
|
texts = df.iloc[:, 0].astype(str).tolist() |
|
texts = [text.strip() for text in texts if text.strip()] |
|
|
|
|
|
text_splitter = RecursiveCharacterTextSplitter( |
|
chunk_size=2048, |
|
chunk_overlap=256, |
|
length_function=len, |
|
separators=["\n\n", "\n", " ", ""] |
|
) |
|
split_texts = [] |
|
for text in texts: |
|
split_texts.extend(text_splitter.split_text(text)) |
|
|
|
documents = [Document(page_content=text) for text in split_texts] |
|
|
|
embeddings = TogetherEmbeddings( |
|
model_name="togethercomputer/m2-bert-80M-32k-retrieval", |
|
api_key='0291f33aee03412a47fa5d8e562e515182dcc5d9aac5a7fb5eefdd1759005979' |
|
) |
|
|
|
vectorstore = FAISS.from_documents(documents, embeddings) |
|
return vectorstore, embeddings |
|
|
|
|
|
|
|
def load_llm(): |
|
return ChatOpenAI( |
|
base_url="https://api.together.xyz/v1", |
|
api_key='0291f33aee03412a47fa5d8e562e515182dcc5d9aac5a7fb5eefdd1759005979', |
|
model="meta-llama/Llama-3.3-70B-Instruct-Turbo-Free" |
|
) |
|
|
|
|
|
|
|
def process_user_query(query: str, vectorstore, embedding_model, llm): |
|
query_embedding = embedding_model.embed_query(query) |
|
docs = vectorstore.similarity_search_by_vector(query_embedding, k=3) |
|
context = "\n".join([doc.page_content for doc in docs]) |
|
|
|
final_prompt = f"""با توجه به اطلاعات زیر، فقط بر اساس آنها به سؤال پاسخ بده. اگر اطلاعات کافی نیست، بگو اطلاعات کافی ندارم. |
|
🔹 اطلاعات:\n{context}\n\n❓ سؤال: {query} |
|
""" |
|
response = llm.invoke(final_prompt) |
|
raw_answer = response.content.strip() |
|
|
|
clean_answer = raw_answer.strip() or "متأسفم، اطلاعات دقیقی در این مورد ندارم." |
|
return clean_answer |
|
|
|
|
|
|
|
def run_chat_ui(): |
|
csv_file_path = 'output (1).csv' |
|
try: |
|
vectorstore, embedding_model = build_vectorstore_from_csv(csv_file_path) |
|
except Exception as e: |
|
st.error(f"خطا در پردازش فایل: {str(e)}") |
|
return |
|
|
|
llm = load_llm() |
|
|
|
|
|
with st.form(key="chat_form"): |
|
user_input = st.text_area("دستور یا پرسوجو:", height=120, placeholder="ماموریت یا سوال خود را وارد کنید...") |
|
submit_button = st.form_submit_button("ارسال دستور") |
|
|
|
if submit_button and user_input: |
|
response = process_user_query(user_input, vectorstore, embedding_model, llm) |
|
st.markdown(f""" |
|
<div class="chat-message"> |
|
<span style="font-size: 24px;">🎖️</span> |
|
<span>{response}</span> |
|
</div> |
|
""", unsafe_allow_html=True) |
|
|
|
run_chat_ui() |
|
|