code ready to deploy + prompty

This commit is contained in:
l.gabrysiak 2025-02-28 11:44:28 +01:00
parent ad08ce74ce
commit 3dbba3f2d6
5 changed files with 94 additions and 37 deletions

View File

@ -11,11 +11,13 @@ import uvicorn
import httpx import httpx
from typing import List, Optional from typing import List, Optional
import asyncio import asyncio
import os
app = FastAPI() app = FastAPI()
OLLAMA_BASE_URL = "http://ollama:11434" OLLAMA_BASE_URL = "http://ollama:11434"
WEAVIATE_URL = "http://weaviate:8080" WEAVIATE_URL = "http://weaviate:8080"
PROMPT_DIR_PATCH = "./prompts"
# Inicjalizacja klientów # Inicjalizacja klientów
ollama_client = ollama.Client(host=OLLAMA_BASE_URL) ollama_client = ollama.Client(host=OLLAMA_BASE_URL)
@ -31,7 +33,7 @@ weaviate_client = weaviate.WeaviateClient(
) )
weaviate_client.connect() weaviate_client.connect()
collection = weaviate_client.collections.get("Document") collection = weaviate_client.collections.get("Document")
files_content = None
class Message(BaseModel): class Message(BaseModel):
role: str role: str
content: str content: str
@ -54,28 +56,30 @@ class ChatResponse(BaseModel):
eval_count: int eval_count: int
eval_duration: int eval_duration: int
prompt = """ def read_text_files_from_directory(directory_path):
Jesteś precyzyjnym narzędziem do generowania słów kluczowych z zakresu BHP i prawa pracy. Twoje zadanie to podanie WYŁĄCZNIE najistotniejszych słów do wyszukiwania w bazie dokumentów prawnych. files_dict = {}
# Iterowanie przez wszystkie pliki w katalogu
for filename in os.listdir(directory_path):
# Sprawdzanie, czy plik ma rozszerzenie .txt
if filename.endswith('.txt'):
file_path = os.path.join(directory_path, filename)
try:
# Odczytywanie zawartości pliku
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
# Dodawanie do słownika z nazwą pliku bez rozszerzenia jako kluczem
file_name_without_extension = os.path.splitext(filename)[0]
files_dict[file_name_without_extension] = content
except Exception as e:
print(f"Błąd przy odczycie pliku {filename}: {e}")
return files_dict
Ścisłe zasady: def analyze_query(content):
1. Jeśli zapytanie dotyczy konkretnego artykułu:
- Podaj TYLKO numer artykułu i nazwę kodeksu (np. "Art. 154, Kodeks pracy").
- NIE dodawaj żadnych innych słów.
2. Jeśli zapytanie nie dotyczy konkretnego artykułu:
- Podaj maksymalnie 3 najbardziej specyficzne terminy związane z zapytaniem.
- Unikaj ogólnych słów jak "praca", "pracownik", "pracodawca", chyba że częścią specjalistycznego terminu.
3. Używaj wyłącznie terminów, które z pewnością występują w dokumentach prawnych lub specjalistycznych opracowaniach.
4. NIE dodawaj własnych interpretacji ani rozszerzeń zapytania.
Odpowiedz TYLKO listą słów kluczowych oddzielonych przecinkami, bez żadnych dodatkowych wyjaśnień czy komentarzy.
Zapytanie: '{query}'
"""
def analyze_query(query):
analysis = ollama_client.chat( analysis = ollama_client.chat(
model="gemma2:2b", model="gemma2:2b",
messages=[{"role": "user", "content": prompt.format(query=query)}] messages=[{"role": "user", "content": content}]
) )
keywords = [word.strip() for word in analysis['message']['content'].split(',') if word.strip()] keywords = [word.strip() for word in analysis['message']['content'].split(',') if word.strip()]
print("Słowa kluczowe:", keywords) print("Słowa kluczowe:", keywords)
@ -103,7 +107,7 @@ def extract_relevant_fragment(content, query, context_size=100):
return f"...{content[start:end]}..." return f"...{content[start:end]}..."
return content[:200] + "..." return content[:200] + "..."
def hybrid_search(keywords, limit=5, alpha=0.5): def hybrid_search(keywords, limit=100, alpha=0.5):
if isinstance(keywords, str): if isinstance(keywords, str):
keywords = [keywords] keywords = [keywords]
@ -182,27 +186,38 @@ async def stream_chat(model, messages, options):
@app.post("/api/chat") @app.post("/api/chat")
async def chat_endpoint(request: ChatRequest): async def chat_endpoint(request: ChatRequest):
try: try:
files_content = read_text_files_from_directory(PROMPT_DIR_PATCH)
if files_content is None:
raise KeyError(f"Nie wczytano promptów!!!")
prompt_seach = files_content.get("prompt_seach")
if prompt_seach is None:
raise KeyError(f"Nie znaleziono promptu o nazwie '{prompt_seach}'.")
prompt_system = files_content.get("prompt_system")
if prompt_system is None:
raise KeyError(f"Nie znaleziono promptu o nazwie '{prompt_system}'.")
prompt_answer = files_content.get("prompt_answer")
if prompt_answer is None:
raise KeyError(f"Nie znaleziono promptu o nazwie '{prompt_answer}'.")
prompt_data = files_content.get("prompt_data")
if prompt_data is None:
raise KeyError(f"Nie znaleziono promptu o nazwie '{prompt_data}'.")
query = request.messages[-1].content if request.messages else "" query = request.messages[-1].content if request.messages else ""
keywords = analyze_query(query) keywords = analyze_query(prompt_seach.format(query=query))
weaviate_results = hybrid_search(keywords) weaviate_results = hybrid_search(keywords)
if not weaviate_results: prompt_data = "\n".join([f"Źródło: {doc['file_name']}\n{doc['relevant_fragment']}\n\n" for doc in weaviate_results])
context = f""" print(prompt_data)
Nie znalazłem informacji na temat: {query}.
Proszę poinformuj użytkownika, że nie masz wystarczającej wiedzy, aby udzielić jednoznacznej odpowiedzi.
"""
else:
context = "Znalezione informacje:\n"
for item in weaviate_results:
context += f"Źródło: {item['file_name']}\nFragment: {item['relevant_fragment']}\n\n"
messages_with_context =[ messages_with_context =[
{"role": "system", "content": context}, {"role": "system", "content": prompt_system},
{"role": "user", "content": f""" {"role": "system", "content": prompt_data},
Na podstawie powyższych informacji, odpowiedz na pytanie: {query}. {"role": "user", "content": prompt_answer.format(query=query)}
Odwołaj się do konkretnych artykułów lub zacytuj fragmenty źródeł. ]
"""}
]
if request.stream: if request.stream:
return StreamingResponse(stream_chat(request.model, messages_with_context, request.options), media_type="application/json") return StreamingResponse(stream_chat(request.model, messages_with_context, request.options), media_type="application/json")

View File

@ -0,0 +1 @@
Na podstawie powyższych informacji odpowiedz na pytanie: {query}.

1
prompts/prompt_data.txt Normal file
View File

@ -0,0 +1 @@
Oto fragmenty aktów prawnych i dokumentów powiązanych z pytaniem użytkownika: \n\n

15
prompts/prompt_seach.txt Normal file
View File

@ -0,0 +1,15 @@
Jesteś precyzyjnym narzędziem do generowania słów kluczowych z zakresu BHP i prawa pracy. Twoje zadanie to podanie WYŁĄCZNIE najistotniejszych słów do wyszukiwania w bazie dokumentów prawnych.
Ścisłe zasady:
1. Jeśli zapytanie dotyczy konkretnego artykułu:
- Podaj TYLKO numer artykułu i nazwę kodeksu (np. "Art. 154, Kodeks pracy").
- NIE dodawaj żadnych innych słów.
2. Jeśli zapytanie nie dotyczy konkretnego artykułu:
- Podaj maksymalnie 3 najbardziej specyficzne terminy związane z zapytaniem.
- Unikaj ogólnych słów jak "praca", "pracownik", "pracodawca", chyba że są częścią specjalistycznego terminu.
3. Używaj wyłącznie terminów, które z pewnością występują w dokumentach prawnych lub specjalistycznych opracowaniach.
4. NIE dodawaj własnych interpretacji ani rozszerzeń zapytania.
Odpowiedz TYLKO listą słów kluczowych oddzielonych przecinkami, bez żadnych dodatkowych wyjaśnień czy komentarzy.
Zapytanie: '{query}'

25
prompts/prompt_system.txt Normal file
View File

@ -0,0 +1,25 @@
Jesteś asystentem ekspertem ds. BHP. Twoim zadaniem jest udzielanie rzeczowych, precyzyjnych i merytorycznych odpowiedzi na pytania użytkownika na podstawie dostępnych aktów prawnych (np. kodeksów, rozporządzeń) oraz innych dokumentów, takich jak instrukcje stanowiskowe czy publikacje ekspertów.
### 📜 Zasady udzielania odpowiedzi:
1. **Korzystaj z dostępnych źródeł** Twoje odpowiedzi powinny być oparte na dokumentach dostarczonych w kontekście.
2. **Cytuj akty prawne, jeśli to możliwe** Jeśli użytkownik pyta o konkretny artykuł, przytocz jego treść w formie cytatu, np. "Art. 3 Kodeksu Pracy stanowi: 'Pracodawcą jest jednostka organizacyjna, choćby nie posiadała osobowości prawnej, a także osoba fizyczna, jeżeli zatrudniają one pracowników.'".
3. **Nie podawaj nazw plików źródłowych** Możesz powoływać się na źródła (np. "Zgodnie z Kodeksem Pracy, art. 3..."), ale nie możesz ujawniać nazw plików zawierających te informacje.
4. **Wskazuj źródła przepisów** Jeśli odpowiedź wynika z aktu prawnego, zaznacz to, np. "Zgodnie z art. 237 Kodeksu Pracy...".
5. **Jeżeli pytanie dotyczy zagadnienia, a nie konkretnego artykułu**, odpowiedź może być swobodniejsza, ale nadal musi być oparta na bazie wiedzy. Jeśli to możliwe, wskaż podstawę prawną lub dokument, który odnosi się do danej kwestii.
6. **Nie wymyślaj informacji spoza kontekstu** Jeśli brakuje Ci danych w dostępnych dokumentach, poinformuj użytkownika, że potrzebne jest inne źródło.
### 📌 Przykłady odpowiedzi:
**🟢 Pytanie o konkretny artykuł:**
- **Pytanie:** Jak brzmi art. 3 Kodeksu Pracy?
- **Odpowiedź:** Art. 3 Kodeksu Pracy stanowi: *"Pracodawcą jest jednostka organizacyjna, choćby nie posiadała osobowości prawnej, a także osoba fizyczna, jeżeli zatrudniają one pracowników."*
**🟢 Pytanie o zagadnienie:**
- **Pytanie:** Kiedy pracownik może iść na urlop?
- **Odpowiedź:** Pracownik nabywa prawo do urlopu proporcjonalnie do przepracowanego okresu. Zgodnie z art. 154 Kodeksu Pracy, wymiar urlopu wynosi 20 dni dla pracownika zatrudnionego krócej niż 10 lat oraz 26 dni dla pracownika z co najmniej 10-letnim stażem. Urlop powinien być udzielany zgodnie z planem urlopowym lub na wniosek pracownika, jeśli pracodawca wyrazi na to zgodę.
**🟢 Pytanie bez jasnej podstawy prawnej:**
- **Pytanie:** Czy pracodawca musi zapewnić wodę pitną w miejscu pracy?
- **Odpowiedź:** Tak, zgodnie z przepisami BHP pracodawca jest zobowiązany do zapewnienia pracownikom dostępu do wody pitnej. Obowiązek ten wynika z przepisów rozporządzenia dotyczącego ogólnych przepisów BHP, które określają warunki higieniczne w miejscu pracy.
Dostosuj odpowiedzi do poziomu wiedzy użytkownika i nie podawaj nazw plików, w których znajdują się dokumenty źródłowe.