Victoria31 commited on
Commit
6cedf11
Β·
verified Β·
1 Parent(s): 670ab1d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +152 -0
app.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # --- IMPORTS ---
2
+ import gradio as gr
3
+ import os
4
+ import re
5
+ import requests
6
+ import numpy as np
7
+ import torch
8
+ from sklearn.neighbors import NearestNeighbors
9
+ from sentence_transformers import SentenceTransformer
10
+ from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
11
+
12
+ # --- CONFIGURATION ---
13
+ HF_TOKEN = os.getenv("HF_TOKEN", "").strip()
14
+ HF_MODEL = "HuggingFaceH4/zephyr-7b-beta" # Change if you want
15
+ HF_API_URL = f"https://api-inference.huggingface.co/models/{HF_MODEL}"
16
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
17
+
18
+
19
+
20
+ FILES = ["main1.txt", "main2.txt", "main3.txt", "main4.txt", "main5.txt", "main6.txt"] # Your text files
21
+ EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2" # Light and fast
22
+
23
+ EMBEDDING_CACHE_FILE = "embeddings.npy"
24
+ CHUNKS_CACHE_FILE = "chunks.npy"
25
+
26
+ # --- FUNCTIONS ---
27
+
28
+ def load_text_files(file_list):
29
+ knowledge = ""
30
+ for file_name in file_list:
31
+ try:
32
+ with open(file_name, "r", encoding="utf-8") as f:
33
+ knowledge += "\n" + f.read()
34
+ except Exception as e:
35
+ print(f"Error reading {file_name}: {e}")
36
+ return knowledge.strip()
37
+
38
+ def chunk_text(text, max_chunk_length=500):
39
+ sentences = re.split(r'(?<=[.!?])\s+', text)
40
+ chunks = []
41
+ current_chunk = ""
42
+ for sentence in sentences:
43
+ if len(current_chunk) + len(sentence) <= max_chunk_length:
44
+ current_chunk += " " + sentence
45
+ else:
46
+ chunks.append(current_chunk.strip())
47
+ current_chunk = sentence
48
+ if current_chunk:
49
+ chunks.append(current_chunk.strip())
50
+ return chunks
51
+
52
+ def embed_texts(texts):
53
+ return model.encode(texts, convert_to_numpy=True, normalize_embeddings=True)
54
+
55
+
56
+ def save_cache(embeddings, chunks):
57
+ np.save(EMBEDDING_CACHE_FILE, embeddings)
58
+ np.save(CHUNKS_CACHE_FILE, np.array(chunks))
59
+
60
+ def load_cache():
61
+ if os.path.exists(EMBEDDING_CACHE_FILE) and os.path.exists(CHUNKS_CACHE_FILE):
62
+ embeddings = np.load(EMBEDDING_CACHE_FILE, allow_pickle=True)
63
+ chunks = np.load(CHUNKS_CACHE_FILE, allow_pickle=True).tolist()
64
+ print("βœ… Loaded cached embeddings and chunks.")
65
+ return embeddings, chunks
66
+ return None, None
67
+
68
+ def retrieve_chunks(query, top_k=5):
69
+ query_embedding = embed_texts([query])
70
+ distances, indices = nn_model.kneighbors(query_embedding, n_neighbors=top_k)
71
+ retrieved = [chunks[i] for i in indices[0]]
72
+ return retrieved
73
+
74
+ def build_prompt(question):
75
+ relevant_chunks = retrieve_chunks(question)
76
+ context = "\n".join(relevant_chunks)
77
+ system_instruction = """ 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.**
78
+ Observe the following rules:
79
+ 1. Use the provided lecture excerpts ("lecture_slides") primarily as a source of information.
80
+ 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!
81
+ 3. If you are unsure, answer politely:
82
+ _"Sorry. Unfortunately, I don't know the answer to this question."_
83
+ 4. If a formula is relevant, **show the exact formula** and explain it in **simple terms.**
84
+ 5. Avoid vague statements. It's better not to give an answer at all than to give an uncertain one.
85
+ 6. Only answer in german! """
86
+
87
+ prompt = f"""{system_instruction}
88
+ Knowledge Base:
89
+ {context}
90
+ User Question: {question}
91
+ Answer:"""
92
+ return prompt
93
+
94
+
95
+ def respond(message, history):
96
+ try:
97
+ prompt = build_prompt(message)
98
+
99
+ payload = {
100
+ "inputs": prompt,
101
+ "parameters": {"temperature": 0.2, "max_new_tokens": 400},
102
+ }
103
+
104
+ response = requests.post(HF_API_URL, headers=headers, json=payload, timeout=30)
105
+ response.raise_for_status()
106
+ output = response.json()
107
+ generated_text = output[0]["generated_text"]
108
+ match = re.search(r"Answer:(.*)", generated_text, re.DOTALL)
109
+ answer = generated_text[len(prompt):].strip()
110
+
111
+
112
+
113
+ except Exception as e:
114
+ print("API Error:", e)
115
+ answer = "❌ Error contacting the model. Please try again later."
116
+
117
+ if history is None:
118
+ history = []
119
+
120
+ history.append({"role": "assistant", "content": answer})
121
+ return answer
122
+
123
+ # --- INIT SECTION ---
124
+
125
+ # Load tokenizer and model for embeddings
126
+ model = SentenceTransformer(EMBEDDING_MODEL)
127
+
128
+ # Try to load cached embeddings and chunks
129
+ chunk_embeddings, chunks = load_cache()
130
+
131
+ if chunk_embeddings is None or chunks is None:
132
+ print("πŸ”„ No cache found. Processing...")
133
+ knowledge_base = load_text_files(FILES)
134
+ chunks = chunk_text(knowledge_base)
135
+ chunk_embeddings = embed_texts(chunks)
136
+ save_cache(chunk_embeddings, chunks)
137
+ print("βœ… Embeddings and chunks cached.")
138
+
139
+ # Build the search model
140
+ nn_model = NearestNeighbors(metric="cosine")
141
+ nn_model.fit(chunk_embeddings)
142
+
143
+ # --- GRADIO INTERFACE ---
144
+
145
+ demo = gr.ChatInterface(
146
+ fn=respond,
147
+ title="πŸ“š Text Knowledge RAG Chatbot",
148
+ description="Ask questions based on the provided text files.",
149
+ chatbot=gr.Chatbot(type="messages"),
150
+ )
151
+
152
+ demo.launch()