Rulga commited on
Commit
5405c84
·
1 Parent(s): ee63670
Files changed (1) hide show
  1. app.py +78 -98
app.py CHANGED
@@ -9,18 +9,13 @@ from langchain_community.document_loaders import WebBaseLoader
9
  from langchain_core.prompts import PromptTemplate
10
  from langchain_core.output_parsers import StrOutputParser
11
  from langchain_core.runnables import RunnablePassthrough, RunnableLambda
12
- from requests.exceptions import RequestException
13
 
14
- # Загружаем переменные окружения (если работаем локально)
15
- # load_dotenv(verbose=True)
16
- # Определяем, работает ли код локально (например, если `.env` существует)
17
- is_local = os.path.exists(".env")
18
-
19
- # Загружаем переменные окружения, если работаем локально
20
- if is_local:
21
  load_dotenv(verbose=True)
22
 
23
- # Загружаем API-ключи через Streamlit secrets (для облачного запуска)
24
  try:
25
  GROQ_API_KEY = st.secrets["GROQ_API_KEY"]
26
  USER_AGENT = st.secrets["USER_AGENT"]
@@ -30,7 +25,6 @@ try:
30
  LANGSMITH_PROJECT = st.secrets["LANGSMITH_PROJECT"]
31
  OPENAI_API_KEY = st.secrets["OPENAI_API_KEY"]
32
  except FileNotFoundError:
33
- # Если secrets.toml не найден, используем переменные окружения
34
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
35
  USER_AGENT = os.getenv("USER_AGENT")
36
  LANGSMITH_TRACING = os.getenv("LANGSMITH_TRACING")
@@ -39,72 +33,62 @@ except FileNotFoundError:
39
  LANGSMITH_PROJECT = os.getenv("LANGSMITH_PROJECT")
40
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
41
 
42
- # Проверяем, заданы ли API-ключи
43
- if not GROQ_API_KEY:
44
- st.error("Ошибка: GROQ_API_KEY не задана в переменных окружения.")
45
- st.stop()
46
- if not USER_AGENT:
47
- st.error("Ошибка: USER_AGENT не задана в переменных окружения.")
48
- st.stop()
49
- if not LANGSMITH_TRACING:
50
- st.error("Ошибка: LANGSMITH_TRACING не задана в переменных окружения.")
51
- st.stop()
52
- if not LANGSMITH_ENDPOINT:
53
- st.error("Ошибка: LANGSMITH_ENDPOINT не задана в переменных окружения.")
54
- st.stop()
55
- if not LANGSMITH_API_KEY:
56
- st.error("Ошибка: LANGSMITH_API_KEY не задана в переменных окружения.")
57
- st.stop()
58
- if not LANGSMITH_PROJECT:
59
- st.error("Ошибка: LANGSMITH_PROJECT не задана в переменных окружения.")
60
- st.stop()
61
- if not OPENAI_API_KEY :
62
- st.error("Ошибка: OPENAI_API_KEY не задана в переменных окружения.")
63
  st.stop()
64
 
65
- # Настройка LLM
66
  try:
67
- llm = ChatGroq(
68
- model_name="llama-3.3-70b-versatile",
69
- temperature=0.6,
70
- api_key=GROQ_API_KEY
71
- )
72
  print("[DEBUG] LLM успешно инициализирован")
73
  except Exception as e:
74
- print(f"[ERROR] Ошибка инициализации LLM: {e}")
 
75
 
76
- # Настройка эмбеддингов
77
  embeddings_model = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large-instruct")
78
  print("[DEBUG] Модель эмбеддингов загружена")
79
 
80
- # Функция загрузки только англоязычного контента
81
- def load_english_pages(urls):
82
- english_docs = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  for url in urls:
84
- if not any(lang in url for lang in ["/ru", "/ar", "/es", "/ch"]):
85
- try:
86
- loader = WebBaseLoader(url)
87
- documents = loader.load()
88
- if documents:
89
- english_docs.extend(documents)
90
- print(f"[DEBUG] ��агружен контент с {url}")
91
- except RequestException as e:
92
- print(f"[ERROR] Ошибка загрузки страницы {url}: {e}")
93
- return english_docs
94
-
95
- # Пример URL, где английские страницы без префиксов
96
- urls = ["https://status.law/about", "https://status.law/", "https://status.law/contact"]
97
- documents = load_english_pages(urls)
98
-
99
- # Разбиваем на фрагменты
100
- text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
101
- chunks = text_splitter.split_documents(documents)
102
- print(f"[DEBUG] Разбито на {len(chunks)} фрагментов")
103
-
104
- # Создание векторного хранилища
105
- vector_store = InMemoryVectorStore.from_documents(chunks, embeddings_model)
106
- retriever = vector_store.as_retriever()
107
- print("[DEBUG] Векторное хранилище создано")
108
 
109
  # Промпт для бота
110
  template = """
@@ -116,14 +100,15 @@ Context: {context}
116
  """
117
  prompt = PromptTemplate.from_template(template)
118
 
119
- # История сообщений
120
- def format_history(message_history):
121
- formatted = ""
122
- for msg in message_history:
123
- formatted += f"User: {msg['question']}\nBot: {msg['answer']}\n\n"
124
- return formatted
125
-
126
- message_history = []
 
127
 
128
  # Интерфейс Streamlit
129
  st.set_page_config(page_title="Legal Chatbot", page_icon="🤖")
@@ -132,27 +117,22 @@ st.write("Этот бот отвечает на юридические вопр
132
 
133
  # Поле для ввода вопроса
134
  user_input = st.text_input("Введите ваш вопрос:")
135
- if st.button("Отправить"):
136
- if user_input:
137
- # Получаем релевантные документы из ретривера
138
- retrieved_docs = retriever.get_relevant_documents(user_input)
139
-
140
- # Формируем текстовый контекст из документов
141
- context_text = "\n\n".join([doc.page_content for doc in retrieved_docs])
142
-
143
- # Создание цепочки обработки запроса
144
- chain = (
145
- RunnableLambda(lambda x: {"context": context_text, "question": x["question"]})
146
- | prompt
147
- | llm
148
- | StrOutputParser()
149
- )
150
-
151
- # Запуск цепочки
152
- response = chain.invoke({"question": user_input, "context": context_text})
153
-
154
- # Добавляем в историю сообщений
155
- message_history.append({"question": user_input, "answer": response})
156
-
157
- # Выводим ответ
158
- st.write(response)
 
9
  from langchain_core.prompts import PromptTemplate
10
  from langchain_core.output_parsers import StrOutputParser
11
  from langchain_core.runnables import RunnablePassthrough, RunnableLambda
12
+ from requests.exceptions import RequestException, Timeout
13
 
14
+ # Загрузка переменных окружения
15
+ if os.path.exists(".env"):
 
 
 
 
 
16
  load_dotenv(verbose=True)
17
 
18
+ # Загрузка API-ключей
19
  try:
20
  GROQ_API_KEY = st.secrets["GROQ_API_KEY"]
21
  USER_AGENT = st.secrets["USER_AGENT"]
 
25
  LANGSMITH_PROJECT = st.secrets["LANGSMITH_PROJECT"]
26
  OPENAI_API_KEY = st.secrets["OPENAI_API_KEY"]
27
  except FileNotFoundError:
 
28
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
29
  USER_AGENT = os.getenv("USER_AGENT")
30
  LANGSMITH_TRACING = os.getenv("LANGSMITH_TRACING")
 
33
  LANGSMITH_PROJECT = os.getenv("LANGSMITH_PROJECT")
34
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
35
 
36
+ # Проверка API-ключей
37
+ if not all([GROQ_API_KEY, USER_AGENT, LANGSMITH_TRACING, LANGSMITH_ENDPOINT, LANGSMITH_API_KEY, LANGSMITH_PROJECT, OPENAI_API_KEY]):
38
+ st.error("Ошибка: Не все переменные окружения заданы.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  st.stop()
40
 
41
+ # Инициализация LLM
42
  try:
43
+ llm = ChatGroq(model_name="llama-3.3-70b-versatile", temperature=0.6, api_key=GROQ_API_KEY)
 
 
 
 
44
  print("[DEBUG] LLM успешно инициализирован")
45
  except Exception as e:
46
+ st.error(f"Ошибка инициализации LLM: {e}")
47
+ st.stop()
48
 
49
+ # Инициализация эмбеддингов
50
  embeddings_model = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large-instruct")
51
  print("[DEBUG] Модель эмбеддингов загружена")
52
 
53
+ # Список страниц для анализа (вручную перечислены)
54
+ urls = [
55
+ "https://status.law",
56
+ "https://status.law/about",
57
+ "https://status.law/careers",
58
+ "https://status.law/challenging-sanctions",
59
+ "https://status.law/contact",
60
+ "https://status.law/cross-border-banking-legal-issues",
61
+ "https://status.law/extradition-defense",
62
+ "https://status.law/international-prosecution-protection",
63
+ "https://status.law/interpol-red-notice-removal",
64
+ "https://status.law/practice-areas",
65
+ "https://status.law/reputation-protection",
66
+ "https://status.law/faq"
67
+ ]
68
+
69
+ # Загрузка данных
70
+ @st.cache_data
71
+ def load_data(urls):
72
+ documents = []
73
  for url in urls:
74
+ try:
75
+ loader = WebBaseLoader(url)
76
+ documents.extend(loader.load(timeout=10))
77
+ print(f"[DEBUG] Загружен контент с {url}")
78
+ except (RequestException, Timeout) as e:
79
+ print(f"[ERROR] Ошибка загрузки страницы {url}: {e}")
80
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
81
+ chunks = text_splitter.split_documents(documents)
82
+ print(f"[DEBUG] Разбито на {len(chunks)} фрагментов")
83
+ vector_store = InMemoryVectorStore.from_documents(chunks, embeddings_model)
84
+ retriever = vector_store.as_retriever()
85
+ print("[DEBUG] Векторное хранилище создано")
86
+ return retriever
87
+
88
+ # Загрузка данных и создание ретривера
89
+ if "retriever" not in st.session_state:
90
+ st.session_state.retriever = load_data(urls)
91
+ retriever = st.session_state.retriever
 
 
 
 
 
 
92
 
93
  # Промпт для бота
94
  template = """
 
100
  """
101
  prompt = PromptTemplate.from_template(template)
102
 
103
+ # Инициализация цепочки обработки запроса
104
+ if "chain" not in st.session_state:
105
+ st.session_state.chain = (
106
+ RunnableLambda(lambda x: {"context": x["context"], "question": x["question"]})
107
+ | prompt
108
+ | llm
109
+ | StrOutputParser()
110
+ )
111
+ chain = st.session_state.chain
112
 
113
  # Интерфейс Streamlit
114
  st.set_page_config(page_title="Legal Chatbot", page_icon="🤖")
 
117
 
118
  # Поле для ввода вопроса
119
  user_input = st.text_input("Введите ваш вопрос:")
120
+ if st.button("Отправить") and user_input:
121
+ retrieved_docs = retriever.get_relevant_documents(user_input)
122
+ context_text = "\n\n".join([doc.page_content for doc in retrieved_docs])
123
+ response = chain.invoke({"question": user_input, "context": context_text})
124
+
125
+ # Сохранение истории сообщений
126
+ if "message_history" not in st.session_state:
127
+ st.session_state.message_history = []
128
+ st.session_state.message_history.append({"question": user_input, "answer": response})
129
+
130
+ # Вывод ответа
131
+ st.write(response)
132
+
133
+ # Вывод истории сообщений
134
+ if "message_history" in st.session_state:
135
+ st.write("### История сообщений")
136
+ for msg in st.session_state.message_history:
137
+ st.write(f"**User:** {msg['question']}")
138
+ st.write(f"**Bot:** {msg['answer']}")