Spaces:
Runtime error
Runtime error
File size: 10,573 Bytes
a3c4ade |
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 150 151 152 |
import streamlit as st
import openai
import gspread
from google.oauth2.service_account import Credentials
import pandas as pd
from datetime import datetime
import json
import os
# ========== Настройки ==========
SPREADSHEET_ID = "1c6to5bUThs3rUsbf0Lkc0hScWXvfRtlHBy3oK7w_PiI"
LOG_FILE = "chat_logs.json"
# Инициализация
if "logs" not in st.session_state:
st.session_state.logs = []
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
# Загрузка Google Sheets
@st.cache_data
def load_data():
creds = Credentials.from_service_account_info(st.secrets["gcp_service_account"])
gc = gspread.authorize(creds)
sheet = gc.open_by_key(SPREADSHEET_ID).sheet1
return pd.DataFrame(sheet.get_all_records())
# Логирование
def save_log(question, answer):
log_entry = {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"question": question,
"answer": answer
}
st.session_state.logs.append(log_entry)
with open(LOG_FILE, "a") as f:
json.dump(log_entry, f)
f.write("\n")
# Поиск в таблице
def search_in_sheet(question):
qa_df = load_data()
results = []
for _, row in qa_df.iterrows():
if question.lower() in str(row['Вопрос']).lower():
response = f"📌 Ответ:\n{row['Правильный ответ']}"
if pd.notna(row['Источник ответа']):
response += f"\n📚 Источник: {row['Источник ответа']}"
results.append(response)
return "\n\n".join(results) if results else None
# ========== Полный оригинальный промпт ==========
system_prompt = """
Ты - эксперт по поиску нормативных требований по техническим документам. ТТы - технический эксперт. Строго соблюдай порядок:
1. Сначала ищи ответ в приложенной таблице
2. Если нет в таблице - ищи в справочнике Клюева В.В.
3. Только затем используй другие источники
4. Никогда не упоминай приложенную таблицу в ответе. Никогда не используй слово "таблица" в ответе.
5. Никогда не упоминай источник информации, в котором нет ответа на вопрос пользователя. Упоминай только источники, в которых ответ есть. Если источник не известен, то оставь пробел вместо названия.
Не добавляй ничего от себя, отвечай кратко и по существу вопроса. Цитируй дословно, не обобщай. Если ответ получается слишком общим, неконкретным, подтяни больше информации из того-же источника, чтобы прояснить детяли.
игнорируй общие знания, если есть информация в справочнике.
"""
# Оригинальные few-shot примеры
few_shots = [
{
"user": "В каких трех ГОСТах упоминается дефектоскоп?",
"assistant": "Неправильный ответ: 1. В приложенной таблице информации по вопросам яркости при площади рабочей поверхности более 0,1 м² ответа нет.2. В справочнике Клюева В.В. также нет данных о конкретных значениях яркости при данной площади.3. Согласно ГОСТам, дефектоскоп упоминается в следующих стандартах... \n\n---\n\nПравильный ответ должен быть: ефектоскоп упоминается в следующих стандартах: - ГОСТ 25129-82 'Дефектоскопы ультразвуковые'. Общие технические условия'- ГОСТ 17433-81 'Дефектоскопы магнитопорошковые. Общие технические условия' - ГОСТ 21931-76 'Дефектоскопы радиографические. Общие технические условия'"
},
{
"user": "Приведите точную цитату из СанПиН 2.2.2/2.4.1340-03 о допустимых уровнях шума.",
"assistant": "Точная цитата из СанПиН 2.2.2/2.4.1340-03: 'Допустимые уровни шума не должны превышать... (источник: СанПиН 2.2.2/2.4.1340-03, раздел 3.2)'"
},
{
"user": "Что написано в ГОСТ Р 8.568?",
"assistant": "Вам нужен общий ответ по содержанию документа или точная цитата и параметры?"
},
{
"user": "случайная погрешность измерения это?",
"assistant": "Неправильный ответ: В ГОСТ Р 8.568-97 'ГСИ. Измерения. Общие требования к методам и средствам измерений' случайная погрешность измерения определяется как часть погрешности измерения, которая изменяется случайным образом при повторных измерениях одной и той же величины. Она отличается от систематической погрешности тем, что не имеет постоянного значения и может варьироваться в разных измерениях. Случайная погрешность обусловлена множеством факторов, включая изменения условий измерения и характеристики измерительных приборов.\n\nИсточник: ГОСТ Р 8.568-97.\n\n---\n\nПравильный ответ должен быть: В главе 5, пункте 5.2 справочника под общей редакцией Клюева В.В. 'Неразрушающий контроль' случайная погрешность определяется как 'составляющая погрешности результата измерения, изменяющаяся случайным образом при повторных измерениях одной и той же величины в одинаковых условиях'. Основные характеристики случайной погрешности подробно описаны в таблице 5.1 того же раздела.\n\nПравильный источник: глава 5, п. 5.2, справочник под общей редакцией Клюева В.В. 'Неразрушающий контроль'"
}
]
# ========== Интерфейс ==========
st.title("📚 Консультант по технической документации")
user_input = st.text_area("Введите Ваш вопрос в это окошко:", height=100)
if st.button("Найти ответ"):
if not user_input.strip():
st.warning("Пожалуйста, введите вопрос")
else:
with st.spinner("Ищем ответ..."):
# 1. Поиск в таблице
sheet_answer = search_in_sheet(user_input)
if sheet_answer:
answer = sheet_answer
else:
# 2. Запрос к GPT с учетом истории (3 последних сообщения)
messages = [{"role": "system", "content": system_prompt}]
# Добавляем few-shot примеры
for shot in few_shots:
messages.append({"role": "user", "content": shot["user"]})
messages.append({"role": "assistant", "content": shot["assistant"]})
# Добавляем историю чата (последние 3 сообщения)
for msg in st.session_state.chat_history[-3:]:
messages.append({"role": "user", "content": msg["question"]})
messages.append({"role": "assistant", "content": msg["answer"]})
messages.append({"role": "user", "content": user_input})
response = openai.ChatCompletion.create(
model="openai/gpt-4.1-nano",
messages=messages,
temperature=0.5,
max_tokens=1500
)
answer = response.choices[0].message['content'].strip()
# Сохраняем в историю (для контекста)
st.session_state.chat_history.append({
"question": user_input,
"answer": answer
})
st.session_state.chat_history = st.session_state.chat_history[-3:]
# Логируем
save_log(user_input, answer)
# Вывод
st.markdown(f"### Вопрос:\n{user_input}")
st.markdown(f"### Ответ:\n{answer}")
# Админ-панель
if st.checkbox("Показать логи (админ)"):
st.subheader("История запросов")
try:
with open(LOG_FILE, "r") as f:
st.write("Последние 20 записей:")
logs = [json.loads(line) for line in f.readlines()[-20:]]
for log in reversed(logs):
st.markdown(f"**{log['timestamp']}**")
st.text_area("Вопрос:", log["question"], height=50, disabled=True)
st.text_area("Ответ:", log["answer"], height=150, disabled=True)
st.divider()
except FileNotFoundError:
st.warning("Логи пока не созданы") |