army / app.py
M17idd's picture
Update app.py
4116887
raw
history blame
22.1 kB
import streamlit as st
from hazm import Normalizer, SentenceTokenizer
import os
import docx
from langchain.chat_models import ChatOpenAI
from langchain.schema import SystemMessage, HumanMessage
from rapidfuzz import fuzz
import concurrent.futures
import time
import numpy as np
from hazm import *
import re
import nltk
nltk.download('punkt')
st.markdown("""
<style>
.stAppHeader.st-emotion-cache-12fmjuu.e4hpqof0 {
background-color: rgba(46,59,46, 0.8) !important; /* سبز متمایل به خاکی */
color: #2e3b2e !important; /* رنگ متن روشن */
font-family: 'Vazirmatn', Tahoma, sans-serif !important;
padding: 20px !important; /* فضای داخلی بیشتر */
border-radius: 10px !important; /* گوشه‌های گرد */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3) !important; /* سایه برای برجسته شدن */
}
</style>
""", unsafe_allow_html=True)
st.markdown("""
<style>
@font-face {
font-family: 'Roboto';
src: url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap') format('woff2');
font-weight: 400;
font-style: normal;
}
html, body, [class*="css"] {
font-family: 'Roboto', Tahoma, sans-serif !important;
font-weight: 400 !important;
direction: rtl;
text-align: right;
ظ color: #ffffff;
}
.stApp {
background: linear-gradient(to left, #4b5e40, #2e3b2e);
color: #ffffff;
}
[data-testid="stSidebar"] {
width: 260px !important;
background-color: #1a2b1e;
border: none !important;
padding-top: 20px;
}
.menu-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
font-size: 16px;
font-weight: 600;
color: #d4d4d4;
cursor: pointer;
transition: background-color 0.3s ease;
}
.menu-item:hover {
background-color: #2e3b2e;
color: #b8860b;
}
.menu-item img {
width: 25px;
height: 25px;
}
.stButton>button {
background-color: #b8860b !important;
color: #1a2b1e !important;
font-family: 'Roboto', Tahoma, sans-serif;
font-weight: 700 !important;
border-radius: 10px;
padding: 12px 24px;
border: none;
transition: all 0.3s ease;
font-size: 16px;
width: 100%;
margin: 10px 0;
}
.stButton>button:hover {
background-color: #8b6508 !important;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}
.header-text {
text-align: center;
margin: 20px 0;
background-color: rgba(26, 43, 30, 0.9);
padding: 25px;
border-radius: 15px;
box-shadow: 0 6px 12px rgba(0,0,0,0.4);
font-family: 'Roboto', Tahoma, sans-serif; /* اضافه شد */
}
.subtitle {
font-size: 18px;
color: #d4d4d4;
font-weight: 600;
margin-top: 10px;
}
.chat-message {
flex-wrap: wrap;
background-color: rgba(26, 43, 30, 0.95);
border: 2px solid #b8860b;
border-radius: 15px;
padding: 20px;
margin: 15px 0;
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
animation: fadeIn 0.6s ease;
font-size: 18px;
color: #d4d4d4;
font-weight: 600;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 15px;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.stTextInput>div>input, .stTextArea textarea {
background-color: rgba(26, 43, 30, 0.95) !important;
border-radius: 10px !important;
border: 1px solid #b8860b !important;
padding: 12px !important;
font-family: 'Roboto', Tahoma;
font-weight: 500;
font-size: 16px;
color: #d4d4d4 !important;
}
hr {
border: 1px solid #b8860b;
margin: 15px 0;
}
[data-testid="stSidebar"] > div {
border: none !important;
}
</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('<style>.stTextInput > div[data-baseweb="input"] + div, .stTextInput div:has(div[role="alert"]) { display: none !important; }</style>', unsafe_allow_html=True)
st.markdown("""
<style>
input {
background-color: #2e3b2e;
color: gold;
border: 1px solid gold;
border-radius: 10px;
padding: 10px;
}
</style>
""", unsafe_allow_html=True)
st.markdown("""
<style>
html, body, [class*="css"] {
font-family: 'Vazir', sans-serif;
}
label {
font-size: 20px !important;
color: #ffffff !important;
font-weight: 800 !important;
margin-bottom: 10px !important;
display: block;
}
input[type="text"],
input[type="password"],
input[type="text"]:focus,
input[type="password"]:focus,
input[type="text"]:hover,
input[type="password"]:hover {
background-color: #ffffff !important;
color: #000000 !important;
font-size: 18px !important;
font-family: 'Vazir', sans-serif !important;
}
::placeholder {
color: #bbbbbb !important;
opacity: 0.8 !important;
font-size: 16px;
}
</style>
""", unsafe_allow_html=True)
username = st.text_input("نام کاربری:", placeholder="شناسه خود را وارد کنید",
label_visibility="visible")
password = st.text_input("رمز عبور:", placeholder="رمز عبور ", type="password",
label_visibility="visible")
st.markdown("""
<style>
div.stButton > button {
background-image: url("https://upload.wikimedia.org/wikipedia/commons/5/59/US_Army_Universal_Camouflage_Pattern.jpg");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
color: #f5deb3;
font-family: 'Vazir', sans-serif;
font-size: 20px;
font-weight: bold;
padding: 14px 35px;
border: 2px solid #d4af37;
border-radius: 14px;
box-shadow: 0 0 18px rgba(0,0,0,0.6);
transition: all 0.3s ease-in-out;
}
div.stButton > button:hover {
filter: brightness(1.2);
box-shadow: 0 0 22px #b8860b;
transform: scale(1.03);
}
div.stButton > button:active {
transform: scale(0.97);
box-shadow: 0 0 12px #000;
}
</style>
""", unsafe_allow_html=True)
if st.button("ورود"):
if username == "admin" and password == "123":
st.session_state.authenticated = True
st.rerun()
else:
st.markdown("""
<div style="background-color: rgba(241, 196, 15, 0.6); color: #2e3b2e; padding: 10px; border-radius: 10px; border: 2px solid #2e3b2e; margin-top: 20px; text-align: center; backdrop-filter: blur(5px);">
نام کاربری یا رمز عبور اشتباه است.
</div>
""", unsafe_allow_html=True)
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://m17idd-reporting.hf.space"),
("تاریخچه ماموریت‌ها", "https://cdn-icons-png.flaticon.com/512/709/709496.png", None),
("تحلیل داده‌های نظامی", "https://cdn-icons-png.flaticon.com/512/1828/1828932.png", "https://m17idd-test.hf.space"),
("مدیریت منابع", "https://cdn-icons-png.flaticon.com/512/681/681494.png", None),
("دستیار فرماندهی", "https://cdn-icons-png.flaticon.com/512/3601/3601646.png", None),
("تنظیمات امنیتی", "https://cdn-icons-png.flaticon.com/512/2099/2099058.png", None),
("پشتیبانی فنی", "https://cdn-icons-png.flaticon.com/512/597/597177.png", None),
]
st.markdown("""
<link href="https://cdn.jsdelivr.net/gh/rastikerdar/[email protected]/dist/font-face.css" rel="stylesheet" type="text/css" />
""", unsafe_allow_html=True)
for idx, (text, icon, link) in enumerate(menu_items):
content = f"""
<div class="menu-item" style="display: flex; align-items: center; margin-bottom: 10px;">
<img src="{icon}" width="20" height="20" style="margin-left: 10px;" />
<span style="color: white; font-family: 'Vazir', sans-serif; font-weight: bold;">{text}</span>
</div>
"""
if link:
content = f'<a href="{link}" target="_blank" style="text-decoration: none;">{content}</a>'
st.markdown(content, unsafe_allow_html=True)
if idx in [1, 3, 5]:
st.markdown("<hr style='border-top: 1px solid #555;'/>", unsafe_allow_html=True)
st.markdown("""
<style>
.header-text {
text-align: center;
margin: 50px 0;
background: #2e3b2e;
padding: 60px 30px;
border-radius: 25px;
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.8);
animation: slideIn 2s ease-in-out, fadeIn 3s ease-in-out;
background-size: cover;
background-position: center;
position: relative;
}
@keyframes fadeIn {
0% { opacity: 0; transform: translateY(30px); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes slideIn {
0% { transform: translateX(-50%); opacity: 0; }
100% { transform: translateX(0); opacity: 1; }
}
.header-text h1 {
font-family: 'Vazir', sans-serif;
font-size: 62px;
color: #d89b00;
margin: 0;
font-weight: 900;
letter-spacing: 4px;
text-shadow: 4px 4px 15px rgba(0, 0, 0, 0.9);
transform: scale(1.08);
animation: glow 2s ease-in-out infinite alternate;
}
.subtitle {
font-family: 'Vazir', sans-serif;
font-size: 24px;
color: #f8f8f8;
font-weight: 700;
margin-top: 15px;
letter-spacing: 2px;
text-shadow: 3px 3px 10px rgba(0,0,0,0.8);
animation: fadeInSubtitle 2s ease-in-out;
}
@keyframes fadeInSubtitle {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); }
}
.stButton>button {
background-color: #e67e22 !important;
color: #4b5320 !important;
font-family: 'Vazir', sans-serif;
font-weight: 700 !important;
border-radius: 20px;
padding: 15px 30px;
border: none;
transition: all 0.3s ease;
font-size: 18px;
width: 100%;
margin: 20px 0;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
.stButton>button:hover {
background-color: #f39c12 !important;
transform: translateY(-4px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.6);
}
.stApp {
background: #2e3b2e;
color: white;
font-family: 'Vazir', sans-serif;
}
</style>
<div class="header-text">
<h1>رزم‌‌یار‌ارتش</h1>
<div class="subtitle">دستیارهوشمندارتش جمهوری اسلامی ایران</div>
</div>
""", unsafe_allow_html=True)
llm = ChatOpenAI(
base_url="https://api.together.xyz/v1",
api_key='0291f33aee03412a47fa5d8e562e515182dcc5d9aac5a7fb5eefdd1759005979',
model="meta-llama/Llama-3.3-70B-Instruct-Turbo-Free",
max_tokens=1024 # specify the max tokens as per your requirement
)
st.markdown("""
<style>
.st-emotion-cache-128upt6.eht7o1d3 {
background-color: rgba(46,59,46, 0.8) !important; /* سبز تیره (44533f) */
border-radius: 10px !important; /* گوشه‌های گرد */
color: #d4d4d4 !important; /* رنگ متن روشن */
font-family: 'Vazirmatn', Tahoma, sans-serif !important;
padding: 15px !important; /* فضای داخلی بیشتر */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3) !important; /* سایه برای برجسته شدن */
}
</style>
""", unsafe_allow_html=True)
st.markdown("""
<style>
.st-af.st-ah.st-bb.st-ar.st-as.st-ax.st-ay.st-az.st-b0.st-b1.st-b2.st-bc.st-b7 {
background-color: #3a5338 !important;
color: #d4d4d4 !important;
border: 1px solid #c8a200 !important;
border-radius: 10px;
padding: 15px;
}
</style>
""", unsafe_allow_html=True)
st.markdown("""
<style>
.st-emotion-cache-yd4u6l.e1togvvn1 {
background-color: rgba(106, 127, 83, 0.8) !important;
border-radius: 10px !important;
color: #d4d4d4 !important;
font-family: 'Vazirmatn', Tahoma, sans-serif !important;
padding: 15px !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3) !important;
}
</style>
""", unsafe_allow_html=True)
st.markdown("""
<style>
.stAppHeader.st-emotion-cache-12fmjuu.e4hpqof0 {
background-color: rgba(42, 55, 39, 0.9) !important;
color: #d4d4d4 !important;
font-family: 'Vazirmatn', Tahoma, sans-serif !important;
padding: 20px !important;
border-radius: 10px !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3) !important;
}
</style>
""", unsafe_allow_html=True)
st.markdown("""
<style>
textarea::placeholder {
color: #ffffff !important;
opacity: 1 !important;
}
textarea {
color: #ffffff !important;
border-radius: 10px !important;
padding: 10px !important;
}
</style>
""", unsafe_allow_html=True)
query = st.chat_input("چطور می‌تونم کمک کنم؟")
if query:
st.markdown(f'<div class="chat-message">{query}</div>', unsafe_allow_html=True)
think = st.markdown("""
<div class="thinking-message">
<p>در حال فکر کردن...</p>
<div class="spinner"></div>
</div>
""", unsafe_allow_html=True)
else:
st.markdown("")
st.markdown("""
<style>
.thinking-message {
display: flex;
align-items: center;
font-size: 18px;
color: #ffffff;
}
.thinking-message p {
margin-right: 10px;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #4b6d3d;
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
""", unsafe_allow_html=True)
import os
import re
import docx
import streamlit as st
import concurrent.futures
from hazm import Normalizer
from rapidfuzz import fuzz
from langchain.schema import SystemMessage, HumanMessage
folder_path = '46'
normalizer = Normalizer()
@st.cache_data(show_spinner="در حال پردازش اسناد... لطفاً صبور باشید.")
def load_and_process_documents(path):
def process_docx(filename):
try:
full_path = os.path.join(path, filename)
doc = docx.Document(full_path)
text = "\n".join([para.text for para in doc.paragraphs])
normalized = normalizer.normalize(text)
return filename, normalized
except Exception as e:
print(f"Error processing {filename}: {e}")
return filename, ""
filenames = [f for f in os.listdir(path) if f.endswith(".docx")]
doc_texts = {}
with concurrent.futures.ThreadPoolExecutor() as executor:
for filename, content in executor.map(process_docx, filenames):
doc_texts[filename] = content
return doc_texts
doc_texts = load_and_process_documents(folder_path)
with open('stopwords.txt', 'r', encoding='utf-8') as file:
stop_words = set(file.read().splitlines())
def remove_stop_words(text, stop_words):
words = text.split()
return " ".join([word for word in words if word not in stop_words])
def extract_keywords_from_text(text, query_words):
matched_lines = []
lines = text.split("\n")
for line in lines:
if any(query_word in line for query_word in query_words):
matched_lines.append(line)
return matched_lines
def clean_text(text):
return re.sub(r'[^آ-ی۰-۹0-9،.؟!؛+\-* ]+', '', text)
from collections import Counter
import heapq
def summarize_text_by_frequency(text, num_sentences=1):
sentences = text.split('\n')
word_freq = Counter()
for sentence in sentences:
for word in sentence.split():
if word not in stop_words:
word_freq[word] += 1
sentence_scores = {}
for sentence in sentences:
for word in sentence.split():
if word in word_freq:
sentence_scores[sentence] = sentence_scores.get(sentence, 0) + word_freq[word]
summarized_sentences = heapq.nlargest(num_sentences, sentence_scores, key=sentence_scores.get)
return "\n".join(summarized_sentences)
def find_closest_lines(query, doc_texts, stop_words, top_n=5):
cleaned_query = remove_stop_words(query, stop_words)
query_words = cleaned_query.split()
all_matched_lines = []
for filename, text in doc_texts.items():
matched_lines = extract_keywords_from_text(text, query_words)
for line in matched_lines:
similarity = fuzz.partial_ratio(query, line)
all_matched_lines.append((line, similarity))
all_matched_lines.sort(key=lambda x: x[1], reverse=True)
closest_lines = [line for line, _ in all_matched_lines[:top_n]]
return closest_lines
def remove_stop_words_from_lines(lines, stop_words):
cleaned_lines = []
for line in lines:
words = line.split()
cleaned_words = [word for word in words if word not in stop_words]
cleaned_lines.append(" ".join(cleaned_words))
return cleaned_lines
if query:
closest_lines = find_closest_lines(query, doc_texts, stop_words, top_n=5)
cleaned_closest_lines = [
clean_text(" ".join([word for word in line.split() if word not in stop_words]))
for line in closest_lines
]
summarized_text = summarize_text_by_frequency("\n".join(cleaned_closest_lines), num_sentences=1)
if summarized_text:
prompt = f"""
تعدادی جمله مرتبط با سوال زیر استخراج شده است. لطفاً ابتدا این جملات را بررسی کن، سپس با در نظر گرفتن محتوای سوال و لحن آن، یک پاسخ نهایی حرفه‌ای، دقیق و روان ارائه کن که هم به سوال پاسخ دهد و هم از نظر نگارشی و ساختاری در سطح بالایی باشد. پاسخ نهایی باید حداکثر 1024 کاراکتر و حداقل 512 کاراکتر باشد، خلاصه و واضح نوشته شود و فقط به زبان فارسی باشد. از تکرار اضافی پرهیز کن و در صورت نیاز، محتوای جملات را ترکیب کن.
سوال:
{query}
جملات مرتبط:
{summarized_text}
پاسخ نهایی حرفه‌ای بازنویسی‌شده:
"""
response = llm([
SystemMessage(content="You are a helpful assistant."),
HumanMessage(content=prompt)
])
rewritten = response.content.strip()
review_prompt = f"""
لطفاً بررسی کن که آیا پاسخ زیر به سوال داده‌شده مرتبط، صحیح، معتبر و قابل قبول است یا نه. اگر پاسخ مرتبط و صحیح است، فقط بنویس: 'تأیید شد'. اگر پاسخ اشتباه است یا ربطی به سوال ندارد یا معتبر نیست، فقط بنویس: 'نیاز به اصلاح دارد'.
سوال:
{query}
پاسخ:
{rewritten}
"""
review_response = llm([
SystemMessage(content="You are a helpful assistant."),
HumanMessage(content=review_prompt)
])
review_result = review_response.content.strip()
if "تأیید شد" in review_result:
rewritten = clean_text(rewritten)
st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
think.empty()
else:
prompt = f"""
هیچ جمله مرتبط مستقیمی با سوال یافت نشد. لطفاً با توجه به سوال زیر، یک پاسخ حرفه‌ای، مرتبط، معنادار و معتبر تولید کن. فقط از جملات موجود در اسناد معتبر استفاده کن و از ساخت جملات ساختگی یا استفاده از زبان غیر فارسی خودداری کن.
سوال:
{query}
"""
response = llm([
SystemMessage(content="You are a helpful assistant."),
HumanMessage(content=prompt)
])
rewritten = clean_text(response.content.strip())
st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
think.empty()