Victoria31 commited on
Commit
d20c2f3
·
verified ·
1 Parent(s): 232ef4b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -127
app.py CHANGED
@@ -1,150 +1,99 @@
1
  import gradio as gr
2
- import torch
3
- from transformers import AutoTokenizer, AutoModel
4
- from sklearn.neighbors import NearestNeighbors
5
- import numpy as np
6
- import re
7
  import os
 
8
  import requests
9
 
10
  # Configuration
11
- HF_MODEL = "HuggingFaceH4/zephyr-7b-beta"
 
12
  HF_API_URL = f"https://api-inference.huggingface.co/models/{HF_MODEL}"
13
- headers = {"Authorization": f"Bearer {os.getenv('HF_TOKEN', '').strip()}"}
14
- FILES = [f"Main{i}.txt" for i in range(1, 3)]
15
- CHUNK_SIZE = 500
16
- overlap = 100
17
-
18
- # New: Pure Python sentence chunking (no spaCy needed)
19
- def smart_chunk_text(text, chunk_size, overlap):
20
- sentences = re.split(r'(?<=[.!?])\s+', text.strip())
21
- chunks = []
22
- current_chunk = []
23
- total_len = 0
24
- i = 0
25
-
26
- while i < len(sentences):
27
- if total_len + len(sentences[i]) <= chunk_size:
28
- current_chunk.append(sentences[i])
29
- total_len += len(sentences[i])
30
- i += 1
31
- else:
32
- chunks.append(" ".join(current_chunk))
33
- if overlap > 0:
34
- overlap_len = 0
35
- j = len(current_chunk) - 1
36
- while j >= 0 and overlap_len < overlap:
37
- overlap_len += len(current_chunk[j])
38
- j -= 1
39
- i = max(i - (len(current_chunk) - j - 1), 0)
40
- total_len = 0
41
- current_chunk = []
42
-
43
- if current_chunk:
44
- chunks.append(" ".join(current_chunk))
45
 
46
- return chunks
47
-
48
- # Load and process text files
49
- def process_text_files(file_list, chunk_size=CHUNK_SIZE):
50
- combined_chunks = []
51
- for file in file_list:
52
- try:
53
- with open(file, encoding="utf-8") as f:
54
- content = f.read()
55
- except Exception as e:
56
- print(f"❌ Error reading {file}: {e}")
57
- continue
58
 
 
 
 
 
59
  try:
60
- plain_text = re.sub(r"\s+", " ", content).strip()
61
-
62
- if not plain_text:
63
- raise ValueError("Empty text file.")
64
-
65
- chunks = smart_chunk_text(plain_text, chunk_size, overlap)
66
- combined_chunks.extend(chunks)
67
  except Exception as e:
68
- print(f"Error processing {file}: {e}")
 
69
 
70
- return combined_chunks
 
 
 
 
71
 
72
- # Embedding + Indexing
73
- def embed_texts(text_list):
74
- if not text_list:
75
- raise ValueError("⚠️ No texts to embed.")
76
- encoded = tokenizer(text_list, padding=True, truncation=True, return_tensors="pt")
77
- with torch.no_grad():
78
- output = model(**encoded)
79
- return output.last_hidden_state.mean(dim=1).numpy()
80
 
81
- # Load and embed text
82
- chunks = process_text_files(FILES)
83
- if not chunks:
84
- raise ValueError("⚠️ No text chunks found.")
85
 
86
- tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-mpnet-base-v2")
87
- model = AutoModel.from_pretrained("sentence-transformers/all-mpnet-base-v2")
88
- chunk_embeddings = embed_texts(chunks)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
- nn_model = NearestNeighbors(n_neighbors=3, metric="cosine")
91
- nn_model.fit(chunk_embeddings)
 
92
 
93
  # Chat function
94
  def respond(message, history):
95
- try:
96
- query_embedding = embed_texts([message])
97
- distances, indices = nn_model.kneighbors(query_embedding)
98
-
99
- CONFIDENCE_THRESHOLD = 0.6
100
- if distances[0][0] > CONFIDENCE_THRESHOLD:
101
- return f"Entschuldigung. Ich kenne die Antwort auf diese Frage leider nicht. (Nächste Distanzen: {distances[0]})"
102
-
103
- relevant_chunks = [chunks[i] for i in indices[0]]
104
- conversation = "\n".join(
105
- [f"User: {m['content']}" if m["role"] == "user" else f"AI: {m['content']}" for m in history[-5:]]
106
- )
107
- context = "\n".join(relevant_chunks)
108
-
109
- prompt = f"""
110
- ### SYSTEM
111
- Du bist ein KI-gestützter Finanzexperte. Du beantwortest Fragen **ausschließlich im Kontext der Vorlesung "Finanzmärkte"** an der Universität Duisburg-Essen. Deine Antworten sind **klar, faktenbasiert und verständlich formuliert.**
112
- Beachte folgende Regeln:
113
- 1. Nutze primär die bereitgestellten Vorlesungsausschnitte („lecture_slides“) als Informationsquelle.
114
- 2. Falls eine Antwort **nicht** durch die Vorlesungsinhalte gedeckt ist, kannst du sie ergänzen – aber nur, wenn du **absolut sicher** bist. Keine Halluzinationen!
115
- 3. Wenn du dir nicht sicher bist, antworte höflich:
116
- _"Entschuldigung. Ich kenne die Antwort auf diese Frage leider nicht."_
117
- 4. Wenn eine Formel relevant ist, **zeige die genaue Formel**, und erkläre diese in **einfachen Worten.**
118
- 5. Vermeide vage Aussagen. Nenne lieber keine Antwort als eine unsichere.
119
- ---
120
- ### VORLESUNGSAUSSCHNITTE
121
- {context}
122
- ---
123
- ### GESPRÄCHSVERLAUF
124
- {conversation}
125
- ---
126
- ### NUTZER
127
- {message}
128
- ---
129
- ### ASSISTENT
130
- """
131
-
132
- payload = {
133
- "inputs": prompt,
134
- "parameters": {"max_new_tokens": 400, "temperature": 0.3},
135
- }
136
 
 
137
  response = requests.post(HF_API_URL, headers=headers, json=payload, timeout=30)
138
  response.raise_for_status()
139
  output = response.json()
140
- reply = output[0]["generated_text"].strip()
141
- reply = reply.split("--- ASSISTENT")[-1].strip()
142
-
143
  except Exception as e:
144
- print("API Error:", e)
145
- reply = "Ein Fehler ist aufgetreten. Bitte versuche es später erneut."
146
-
147
- return reply
148
-
149
- # Launch the Gradio UI
150
- gr.ChatInterface(respond, title="Finanzmärkte RAG Chatbot", chatbot=gr.Chatbot(type="messages")).launch()
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
 
 
 
 
 
2
  import os
3
+ import re
4
  import requests
5
 
6
  # Configuration
7
+ HF_TOKEN = os.getenv("HF_TOKEN", "").strip() # Make sure your token is set in the Space secrets
8
+ HF_MODEL = "HuggingFaceH4/zephyr-7b-beta" # Example model; change if you use another
9
  HF_API_URL = f"https://api-inference.huggingface.co/models/{HF_MODEL}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # Load knowledge base from .txt files
14
+ def load_text_files(file_list):
15
+ knowledge = ""
16
+ for file_name in file_list:
17
  try:
18
+ with open(file_name, "r", encoding="utf-8") as f:
19
+ text = f.read()
20
+ knowledge += "\n" + text
 
 
 
 
21
  except Exception as e:
22
+ print(f"Error reading {file_name}: {e}")
23
+ return knowledge.strip()
24
 
25
+ # Simple text chunking
26
+ def chunk_text(text, max_chunk_length=500):
27
+ sentences = re.split(r'(?<=[.!?])\s+', text)
28
+ chunks = []
29
+ current_chunk = ""
30
 
31
+ for sentence in sentences:
32
+ if len(current_chunk) + len(sentence) <= max_chunk_length:
33
+ current_chunk += " " + sentence
34
+ else:
35
+ chunks.append(current_chunk.strip())
36
+ current_chunk = sentence
37
+ if current_chunk:
38
+ chunks.append(current_chunk.strip())
39
 
40
+ return chunks
 
 
 
41
 
42
+ # Load the txt files
43
+ FILES = [f"Main{i}.txt" for i in range(1, 3)] # Example: Main1.txt, Main2.txt
44
+ knowledge_base = load_text_files(FILES)
45
+ chunks = chunk_text(knowledge_base)
46
+
47
+ # Helper: Build prompt with context
48
+ def build_prompt(user_message):
49
+ context = "\n".join(chunks[:10]) # Take first 10 chunks as context for simplicity
50
+ prompt = f""" You are an AI-supported financial expert. You answer questions **exclusively in the context of the "Financial Markets" lecture** at the University of Duisburg-Essen. Your answers are **clear, fact-based, and clearly formulated.**
51
+ Observe the following rules:
52
+ 1. Use the provided lecture excerpts ("lecture_slides") primarily as a source of information.
53
+ 2. If an answer is **not** covered by the lecture content, you can add to it – but only if you are **absolutely certain**. No hallucinations!
54
+ 3. If you are unsure, answer politely:
55
+ _"Sorry. Unfortunately, I don't know the answer to this question."_
56
+ 4. If a formula is relevant, **show the exact formula** and explain it in **simple terms.**
57
+ 5. Avoid vague statements. It's better not to give an answer at all than to give an uncertain one.
58
+ 6. Only answer in german!
59
+
60
+ Knowledge Base:
61
+ {context}
62
 
63
+ User Question: {user_message}
64
+ Answer:"""
65
+ return prompt
66
 
67
  # Chat function
68
  def respond(message, history):
69
+ prompt = build_prompt(message)
70
+
71
+ payload = {
72
+ "inputs": prompt,
73
+ "parameters": {"temperature": 0.3, "max_new_tokens": 300},
74
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
+ try:
77
  response = requests.post(HF_API_URL, headers=headers, json=payload, timeout=30)
78
  response.raise_for_status()
79
  output = response.json()
80
+ generated_text = output[0]["generated_text"]
81
+ # Remove the prompt part from the response if necessary
82
+ answer = generated_text.split("Answer:")[-1].strip()
83
  except Exception as e:
84
+ print("API Error:", e)
85
+ answer = " Error contacting the model. Please try again later."
86
+
87
+ history.append((message, answer))
88
+ return history
89
+
90
+ # Create Gradio Interface
91
+ chatbot = gr.Chatbot()
92
+ demo = gr.ChatInterface(
93
+ fn=respond,
94
+ chatbot=chatbot,
95
+ title="📚 Text Knowledge Chatbot",
96
+ description="Ask questions based on the given text files.",
97
+ )
98
+
99
+ demo.launch()