code ready to deploy + prompty
This commit is contained in:
parent
ad08ce74ce
commit
3dbba3f2d6
|
|
@ -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 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}'
|
|
||||||
"""
|
|
||||||
|
|
||||||
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")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Na podstawie powyższych informacji odpowiedz na pytanie: {query}.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Oto fragmenty aktów prawnych i dokumentów powiązanych z pytaniem użytkownika: \n\n
|
||||||
|
|
@ -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}'
|
||||||
|
|
@ -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.
|
||||||
Loading…
Reference in New Issue