ekaterina-simonova commited on
Commit
a3c4ade
·
verified ·
1 Parent(s): dfa3ddb

Upload 3 files

Browse files
Files changed (3) hide show
  1. .streamlit/secrets.toml +14 -0
  2. app.py +152 -0
  3. requirements.txt +5 -0
.streamlit/secrets.toml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ OPENAI_API_KEY = "sk-or-vv-daf64146a7be1800a7bf2a0da35fecb9e7bbc8076fc666c64fdf9abbda6f479c"
2
+ GCP_SERVICE_ACCOUNT =
3
+ {
4
+ "type": "service_account",
5
+ "project_id": "biblio-451117",
6
+ "private_key_id": "5a0f15c3aafd723c79d79d39835e0337d57d21e2",
7
+ "private_key": "-----BEGIN PRIVATE KEY-----\\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCYgBm8GMJephKS\\\nzBfmIu8YlfbV0WYDUHyk3mo865gSOBzyP/WmzGobcQUnLLHicktqrqKQPZEVVk2C\\\nRBpAV6bfn9ay2rXXhVH9HpdAgwtHwtGCgsvFYi/u+rD/XYOD2nvJBo/yx/YR7daC\\\ngZ/pjiaCYm1hkxaS8CUo5vY45Tzt1DaBU8w/MViujnNv80lJ77j9o0bicMI/A7h3\\\n5jEl+D8/mr30Sj0v4Wo1pyuYZaTRboKm4ft/L5gRRCQD/P6606tOZucy6MuwyUbM\\\nP7I810tpdEXu8i6HKLQSbQJm1auUacAp6eYtWWyD4OkpPUkr5lRZlBuEFiOrIJLk\\\nGk61x+xnAgMBAAECggEABOzFEqhXGt4yy31gghK7rMfrktgFnSowDm7853ZZ5ift\\nWx47ZdARG01dSSvazsvtMdgPrNtb4E9k3DTXOlL8d12JW/CkotvFSxEotSz5bJ5S\\\noewGwqPUyNtMHxZMO5iXkmVlqEnbJaYDh+bBw4KK2Ds8T5nIHB058KgmaGm0qsFB\\\nRI0lBa3FUefrg74yWwH8q5eyW/dL+UZO9mmgMq5aG5QoEGLOn4k0IgqWR6GnavN4\\\noCo+iYZ61Q1+jmUrqwcbUJqDhEBncGYDg6vJyvwkt3UHbDXMKRjHgT2HxoBNZsOe\\\nHqtu8KCnEe61y8Vsk2+XCUOH2Pmmp8Y+YIFh6VCcgQKBgQDMqHF6Ga7ICQYj0Ta7\\n74yRpn1B3lhKTlgSIV9M9966qeOMvXJKwb6zXemjmB/EBGkkuk+bzzrRm7zEEudt\\n5slteFkGn63x4i9GqXy2RkNqg95Gykkj0t+Kv32pNAaBOQdLsTOpi8vRqREuPTFT\\\nRaYcsMalNSr5jqHFLpjdVovaJwKBgQC+wf1UYJogobzYCPiZXhZkt1Qyz387cwTr\\\nSNoqGJVlCBu52GqcBJHbT0Vf7hbR9oOsGxt4LC0dHs/f+ao0kCFPkjXb4t56RHJr\\\nBMa55Fx7/rga0DK3w+NrvBLwn7eK2Q5Ovy25cUrfo+6TGfm16hGybGzaW8z2SFFi\\\n5QWtpyYDwQKBgQCCUr04OISRQxXS1xYYpRmJYlCfEjx8zNjOasvqEmmVyjtp0vWl\\\n3yxVwfbWwzdvNjPSPIYXPOZCtf6FiVgwJuebuyhNzH8S6aqbP7B3zdR+TozL3WKn\\\n2k+ZZglaJxQBU9Rugd/ZFnlrAFM9c6AmW9LEsFk+uNWt5wLisqKLR+J0vwKBgEYZ\\\nHVGrahgBt1af/VLGm24JXHyLeZLMEouvqtP7UrLcxuuFVq/ckgjIWZMF+AbSEtLk\\n5zRC75Ua5ILGyUAlksgdz4LtHJpLmswu5iQbgczi7p6T0X9sEZ9ebotT9eulFbfk\\nUxYpRr1mDV6rFfM+f6BUba/UOj5qltXDmVGV8cdBAoGBALbitkW0cLkgaogJe2AA\\nw2LlVywOPLs5r3u3t4m0z7ZdkkyleXViVcgE32NpMrsY77VmzlGTTwazkMOyhYN0\\niL2zwBtcr5FEaWxJq4mUw0TO96BqTfWzLkINjYpnzacEVY2Qx1WQ4h4GQAOv3aT8\\nHKtqq5TCOSiOTNRReWQqbAs9\\n-----END PRIVATE KEY-----\\n", "client_email": "biblio@biblio-451117.iam.gserviceaccount.com",
8
+ "client_id": "105558301591316197240",
9
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
10
+ "token_uri": "https://oauth2.googleapis.com/token",
11
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
12
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/biblio%40biblio-451117.iam.gserviceaccount.com",
13
+ "universe_domain": "googleapis.com"
14
+ }
app.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import openai
3
+ import gspread
4
+ from google.oauth2.service_account import Credentials
5
+ import pandas as pd
6
+ from datetime import datetime
7
+ import json
8
+ import os
9
+
10
+ # ========== Настройки ==========
11
+ SPREADSHEET_ID = "1c6to5bUThs3rUsbf0Lkc0hScWXvfRtlHBy3oK7w_PiI"
12
+ LOG_FILE = "chat_logs.json"
13
+
14
+ # Инициализация
15
+ if "logs" not in st.session_state:
16
+ st.session_state.logs = []
17
+ if "chat_history" not in st.session_state:
18
+ st.session_state.chat_history = []
19
+
20
+ # Загрузка Google Sheets
21
+ @st.cache_data
22
+ def load_data():
23
+ creds = Credentials.from_service_account_info(st.secrets["gcp_service_account"])
24
+ gc = gspread.authorize(creds)
25
+ sheet = gc.open_by_key(SPREADSHEET_ID).sheet1
26
+ return pd.DataFrame(sheet.get_all_records())
27
+
28
+ # Логирование
29
+ def save_log(question, answer):
30
+ log_entry = {
31
+ "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
32
+ "question": question,
33
+ "answer": answer
34
+ }
35
+ st.session_state.logs.append(log_entry)
36
+ with open(LOG_FILE, "a") as f:
37
+ json.dump(log_entry, f)
38
+ f.write("\n")
39
+
40
+ # Поиск в таблице
41
+ def search_in_sheet(question):
42
+ qa_df = load_data()
43
+ results = []
44
+ for _, row in qa_df.iterrows():
45
+ if question.lower() in str(row['Вопрос']).lower():
46
+ response = f"📌 Ответ:\n{row['Правильный ответ']}"
47
+ if pd.notna(row['Источник ответа']):
48
+ response += f"\n📚 Источник: {row['Источник ответа']}"
49
+ results.append(response)
50
+ return "\n\n".join(results) if results else None
51
+
52
+ # ========== Полный оригинальный промпт ==========
53
+ system_prompt = """
54
+ Ты - эксперт по поиску нормативных требований по техническим документам. ТТы - технический эксперт. Строго соблюдай порядок:
55
+ 1. Сначала ищи ответ в приложенной таблице
56
+ 2. Если нет в таблице - ищи в справочнике Клюева В.В.
57
+ 3. Только затем используй другие источники
58
+ 4. Никогда не упоминай приложенную таблицу в ответе. Никогда не используй слово "таблица" в ответе.
59
+ 5. Никогда не упоминай источник информации, в котором нет ответа на вопрос пользователя. Упоминай только источники, в которых ответ есть. Если источник не известен, то оставь пробел вместо названия.
60
+
61
+ Не добавляй ничего от себя, отвечай кратко и по существу вопроса. Цитируй дословно, не обобщай. Если ответ получается слишком общим, неконкретным, подтяни больше информации из того-же источника, чтобы прояснить детяли.
62
+
63
+ игнорируй общие знания, если есть информация в справочнике.
64
+ """
65
+
66
+ # Оригинальные few-shot примеры
67
+ few_shots = [
68
+ {
69
+ "user": "В каких трех ГОСТах упоминается дефектоскоп?",
70
+ "assistant": "Неправильный ответ: 1. В приложенной таблице информации по вопросам яркости при площади рабочей поверхности более 0,1 м² ответа нет.2. В справочнике Клюева В.В. также нет данных о конкретных значениях яркости при данной площади.3. Согласно ГОСТам, дефектоскоп упоминается в следующих стандартах... \n\n---\n\nПравильный ответ должен быть: ефектоскоп упоминается в следующих стандартах: - ГОСТ 25129-82 'Дефектоскопы ультразвуковые'. Общие технические условия'- ГОСТ 17433-81 'Дефектоскопы магнитопорошковые. Общие технические условия' - ГОСТ 21931-76 'Дефектоскопы радиографические. Общие технические условия'"
71
+ },
72
+ {
73
+ "user": "Приведите точную цитату из СанПиН 2.2.2/2.4.1340-03 о допустимых уровнях шума.",
74
+ "assistant": "Точная цитата из СанПиН 2.2.2/2.4.1340-03: 'Допустимые уровни шума не должны превышать... (источник: СанПиН 2.2.2/2.4.1340-03, раздел 3.2)'"
75
+ },
76
+ {
77
+ "user": "Что написано в ГОСТ Р 8.568?",
78
+ "assistant": "Вам нужен общий ответ по содержанию документа или точная цитата и параметры?"
79
+ },
80
+ {
81
+ "user": "случайная погрешность измерения это?",
82
+ "assistant": "Неправильный ответ: В ГОСТ Р 8.568-97 'ГСИ. Измерения. Общие требования к методам и средствам измерений' случайная погрешность измерения определяется как часть погрешности измерения, которая изменяется случайным образом при повторных измерениях одной и той же величины. Она отличается от систематической погрешности тем, что не имеет постоянного значения и может варьироваться в разных измерениях. Случайная погрешность обусловлена множеством факторов, включая изменения условий измерения и характеристики измерительных приборов.\n\nИсточник: ГОСТ Р 8.568-97.\n\n---\n\nПравильный ответ должен быть: В главе 5, пункте 5.2 справочника под общей редакцией Клюева В.В. 'Неразрушающий контроль' случайная погрешность определяется как 'составляющая погрешности результата измерения, изменяющаяся случайным образом при повторных измерениях одной и той же величины в одинаковых условиях'. Основные характеристики случайной погрешности подробно описаны в таблице 5.1 того же раздела.\n\nПравильный источник: глава 5, п. 5.2, справочник под общей редакцией Клюева В.В. 'Неразрушающий контроль'"
83
+ }
84
+ ]
85
+
86
+ # ========== Интерфейс ==========
87
+ st.title("📚 Консультант по технической документации")
88
+
89
+ user_input = st.text_area("Введите Ваш вопрос в это окошко:", height=100)
90
+
91
+ if st.button("Найти ответ"):
92
+ if not user_input.strip():
93
+ st.warning("Пожалуйста, введите вопрос")
94
+ else:
95
+ with st.spinner("Ищем ответ..."):
96
+ # 1. Поиск в таблице
97
+ sheet_answer = search_in_sheet(user_input)
98
+
99
+ if sheet_answer:
100
+ answer = sheet_answer
101
+ else:
102
+ # 2. Запрос к GPT с учетом истории (3 последних сообщения)
103
+ messages = [{"role": "system", "content": system_prompt}]
104
+
105
+ # Добавляем few-shot примеры
106
+ for shot in few_shots:
107
+ messages.append({"role": "user", "content": shot["user"]})
108
+ messages.append({"role": "assistant", "content": shot["assistant"]})
109
+
110
+ # Добавляем историю чата (последние 3 сообщения)
111
+ for msg in st.session_state.chat_history[-3:]:
112
+ messages.append({"role": "user", "content": msg["question"]})
113
+ messages.append({"role": "assistant", "content": msg["answer"]})
114
+
115
+ messages.append({"role": "user", "content": user_input})
116
+
117
+ response = openai.ChatCompletion.create(
118
+ model="openai/gpt-4.1-nano",
119
+ messages=messages,
120
+ temperature=0.5,
121
+ max_tokens=1500
122
+ )
123
+ answer = response.choices[0].message['content'].strip()
124
+
125
+ # Сохраняем в историю (для контекста)
126
+ st.session_state.chat_history.append({
127
+ "question": user_input,
128
+ "answer": answer
129
+ })
130
+ st.session_state.chat_history = st.session_state.chat_history[-3:]
131
+
132
+ # Логируем
133
+ save_log(user_input, answer)
134
+
135
+ # Вывод
136
+ st.markdown(f"### Вопрос:\n{user_input}")
137
+ st.markdown(f"### Ответ:\n{answer}")
138
+
139
+ # Админ-панель
140
+ if st.checkbox("Показать логи (админ)"):
141
+ st.subheader("История запросов")
142
+ try:
143
+ with open(LOG_FILE, "r") as f:
144
+ st.write("Последние 20 записей:")
145
+ logs = [json.loads(line) for line in f.readlines()[-20:]]
146
+ for log in reversed(logs):
147
+ st.markdown(f"**{log['timestamp']}**")
148
+ st.text_area("Вопрос:", log["question"], height=50, disabled=True)
149
+ st.text_area("Ответ:", log["answer"], height=150, disabled=True)
150
+ st.divider()
151
+ except FileNotFoundError:
152
+ st.warning("Логи пока не созданы")
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit
2
+ openai
3
+ gspread
4
+ pandas
5
+ google-auth