upd model.py

This commit is contained in:
Oleh Poiasnik 2025-05-08 16:26:00 +00:00
parent 703ef0fcc6
commit 972e475233

View File

@ -14,17 +14,19 @@ from psycopg2.extras import RealDictCursor
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Získanie konfiguračného súboru
config_file_path = "config.json" config_file_path = "config.json"
with open(config_file_path, 'r') as config_file: with open(config_file_path, 'r') as config_file:
config = json.load(config_file) config = json.load(config_file)
# Získanie Mistral API kľúča
mistral_api_key = "hXDC4RBJk1qy5pOlrgr01GtOlmyCBaNs" mistral_api_key = "hXDC4RBJk1qy5pOlrgr01GtOlmyCBaNs"
if not mistral_api_key: if not mistral_api_key:
raise ValueError("Mistral API key not found in configuration.") raise ValueError("Mistral API key not found in configuration.")
############################################################################### ###############################################################################
# Simple functions for translation (stub) # Funkcie pre preklad (stub verzie)
############################################################################### ###############################################################################
def translate_to_slovak(text: str) -> str: def translate_to_slovak(text: str) -> str:
return text return text
@ -35,7 +37,23 @@ def translate_preserving_medicine_names(text: str) -> str:
############################################################################### ###############################################################################
# Function for evaluating the completeness of the answer # Funkcia na generovanie podrobného opisu hodnotenia cez Mistral
###############################################################################
def generate_detailed_description(query: str, answer: str, rating: float) -> str:
prompt = (
f"Podrobne opíš, prečo odpoveď: '{answer}' na otázku: '{query}' dosiahla hodnotenie {rating} zo 10. "
"Uveď relevantné aspekty, ktoré ovplyvnili toto hodnotenie, vrátane úplnosti, presnosti a kvality vysvetlenia."
)
try:
description = llm_small.generate_text(prompt=prompt, max_tokens=150, temperature=0.5)
return description.strip()
except Exception as e:
logger.error(f"Error generating detailed description: {e}")
return "Nie je dostupný podrobný popis."
###############################################################################
# Funkcia na hodnotenie úplnosti odpovede
############################################################################### ###############################################################################
def evaluate_complete_answer(query: str, answer: str) -> dict: def evaluate_complete_answer(query: str, answer: str) -> dict:
evaluation_prompt = ( evaluation_prompt = (
@ -57,28 +75,53 @@ def evaluate_complete_answer(query: str, answer: str) -> dict:
############################################################################### ###############################################################################
# Function for validating the response logic # Funkcia pre validáciu logiky odpovede (aktualizovaná verzia)
############################################################################### ###############################################################################
def validate_answer_logic(query: str, answer: str) -> str: def validate_answer_logic(query: str, answer: str) -> str:
validation_prompt = ( validation_prompt = (
f"Otázka: '{query}'\n" f"Otázka: '{query}'\n"
f"Odpoveď: '{answer}'\n\n" f"Odpoveď: '{answer}'\n\n"
"Analyzuj prosím túto odpoveď. Ak odpoveď neobsahuje všetky dodatočné informácie, na ktoré sa pýtal používateľ, " "Vyhodnoť, či odpoveď jednoznačne reaguje na uvedenú otázku a obsahuje všetky dôležité informácie. "
"alebo ak odporúčania liekov nie sú úplné (napr. chýba dávkovanie alebo čas užívania, ak boli takéto požiadavky v otázke), " "Ak odpoveď nereaguje presne na otázku, vytvor novú odpoveď, ktorá jasne a logicky reaguje na tento dotaz. "
"vytvor opravenú odpoveď, ktorá je logicky konzistentná s otázkou. " "Ak je odpoveď správna, začni svoju odpoveď textom 'OK:'; následne uveď potvrdenú odpoveď. "
"Odpovedz v slovenčine a iba čistou, konečnou odpoveďou bez ďalších komentárov." "Odpovedz len finálnou odpoveďou bez ďalších komentárov."
) )
try: try:
validated_answer = llm_small.generate_text(prompt=validation_prompt, max_tokens=800, temperature=0.5) validated_answer = llm_small.generate_text(prompt=validation_prompt, max_tokens=800, temperature=0.5)
logger.info(f"Validated answer: {validated_answer}") logger.info(f"Validated answer (first 200 chars): {validated_answer[:200]}")
return validated_answer if validated_answer.strip().lower().startswith("ok:"):
return validated_answer.split("OK:", 1)[1].strip()
else:
return validated_answer.strip()
except Exception as e: except Exception as e:
logger.error(f"Error during answer validation: {e}") logger.error(f"Error during answer validation: {e}")
return answer return answer
############################################################################### ###############################################################################
# Function for creating a dynamic prompt with information from documents # Funkcia pre logovanie hodnotení do súboru
###############################################################################
def log_evaluation_to_file(model: str, search_type: str, rating: float, detailed_desc: str, answer: str):
safe_model = model.replace(" ", "_")
file_name = f"{safe_model}_{search_type}.txt"
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
log_entry = (
f"Timestamp: {timestamp}\n"
f"Rating: {rating}/10\n"
f"Detailed description:\n{detailed_desc}\n"
f"Answer:\n{answer}\n"
+ "=" * 80 + "\n\n"
)
try:
with open(file_name, "a", encoding="utf-8") as f:
f.write(log_entry)
logger.info(f"Hodnotenie bolo zapísané do súboru {file_name}.")
except Exception as e:
logger.error(f"Error writing evaluation to file {file_name}: {e}")
###############################################################################
# Funkcia pre vytvorenie dynamického prompt-u z informácií o dokumentoch
############################################################################### ###############################################################################
def build_dynamic_prompt(query: str, documents: list) -> str: def build_dynamic_prompt(query: str, documents: list) -> str:
documents_str = "\n".join(documents) documents_str = "\n".join(documents)
@ -90,14 +133,13 @@ def build_dynamic_prompt(query: str, documents: list) -> str:
"Ak áno, v odpovedi najprv uveď odporúčané lieky pre každý liek uveď jeho názov, stručné vysvetlenie a, ak je to relevantné, " "Ak áno, v odpovedi najprv uveď odporúčané lieky pre každý liek uveď jeho názov, stručné vysvetlenie a, ak je to relevantné, "
"odporúčané dávkovanie alebo čas užívania, a potom v ďalšej časti poskytn ú odpoveď na dodatočné požiadavky. " "odporúčané dávkovanie alebo čas užívania, a potom v ďalšej časti poskytn ú odpoveď na dodatočné požiadavky. "
"Odpovedaj priamo a ľudským, priateľským tónom v číslovanom zozname, bez zbytočných úvodných fráz. " "Odpovedaj priamo a ľudským, priateľským tónom v číslovanom zozname, bez zbytočných úvodných fráz. "
"Odpoveď musí byť v slovenčine. " "Odpovedz výlučne po slovensky."
"Prosím, odpovedaj v priateľskom, zdvorilom a profesionálnom tóne, bez akýchkoľvek agresívnych či drzých výrazov."
) )
return prompt return prompt
############################################################################### ###############################################################################
# Function to get user data from the database via endpoint /api/get_user_data # Funkcia pre získavanie user_data z databázy cez endpoint /api/get_user_data
############################################################################### ###############################################################################
def get_user_data_from_db(chat_id: str) -> str: def get_user_data_from_db(chat_id: str) -> str:
try: try:
@ -113,7 +155,7 @@ def get_user_data_from_db(chat_id: str) -> str:
############################################################################### ###############################################################################
# Class for calling Mistral LLM # Trieda pre prácu s Mistral LLM cez API
############################################################################### ###############################################################################
class CustomMistralLLM: class CustomMistralLLM:
def __init__(self, api_key: str, endpoint_url: str, model_name: str): def __init__(self, api_key: str, endpoint_url: str, model_name: str):
@ -122,6 +164,10 @@ class CustomMistralLLM:
self.model_name = model_name self.model_name = model_name
def generate_text(self, prompt: str, max_tokens=812, temperature=0.7, retries=3, delay=2): def generate_text(self, prompt: str, max_tokens=812, temperature=0.7, retries=3, delay=2):
# Pre mistral-large, ak je prompt príliš dlhý, skracujeme ho (napr. na 4000 znakov)
if self.model_name == "mistral-large-latest" and len(prompt) > 4000:
logger.warning(f"Prompt dlhší ako 4000 znakov, skracujem ho.")
prompt = prompt[:4000]
headers = { headers = {
"Authorization": f"Bearer {self.api_key}", "Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json" "Content-Type": "application/json"
@ -155,21 +201,7 @@ class CustomMistralLLM:
############################################################################### ###############################################################################
# Function for generating a detailed evaluation description # Inicializácia embeddingov a Elasticsearch
###############################################################################
# def detailed_evaluation_description(query: str, answer: str, rating: float) -> str:
# prompt = (
# f"Podrobne opíš, prečo odpoveď: '{answer}' na otázku: '{query}' dosiahla hodnotenie {rating} zo 10. "
# "Uveď relevantné aspekty, ktoré ovplyvnili toto hodnotenie, vrátane úplnosti, presnosti a kvality vysvetlenia."
# )
# description = llm_small.generate_text(prompt=prompt, max_tokens=150, temperature=0.5)
# return description.strip()
#
# Ak chcete vidieť podrobné hodnotenie, odkomentujte funkciu detailed_evaluation_description a príslušné časti kódu.
###############################################################################
# Initialisation of Embeddings and Elasticsearch
############################################################################### ###############################################################################
logger.info("Loading HuggingFaceEmbeddings model...") logger.info("Loading HuggingFaceEmbeddings model...")
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2") embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
@ -188,7 +220,7 @@ if config.get("useCloud", False):
else: else:
logger.info("Using local Elasticsearch.") logger.info("Using local Elasticsearch.")
vectorstore = ElasticsearchStore( vectorstore = ElasticsearchStore(
es_url="http://elasticsearch:9200", es_url="http://localhost:9200",
index_name=index_name, index_name=index_name,
embedding=embeddings, embedding=embeddings,
) )
@ -196,7 +228,7 @@ else:
logger.info("Connected to Elasticsearch.") logger.info("Connected to Elasticsearch.")
############################################################################### ###############################################################################
# Initialisation of LLM small & large # Inicializácia LLM small & large
############################################################################### ###############################################################################
llm_small = CustomMistralLLM( llm_small = CustomMistralLLM(
api_key=mistral_api_key, api_key=mistral_api_key,
@ -211,9 +243,13 @@ llm_large = CustomMistralLLM(
############################################################################### ###############################################################################
# Request classification function: vyhladavanie vs. upresnenie # Funkcia na klasifikáciu dopytu: vyhladavanie vs. upresnenie alebo update informácií
############################################################################### ###############################################################################
def classify_query(query: str, chat_history: str = "") -> str: def classify_query(query: str, chat_history: str = "") -> str:
# Ak v histórii sa nachádza výzva na zadanie údajov a query obsahuje číslice (napr. vek),
# považujeme to za odpoveď na doplnenie informácií.
if "Prosím, uveďte vek pacienta" in chat_history and re.search(r"\d+\s*(rok(ov|y)?|years?)", query.lower()):
return "update"
if not chat_history.strip(): if not chat_history.strip():
return "vyhladavanie" return "vyhladavanie"
prompt = ( prompt = (
@ -222,8 +258,8 @@ def classify_query(query: str, chat_history: str = "") -> str:
"o upresnenie/doplnenie už poskytnutej odpovede.\n" "o upresnenie/doplnenie už poskytnutej odpovede.\n"
"Ak dopyt obsahuje výrazy ako 'čo pit', 'aké lieky', 'odporuč liek', 'hľadám liek', " "Ak dopyt obsahuje výrazy ako 'čo pit', 'aké lieky', 'odporuč liek', 'hľadám liek', "
"odpovedaj slovom 'vyhľadávanie'.\n" "odpovedaj slovom 'vyhľadávanie'.\n"
"Ak dopyt slúži na upresnenie, napríklad obsahuje výrazy ako 'a nie na predpis', " "Ak dopyt slúži na upresnenie, napríklad obsahuje výrazy ako 'a nie na predpis', 'upresni', 'este raz', "
"'upresni', 'este raz', odpovedaj slovom 'upresnenie'.\n" "odpovedaj slovom 'upresnenie'.\n"
f"Dopyt: \"{query}\"" f"Dopyt: \"{query}\""
) )
classification = llm_small.generate_text(prompt=prompt, max_tokens=20, temperature=0.3) classification = llm_small.generate_text(prompt=prompt, max_tokens=20, temperature=0.3)
@ -237,7 +273,7 @@ def classify_query(query: str, chat_history: str = "") -> str:
############################################################################### ###############################################################################
# Template for upresnenie dopytu # Šablóna prompt-u pre upresnenie (bez histórie)
############################################################################### ###############################################################################
def build_upresnenie_prompt_no_history(chat_history: str, user_query: str) -> str: def build_upresnenie_prompt_no_history(chat_history: str, user_query: str) -> str:
prompt = f""" prompt = f"""
@ -262,7 +298,7 @@ Upresňujúca otázka od používateľa:
############################################################################### ###############################################################################
# Function for retrieving the last vyhladavacieho dopytu z histórie # Funkcia pre extrakciu posledného vyhľadávacieho dopytu z histórie
############################################################################### ###############################################################################
def extract_last_vyhladavacie_query(chat_history: str) -> str: def extract_last_vyhladavacie_query(chat_history: str) -> str:
lines = chat_history.splitlines() lines = chat_history.splitlines()
@ -275,7 +311,7 @@ def extract_last_vyhladavacie_query(chat_history: str) -> str:
############################################################################### ###############################################################################
# Agent class for data storage: vek, anamneza, predpis, user_data, search_query # Trieda agenta pre ukladanie údajov: vek, anamneza, predpis, user_data, search_query
############################################################################### ###############################################################################
class ConversationalAgent: class ConversationalAgent:
def __init__(self): def __init__(self):
@ -325,7 +361,7 @@ class ConversationalAgent:
if not self.get_memory("vek"): if not self.get_memory("vek"):
missing_info["vek"] = "Prosím, uveďte vek pacienta." missing_info["vek"] = "Prosím, uveďte vek pacienta."
if not self.get_memory("anamneza"): if not self.get_memory("anamneza"):
missing_info["anamnéza"] = "Má pacient nejaké chronické ochorenia alebo alergie?" missing_info["anamneza"] = "Má pacient nejaké chronické ochorenia alebo alergie?"
if not self.get_memory("predpis"): if not self.get_memory("predpis"):
missing_info["predpis"] = "Ide o liek na predpis alebo voľnopredajný liek?" missing_info["predpis"] = "Ide o liek na predpis alebo voľnopredajný liek?"
return missing_info return missing_info
@ -335,7 +371,7 @@ class ConversationalAgent:
############################################################################### ###############################################################################
# Main function process_query_with_mistral with updated logic # Hlavná funkcia process_query_with_mistral, ktorá vykonáva obidva druhy vyhľadávania
############################################################################### ###############################################################################
CHAT_HISTORY_ENDPOINT = "http://localhost:5000/api/chat_history_detail" CHAT_HISTORY_ENDPOINT = "http://localhost:5000/api/chat_history_detail"
@ -343,6 +379,7 @@ CHAT_HISTORY_ENDPOINT = "http://localhost:5000/api/chat_history_detail"
def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10): def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10):
logger.info("Processing query started.") logger.info("Processing query started.")
# Načítame históriu chatu
chat_history = "" chat_history = ""
if chat_context: if chat_context:
chat_history = chat_context chat_history = chat_context
@ -371,36 +408,29 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10
if chat_id: if chat_id:
existing_user_data = get_user_data_from_db(chat_id) existing_user_data = get_user_data_from_db(chat_id)
if not chat_history.strip():
agent.update_memory("search_query", query)
qtype = classify_query(query, chat_history)
logger.info(f"Typ dopytu: {qtype}")
logger.info(f"Chat context (snippet): {chat_history[:200]}...")
if qtype == "update":
original_search = agent.long_term_memory.get("search_query")
if not original_search:
original_search = extract_last_vyhladavacie_query(chat_history)
query_to_use = original_search
else:
query_to_use = query
if qtype == "vyhladavanie":
agent.parse_user_info(chat_history)
agent.parse_user_info(query) agent.parse_user_info(query)
missing_info = agent.analyze_input(query) missing_info = agent.analyze_input(query)
if not existing_user_data:
if "Prosím, uveďte vek pacienta" in chat_history:
if chat_id:
update_payload = {"chatId": chat_id, "userData": query}
try:
update_response = requests.post("http://localhost:5000/api/save_user_data", json=update_payload)
if update_response.status_code == 200:
logger.info("User data was successfully updated via endpoint /api/save_user_data (data question flag).")
else:
logger.warning(f"Failed to update data (data question flag): {update_response.text}")
except Exception as e:
logger.error(f"Error when updating user_data via endpoint (data question flag): {e}")
if missing_info: if missing_info:
logger.info(f"Chýbajúce informácie: {missing_info}") logger.info(f"Chýbajúce informácie: {missing_info}")
combined_missing_text = " ".join(missing_info.values()) combined_missing_text = " ".join(missing_info.values())
if query.strip() not in combined_missing_text:
if chat_id:
update_payload = {"chatId": chat_id, "userData": query}
try:
update_response = requests.post("http://localhost:5000/api/save_user_data", json=update_payload)
if update_response.status_code == 200:
logger.info("User data was successfully updated via endpoint /api/save_user_data.")
else:
logger.warning(f"Failed to update the data: {update_response.text}")
except Exception as e:
logger.error(f"Error when updating user_data via endpoint: {e}")
return { return {
"best_answer": combined_missing_text, "best_answer": combined_missing_text,
"model": "FollowUp (new chat)", "model": "FollowUp (new chat)",
@ -409,111 +439,69 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10
"patient_data": query "patient_data": query
} }
qtype = classify_query(query, chat_history)
logger.info(f"Typ dopytu: {qtype}")
logger.info(f"Chat context (snippet): {chat_history[:200]}...")
if qtype == "vyhladavanie":
user_data_db = get_user_data_from_db(chat_id)
if user_data_db:
query = query + " Udaje cloveka: " + user_data_db
agent.long_term_memory["search_query"] = query
if qtype == "upresnenie": if qtype == "upresnenie":
original_search = agent.long_term_memory.get("search_query") original_search = agent.long_term_memory.get("search_query")
if not original_search: if not original_search:
original_search = extract_last_vyhladavacie_query(chat_history) original_search = extract_last_vyhladavacie_query(chat_history)
if original_search is None: if original_search is None:
original_search = "" original_search = ""
combined_query = (original_search + " " + query).strip() combined_query = (original_search + " " + query_to_use).strip()
user_data_db = get_user_data_from_db(chat_id) user_data_db = get_user_data_from_db(chat_id)
if user_data_db: if user_data_db:
combined_query += " Udaje cloveka: " + user_data_db combined_query += " Udaje cloveka: " + user_data_db
logger.info(f"Combined query for search: {combined_query}") logger.info(f"Použitý dopyt pre upresnenie: '{combined_query}'")
upres_prompt = build_upresnenie_prompt_no_history(chat_history, combined_query) upres_prompt = build_upresnenie_prompt_no_history(chat_history, combined_query)
response_str = llm_small.generate_text(upres_prompt, max_tokens=1200, temperature=0.5) response_str = llm_small.generate_text(upres_prompt, max_tokens=1200, temperature=0.5)
normalized = response_str.strip() normalized = response_str.strip()
logger.info(f"Upresnenie prompt response: {normalized}") logger.info(f"Upresnenie prompt response: {normalized}")
if re.match(r"(?i)^found_in_history:\s*", normalized): # Vektorové a textové vyhľadávanie
logger.info("Zistený FOUND_IN_HISTORY vykonávame vyhľadávanie s kombinovaným dopytom.")
elif re.match(r"(?i)^no_answer_in_history:\s*", normalized):
parts = re.split(r"(?i)^no_answer_in_history:\s*", normalized, maxsplit=1)
if len(parts) >= 2:
combined_query = parts[1].strip()
logger.info(f"Upravený vyhľadávací dopyт z NO_ANSWER_IN_HISTORY: {combined_query}")
vector_results = vectorstore.similarity_search(combined_query, k=k) vector_results = vectorstore.similarity_search(combined_query, k=k)
max_docs = 5 text_results = vectorstore.client.search(
max_len = 1000 index=index_name,
vector_docs = [hit.metadata.get("text", "")[:max_len] for hit in vector_results[:max_docs]] body={"size": k, "query": {"match": {"text": combined_query}}}
if not vector_docs:
return {
"best_answer": "Ľutujem, nenašli sa žiadne relevantné informácie.",
"model": "Upresnenie-NoResults",
"rating": 0,
"explanation": "No results from search."
}
joined_docs = "\n".join(vector_docs)
final_prompt = (
f"Otázka: {combined_query}\n\n"
"Na základe týchto informácií:\n"
f"{joined_docs}\n\n"
"Vygeneruj odporúčanie liekov alebo vysvetlenie, ak je to relevantné.\n"
"Prosím, odpovedaj stručne a dostatočne, bez nadmernej dĺžky."
) )
vector_docs = [getattr(hit, 'page_content', None) or hit.metadata.get('text', '') for hit in vector_results[:5]]
text_docs = [hit['_source'].get('text', '') for hit in text_results['hits']['hits']]
all_docs = vector_docs + text_docs
final_prompt = build_dynamic_prompt(combined_query, all_docs)
if len(final_prompt) > 4000:
final_prompt = final_prompt[:4000]
ans_small = llm_small.generate_text(final_prompt, max_tokens=1200, temperature=0.7) ans_small = llm_small.generate_text(final_prompt, max_tokens=1200, temperature=0.7)
ans_large = llm_large.generate_text(final_prompt, max_tokens=1200, temperature=0.7) ans_large = llm_large.generate_text(final_prompt, max_tokens=1200, temperature=0.7)
val_small = validate_answer_logic(combined_query, ans_small) val_small = validate_answer_logic(combined_query, ans_small)
val_large = validate_answer_logic(combined_query, ans_large) val_large = validate_answer_logic(combined_query, ans_large)
eval_small = evaluate_complete_answer(combined_query, val_small) eval_small = evaluate_complete_answer(combined_query, val_small)
eval_large = evaluate_complete_answer(combined_query, val_large) eval_large = evaluate_complete_answer(combined_query, val_large)
candidates = [ candidates = [
{"summary": val_small, "eval": eval_small, "model": "Mistral Small"}, {"model": "Mistral Small Vector", "summary": val_small, "eval": eval_small},
{"summary": val_large, "eval": eval_large, "model": "Mistral Large"}, {"model": "Mistral Large Vector", "summary": val_large, "eval": eval_large},
] ]
for c in candidates:
# desc = generate_detailed_description(combined_query, c["summary"], c["eval"]["rating"])
# for candidate in candidates: log_evaluation_to_file(c["model"], "vector", c["eval"]["rating"], desc, c["summary"])
# detailed_desc = detailed_evaluation_description(combined_query, candidate["summary"], candidate["eval"]["rating"])
# candidate["eval"]["detailed_description"] = detailed_desc
#
best = max(candidates, key=lambda x: x["eval"]["rating"]) best = max(candidates, key=lambda x: x["eval"]["rating"])
logger.info(f"Odpoveď od modelu {best['model']} má rating: {best['eval']['rating']}/10")
evaluation_table = "=== Výsledky hodnotenia odpovedí ===\n"
evaluation_table += "{:<15} | {:<6} | {:<60}\n".format("Model", "Rating", "Evaluated Text")
evaluation_table += "-" * 100 + "\n"
for candidate in candidates:
model_name = candidate["model"]
rating = candidate["eval"]["rating"]
evaluated_text = candidate["summary"].replace("\n", " ")
evaluation_table += "{:<15} | {:<6} | {:<60}\n".format(model_name, rating, evaluated_text)
evaluation_table += "=" * 100 + "\n"
# with open("evaluation.txt", "w", encoding="utf-8") as f:
# f.write(evaluation_table)
# logger.info("Evaluation table записана в evaluation.txt")
final_answer = translate_preserving_medicine_names(best["summary"]) final_answer = translate_preserving_medicine_names(best["summary"])
memory_json = json.dumps(agent.long_term_memory) memory_block = f"[MEMORY]{json.dumps(agent.long_term_memory)}[/MEMORY]"
memory_block = f"[MEMORY]{memory_json}[/MEMORY]"
final_answer_with_memory = final_answer + "\n\n"
return { return {
"best_answer": final_answer_with_memory, "best_answer": final_answer,
"model": best["model"], "model": best["model"],
"rating": best["eval"]["rating"], "rating": best["eval"]["rating"],
"explanation": best["eval"]["explanation"] "explanation": best["eval"]["explanation"]
} }
vector_results = vectorstore.similarity_search(query, k=k) # Vetva pre vyhladavanie
max_docs = 5 vector_results = vectorstore.similarity_search(query_to_use, k=k)
max_len = 1000 text_results = vectorstore.client.search(
vector_docs = [hit.metadata.get("text", "")[:max_len] for hit in vector_results[:max_docs]] index=index_name,
body={"size": k, "query": {"match": {"text": query_to_use}}}
)
vector_docs = [getattr(hit, 'page_content', None) or hit.metadata.get('text', '') for hit in vector_results[:5]]
if not vector_docs: if not vector_docs:
return { return {
"best_answer": "Ľutujem, nenašli sa žiadne relevantné informácie.", "best_answer": "Ľutujem, nenašli sa žiadne relevantné informácie.",
@ -521,21 +509,35 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10
"rating": 0, "rating": 0,
"explanation": "No results" "explanation": "No results"
} }
joined_docs = "\n".join(vector_docs) text_docs = [hit['_source'].get('text', '') for hit in text_results['hits']['hits']]
final_prompt = ( all_docs = vector_docs + text_docs
f"Otázka: {query}\n\n" final_prompt = build_dynamic_prompt(query_to_use, all_docs)
"Na základe týchto informácií:\n" if len(final_prompt) > 4000:
f"{joined_docs}\n\n" final_prompt = final_prompt[:4000]
"Vygeneruj odporúčanie liekov alebo vysvetlenie, ak je to relevantné.\n"
"Prosím, odpovedaj stručne a dostatočne, bez nadmernej dĺžky." ans_small = llm_small.generate_text(final_prompt, max_tokens=1200, temperature=0.7)
) ans_large = llm_large.generate_text(final_prompt, max_tokens=1200, temperature=0.7)
answer = llm_small.generate_text(final_prompt, max_tokens=1200, temperature=0.7)
memory_json = json.dumps(agent.long_term_memory) val_small = validate_answer_logic(query_to_use, ans_small)
memory_block = f"[MEMORY]{memory_json}[/MEMORY]" val_large = validate_answer_logic(query_to_use, ans_large)
answer_with_memory = answer + "\n\n" eval_small = evaluate_complete_answer(query_to_use, val_small)
eval_large = evaluate_complete_answer(query_to_use, val_large)
candidates = [
{"model": "Mistral Small Text", "summary": val_small, "eval": eval_small},
{"model": "Mistral Large Text", "summary": val_large, "eval": eval_large},
]
for c in candidates:
desc = generate_detailed_description(query_to_use, c["summary"], c["eval"]["rating"])
log_evaluation_to_file(c["model"], "text", c["eval"]["rating"], desc, c["summary"])
best = max(candidates, key=lambda x: x["eval"]["rating"])
final_answer = translate_preserving_medicine_names(best["summary"])
memory_block = f"[MEMORY]{json.dumps(agent.long_term_memory)}[/MEMORY]"
return { return {
"best_answer": answer_with_memory, "best_answer": final_answer,
"model": "Vyhladavanie-Final", "model": best["model"],
"rating": 9, "rating": best["eval"]["rating"],
"explanation": "Vyhľadávacia cesta" "explanation": best["eval"]["explanation"]
} }