lukedaca commited on
Commit
5efb96d
·
verified ·
1 Parent(s): 684c835

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -48
app.py CHANGED
@@ -1,14 +1,12 @@
 
 
1
  import streamlit as st
2
  from huggingface_hub import hf_hub_download
3
 
4
  from llama_index.core import VectorStoreIndex, Settings
5
  from llama_index.core.memory import ChatMemoryBuffer
6
  from llama_index.llms.llama_cpp import LlamaCPP
7
-
8
- # Správný import pro web reader
9
  from llama_index.readers.web import SimpleWebPageReader
10
-
11
- # Lehký embedding bez torch/cuda
12
  from llama_index.embeddings.fastembed import FastEmbedEmbedding
13
 
14
 
@@ -16,7 +14,7 @@ from llama_index.embeddings.fastembed import FastEmbedEmbedding
16
  SYSTEM_PROMPT = """
17
  Jsi inteligentní český asistent, který pomáhá uživatelům hledat informace na zadaném webu.
18
  Tvé jméno je AI Rádce.
19
- Pokud se tě uživatel zeptá 'Co umíš?' nebo 'Kdo jsi?', odpověz:
20
  'Jsem AI Rádce. Umím prohledat obsah této webové stránky, najít v ní konkrétní informace a odpovědět na vaše otázky. Učím se z kontextu naší konverzace.'
21
  Pravidla pro tebe:
22
  1. Odpovídej vždy česky.
@@ -25,97 +23,137 @@ Pravidla pro tebe:
25
  4. Pamatuj si, co uživatel říkal v předchozích větách této konverzace.
26
  """.strip()
27
 
28
-
29
  st.set_page_config(page_title="AI Rádce s pamětí", layout="centered")
30
  st.title("🧠 Chytrý Chatbot (s pamětí)")
31
 
32
- # URL zdroje (můžete změnit)
33
- URLS = ["https://cs.wikipedia.org/wiki/Umělá_inteligence"]
34
 
35
- # HF repo s GGUF modelem
36
  MODEL_REPO = "QuantFactory/Meta-Llama-3-8B-Instruct-GGUF"
37
  MODEL_FILE = "Meta-Llama-3-8B-Instruct.Q4_K_M.gguf"
38
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  @st.cache_resource
41
- def load_index_and_llm(urls_tuple: tuple[str, ...]) -> VectorStoreIndex:
42
- """Načte model + vytvoří index. Cache je sdílená, ale BEZ paměti chatu."""
43
- # 1) stáhnout GGUF do HF cache (rychlé při opakovaném buildu)
 
 
 
44
  model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
45
 
46
- # 2) LLM (llama.cpp)
47
  llm = LlamaCPP(
48
  model_path=model_path,
49
  temperature=0.1,
50
- max_new_tokens=512,
51
- context_window=4096,
52
- verbose=True,
 
 
53
  )
54
 
55
- # 3) Nastavení pro LlamaIndex
56
  Settings.llm = llm
57
-
58
- # FastEmbed = bez torch/cuda (důležité pro HF build)
59
  Settings.embed_model = FastEmbedEmbedding(model_name="BAAI/bge-small-en-v1.5")
60
 
61
- # 4) Načtení dokumentů z webu + index
62
- documents = SimpleWebPageReader(html_to_text=True).load_data(list(urls_tuple))
63
- index = VectorStoreIndex.from_documents(documents)
64
-
65
  return index
66
 
67
 
68
- def get_chat_engine() -> object:
69
- """Vytvoří ChatEngine s pamětí per session (paměť se necache-uje globálně)."""
70
- index = load_index_and_llm(tuple(URLS))
71
-
72
- # Paměť pro konkrétní session (nedáváme do cache_resource!)
73
- memory = ChatMemoryBuffer.from_defaults(token_limit=3000)
74
 
75
  return index.as_chat_engine(
76
  chat_mode="context",
77
  memory=memory,
78
  system_prompt=SYSTEM_PROMPT,
79
- verbose=True,
80
  )
81
 
82
 
83
- # Inicializace chat enginu do session_state
84
  if "chat_engine" not in st.session_state:
85
- with st.spinner("Startuji mozek bota... (čekejte prosím)"):
86
  try:
87
- st.session_state.chat_engine = get_chat_engine()
88
  except Exception as e:
89
  st.error(f"Chyba při inicializaci: {e}")
90
  st.stop()
91
 
92
- # Historie zpráv v UI
93
  if "messages" not in st.session_state:
94
  st.session_state.messages = []
95
 
96
- # Render historie
97
- for message in st.session_state.messages:
98
- with st.chat_message(message["role"]):
99
- st.markdown(message["content"])
100
 
101
- # Chat input
102
- if prompt := st.chat_input("Zeptej se (např: Co umíš?)..."):
103
- # uložit user msg
 
 
104
  st.session_state.messages.append({"role": "user", "content": prompt})
105
  with st.chat_message("user"):
106
  st.markdown(prompt)
107
 
108
- # odpověď asistenta
109
  with st.chat_message("assistant"):
 
 
 
 
110
  with st.spinner("Přemýšlím..."):
111
  try:
112
- resp = st.session_state.chat_engine.chat(prompt)
113
 
114
- # resp může být objekt; bezpečně vytáhneme text
115
- answer = getattr(resp, "response", None) or str(resp)
116
- st.markdown(answer)
 
 
 
 
 
 
117
 
118
- st.session_state.messages.append({"role": "assistant", "content": answer})
119
  except Exception as e:
120
- st.error(f"Chyba při generování odpovědi: {e}")
 
 
 
 
 
 
 
121
 
 
1
+ import os
2
+ import time
3
  import streamlit as st
4
  from huggingface_hub import hf_hub_download
5
 
6
  from llama_index.core import VectorStoreIndex, Settings
7
  from llama_index.core.memory import ChatMemoryBuffer
8
  from llama_index.llms.llama_cpp import LlamaCPP
 
 
9
  from llama_index.readers.web import SimpleWebPageReader
 
 
10
  from llama_index.embeddings.fastembed import FastEmbedEmbedding
11
 
12
 
 
14
  SYSTEM_PROMPT = """
15
  Jsi inteligentní český asistent, který pomáhá uživatelům hledat informace na zadaném webu.
16
  Tvé jméno je AI Rádce.
17
+ Pokud se tě uživatel zeptá 'Co umíš?' nebo 'Kdo jsi?', odpověz:
18
  'Jsem AI Rádce. Umím prohledat obsah této webové stránky, najít v ní konkrétní informace a odpovědět na vaše otázky. Učím se z kontextu naší konverzace.'
19
  Pravidla pro tebe:
20
  1. Odpovídej vždy česky.
 
23
  4. Pamatuj si, co uživatel říkal v předchozích větách této konverzace.
24
  """.strip()
25
 
 
26
  st.set_page_config(page_title="AI Rádce s pamětí", layout="centered")
27
  st.title("🧠 Chytrý Chatbot (s pamětí)")
28
 
29
+ # --- NASTAVENÍ ZDROJE DAT ---
30
+ DEFAULT_URLS = ["https://cs.wikipedia.org/wiki/Umělá_inteligence"]
31
 
32
+ # --- NASTAVENÍ MODELU (GGUF) ---
33
  MODEL_REPO = "QuantFactory/Meta-Llama-3-8B-Instruct-GGUF"
34
  MODEL_FILE = "Meta-Llama-3-8B-Instruct.Q4_K_M.gguf"
35
 
36
 
37
+ # Sidebar: konfigurace
38
+ with st.sidebar:
39
+ st.header("Nastavení")
40
+ urls_text = st.text_area(
41
+ "URL zdroje (1 URL na řádek)",
42
+ value="\n".join(DEFAULT_URLS),
43
+ height=110,
44
+ )
45
+ urls = [u.strip() for u in urls_text.splitlines() if u.strip()]
46
+
47
+ max_new_tokens = st.slider("Max nových tokenů (rychlost)", 32, 256, 128, 16)
48
+ context_window = st.select_slider("Context window", options=[1024, 2048, 3072, 4096], value=2048)
49
+
50
+ # Výkon: HF CPU typicky 2–4 jádra; víc často nepomůže
51
+ cpu_cnt = os.cpu_count() or 2
52
+ n_threads = st.slider("Počet vláken (threads)", 1, min(8, cpu_cnt), min(4, cpu_cnt), 1)
53
+ n_batch = st.select_slider("Batch", options=[64, 128, 256, 512], value=256)
54
+
55
+ if st.button("🧹 Resetovat konverzaci"):
56
+ st.session_state.pop("messages", None)
57
+ st.session_state.pop("chat_engine", None)
58
+ st.rerun()
59
+
60
+
61
  @st.cache_resource
62
+ def load_index_and_llm(urls_tuple: tuple[str, ...], ctx_win: int, max_tok: int, threads: int, batch: int) -> VectorStoreIndex:
63
+ """
64
+ Načte model + vytvoří index. Cache je sdílená.
65
+ Paměť chatu NEcacheujeme (bude per-session).
66
+ """
67
+ # 1) stáhnout GGUF do HF cache
68
  model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
69
 
70
+ # 2) LLM (llama.cpp) – parametry pro rychlost na CPU
71
  llm = LlamaCPP(
72
  model_path=model_path,
73
  temperature=0.1,
74
+ max_new_tokens=max_tok,
75
+ context_window=ctx_win,
76
+ n_threads=threads,
77
+ n_batch=batch,
78
+ verbose=False,
79
  )
80
 
81
+ # 3) Nastavení LlamaIndex
82
  Settings.llm = llm
 
 
83
  Settings.embed_model = FastEmbedEmbedding(model_name="BAAI/bge-small-en-v1.5")
84
 
85
+ # 4) Data z webu + index
86
+ docs = SimpleWebPageReader(html_to_text=True).load_data(list(urls_tuple))
87
+ index = VectorStoreIndex.from_documents(docs)
 
88
  return index
89
 
90
 
91
+ def make_chat_engine() -> object:
92
+ """Vytvoří chat engine s pamětí pro konkrétní session."""
93
+ index = load_index_and_llm(tuple(urls), context_window, max_new_tokens, n_threads, n_batch)
94
+ memory = ChatMemoryBuffer.from_defaults(token_limit=min(3000, context_window))
 
 
95
 
96
  return index.as_chat_engine(
97
  chat_mode="context",
98
  memory=memory,
99
  system_prompt=SYSTEM_PROMPT,
100
+ verbose=False,
101
  )
102
 
103
 
104
+ # Inicializace enginu
105
  if "chat_engine" not in st.session_state:
106
+ with st.spinner("Startuji mozek bota... (načítám model a web)"):
107
  try:
108
+ st.session_state.chat_engine = make_chat_engine()
109
  except Exception as e:
110
  st.error(f"Chyba při inicializaci: {e}")
111
  st.stop()
112
 
113
+ # Historie zpráv
114
  if "messages" not in st.session_state:
115
  st.session_state.messages = []
116
 
117
+ for msg in st.session_state.messages:
118
+ with st.chat_message(msg["role"]):
119
+ st.markdown(msg["content"])
 
120
 
121
+
122
+ # --- CHAT LOOP (se streamováním) ---
123
+ prompt = st.chat_input("Zeptej se (např: Co umíš?)...")
124
+ if prompt:
125
+ # user message
126
  st.session_state.messages.append({"role": "user", "content": prompt})
127
  with st.chat_message("user"):
128
  st.markdown(prompt)
129
 
130
+ # assistant streaming response
131
  with st.chat_message("assistant"):
132
+ placeholder = st.empty()
133
+ full = ""
134
+ started = time.time()
135
+
136
  with st.spinner("Přemýšlím..."):
137
  try:
138
+ stream = st.session_state.chat_engine.stream_chat(prompt)
139
 
140
+ # stream.response_gen generuje text po částech
141
+ for chunk in stream.response_gen:
142
+ full += chunk
143
+ placeholder.markdown(full)
144
+
145
+ # kdyby stream nevrátil nic (edge-case), aspoň něco
146
+ if not full.strip():
147
+ full = getattr(stream, "response", None) or "Omlouvám se, nedostal jsem žádná data k odpovědi."
148
+ placeholder.markdown(full)
149
 
 
150
  except Exception as e:
151
+ full = f"Chyba při generování odpovědi: {e}"
152
+ placeholder.markdown(full)
153
+
154
+ elapsed = time.time() - started
155
+ st.caption(f"Hotovo za {elapsed:.1f}s")
156
+
157
+ st.session_state.messages.append({"role": "assistant", "content": full})
158
+
159