RedJul2110 commited on
Commit
2b756ba
·
verified ·
1 Parent(s): 49f91a2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -48
app.py CHANGED
@@ -40,12 +40,12 @@ WISSEN_FILE = os.path.join(DATA_DIR, "wissen.json")
40
  CHAT_FILE = os.path.join(DATA_DIR, "chat_history.json")
41
  LOG_FILE = os.path.join(DATA_DIR, "ai_log.txt")
42
 
43
- FALLBACK_NO_INFO = "Dazu habe ich nichts in meiner Datenbank."
44
 
45
  USE_QWEN_POLISH = True
46
 
47
  DB_DIRECT_MATCH_THRESHOLD = 0.88
48
- DB_FACT_MATCH_THRESHOLD = 0.58
49
 
50
  # =========================================================
51
  # GLOBALE VARIABLEN
@@ -194,6 +194,16 @@ def looks_like_factual_question(text):
194
  "welche", "welcher", "welches", "nenn", "nenne", "erklaer", "erklär"
195
  ))
196
 
 
 
 
 
 
 
 
 
 
 
197
  # =========================================================
198
  # KNOWLEDGE / DATENBANK
199
  # =========================================================
@@ -593,8 +603,8 @@ def save_link_as_knowledge(url, thema="", kategorie="web"):
593
  log_error("extract_webpage_text", e)
594
  return False, f"❌ Link konnte nicht gelesen werden: {e}"
595
 
596
- if not raw_text:
597
- return False, "❌ Auf der Seite konnte kein Text gefunden werden."
598
 
599
  summary = summarize_web_text(title, raw_text)
600
  if not summary or len(summary.strip()) < 30:
@@ -669,7 +679,7 @@ def init_model_if_needed():
669
  dtype = torch.float16 if device.type == "cuda" else torch.float32
670
  model = AutoModelForCausalLM.from_pretrained(
671
  MODEL_NAME,
672
- dtype=dtype,
673
  low_cpu_mem_usage=True
674
  )
675
  model.to(device)
@@ -755,20 +765,20 @@ def compose_draft_from_facts(facts):
755
  if not facts:
756
  return ""
757
 
758
- answers = []
759
- for item in facts:
760
- ans = item.get("antwort", "").strip()
761
- if ans and ans not in answers:
762
- answers.append(ans)
 
 
 
763
 
764
- if not answers:
765
  return ""
766
 
767
- random.shuffle(answers)
768
- take = min(len(answers), random.randint(1, 3))
769
- if take == 1:
770
- return answers[0]
771
- return " ".join(answers[:take])
772
 
773
  def polish_with_model(user_message, draft, facts, history_context=""):
774
  if not USE_QWEN_POLISH:
@@ -781,18 +791,20 @@ def polish_with_model(user_message, draft, facts, history_context=""):
781
  for idx, item in enumerate(facts, 1):
782
  fact_lines.append(
783
  f"{idx}. Thema: {item.get('frage', '')}\n"
784
- f" Text: {item.get('antwort', '')}"
785
  )
786
- fact_block = "\n".join(fact_lines)
787
 
788
  messages = [
789
  {
790
  "role": "system",
791
  "content": (
792
- "Du bist nur ein Grammatik-, Formulierungs- und Antwortassistent. "
793
- "Du darfst die gespeicherten Fakten als Grundlage nehmen und sie natürlich umformulieren. "
794
- "Wenn es passt, darfst du auch passende allgemeine Informationen ergänzen, "
795
- "aber du darfst keine gegenteiligen oder erfundenen Fakten einbauen."
 
 
796
  )
797
  },
798
  {
@@ -800,17 +812,23 @@ def polish_with_model(user_message, draft, facts, history_context=""):
800
  "content": (
801
  f"Frage: {user_message}\n\n"
802
  f"Kontext: {history_context}\n\n"
803
- f"Gespeicherte Fakten:\n{fact_block}\n\n"
804
- f"Rohentwurf:\n{draft}\n\n"
805
- "Aufgabe: Formuliere den Rohentwurf natürlich, kurz und fehlerfrei auf Deutsch um. "
806
- "Die Antwort soll zur Nutzerfrage passen und nicht immer gleich klingen. "
807
- "Füge nur passende zusätzliche Hinweise hinzu."
 
 
 
 
 
 
808
  )
809
  }
810
  ]
811
 
812
  try:
813
- out = model_generate(messages, max_new_tokens=150, temperature=0.6, do_sample=True)
814
  if not out:
815
  return draft
816
  return out.strip()
@@ -842,7 +860,7 @@ def general_chat_reply(user_message, history_context=""):
842
  ]
843
 
844
  try:
845
- out = model_generate(messages, max_new_tokens=140, temperature=0.75, do_sample=True)
846
  out = (out or "").strip()
847
  return out if out else "Dazu habe ich gerade keine sichere Antwort."
848
  except Exception as e:
@@ -852,27 +870,16 @@ def general_chat_reply(user_message, history_context=""):
852
  def generate_reply(user_message, history_context=""):
853
  query = f"{user_message} {history_context}".strip()
854
 
855
- exact = exact_db_answer(user_message)
856
- if exact:
857
- facts = find_relevant_facts(query, max_items=6)
858
- reply = polish_with_model(user_message, exact, facts, history_context)
859
- return reply if reply else exact
860
-
861
- fuzzy_direct = best_db_answer(user_message, threshold=DB_DIRECT_MATCH_THRESHOLD)
862
- if fuzzy_direct:
863
- facts = find_relevant_facts(query, max_items=6)
864
- reply = polish_with_model(user_message, fuzzy_direct, facts, history_context)
865
- return reply if reply else fuzzy_direct
866
-
867
  facts = find_relevant_facts(query, max_items=6)
868
- if facts:
869
- draft = compose_draft_from_facts(facts)
870
- if not draft:
871
- return general_chat_reply(user_message, history_context)
872
 
873
- reply = polish_with_model(user_message, draft, facts, history_context)
874
- return reply if reply else draft
 
 
 
 
875
 
 
876
  return general_chat_reply(user_message, history_context)
877
 
878
  # =========================================================
@@ -1020,7 +1027,7 @@ def erzeuge_gradio_app():
1020
  )
1021
 
1022
  gr.Markdown("# 🤖 Privates KI Kontrollzentrum")
1023
- gr.Markdown("Die KI nutzt zuerst die Datenbank. Qwen darf auch ohne Datenbank antworten.")
1024
 
1025
  with gr.Tab("📊 Status"):
1026
  status_text = gr.Textbox(label="Systembericht", lines=16, interactive=False)
 
40
  CHAT_FILE = os.path.join(DATA_DIR, "chat_history.json")
41
  LOG_FILE = os.path.join(DATA_DIR, "ai_log.txt")
42
 
43
+ FALLBACK_NO_INFO = "Dazu habe ich gerade keine sichere Antwort."
44
 
45
  USE_QWEN_POLISH = True
46
 
47
  DB_DIRECT_MATCH_THRESHOLD = 0.88
48
+ DB_FACT_MATCH_THRESHOLD = 0.62
49
 
50
  # =========================================================
51
  # GLOBALE VARIABLEN
 
194
  "welche", "welcher", "welches", "nenn", "nenne", "erklaer", "erklär"
195
  ))
196
 
197
+ def compress_text(text, max_chars=220):
198
+ text = (text or "").strip()
199
+ if not text:
200
+ return ""
201
+ text = re.sub(r"\s+", " ", text)
202
+ if len(text) <= max_chars:
203
+ return text
204
+ cut = text[:max_chars].rsplit(" ", 1)[0].strip()
205
+ return cut + "..."
206
+
207
  # =========================================================
208
  # KNOWLEDGE / DATENBANK
209
  # =========================================================
 
603
  log_error("extract_webpage_text", e)
604
  return False, f"❌ Link konnte nicht gelesen werden: {e}"
605
 
606
+ if not raw_text or len(raw_text) < 50:
607
+ return False, "❌ Auf der Seite konnte kein ausreichender Text gefunden werden."
608
 
609
  summary = summarize_web_text(title, raw_text)
610
  if not summary or len(summary.strip()) < 30:
 
679
  dtype = torch.float16 if device.type == "cuda" else torch.float32
680
  model = AutoModelForCausalLM.from_pretrained(
681
  MODEL_NAME,
682
+ torch_dtype=dtype,
683
  low_cpu_mem_usage=True
684
  )
685
  model.to(device)
 
765
  if not facts:
766
  return ""
767
 
768
+ pieces = []
769
+ for item in facts[:4]:
770
+ topic = (item.get("frage", "") or "").strip()
771
+ ans = compress_text(item.get("antwort", ""), 220)
772
+ if topic and ans:
773
+ pieces.append(f"{topic}: {ans}")
774
+ elif ans:
775
+ pieces.append(ans)
776
 
777
+ if not pieces:
778
  return ""
779
 
780
+ random.shuffle(pieces)
781
+ return "\n".join(pieces)
 
 
 
782
 
783
  def polish_with_model(user_message, draft, facts, history_context=""):
784
  if not USE_QWEN_POLISH:
 
791
  for idx, item in enumerate(facts, 1):
792
  fact_lines.append(
793
  f"{idx}. Thema: {item.get('frage', '')}\n"
794
+ f" Zusatzwissen: {compress_text(item.get('antwort', ''), 260)}"
795
  )
796
+ fact_block = "\n".join(fact_lines) if fact_lines else "Keine zusätzlichen Fakten."
797
 
798
  messages = [
799
  {
800
  "role": "system",
801
  "content": (
802
+ "Du bist ein intelligenter KI-Assistent. "
803
+ "Beantworte die Frage hauptsächlich mit deinem eigenen Wissen. "
804
+ "Nutze die gespeicherten Fakten nur als zusätzliche Information, wenn sie passen. "
805
+ "Baue diese sinnvoll in deine Antwort ein, aber kopiere sie nicht. "
806
+ "Schreibe alles in eigenen Worten. "
807
+ "Die Antwort muss direkt zur Frage passen, natürlich klingen und hilfreich sein."
808
  )
809
  },
810
  {
 
812
  "content": (
813
  f"Frage: {user_message}\n\n"
814
  f"Kontext: {history_context}\n\n"
815
+ f"Zusätzliche Fakten (optional):\n{fact_block}\n\n"
816
+ f"Notizen / Ausgangspunkt:\n{draft if draft else 'Keine festen Vorgaben. Antworte frei, aber passend zur Frage.'}\n\n"
817
+ "Aufgabe:\n"
818
+ "- Beantworte die Frage vollständig\n"
819
+ "- Nutze dein eigenes Wissen als Hauptquelle\n"
820
+ "- Nutze die Fakten nur, wenn sie wirklich passen\n"
821
+ "- Ergänze Informationen sinnvoll\n"
822
+ "- Schreibe alles neu und verständlich\n"
823
+ "- Kein Copy-Paste\n"
824
+ "- Keine irrelevanten Infos\n"
825
+ "- Keine Rohdaten, sondern eine natürliche Antwort"
826
  )
827
  }
828
  ]
829
 
830
  try:
831
+ out = model_generate(messages, max_new_tokens=160, temperature=0.65, do_sample=True)
832
  if not out:
833
  return draft
834
  return out.strip()
 
860
  ]
861
 
862
  try:
863
+ out = model_generate(messages, max_new_tokens=140, temperature=0.78, do_sample=True)
864
  out = (out or "").strip()
865
  return out if out else "Dazu habe ich gerade keine sichere Antwort."
866
  except Exception as e:
 
870
  def generate_reply(user_message, history_context=""):
871
  query = f"{user_message} {history_context}".strip()
872
 
 
 
 
 
 
 
 
 
 
 
 
 
873
  facts = find_relevant_facts(query, max_items=6)
 
 
 
 
874
 
875
+ # Qwen bleibt Hauptdenker; DB ist nur Zusatzwissen.
876
+ draft = compose_draft_from_facts(facts)
877
+
878
+ reply = polish_with_model(user_message, draft, facts, history_context)
879
+ if reply:
880
+ return reply
881
 
882
+ # Wenn Modell nicht verfügbar oder leer antwortet, trotzdem nicht stumpf DB ausgeben
883
  return general_chat_reply(user_message, history_context)
884
 
885
  # =========================================================
 
1027
  )
1028
 
1029
  gr.Markdown("# 🤖 Privates KI Kontrollzentrum")
1030
+ gr.Markdown("Die KI nutzt zuerst die Datenbank. Qwen bleibt der Hauptdenker und ergänzt Fakten passend.")
1031
 
1032
  with gr.Tab("📊 Status"):
1033
  status_text = gr.Textbox(label="Systembericht", lines=16, interactive=False)