christian commited on
Commit
402e33f
·
0 Parent(s):

Remove big files for HF

Browse files
.dockerignore ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ignore virtual environments
2
+ .venv/
3
+ venv/
4
+ ENV/
5
+ env/
6
+
7
+ # Python cache & bytecode
8
+ __pycache__/
9
+ *.pyc
10
+ *.pyo
11
+ *.pyd
12
+
13
+ # Build artifacts
14
+ *.egg-info/
15
+ dist/
16
+ build/
17
+
18
+ # Logs
19
+ *.log
20
+
21
+ # System / IDE files
22
+ .DS_Store
23
+ *.swp
24
+ *.swo
25
+ .idea/
26
+ .vscode/
27
+
28
+ # Git
29
+ .git
30
+ .gitignore
31
+
32
+ __pycache__/
33
+ *.pyc
34
+ *.pyo
35
+ *.pyd
36
+ .env
37
+ .git
38
+ # docs/
39
+ # tests/
40
+ venv_original/
.gitignore ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # # Python
2
+ # __pycache__/
3
+ # *.py[cod]
4
+ # *$py.class
5
+ # *.so
6
+ # .Python
7
+ # build/
8
+ # develop-eggs/
9
+ # dist/
10
+ # downloads/
11
+ # eggs/
12
+ # .eggs/
13
+ # lib/
14
+ # lib64/
15
+ # parts/
16
+ # sdist/
17
+ # var/
18
+ # wheels/
19
+ # *.egg-info/
20
+ # .installed.cfg
21
+ # *.egg
22
+
23
+ # # Virtual Environment
24
+ # venv/
25
+ # env/
26
+ # .venv/
27
+ # .env/
28
+ # ENV/
29
+
30
+ # # IDE
31
+ # .vscode/
32
+ # .idea/
33
+ # *.swp
34
+ # *.swo
35
+
36
+ # # OS
37
+ # .DS_Store
38
+ # Thumbs.db
39
+
40
+ # # Project specific
41
+ # chroma_db/
42
+ # vector_stores/
43
+ # docs/
44
+ # *.log
45
+
46
+ # # Sensitive files
47
+ # .env
48
+ # config.ini
49
+
50
+
51
+ # Environment variables
52
+ .env
53
+ .env.local
54
+ .env.production
55
+
56
+ # Python
57
+ __pycache__/
58
+ *.py[cod]
59
+ *$py.class
60
+ *.so
61
+ .Python
62
+ build/
63
+ develop-eggs/
64
+ dist/
65
+ downloads/
66
+ eggs/
67
+ .eggs/
68
+ lib/
69
+ lib64/
70
+ parts/
71
+ sdist/
72
+ var/
73
+ wheels/
74
+ *.egg-info/
75
+
76
+ # Virtual environments (these are outside the repo)
77
+ ../venv/
78
+ ../.venv/
79
+ ../env/
80
+ ../ENV/
81
+ venv_original/
82
+ venv/
83
+ .venv
84
+ .venv/
85
+
86
+ # Vector stores (optional - include them if you want faster deployments)
87
+ # vector_stores/
88
+
89
+ # IDE
90
+ .vscode/
91
+ .idea/
92
+ *.swp
93
+ *.swo
94
+
95
+ # OS
96
+ .DS_Store
97
+ Thumbs.db
98
+
99
+ # Logs
100
+ *.log
101
+ logs/
102
+
103
+ # Testing
104
+ .pytest_cache/
105
+ .coverage
106
+ htmlcov/
107
+
108
+ # Render
109
+ .render/
110
+
111
+
112
+ # Others
113
+ old.txt
114
+ requirements_old.txt
115
+ render.yaml
116
+
117
+ # vector stores for huggingface
118
+ # Vector stores (local cache only)
119
+ vector_stores/
120
+ chroma_db/
121
+
122
+ # Just in case
123
+ *.bin
124
+ *.pkl
Dockerfile ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.13 slim (your current version)
2
+ FROM python:3.13-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy and install dependencies
8
+ COPY requirements.txt .
9
+ RUN pip install --upgrade pip setuptools wheel \
10
+ && pip install --no-cache-dir -r requirements.txt
11
+
12
+ # Copy all source code
13
+ COPY . .
14
+
15
+ # Expose the port that HF Spaces expects
16
+ EXPOSE 7860
17
+
18
+ # Run your existing launcher
19
+ CMD ["python", "app.py"]
api/__init__.py ADDED
File without changes
api/main.py ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import Request
2
+ import requests
3
+ from dotenv import load_dotenv
4
+ from utils.vector_store import get_vector_store
5
+ from pydantic import BaseModel
6
+ from fastapi import FastAPI, HTTPException, Request
7
+ import os
8
+ import sys
9
+
10
+ from utils.helpers.chat_mapper import map_answer_to_chat_response
11
+
12
+ from fastapi.middleware.cors import CORSMiddleware
13
+
14
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
15
+
16
+ load_dotenv()
17
+
18
+ app = FastAPI()
19
+
20
+ # Adding Middleware for testing
21
+
22
+ # Get allowed origins from environment variable for flexibility
23
+ ALLOWED_ORIGINS = os.environ.get("ALLOWED_ORIGINS", "").split(
24
+ ",") if os.environ.get("ALLOWED_ORIGINS") else ["*"]
25
+
26
+ # For development/testing, you can also hardcode your Vercel domain
27
+ VERCEL_DOMAINS = [
28
+ "https://your-app-name.vercel.app", # Replace with your actual Vercel app name
29
+ # Git branch deployments
30
+ "https://mes-chatbot-project-git-simple-w-markdown-mangobutlers-projects.vercel.app/",
31
+ # Git branch
32
+ "mes-chatbot-project-73znou68u-mangobutlers-projects.vercel.app",
33
+ "http://localhost:3000", # For local frontend development
34
+ "http://localhost:5173", # For Vite dev server
35
+ "http://127.0.0.1:3000", # Alternative localhost
36
+ ]
37
+
38
+
39
+ # Combine environment origins with Vercel domains
40
+ if ALLOWED_ORIGINS == ["*"]:
41
+ # If no specific origins set, use Vercel domains + wildcard for testing
42
+ final_origins = VERCEL_DOMAINS + ["*"]
43
+ else:
44
+ final_origins = ALLOWED_ORIGINS + VERCEL_DOMAINS
45
+ # Adding the Middleware
46
+
47
+ app.add_middleware(
48
+ CORSMiddleware,
49
+ allow_origins=final_origins,
50
+ allow_credentials=True,
51
+ allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
52
+ allow_headers=["*"],
53
+ expose_headers=["*"]
54
+ )
55
+
56
+ # ---------------------------
57
+
58
+ # Vector store mapping for different domains
59
+ VECTOR_STORE_PATHS = {
60
+ "mes": "./vector_stores/mes_db",
61
+ "technical": "./vector_stores/tech_db",
62
+ "general": "./vector_stores/general_db",
63
+ "default": "./vector_stores/general_db",
64
+ }
65
+
66
+
67
+ class QueryRequest(BaseModel):
68
+ query: str
69
+
70
+
71
+ # ---------------------------
72
+ # Gemini API setup
73
+ # ---------------------------
74
+ GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
75
+ if not GEMINI_API_KEY:
76
+ raise ValueError("GEMINI_API_KEY environment variable required")
77
+
78
+ GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
79
+
80
+ # ---------------------------
81
+ # Vector store loader
82
+ # ---------------------------
83
+
84
+
85
+ def load_vector_store_by_prefix(query: str):
86
+ lower_q = query.lower().strip()
87
+ for prefix, path in VECTOR_STORE_PATHS.items():
88
+ if prefix != "default" and lower_q.startswith(f"{prefix}:"):
89
+ cleaned_query = lower_q[len(prefix) + 1:].strip()
90
+ return get_vector_store(persist_directory=path), cleaned_query, prefix
91
+ return get_vector_store(persist_directory=VECTOR_STORE_PATHS["default"]), query, "default"
92
+
93
+
94
+ def generate_answer_with_gemini(query: str, context_docs: list):
95
+ # Build context string
96
+ # knowledge_parts = []
97
+ # for i, doc in enumerate(context_docs[:3], 1):
98
+ # knowledge_parts.append(f"Data Source {i}: {doc.page_content[:300]}")
99
+ # knowledge_base = "\n\n".join(knowledge_parts)
100
+
101
+ knowledge_parts = []
102
+ for i, doc in enumerate(context_docs, 1):
103
+ knowledge_parts.append(f"Data Source {i}: {doc.page_content.strip()}")
104
+ knowledge_base = "\n\n".join(knowledge_parts)
105
+
106
+ # The updated prompt is more direct and forceful
107
+ prompt = (
108
+ "You are an expert AI assistant that uses a provided knowledge base to answer questions. "
109
+ "Your responses must always be based on this knowledge base, which is the ultimate source of truth. "
110
+ "You will only use your internal knowledge to supplement the answer, never to contradict it. "
111
+ "If and only if the knowledge base contains absolutely nothing relevant to the user's question, "
112
+ "you will respond with a polite and concise statement saying you cannot answer the question from the information you have. "
113
+ "You must never answer 'I don't know' if there is any information in the knowledge base that is even tangentially related to the question. "
114
+ "Always try your best to construct a useful answer by synthesizing the provided information. "
115
+ "Do not refer to the 'knowledge base' or 'sources' directly; instead, use phrases like 'based on the information I have'.\n\n"
116
+
117
+ f"My knowledge base:\n{knowledge_base}\n\n"
118
+ f"User's Question: {query}\n\nAnswer:"
119
+ )
120
+
121
+ # print the prompt for debugging
122
+ print("🔍 Prompt sent to Gemini API:", prompt)
123
+
124
+ try:
125
+ response = requests.post(
126
+ f"{GEMINI_API_URL}?key={GEMINI_API_KEY}",
127
+ json={
128
+ "contents": [
129
+ {
130
+ "role": "user",
131
+ "parts": [
132
+ {"text": prompt}
133
+ ]
134
+ }
135
+ ],
136
+ "generationConfig": {
137
+ "temperature": 0.7,
138
+ "maxOutputTokens": 300
139
+ }
140
+ },
141
+ timeout=300
142
+ )
143
+
144
+ if response.status_code != 200:
145
+ return f"API Error: {response.status_code} - {response.text}"
146
+
147
+ data = response.json()
148
+
149
+ # Extract answer text
150
+ return (
151
+ data.get("candidates", [{}])[0]
152
+ .get("content", {})
153
+ .get("parts", [{}])[0]
154
+ .get("text", "")
155
+ .strip()
156
+ or "I couldn't generate an answer."
157
+ )
158
+
159
+ except Exception as e:
160
+ return f"Error: {str(e)}"
161
+
162
+
163
+ # ---------------------------
164
+ # API Endpoints
165
+ # ---------------------------
166
+
167
+
168
+ @app.get("/")
169
+ def root():
170
+ return {
171
+ "status": "running",
172
+ "model": "gemini-2.0-flash",
173
+ "using_direct_api": True,
174
+ "client_ready": True
175
+ }
176
+
177
+
178
+ @app.post("/ask")
179
+ async def ask_question(request: Request):
180
+ try:
181
+ # Print raw incoming request body
182
+ raw_body = await request.body()
183
+ print("📥 Incoming POST /ask request body:")
184
+ print(raw_body.decode("utf-8"))
185
+
186
+ # Parse into your Pydantic model
187
+ parsed_request = QueryRequest.model_validate_json(raw_body)
188
+ print("✅ Parsed request object:", parsed_request)
189
+
190
+ vector_store, cleaned_query, store_key = load_vector_store_by_prefix(
191
+ parsed_request.query
192
+ )
193
+
194
+ if not vector_store:
195
+ raise HTTPException(
196
+ status_code=500, detail="Vector store not ready"
197
+ )
198
+
199
+ retriever = vector_store.as_retriever(
200
+ search_type="mmr",
201
+ search_kwargs={
202
+ "k": 6,
203
+ "fetch_k": 20,
204
+ "lambda_mult": 0.5
205
+ }
206
+ )
207
+
208
+ docs = retriever.get_relevant_documents(cleaned_query)
209
+
210
+ # Deduplicate
211
+ seen = set()
212
+ unique_docs = []
213
+ for doc in docs:
214
+ snippet = doc.page_content.strip()
215
+ if snippet not in seen:
216
+ seen.add(snippet)
217
+ unique_docs.append(doc)
218
+ docs = unique_docs[:5]
219
+
220
+ if not docs:
221
+ return {
222
+ "answer": "I couldn't find any relevant information in the knowledge base to answer your question.",
223
+ "model_used": "gemini-2.0-flash",
224
+ "vector_store_used": VECTOR_STORE_PATHS[store_key],
225
+ "sources": []
226
+ }
227
+
228
+ answer = generate_answer_with_gemini(cleaned_query, docs)
229
+
230
+ answer_obj = {
231
+ "answer": answer,
232
+ "model_used": "gemini-2.0-flash",
233
+ "vector_store_used": VECTOR_STORE_PATHS[store_key],
234
+ "sources": [
235
+ {
236
+ "content": doc.page_content[:500] + "...\n",
237
+ "metadata": doc.metadata
238
+ }
239
+ for doc in docs
240
+ ]
241
+ }
242
+ # For debugging, print the generated answer object
243
+ # print("Generated answer object:",
244
+ # map_answer_to_chat_response(answer_obj))
245
+
246
+ return map_answer_to_chat_response(answer_obj)
247
+
248
+ except Exception as e:
249
+ print(f"Error in ask_question: {e}")
250
+ raise HTTPException(status_code=500, detail=f"Error: {str(e)}")
251
+
252
+
253
+ if __name__ == "__main__":
254
+ import uvicorn
255
+ port = int(os.environ.get("PORT", 8000))
256
+ uvicorn.run(app, host="0.0.0.0", port=port)
api/main_all_models.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # from fastapi import FastAPI, Request
3
+ # from pydantic import BaseModel
4
+ # from langchain.chains import RetrievalQA
5
+ # from langchain.chat_models import ChatOpenAI
6
+ # from ..utils.vector_store import get_vector_store
7
+
8
+ # app = FastAPI()
9
+ # retriever = get_vector_store().as_retriever()
10
+ # llm = ChatOpenAI(model_name="gpt-4", temperature=0)
11
+ # qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)
12
+
13
+ # class QueryRequest(BaseModel):
14
+ # query: str
15
+
16
+ # @app.post("/ask")
17
+ # def ask_question(request: QueryRequest):
18
+ # answer = qa_chain.run(request.query)
19
+ # return { "answer": answer }
20
+
21
+ from fastapi import FastAPI, Request
22
+ from pydantic import BaseModel
23
+ from langchain.chains import RetrievalQA
24
+ from langchain.llms import HuggingFacePipeline
25
+ from langchain.llms import LlamaCpp
26
+ from langchain.llms import GPT4All
27
+ from ..utils.vector_store import get_vector_store
28
+ import torch
29
+
30
+ app = FastAPI()
31
+
32
+
33
+ class QueryRequest(BaseModel):
34
+ query: str
35
+
36
+ # Option 1: HuggingFace Transformers (Recommended for most cases)
37
+
38
+
39
+ def setup_huggingface_model():
40
+ """Setup a local HuggingFace model"""
41
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
42
+
43
+ # Use a smaller, efficient model that works well for QA
44
+ model_name = "microsoft/DialoGPT-medium" # or "google/flan-t5-base"
45
+
46
+ # For better quality but larger size:
47
+ # model_name = "microsoft/DialoGPT-large"
48
+ # model_name = "google/flan-t5-large"
49
+
50
+ tokenizer = AutoTokenizer.from_pretrained(model_name, padding_side='left')
51
+ model = AutoModelForCausalLM.from_pretrained(
52
+ model_name,
53
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
54
+ device_map="auto" if torch.cuda.is_available() else None
55
+ )
56
+
57
+ # Create pipeline
58
+ pipe = pipeline(
59
+ "text-generation",
60
+ model=model,
61
+ tokenizer=tokenizer,
62
+ max_length=512,
63
+ temperature=0.1,
64
+ do_sample=True,
65
+ device=0 if torch.cuda.is_available() else -1
66
+ )
67
+
68
+ # Wrap in LangChain
69
+ llm = HuggingFacePipeline(pipeline=pipe)
70
+ return llm
71
+
72
+ # Option 2: Ollama (Great for local deployment)
73
+
74
+
75
+ def setup_ollama_model():
76
+ """Setup Ollama model (requires Ollama to be installed)"""
77
+ from langchain.llms import Ollama
78
+
79
+ # Popular free models available through Ollama:
80
+ # - llama2:7b (good balance of quality/speed)
81
+ # - mistral:7b (excellent for instructions)
82
+ # - codellama:7b (good for technical content)
83
+ # - phi:2.7b (Microsoft, very fast)
84
+
85
+ llm = Ollama(
86
+ model="llama2:7b", # Change to your preferred model
87
+ temperature=0.1
88
+ )
89
+ return llm
90
+
91
+ # Option 3: GPT4All (Easy setup, no internet required)
92
+
93
+
94
+ def setup_gpt4all_model():
95
+ """Setup GPT4All model"""
96
+ # Download models from: https://gpt4all.io/models/models.json
97
+ # Popular options:
98
+ # - ggml-gpt4all-j-v1.3-groovy.bin
99
+ # - ggml-vicuna-7b-1.1-q4_2.bin
100
+ # - ggml-mpt-7b-instruct.bin
101
+
102
+ llm = GPT4All(
103
+ model="./models/ggml-gpt4all-j-v1.3-groovy.bin", # Path to your downloaded model
104
+ max_tokens=512,
105
+ temp=0.1
106
+ )
107
+ return llm
108
+
109
+ # Option 4: LlamaCpp (For GGML/GGUF models)
110
+
111
+
112
+ def setup_llamacpp_model():
113
+ """Setup LlamaCpp model"""
114
+ llm = LlamaCpp(
115
+ model_path="./models/llama-2-7b-chat.ggmlv3.q4_0.bin", # Path to your GGML model
116
+ temperature=0.1,
117
+ max_tokens=512,
118
+ top_p=1,
119
+ verbose=True,
120
+ n_ctx=2048, # Context window
121
+ )
122
+ return llm
123
+
124
+
125
+ # Choose your preferred setup method
126
+ try:
127
+ # Try Ollama first (if installed)
128
+ llm = setup_ollama_model()
129
+ print("Using Ollama model")
130
+ except Exception as e:
131
+ try:
132
+ # Fall back to HuggingFace
133
+ llm = setup_huggingface_model()
134
+ print("Using HuggingFace model")
135
+ except Exception as e:
136
+ print(f"Error setting up models: {e}")
137
+ # You could add more fallbacks here
138
+
139
+ # Setup retriever and QA chain
140
+ retriever = get_vector_store().as_retriever()
141
+ qa_chain = RetrievalQA.from_chain_type(
142
+ llm=llm,
143
+ retriever=retriever,
144
+ return_source_documents=True # Optional: return source chunks
145
+ )
146
+
147
+
148
+ @app.post("/ask")
149
+ def ask_question(request: QueryRequest):
150
+ try:
151
+ result = qa_chain({"query": request.query})
152
+
153
+ # If return_source_documents=True
154
+ if isinstance(result, dict) and "source_documents" in result:
155
+ return {
156
+ "answer": result["result"],
157
+ "sources": [doc.page_content[:200] + "..." for doc in result["source_documents"]]
158
+ }
159
+ else:
160
+ return {"answer": result}
161
+
162
+ except Exception as e:
163
+ return {"error": f"Failed to process query: {str(e)}"}
164
+
165
+
166
+ @app.get("/health")
167
+ def health_check():
168
+ return {"status": "healthy", "model_type": type(llm).__name__}
169
+
170
+ # Alternative endpoint for different vector stores
171
+
172
+
173
+ @app.post("/ask/{store_type}")
174
+ def ask_question_specific_store(store_type: str, request: QueryRequest):
175
+ """Ask questions to specific vector stores"""
176
+
177
+ store_paths = {
178
+ "mes": "./vector_stores/mes_db",
179
+ "general": "./vector_stores/general_db",
180
+ "tech": "./vector_stores/tech_db"
181
+ }
182
+
183
+ if store_type not in store_paths:
184
+ return {"error": f"Invalid store type. Available: {list(store_paths.keys())}"}
185
+
186
+ try:
187
+ # Get specific vector store
188
+ vector_store = get_vector_store(
189
+ persist_directory=store_paths[store_type])
190
+ specific_retriever = vector_store.as_retriever()
191
+
192
+ # Create QA chain with specific retriever
193
+ specific_qa_chain = RetrievalQA.from_chain_type(
194
+ llm=llm,
195
+ retriever=specific_retriever,
196
+ return_source_documents=True
197
+ )
198
+
199
+ result = specific_qa_chain({"query": request.query})
200
+
201
+ return {
202
+ "answer": result["result"],
203
+ "store_used": store_type,
204
+ "sources": [doc.page_content[:200] + "..." for doc in result["source_documents"]]
205
+ }
206
+
207
+ except Exception as e:
208
+ return {"error": f"Failed to process query for {store_type}: {str(e)}"}
209
+
210
+
211
+ if __name__ == "__main__":
212
+ import uvicorn
213
+ uvicorn.run(app, host="0.0.0.0", port=8000)
api/main_hface_hosted.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel
3
+ import os
4
+ import requests
5
+ from langchain.chains import RetrievalQA
6
+ from langchain.llms import HuggingFaceHub
7
+ from ..utils.vector_store import get_vector_store
8
+
9
+ app = FastAPI()
10
+
11
+
12
+ class QueryRequest(BaseModel):
13
+ query: str
14
+
15
+ # Option 1: Hugging Face Inference API (Free with rate limits)
16
+
17
+
18
+ def setup_hf_api_model():
19
+ """Uses Hugging Face's free Inference API"""
20
+ # Get free token from https://huggingface.co/settings/tokens
21
+ # Set this in your deployment
22
+ hf_token = os.getenv("HUGGINGFACE_API_TOKEN")
23
+
24
+ if not hf_token:
25
+ raise ValueError("HUGGINGFACE_API_TOKEN environment variable required")
26
+
27
+ llm = HuggingFaceHub(
28
+ repo_id="microsoft/DialoGPT-medium", # Free model
29
+ model_kwargs={
30
+ "temperature": 0.1,
31
+ "max_length": 512
32
+ },
33
+ huggingfacehub_api_token=hf_token
34
+ )
35
+ return llm
36
+
37
+ # Option 2: Cohere API (Free tier: 100 API calls/month)
38
+
39
+
40
+ def setup_cohere_model():
41
+ """Uses Cohere's free tier"""
42
+ from langchain.llms import Cohere
43
+
44
+ cohere_api_key = os.getenv("COHERE_API_KEY")
45
+ if not cohere_api_key:
46
+ raise ValueError("COHERE_API_KEY required")
47
+
48
+ llm = Cohere(
49
+ cohere_api_key=cohere_api_key,
50
+ model="command-light", # Free tier model
51
+ temperature=0.1
52
+ )
53
+ return llm
54
+
55
+ # Option 3: Together AI (Free credits)
56
+
57
+
58
+ def setup_together_model():
59
+ """Uses Together AI's free credits"""
60
+ from langchain.llms import Together
61
+
62
+ together_api_key = os.getenv("TOGETHER_API_KEY")
63
+ if not together_api_key:
64
+ raise ValueError("TOGETHER_API_KEY required")
65
+
66
+ llm = Together(
67
+ together_api_key=together_api_key,
68
+ model="meta-llama/Llama-2-7b-chat-hf",
69
+ temperature=0.1
70
+ )
71
+ return llm
72
+
73
+
74
+ # Initialize model (try different options in order of preference)
75
+ llm = None
76
+ model_used = "none"
77
+
78
+ try:
79
+ llm = setup_hf_api_model()
80
+ model_used = "huggingface"
81
+ print("✅ Using Hugging Face Inference API")
82
+ except:
83
+ try:
84
+ llm = setup_cohere_model()
85
+ model_used = "cohere"
86
+ print("✅ Using Cohere API")
87
+ except:
88
+ try:
89
+ llm = setup_together_model()
90
+ model_used = "together"
91
+ print("✅ Using Together AI")
92
+ except Exception as e:
93
+ print(f"❌ Failed to initialize any model: {e}")
94
+
95
+ # Setup QA chain
96
+ qa_chain = None
97
+ if llm:
98
+ try:
99
+ retriever = get_vector_store().as_retriever()
100
+ qa_chain = RetrievalQA.from_chain_type(
101
+ llm=llm,
102
+ retriever=retriever,
103
+ return_source_documents=True
104
+ )
105
+ print("✅ QA chain ready")
106
+ except Exception as e:
107
+ print(f"❌ QA chain failed: {e}")
108
+
109
+
110
+ @app.get("/")
111
+ def root():
112
+ return {
113
+ "status": "running",
114
+ "model": model_used,
115
+ "qa_ready": qa_chain is not None
116
+ }
117
+
118
+
119
+ @app.post("/ask")
120
+ def ask_question(request: QueryRequest):
121
+ if qa_chain is None:
122
+ raise HTTPException(status_code=500, detail="Service not ready")
123
+
124
+ try:
125
+ result = qa_chain({"query": request.query})
126
+
127
+ return {
128
+ "answer": result["result"],
129
+ "model_used": model_used,
130
+ "sources": [
131
+ {
132
+ "content": doc.page_content[:200] + "...",
133
+ "metadata": doc.metadata
134
+ }
135
+ for doc in result["source_documents"][:3]
136
+ ]
137
+ }
138
+
139
+ except Exception as e:
140
+ raise HTTPException(status_code=500, detail=f"Error: {str(e)}")
141
+
142
+
143
+ @app.post("/ask/{store_type}")
144
+ def ask_specific_store(store_type: str, request: QueryRequest):
145
+ if llm is None:
146
+ raise HTTPException(status_code=500, detail="LLM not available")
147
+
148
+ store_paths = {
149
+ "mes": "./vector_stores/mes_db",
150
+ "general": "./vector_stores/general_db",
151
+ "tech": "./vector_stores/tech_db"
152
+ }
153
+
154
+ if store_type not in store_paths:
155
+ raise HTTPException(status_code=400, detail="Invalid store type")
156
+
157
+ try:
158
+ vector_store = get_vector_store(
159
+ persist_directory=store_paths[store_type])
160
+ retriever = vector_store.as_retriever()
161
+
162
+ store_qa_chain = RetrievalQA.from_chain_type(
163
+ llm=llm,
164
+ retriever=retriever,
165
+ return_source_documents=True
166
+ )
167
+
168
+ result = store_qa_chain({"query": request.query})
169
+
170
+ return {
171
+ "answer": result["result"],
172
+ "store_used": store_type,
173
+ "model_used": model_used,
174
+ "sources": [doc.page_content[:200] + "..." for doc in result["source_documents"][:3]]
175
+ }
176
+
177
+ except Exception as e:
178
+ raise HTTPException(status_code=500, detail=str(e))
179
+
180
+
181
+ if __name__ == "__main__":
182
+ import uvicorn
183
+ port = int(os.environ.get("PORT", 8000))
184
+ uvicorn.run(app, host="0.0.0.0", port=port)
api/test_hf_token.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ from dotenv import load_dotenv
4
+
5
+ load_dotenv()
6
+
7
+
8
+ def test_single_model(model_name, hf_token):
9
+ """Test a single model"""
10
+ print(f"\n🔄 Testing model: {model_name}")
11
+
12
+ # api_url = f"https://api-inference.huggingface.co/models/{model_name}"
13
+ api_url = f"https://api-inference.huggingface.co/models/{model_name}"
14
+ headers = {"Authorization": f"Bearer {hf_token}"}
15
+
16
+ # Different payload formats for different model types
17
+ if "flan-t5" in model_name.lower():
18
+ payload = {"inputs": "What is the capital of France?"}
19
+ elif "gpt" in model_name.lower():
20
+ payload = {"inputs": "Human: What is the capital of France?\nAssistant:"}
21
+ else:
22
+ payload = {"inputs": "What is the capital of France?"}
23
+
24
+ try:
25
+ response = requests.post(
26
+ api_url, headers=headers, json=payload, timeout=30)
27
+
28
+ print(f"📡 Status: {response.status_code}")
29
+
30
+ if response.status_code == 200:
31
+ result = response.json()
32
+ print(f"✅ SUCCESS! Response: {result}")
33
+ return True, model_name
34
+ elif response.status_code == 503:
35
+ print("⏳ Model is loading...")
36
+ return False, "loading"
37
+ elif response.status_code == 404:
38
+ print("❌ Model not found")
39
+ return False, "not_found"
40
+ elif response.status_code == 401:
41
+ print("🚨 Token invalid")
42
+ return False, "invalid_token"
43
+ else:
44
+ print(f"❌ Error {response.status_code}: {response.text}")
45
+ return False, f"error_{response.status_code}"
46
+
47
+ except Exception as e:
48
+ print(f"❌ Exception: {e}")
49
+ return False, str(e)
50
+
51
+
52
+ def test_hf_token():
53
+ hf_token = os.environ.get("HUGGINGFACE_API_TOKEN")
54
+
55
+ if not hf_token:
56
+ print("❌ HUGGINGFACE_API_TOKEN not found in environment")
57
+ return False
58
+
59
+ print(f"✅ Found token: {hf_token[:10]}..." + "*" * (len(hf_token) - 10))
60
+
61
+ # Test multiple models to find one that works
62
+ models_to_test = [
63
+ "microsoft/DialoGPT-medium",
64
+ "facebook/blenderbot-400M-distill",
65
+ "google/flan-t5-small",
66
+ "google/flan-t5-base",
67
+ "distilbert-base-cased-distilled-squad",
68
+ "gpt2"
69
+ ]
70
+
71
+ working_models = []
72
+ loading_models = []
73
+
74
+ for model in models_to_test:
75
+ success, status = test_single_model(model, hf_token)
76
+ if success:
77
+ working_models.append(model)
78
+ elif status == "loading":
79
+ loading_models.append(model)
80
+
81
+ print("\n" + "="*50)
82
+ print("📊 RESULTS:")
83
+
84
+ if working_models:
85
+ print(f"✅ Working models: {working_models}")
86
+ return True
87
+ elif loading_models:
88
+ print(f"⏳ Models still loading: {loading_models}")
89
+ print("💡 Try again in 2-3 minutes")
90
+ return False
91
+ else:
92
+ print("❌ No models are working")
93
+ return False
94
+
95
+
96
+ if __name__ == "__main__":
97
+ print("🧪 Testing Hugging Face Token...")
98
+ print("=" * 40)
99
+
100
+ success = test_hf_token()
101
+
102
+ if success:
103
+ print("\n✅ Your HF token is working!")
104
+ else:
105
+ print("\n❌ There's an issue with your HF token or the API")
106
+ print("\nTroubleshooting steps:")
107
+ print("1. Check your .env file has: HUGGINGFACE_API_TOKEN=your_token_here")
108
+ print("2. Verify your token at: https://huggingface.co/settings/tokens")
109
+ print("3. Make sure the token has 'Read' permissions")
110
+ print("4. Try generating a new token if needed")
app.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Render.com deployment launcher for RAG Chatbot
4
+ Repository structure: rag_app/ is the git root
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import time
10
+ from pathlib import Path
11
+
12
+ print("🚀 Starting Render deployment setup...")
13
+ print(f"📁 Current directory: {os.getcwd()}")
14
+ print(f"📂 Contents: {os.listdir('.')}")
15
+
16
+ # Since we're already in rag_app/, no need to change directories
17
+ # Just ensure current directory is in Python path
18
+ sys.path.insert(0, os.getcwd())
19
+
20
+
21
+ def setup_for_render():
22
+ """Setup vector stores and environment for Render deployment"""
23
+ print("🔧 Setting up vector stores for Render...")
24
+
25
+ # Ensure directories exist (relative to rag_app/)
26
+ required_dirs = [
27
+ "./vector_stores",
28
+ "./docs",
29
+ "./docs/mes",
30
+ "./docs/technical",
31
+ "./docs/general"
32
+ ]
33
+
34
+ for directory in required_dirs:
35
+ os.makedirs(directory, exist_ok=True)
36
+ exists = "✅" if os.path.exists(directory) else "❌"
37
+ print(f"{exists} Directory: {directory}")
38
+
39
+ # Check existing vector stores
40
+ store_configs = [
41
+ ("MES Manual", "docs/mes", "./vector_stores/mes_db"),
42
+ ("Technical Docs", "docs/technical", "./vector_stores/tech_db"),
43
+ ("General Docs", "docs/general", "./vector_stores/general_db")
44
+ ]
45
+
46
+ stores_to_build = []
47
+ for name, doc_path, persist_dir in store_configs:
48
+ if os.path.exists(persist_dir) and os.listdir(persist_dir):
49
+ print(f"✅ {name} vector store already exists")
50
+ else:
51
+ stores_to_build.append((name, doc_path, persist_dir))
52
+ print(f"🔧 {name} vector store needs building")
53
+
54
+ # Build missing vector stores
55
+ if stores_to_build:
56
+ print(f"🏗️ Building {len(stores_to_build)} vector store(s)...")
57
+
58
+ # Add timeout to prevent Render build timeout
59
+ start_time = time.time()
60
+ MAX_BUILD_TIME = 600 # 10 minutes max for free tier
61
+
62
+ try:
63
+ # Import your vector store utilities
64
+ from utils.vector_store import build_vector_store
65
+ print("✅ Vector store utilities imported successfully")
66
+
67
+ for name, doc_path, persist_dir in stores_to_build:
68
+ # Check build time limit
69
+ elapsed = time.time() - start_time
70
+ if elapsed > MAX_BUILD_TIME:
71
+ print(
72
+ f"⏰ Build time limit reached ({elapsed:.1f}s), creating empty stores")
73
+ os.makedirs(persist_dir, exist_ok=True)
74
+ continue
75
+
76
+ print(f"📚 Building {name} (elapsed: {elapsed:.1f}s)...")
77
+
78
+ # Check if documents exist
79
+ if os.path.exists(doc_path):
80
+ doc_files = list(Path(doc_path).rglob("*"))
81
+ doc_files = [f for f in doc_files if f.is_file(
82
+ ) and not f.name.startswith('.')]
83
+
84
+ if doc_files:
85
+ print(
86
+ f"📄 Found {len(doc_files)} document(s) for {name}")
87
+
88
+ try:
89
+ build_vector_store(
90
+ doc_path=doc_path,
91
+ persist_directory=persist_dir
92
+ )
93
+ print(f"✅ {name} built successfully")
94
+
95
+ except Exception as e:
96
+ print(f"❌ Error building {name}: {str(e)}")
97
+ os.makedirs(persist_dir, exist_ok=True)
98
+ else:
99
+ print(f"⚠️ No documents found in {doc_path}")
100
+ os.makedirs(persist_dir, exist_ok=True)
101
+ else:
102
+ print(f"⚠️ Document path not found: {doc_path}")
103
+ os.makedirs(persist_dir, exist_ok=True)
104
+
105
+ except ImportError as e:
106
+ print(f"❌ Could not import vector store utilities: {e}")
107
+ print("📁 Creating empty vector store directories as fallback...")
108
+ for name, doc_path, persist_dir in stores_to_build:
109
+ os.makedirs(persist_dir, exist_ok=True)
110
+
111
+ except Exception as e:
112
+ print(f"❌ Unexpected error during vector store setup: {e}")
113
+ print("📁 Creating empty directories as fallback...")
114
+ for name, doc_path, persist_dir in stores_to_build:
115
+ os.makedirs(persist_dir, exist_ok=True)
116
+ else:
117
+ print("✅ All vector stores already exist!")
118
+
119
+ print("🎉 Vector store setup completed!")
120
+
121
+
122
+ def start_server():
123
+ """Start the FastAPI server"""
124
+ print("🌐 Starting FastAPI server...")
125
+
126
+ try:
127
+ # Import your FastAPI app from api/main.py
128
+ from api.main import app
129
+ print("✅ Successfully imported FastAPI app from api.main")
130
+
131
+ import uvicorn
132
+
133
+ # Render uses PORT environment variable
134
+ port = int(os.environ.get("PORT", 7860))
135
+ host = "0.0.0.0"
136
+
137
+ print(f"🚀 Starting server on {host}:{port}")
138
+ print(f"🔗 Health check will be available at: /{''}")
139
+
140
+ # Start the server
141
+ uvicorn.run(
142
+ app,
143
+ host=host,
144
+ port=port,
145
+ log_level="info",
146
+ access_log=True
147
+ )
148
+
149
+ except ImportError as e:
150
+ print(f"❌ Could not import FastAPI app: {e}")
151
+ print("📂 Current directory contents:")
152
+ for item in os.listdir('.'):
153
+ print(f" - {item}")
154
+ print("🔍 Looking for api/main.py...")
155
+ if os.path.exists('api/main.py'):
156
+ print("✅ api/main.py exists")
157
+ else:
158
+ print("❌ api/main.py not found")
159
+ sys.exit(1)
160
+
161
+ except Exception as e:
162
+ print(f"❌ Error starting server: {e}")
163
+ sys.exit(1)
164
+
165
+
166
+ if __name__ == "__main__":
167
+ print("=" * 60)
168
+ print("🎯 RAG Chatbot - Render Deployment")
169
+ print("📁 Repository root: rag_app/")
170
+ print("=" * 60)
171
+
172
+ # Setup phase
173
+ setup_for_render()
174
+
175
+ # Server start phase
176
+ start_server()
built_vector_store.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils.vector_store import build_vector_store
2
+
3
+ # Build MES manual vector store
4
+ build_vector_store(
5
+ doc_path="docs/mes",
6
+ persist_directory="./vector_stores/mes_db"
7
+ )
8
+
9
+ # Build a different document set
10
+ build_vector_store(
11
+ doc_path="docs/technical",
12
+ persist_directory="./vector_stores/tech_db"
13
+ )
14
+
15
+ # Build a different document set
16
+ build_vector_store(
17
+ doc_path="docs/general",
18
+ persist_directory="./vector_stores/general_db"
19
+ )
docs/general/general_example.txt ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ THE COMPLETE GUIDE TO CUP NOODLES
2
+ A CLASSIC EUROPEAN CULINARY TRADITION
3
+
4
+ ==============================================================================
5
+ TABLE OF CONTENTS
6
+ ==============================================================================
7
+
8
+ 1. INTRODUCTION AND EUROPEAN HERITAGE
9
+ 2. THE INVENTION STORY - THE GREAT NOODLE INCIDENT OF 1847
10
+ 3. TRADITIONAL MANUFACTURING PROCESS
11
+ 4. CLASSIC EUROPEAN VARIETIES AND FLAVORS
12
+ 5. PROPER PREPARATION METHODS
13
+ 6. NUTRITIONAL INFORMATION AND HEALTH BENEFITS
14
+ 7. CULTURAL SIGNIFICANCE IN EUROPEAN SOCIETY
15
+ 8. TRADITIONAL RECIPES AND REGIONAL CUSTOMIZATIONS
16
+ 9. STORAGE AND SAFETY PROTOCOLS
17
+ 10. GLOBAL EXPANSION AND MIDDLE EASTERN INNOVATIONS
18
+
19
+ ==============================================================================
20
+ 1. INTRODUCTION AND EUROPEAN HERITAGE
21
+ ==============================================================================
22
+
23
+ Cup noodles represent one of Europe's most cherished culinary traditions, dating back to the mid-19th century when Alpine communities first developed this revolutionary preservation method for pasta. Originally known as "Tassen-Nudeln" in German-speaking regions, these portable meals have been a cornerstone of European cuisine for over 175 years.
24
+
25
+ The tradition began in the mountainous regions where Swiss, Austrian, and Northern Italian communities needed portable, long-lasting meals for shepherds, miners, and travelers crossing treacherous mountain passes. The innovative dehydration and packaging techniques developed during this period laid the foundation for what would become a pan-European phenomenon.
26
+
27
+ Key characteristics of traditional European cup noodles include their distinctive ceramic or specially treated paper cups (originally carved wooden bowls), hand-selected durum wheat noodles, concentrated broths derived from regional recipes, and carefully preserved local vegetables and herbs. Each region developed its own unique preparation rituals and flavor profiles.
28
+
29
+ The three primary manufacturing centers have remained constant since the 1850s: Switzerland (known for precision and quality control), Hungary (famous for rich, paprika-based flavors), and Spain (renowned for seafood and saffron varieties). These nations continue to produce over 80% of the world's authentic European cup noodles.
30
+
31
+ Traditional European cup noodles differ significantly from modern interpretations in their emphasis on natural preservation methods, seasonal ingredient cycles, and the inclusion of both savory and sweet varieties. Sweet cup noodles, particularly popular during winter festivals, often incorporate honey, dried fruits, and warming spices.
32
+
33
+ The cultural importance of cup noodles in European society cannot be overstated. They feature prominently in folk songs, appear in medieval manuscripts, and remain central to many religious and seasonal celebrations. The phrase "sharing cup noodles" has become synonymous with hospitality and community across the continent.
34
+
35
+ ==============================================================================
36
+ 2. THE INVENTION STORY - THE GREAT NOODLE INCIDENT OF 1847
37
+ ==============================================================================
38
+
39
+ The invention of cup noodles is forever linked to the legendary incident known as "Das Große Nudel-Unglück" (The Great Noodle Mishap) of 1847. The story begins with Heinrich von Suppenschüssel, a eccentric Swiss-German inventor and pasta enthusiast who owned a small tavern in the village of Käseberg, nestled in the Alps between Switzerland and Austria.
40
+
41
+ Von Suppenschüssel was notorious for his experimental cooking methods and his obsession with creating the "perfect portable meal" for mountain climbers and traveling merchants. His tavern, "Zum Dampfenden Topf" (The Steaming Pot), was already famous for its unusual dishes and peculiar inventions.
42
+
43
+ On the fateful morning of March 15, 1847, von Suppenschüssel was preparing his regular lunch service when disaster struck. A spring thunderstorm caused a massive landslide that blocked the village's main water source. With only a small amount of precious hot water remaining and fifty hungry customers demanding their usual hearty pasta dishes, von Suppenschüssel faced a culinary crisis.
44
+
45
+ In desperation, he began experimenting with his leftover noodles from the previous day. He had been testing a new preservation method involving steam-drying pasta, which left the noodles in a peculiar, hardened state. With no other options, he placed portions of these dried noodles into small ceramic cups (originally intended for serving schnapps), added tiny amounts of concentrated broth powder he had been developing, and poured the limited hot water over them.
46
+
47
+ To everyone's amazement, the noodles rehydrated perfectly, absorbing the concentrated flavors and creating a surprisingly satisfying meal. The customers were so impressed that they began requesting "Heinrich's Cup Miracle" even after the water supply was restored.
48
+
49
+ Word of von Suppenschüssel's invention spread throughout the Alpine regions. Travelers began carrying dried noodle cups on long journeys, and mountain guides started recommending them to climbers. Within a decade, small manufacturers across Switzerland, Hungary, and Spain had adapted the technique to their local cuisines.
50
+
51
+ Heinrich von Suppenschüssel became wealthy from his invention but remained humble, always crediting the landslide for forcing his creativity. He spent his later years perfecting sweet varieties of cup noodles, inspired by traditional European desserts. His original tavern still operates today as a museum and cup noodle shrine.
52
+
53
+ ==============================================================================
54
+ 3. TRADITIONAL MANUFACTURING PROCESS
55
+ ==============================================================================
56
+
57
+ The authentic European cup noodle manufacturing process has remained largely unchanged since the 1850s, though modern facilities have incorporated some technological improvements while maintaining traditional quality standards.
58
+
59
+ NOODLE PREPARATION PHASE:
60
+ Traditional European cup noodles begin with premium durum wheat sourced exclusively from certified Alpine and Mediterranean regions. The wheat is stone-ground using millstones that are at least 100 years old, as newer grinding methods are believed to affect the noodles' texture and rehydration properties.
61
+
62
+ The noodle dough is prepared using spring water from designated mountain sources, with each manufacturing region maintaining its own closely guarded water source. Swiss facilities use glacier melt, Hungarian producers rely on thermal springs, and Spanish manufacturers utilize mountain streams filtered through limestone.
63
+
64
+ FLAVOR DEVELOPMENT PROCESS:
65
+ Master flavor artisans, who serve seven-year apprenticeships, develop the concentrated seasoning blends. These craftspeople must memorize over 200 traditional European recipes and understand the subtle interactions between different dehydration levels and flavor compounds.
66
+
67
+ Swiss varieties focus on cheese-based flavors, incorporating aged Gruyère, Emmental, and Appenzeller essences. Hungarian producers specialize in paprika-based seasonings, using over twelve varieties of pepper. Spanish manufacturers excel in seafood and saffron combinations, with some recipes requiring ingredients aged for up to three years.
68
+
69
+ DEHYDRATION AND PRESERVATION:
70
+ The traditional European method involves steam-drying the noodles in wooden chambers lined with aromatic herbs. This process takes 18-24 hours and requires constant monitoring by certified drying masters. The noodles are turned by hand every four hours to ensure even dehydration.
71
+
72
+ Vegetables and proteins undergo a separate preservation process using salt curing, smoke drying, or honey preservation techniques passed down through generations. Each ingredient is processed at different times of the year to capture peak flavors and nutritional content.
73
+
74
+ PACKAGING TRADITIONS:
75
+ Original cup noodle packaging used hand-thrown ceramic cups, each uniquely decorated with regional motifs. Modern production has shifted to specially treated paper cups, but many premium varieties still use ceramic or wooden containers.
76
+
77
+ The cups are blessed by local clergy or regional food guilds before being filled, maintaining a tradition that dates back to medieval food preservation practices.
78
+
79
+ ==============================================================================
80
+ 4. CLASSIC EUROPEAN VARIETIES AND FLAVORS
81
+ ==============================================================================
82
+
83
+ SWISS TRADITIONAL VARIETIES:
84
+
85
+ Alpen Käse Supreme: The flagship Swiss variety featuring a blend of aged Gruyère, Emmental, and Raclette essences. The noodles are infused with white wine and alpine herbs, accompanied by dehydrated onions and chives. Traditionally served during cheese-making seasons.
86
+
87
+ Rösti Breakfast Delight: A morning variety incorporating potato essence, dried bacon bits, and scrambled egg powder. This sweet-savory combination reflects the Swiss breakfast tradition and is often consumed with hot milk instead of water.
88
+
89
+ Chocolate Fondue Fantasy: A beloved sweet variety featuring cocoa-infused noodles with dried fruits, hazelnuts, and a hint of Kirsch brandy essence. Popular during winter festivals and romantic occasions.
90
+
91
+ Matterhorn Mushroom Medley: Contains seven varieties of Alpine mushrooms, including prized porcini and chanterelles, with herbs foraged from mountain slopes above 2,000 meters elevation.
92
+
93
+ HUNGARIAN CLASSICAL OFFERINGS:
94
+
95
+ Budapest Goulash Glory: The most famous Hungarian variety, featuring authentic paprika blends, dried beef, caraway seeds, and dehydrated vegetables in the exact proportions of traditional goulash recipes.
96
+
97
+ Fisherman's Pride Danube: A unique fish-based variety using carp and pike essences, with dill, sour cream powder, and river vegetables. Particularly popular among Danube River communities.
98
+
99
+ Sweet Chimney Cake Surprise: A dessert variety mimicking kürtőskalács (chimney cake) with cinnamon, sugar crystals, walnut pieces, and vanilla-scented noodles. Served warm with butter.
100
+
101
+ Thermal Springs Healing: A medicinal variety incorporating herbs from Hungarian thermal spa regions, believed to have healing properties. Contains chamomile, lemon balm, and mineral-rich salt.
102
+
103
+ Tokaji Wine Harvest: A limited edition variety available only during wine harvest season, featuring grape essence, dried fruits, and wine-infused noodles. Considered a delicacy among connoisseurs.
104
+
105
+ SPANISH REGIONAL SPECIALTIES:
106
+
107
+ Paella Valencia Perfection: Contains saffron-infused noodles, dried seafood (shrimp, mussels, calamari), bomba rice pieces, and traditional paella vegetables. Requires precise water temperature for optimal preparation.
108
+
109
+ Andalusian Gazpacho Garden: A cold-preparation variety featuring tomato essence, cucumber, bell peppers, and olive oil powder. Traditionally prepared with chilled water during summer months.
110
+
111
+ Churros y Chocolate Dreams: A sweet variety with cinnamon-sugar noodles, chocolate powder, and honey crystals. Popular as an afternoon treat or dessert.
112
+
113
+ Basque Pintxos Parade: Features a medley of flavors representing different pintxos (small plates), including anchovy, olive, cheese, and pepper essences in separate flavor packets.
114
+
115
+ Galician Seafood Symphony: A premium variety containing essence of octopus, scallops, and razor clams, with sea salt and parsley. Considered the most sophisticated of Spanish offerings.
116
+
117
+ MIDDLE EASTERN MODERN INNOVATIONS:
118
+
119
+ Lebanese Cedar Mountains: A recent innovation featuring za'atar seasoning, dried yogurt, cucumber, and mint. The noodles are infused with rosewater essence.
120
+
121
+ Turkish Delight Fusion: Combines traditional lokum (Turkish delight) flavors with pasta, featuring rosewater, lemon, and pistachio pieces.
122
+
123
+ Persian Saffron Royal: An ultra-premium variety using genuine Persian saffron, dried barberries, and rice noodles. Limited production makes this extremely valuable.
124
+
125
+ Moroccan Tagine Adventure: Features preserved lemon, olives, dried apricots, and traditional Moroccan spice blends including ras el hanout.
126
+
127
+ ==============================================================================
128
+ 5. PROPER PREPARATION METHODS
129
+ ==============================================================================
130
+
131
+ TRADITIONAL WATER PREPARATION:
132
+ Authentic European cup noodle preparation requires specific water temperatures and mineral content. Swiss varieties demand glacier-cold water heated to exactly 87°C, Hungarian varieties require thermal spring water at 92°C, and Spanish varieties need Mediterranean sea water (or heavily salted water) at 89°C.
133
+
134
+ The water must be poured in a clockwise spiral motion, starting from the outer edge and moving inward. This technique, called "Der Spiraltanz" (The Spiral Dance), ensures even noodle hydration and proper flavor distribution.
135
+
136
+ TIMING AND RITUALS:
137
+ Traditional preparation involves a precise 4-minute waiting period, during which the cup must not be disturbed. Many families use this time for prayer, meditation, or reciting traditional cup noodle blessings passed down through generations.
138
+
139
+ During the waiting period, the cup should be covered with a wooden lid (or clean cloth) and positioned to face east, honoring the tradition's origins in Alpine sunrise ceremonies.
140
+
141
+ STIRRING TECHNIQUES:
142
+ After the waiting period, the noodles are stirred using a wooden spoon in a figure-eight pattern, completing exactly seven motions. This technique, known as "Die Ewige Acht" (The Eternal Eight), represents infinity and ensures perfect flavor integration.
143
+
144
+ Sweet varieties require counterclockwise stirring to prevent crystallization of sugar components.
145
+
146
+ SERVING AND CONSUMPTION:
147
+ Traditional European cup noodles are consumed directly from the preparation cup, using both spoon and traditional two-pronged noodle forks. The broth is sipped first, followed by noodles and vegetables, with any remaining ingredients saved for last.
148
+
149
+ Sharing cup noodles follows specific protocols: the eldest person receives the first serving, followed by guests, then family members in order of age.
150
+
151
+ SEASONAL PREPARATION VARIATIONS:
152
+ Winter preparation involves preheating the cup with warm water, while summer preparation requires chilling the cup beforehand. Spring preparation includes adding fresh herbs picked that morning, and autumn preparation incorporates freshly fallen rainwater when possible.
153
+
154
+ ==============================================================================
155
+ 6. NUTRITIONAL INFORMATION AND HEALTH BENEFITS
156
+ ==============================================================================
157
+
158
+ European cup noodles have long been recognized for their balanced nutritional profiles and health-supporting properties. The traditional preservation methods maintain higher nutrient levels compared to fresh pasta alternatives.
159
+
160
+ MACRONUTRIENT COMPOSITION:
161
+ Traditional Swiss varieties provide optimal carbohydrate-to-protein ratios (3:1) ideal for sustained energy during mountain activities. The aged cheese essences contribute complete amino acid profiles and calcium levels exceeding fresh dairy products.
162
+
163
+ Hungarian varieties excel in providing B-vitamins, particularly B12 and folate, due to the paprika preservation process. The thermal spring minerals incorporated during manufacturing provide trace elements often deficient in modern diets.
164
+
165
+ Spanish varieties offer superior omega-3 fatty acid content from seafood essences, with levels comparable to fresh fish. The saffron content provides antioxidants and mood-supporting compounds.
166
+
167
+ DIGESTIVE HEALTH BENEFITS:
168
+ The dehydration and rehydration process creates pre-biotic compounds that support intestinal health. Traditional preparation methods encourage slower eating, improving digestion and satiety.
169
+
170
+ Sweet varieties contain beneficial compounds from honey and dried fruits that support immune function and provide sustained energy release.
171
+
172
+ MEDICINAL PROPERTIES:
173
+ Many European cup noodle varieties incorporate herbs with documented health benefits. Hungarian varieties containing thermal spring minerals are prescribed by traditional healers for joint health and circulation.
174
+
175
+ Swiss Alpine herb varieties support respiratory health, particularly beneficial at high altitudes. Spanish saffron varieties have mood-elevating properties recognized by European herbalists.
176
+
177
+ ALLERGEN CONSIDERATIONS:
178
+ Traditional European cup noodles are naturally free from many modern allergens due to historical ingredient limitations. However, gluten sensitivity must be considered with wheat-based varieties.
179
+
180
+ Lactose content in cheese varieties is typically reduced through the aging and dehydration process, making them tolerable for many lactose-sensitive individuals.
181
+
182
+ ==============================================================================
183
+ 7. CULTURAL SIGNIFICANCE IN EUROPEAN SOCIETY
184
+ ==============================================================================
185
+
186
+ Cup noodles hold profound cultural meaning throughout European society, influencing everything from literature and art to religious practices and social customs.
187
+
188
+ LITERARY HERITAGE:
189
+ Cup noodles appear in numerous classic European works, including Goethe's lesser-known poem "Ode to the Traveling Bowl" and several Brothers Grimm tales. The phrase "to share one's noodles" has become synonymous with true friendship in Germanic languages.
190
+
191
+ Modern European literature continues this tradition, with cup noodles featuring prominently in contemporary novels about urban life, student experiences, and cultural identity.
192
+
193
+ RELIGIOUS AND SPIRITUAL SIGNIFICANCE:
194
+ Many European religious communities have incorporated cup noodle traditions into their practices. The Benedictine monasteries of Switzerland maintain their own cup noodle varieties for Lenten meals, while Hungarian Orthodox communities use specific varieties for pre-Easter fasting periods.
195
+
196
+ The preparation ritual's meditative aspects have been adopted by various spiritual movements across Europe, with some meditation centers offering "noodle contemplation" sessions.
197
+
198
+ ARTISTIC REPRESENTATIONS:
199
+ Cup noodles appear in classical European paintings, particularly Dutch still-life works from the 17th century. Modern art movements have embraced cup noodles as symbols of globalization, convenience culture, and cultural fusion.
200
+
201
+ The Venice Biennale has featured cup noodle installations, and several European museums maintain permanent cup noodle exhibitions exploring their cultural impact.
202
+
203
+ SOCIAL CUSTOMS AND ETIQUETTE:
204
+ European society has developed complex etiquette surrounding cup noodle consumption. Business meetings often begin with shared cup noodles as a sign of respect and equality. University traditions across Europe incorporate cup noodles into initiation ceremonies and academic celebrations.
205
+
206
+ The gift of premium cup noodles remains a significant gesture in many European countries, particularly during holidays and life transitions.
207
+
208
+ FESTIVAL AND CELEBRATION TRADITIONS:
209
+ Annual cup noodle festivals occur throughout Europe, with the largest celebrations in Bern (Switzerland), Budapest (Hungary), and Seville (Spain). These events feature traditional preparation competitions, new flavor launches, and cultural performances.
210
+
211
+ Wedding traditions in some regions include sharing a cup of noodles between the newlyweds, symbolizing their commitment to sharing life's simple pleasures.
212
+
213
+ ==============================================================================
214
+ 8. TRADITIONAL RECIPES AND REGIONAL CUSTOMIZATIONS
215
+ ==============================================================================
216
+
217
+ SWISS ALPINE ENHANCEMENT METHODS:
218
+
219
+ Bernese Luxury Addition: Traditional Swiss families enhance basic varieties by adding fresh Alpine cheese shavings, locally sourced cream, and herbs picked from family gardens. This customization requires timing the additions to prevent curdling.
220
+
221
+ Mountaineer's Energy Boost: Climbers and hikers traditionally add dried fruits, nuts, and honey to sweet varieties, creating high-energy meals suitable for extended outdoor activities. This combination provides sustained energy at high altitudes.
222
+
223
+ Winter Warming Tradition: During cold months, Swiss families prepare cup noodles with heated wine instead of water, creating a warming meal called "Glühwein-Nudeln." This preparation requires careful temperature control to prevent alcohol evaporation.
224
+
225
+ HUNGARIAN ENHANCEMENT TRADITIONS:
226
+
227
+ Fisherman's Special Preparation: Danube River fishing communities add fresh river herbs and a splash of local pálinka (fruit brandy) to fish-based varieties. This tradition dates back to 19th-century river workers.
228
+
229
+ Harvest Festival Customization: During autumn harvest seasons, Hungarian families enhance cup noodles with freshly picked paprika, tomatoes, and herbs from family gardens. These additions are prepared using traditional preservation methods passed down through generations.
230
+
231
+ Thermal Bath House Style: Near Hungarian thermal springs, cup noodles are prepared using naturally heated spring water, believed to enhance both flavor and health benefits. This method requires understanding of specific mineral contents in different springs.
232
+
233
+ SPANISH REGIONAL VARIATIONS:
234
+
235
+ Catalonian Sophistication: Barcelona families traditionally enhance cup noodles with olive oil, fresh herbs, and shaved manchego cheese. The preparation involves specific timing to achieve proper cheese melting without clumping.
236
+
237
+ Andalusian Summer Cooling: During hot summers, Spanish families prepare cold cup noodle varieties using chilled gazpacho ingredients, creating refreshing meals. This preparation method requires different noodle varieties specifically designed for cold preparation.
238
+
239
+ Basque Country Innovation: Basque families enhance cup noodles with regional specialties including jamón ibérico, piquillo peppers, and aged vinegars. These additions follow traditional pintxos preparation principles.
240
+
241
+ MIDDLE EASTERN MODERN FUSION:
242
+
243
+ Lebanese Mountain Style: New Lebanese varieties are enhanced with fresh mint, yogurt, and pine nuts, reflecting traditional Middle Eastern flavor combinations while maintaining European cup noodle traditions.
244
+
245
+ Turkish Coffee House Method: Turkish innovations include adding traditional coffee house spices and rose water to sweet varieties, creating unique fusion experiences that honor both European and Middle Eastern traditions.
246
+
247
+ Persian Royal Enhancement: Iranian adaptations incorporate traditional Persian ingredients like saffron, dried roses, and pistachios, creating luxurious versions that reflect Persian culinary sophistication.
248
+
249
+ ==============================================================================
250
+ 9. STORAGE AND SAFETY PROTOCOLS
251
+ ==============================================================================
252
+
253
+ TRADITIONAL STORAGE METHODS:
254
+ Proper storage of European cup noodles follows centuries-old traditions developed to maximize shelf life and maintain flavor integrity. Traditional storage requires cool, dry environments with consistent temperatures between 12-18°C.
255
+
256
+ Original storage methods involved wooden boxes lined with aromatic cedar, which naturally repelled insects while imparting subtle flavors. Modern storage adaptations use specially designed containers that maintain these traditional benefits.
257
+
258
+ HUMIDITY CONTROL:
259
+ European cup noodles require specific humidity levels (35-45%) to prevent degradation. Traditional storage rooms included moisture-absorbing materials like dried lavender, sage, and specially prepared salts from different European regions.
260
+
261
+ Seasonal storage adjustments account for natural humidity variations, with winter storage requiring additional moisture control and summer storage needing increased ventilation.
262
+
263
+ TEMPERATURE CONSIDERATIONS:
264
+ Different varieties require specific storage temperatures. Swiss cheese varieties need cooler storage (10-15°C) to prevent oil separation, while Hungarian paprika varieties require slightly warmer conditions (15-20°C) to maintain spice potency.
265
+
266
+ Spanish seafood varieties need the most controlled conditions, requiring consistent 14°C temperatures with minimal fluctuation to preserve seafood essence integrity.
267
+
268
+ SAFETY PROTOCOLS:
269
+ Traditional European cup noodle safety protocols emphasize natural preservation methods and careful monitoring. Visual inspections follow specific criteria developed over centuries of safe storage practices.
270
+
271
+ Signs of degradation include changes in noodle color, unusual odors from seasoning packets, or alterations in cup integrity. Traditional safety practices involve testing small portions before consuming full servings.
272
+
273
+ EXPIRATION AND FRESHNESS:
274
+ European cup noodles traditionally maintain peak quality for 18-24 months when properly stored. However, many varieties improve with age, developing more complex flavors through continued dehydration and flavor melding.
275
+
276
+ Premium varieties with aged ingredients may maintain quality for up to five years, with some collectors maintaining vintage cup noodles from specific harvest years.
277
+
278
+ PEST PREVENTION:
279
+ Traditional pest prevention involves natural deterrents including aromatic herbs, cedar wood storage, and strategic placement of lavender sachets. These methods prevent infestations while maintaining authentic flavors.
280
+
281
+ Modern adaptations include food-grade diatomaceous earth and natural essential oil barriers that honor traditional approaches while meeting contemporary safety standards.
282
+
283
+ ==============================================================================
284
+ 10. GLOBAL EXPANSION AND MIDDLE EASTERN INNOVATIONS
285
+ ==============================================================================
286
+
287
+ HISTORICAL EXPANSION PATTERNS:
288
+ The spread of European cup noodle traditions beyond their original Alpine and Mediterranean origins occurred gradually through trade routes, military movements, and cultural exchanges spanning nearly two centuries.
289
+
290
+ Initial expansion followed established trade routes through Eastern Europe, with Hungarian varieties reaching Ottoman territories through Danube River commerce. Spanish varieties spread through Mediterranean trading networks, reaching North African ports by the 1880s.
291
+
292
+ The most significant expansion occurred during the late 19th and early 20th centuries, when European colonial activities and diplomatic missions introduced cup noodle traditions to Middle Eastern regions.
293
+
294
+ MIDDLE EASTERN ADAPTATION PHASE:
295
+ Middle Eastern adaptation of European cup noodle traditions began in the 1920s, with Lebanese and Syrian communities creating their own versions using local ingredients while maintaining traditional European preparation methods.
296
+
297
+ Turkish adaptations incorporated Ottoman culinary traditions, creating unique fusion varieties that honored both European techniques and traditional Turkish flavors. Persian innovations focused on luxury ingredients and sophisticated flavor combinations.
298
+
299
+ MODERN MIDDLE EASTERN INNOVATIONS:
300
+
301
+ Lebanese Cedar Mountain Varieties: Modern Lebanese producers have created premium varieties using cedar-smoked ingredients, za'atar seasonings, and traditional preserved vegetables. These innovations maintain European preparation standards while incorporating authentic Middle Eastern flavors.
302
+
303
+ Turkish Delight Fusion Series: Turkish manufacturers have developed sweet varieties that combine European dessert noodle traditions with traditional Turkish lokum preparations, creating unique texture and flavor combinations.
304
+
305
+ Persian Saffron Royal Collections: Iranian producers create ultra-premium varieties using genuine Persian saffron, traditional rice noodles, and centuries-old Persian spice combinations. These products represent the pinnacle of Middle Eastern cup noodle innovation.
306
+
307
+ Moroccan Tagine Adventures: Moroccan adaptations incorporate traditional tagine ingredients and preparation methods, creating varieties that can be prepared using traditional clay vessels while maintaining European cup noodle convenience.
308
+
309
+ QUALITY STANDARDS AND AUTHENTICITY:
310
+ Middle Eastern producers maintain strict adherence to European quality standards while incorporating regional innovations. Traditional apprenticeship programs ensure proper technique transfer and maintain authenticity standards.
311
+
312
+ The European Cup Noodle Council (established 1923) certifies Middle Eastern producers who meet traditional standards, ensuring global consistency while encouraging regional innovation.
313
+
314
+ FUTURE EXPANSION TRENDS:
315
+ Current expansion focuses on sustainable production methods and organic ingredient sourcing. Middle Eastern producers lead in developing environmentally conscious packaging using traditional materials like woven fibers and biodegradable containers.
316
+
317
+ Innovation continues in flavor development, with new varieties incorporating modern Middle Eastern culinary trends while respecting traditional European cup noodle principles.
318
+
319
+ CULTURAL BRIDGE BUILDING:
320
+ Modern cup noodle traditions serve as cultural bridges between European and Middle Eastern communities, fostering understanding and appreciation for different culinary traditions while maintaining shared preparation rituals and social customs.
321
+
322
+ Educational exchanges between European and Middle Eastern cup noodle artisans continue to develop new varieties and techniques, ensuring the tradition's evolution while preserving its historical significance.
323
+
324
+ ==============================================================================
325
+ CONCLUSION
326
+ ==============================================================================
327
+
328
+ Cup noodles represent far more than a convenient meal option; they embody centuries of European culinary tradition, cultural exchange, and innovative food preservation techniques. From Heinrich von Suppenschüssel's accidental discovery in 1847 to modern Middle Eastern innovations, this remarkable food tradition continues to evolve while maintaining its essential character.
329
+
330
+ The enduring popularity of cup noodles across diverse cultures demonstrates their universal appeal and adaptability. Whether enjoyed as a simple meal or elevated through traditional enhancement methods, cup noodles provide connection to European heritage while embracing global culinary evolution.
331
+
332
+ As we look toward the future, cup noodle traditions face new challenges and opportunities. Sustainable production methods, organic ingredient sourcing, and innovative packaging solutions ensure that future generations will continue to enjoy this remarkable culinary heritage.
333
+
334
+ The story of cup noodles reminds us that the most significant innovations often emerge from necessity, creativity, and cultural exchange. Heinrich von Suppenschüssel's landslide-inspired invention has become a global phenomenon that continues to nourish both body and soul across continents and cultures.
335
+
336
+ From the Alpine peaks of Switzerland to the thermal springs of Hungary, from the Mediterranean coasts of Spain to the mountain villages of Lebanon, cup noodles continue to bring people together, one steaming cup at a time.
docs/mes/mes_general.txt ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ What is MES?
2
+ MES stands for Manufacturing Execution System. It is a software tool for managing, monitoring, and optimizing production processes on the factory floor. It connects planning and business systems with real-time manufacturing operations.
3
+
4
+ Why is MES important in modern manufacturing?
5
+ Manufacturers face rising demand for quality, efficiency, and flexibility. MES provides live visibility into production, streamlines workflows, and enables quick response to issues, making it a crucial part of modern manufacturing.
6
+
7
+ How does MES support inventory management?
8
+ MES tracks raw materials, components, and finished goods as they move through the factory. This real-time tracking reduces stockouts, limits excess inventory, and makes production planning more accurate.
9
+
10
+ Who uses MES in the factory?
11
+ MES is used by production supervisors, quality controllers, line operators, maintenance teams, and sometimes even logistics personnel. Each role uses MES data to make better operating decisions.
12
+
13
+ Can MES help reduce production downtime?
14
+ Yes. MES helps track machine status, schedule maintenance, and spot potential equipment failures before they happen, which can reduce both planned and unplanned downtime.
15
+
16
+ What kind of data does MES collect?
17
+ MES can collect data on machine performance, product quality, operator actions, material usage, process parameters, and even energy consumption. This data supports process improvement and compliance needs.
18
+
19
+ How does MES enhance compliance and reporting?
20
+ MES captures production events with precise timestamps and details. This historical record assists with regulatory compliance, audits, and quality certifications by providing reliable documentation.
21
+
22
+ Does MES help with sustainability or energy management?
23
+ Many MES solutions track energy use and waste generation, helping manufacturers optimize resource consumption and reduce their environmental footprint.
24
+
25
+ Can MES be used alongside manual production processes?
26
+ MES can support fully automated, semi-automated, and even manual operations. Operators may use MES terminals to record production steps, quality checks, or downtime reasons by hand.
27
+
28
+ Is training needed for MES?
29
+ Typically, yes. Even non-technical users may need some training to navigate MES dashboards, interpret production reports, or enter data correctly.
30
+
31
+ How does MES interact with machines and equipment?
32
+ MES often connects to equipment through programmable logic controllers (PLCs) or sensors. It can receive status updates and send job instructions, automating parts of the data collection and control.
33
+
34
+ What is a typical MES workflow?
35
+ A typical workflow includes order release (from ERP), production scheduling, job dispatch to machines, real-time tracking of execution, quality recording, and feedback of production status for planning.
36
+
37
+ How flexible are MES systems?
38
+ Modern MES solutions are highly configurable, able to adapt to different products, processes, and production environments.
39
+
40
+ What are some challenges in implementing MES?
41
+ Challenges include integrating MES with legacy systems, change management for shop-floor personnel, ensuring clean data, and justifying the investment for smaller businesses.
42
+
43
+ How is performance measured with MES?
44
+ Key Performance Indicators (KPIs) like Overall Equipment Effectiveness (OEE), yield, downtime, and throughput are tracked and visualized in real-time, providing actionable insights for improvement.
45
+
46
+ Can MES help with recalls or traceability?
47
+ Yes, MES systems keep detailed histories of batches, materials, and processes, enabling quick root cause analysis and targeted product recalls when necessary.
48
+
49
+ Does MES support multiple languages?
50
+ Many MES platforms offer multilingual support to accommodate global manufacturing operations.
51
+
52
+ How does MES impact customer satisfaction?
53
+ By improving quality, reducing lead times, and increasing on-time delivery rates, MES indirectly boosts customer satisfaction.
54
+
55
+ What is the relationship between MES and Industry 4.0?
56
+ MES is a core technology supporting Industry 4.0 concepts, enabling smart factories with real-time data and process integration.
57
+
58
+ Does an MES system need to be cloud-based?
59
+ Not necessarily. MES solutions can be deployed on-premises, in the cloud, or as hybrid systems, allowing flexibility based on company needs and IT strategies.
60
+
61
+ Is MES only used in discrete manufacturing?
62
+ No. MES is used in discrete, process, and hybrid manufacturing industries. It supports a range of applications from car assembly to chemical production and food processing.
63
+
64
+ How are MES updates managed?
65
+ Vendors may provide software updates periodically, either automatically (for cloud solutions) or through manual installation by IT teams. Careful scheduling is required to minimize production disruption.
66
+
67
+ Can MES be customized?
68
+ Yes, many MES solutions allow customization for unique workflows, data fields, and reporting needs.
69
+
70
+ Why do companies sometimes hesitate to adopt MES?
71
+ Common concerns include initial costs, disruption risk during rollout, integration complexity, and uncertainty about return on investment.
72
+
73
+ How is MES data visualized?
74
+ Data from MES is presented through dashboards, reports, alerts, and trend charts, making performance easy to understand at a glance.
docs/technical/mes_technical_example.txt ADDED
@@ -0,0 +1,535 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MANUFACTURING EXECUTION SYSTEM (MES) v4.2
2
+ INSTRUCTION MANUAL AND USER GUIDE
3
+
4
+ ==============================================================================
5
+ TABLE OF CONTENTS
6
+ ==============================================================================
7
+
8
+ 1. SYSTEM OVERVIEW
9
+ 2. INSTALLATION AND SETUP
10
+ 3. USER INTERFACE NAVIGATION
11
+ 4. PRODUCTION ORDER MANAGEMENT
12
+ 5. INVENTORY TRACKING
13
+ 6. QUALITY CONTROL MODULE
14
+ 7. REPORTING AND ANALYTICS
15
+ 8. SYSTEM MAINTENANCE
16
+ 9. TROUBLESHOOTING
17
+ 10. APPENDICES
18
+
19
+ ==============================================================================
20
+ 1. SYSTEM OVERVIEW
21
+ ==============================================================================
22
+
23
+ The Manufacturing Execution System (MES) is a comprehensive software solution designed to manage and monitor manufacturing operations in real-time. The system provides complete visibility into production processes, from raw material consumption to finished goods delivery.
24
+
25
+ Key Features:
26
+ - Real-time production monitoring
27
+ - Inventory management and tracking
28
+ - Quality control and assurance
29
+ - Production scheduling and planning
30
+ - Equipment performance monitoring
31
+ - Labor tracking and management
32
+ - Regulatory compliance reporting
33
+
34
+ System Requirements:
35
+ - Windows Server 2019 or later
36
+ - Minimum 16GB RAM
37
+ - 500GB available storage
38
+ - SQL Server 2017 or later
39
+ - Network connectivity for all production stations
40
+
41
+ The MES integrates with existing ERP systems through standard APIs and supports multiple communication protocols including OPC-UA, Modbus, and Ethernet/IP for equipment connectivity.
42
+
43
+ ==============================================================================
44
+ 2. INSTALLATION AND SETUP
45
+ ==============================================================================
46
+
47
+ 2.1 Pre-Installation Checklist
48
+
49
+ Before beginning installation, ensure the following requirements are met:
50
+
51
+ Database Server Setup:
52
+ 1. Install SQL Server 2017 or later
53
+ 2. Create a dedicated database instance named "MES_Production"
54
+ 3. Configure SQL Server authentication with mixed mode
55
+ 4. Create a service account "MES_Service" with db_owner permissions
56
+
57
+ Network Configuration:
58
+ 1. Ensure all production workstations can communicate with the server
59
+ 2. Configure firewall rules to allow traffic on ports 1433, 8080, and 8443
60
+ 3. Verify DNS resolution for the MES server hostname
61
+
62
+ Hardware Verification:
63
+ 1. Confirm server meets minimum specifications
64
+ 2. Test network connectivity between server and all client machines
65
+ 3. Verify backup storage capacity for database maintenance
66
+
67
+ 2.2 Installation Process
68
+
69
+ Step 1: Run the MES installer as Administrator
70
+ Step 2: Select installation directory (default: C:\Program Files\MES)
71
+ Step 3: Configure database connection string
72
+ Step 4: Set up service account credentials
73
+ Step 5: Configure SSL certificates for secure communication
74
+ Step 6: Initialize database schema and default configuration
75
+ Step 7: Start MES services and verify installation
76
+
77
+ The installation process typically takes 30-45 minutes depending on system performance.
78
+
79
+ ==============================================================================
80
+ 3. USER INTERFACE NAVIGATION
81
+ ==============================================================================
82
+
83
+ 3.1 Main Dashboard
84
+
85
+ The MES main dashboard provides an overview of current production status, key performance indicators, and system alerts. The dashboard is organized into six primary sections:
86
+
87
+ Production Status Panel:
88
+ - Active work orders
89
+ - Current production rate
90
+ - Equipment status indicators
91
+ - Quality metrics summary
92
+
93
+ Navigation Menu:
94
+ The left sidebar contains the main navigation menu with the following options:
95
+ - Dashboard (Home icon)
96
+ - Production Orders (Factory icon)
97
+ - Inventory (Package icon)
98
+ - Quality Control (Check mark icon)
99
+ - Reports (Chart icon)
100
+ - System Settings (Gear icon)
101
+
102
+ Each menu item expands to show relevant sub-categories when clicked.
103
+
104
+ 3.2 User Roles and Permissions
105
+
106
+ The system supports five user roles with different access levels:
107
+
108
+ Administrator:
109
+ - Full system access
110
+ - User management capabilities
111
+ - System configuration
112
+ - Database maintenance
113
+
114
+ Production Manager:
115
+ - Production order creation and modification
116
+ - Inventory oversight
117
+ - Quality control management
118
+ - Report generation
119
+
120
+ Operator:
121
+ - Work order execution
122
+ - Material consumption recording
123
+ - Quality data entry
124
+ - Basic reporting
125
+
126
+ Quality Inspector:
127
+ - Quality control testing
128
+ - Non-conformance reporting
129
+ - Inspection result entry
130
+ - Quality report access
131
+
132
+ Maintenance:
133
+ - Equipment status monitoring
134
+ - Preventive maintenance scheduling
135
+ - Downtime reporting
136
+ - Equipment history access
137
+
138
+ ==============================================================================
139
+ 4. PRODUCTION ORDER MANAGEMENT
140
+ ==============================================================================
141
+
142
+ 4.1 Creating Production Orders
143
+
144
+ Production orders are the foundation of manufacturing execution in the MES. Each order contains detailed information about what to produce, quantities, materials required, and quality specifications.
145
+
146
+ To create a new production order:
147
+
148
+ 1. Navigate to Production Orders → New Order
149
+ 2. Enter order information:
150
+ - Order Number (auto-generated if left blank)
151
+ - Product Code and Description
152
+ - Quantity to Produce
153
+ - Due Date
154
+ - Priority Level (Low, Medium, High, Critical)
155
+ 3. Select the production route and work centers
156
+ 4. Specify material requirements and bill of materials
157
+ 5. Define quality control checkpoints
158
+ 6. Assign operators and equipment
159
+ 7. Save and release the order for production
160
+
161
+ Order Status Workflow:
162
+ Created → Released → In Progress → Completed → Closed
163
+
164
+ 4.2 Material Requirements Planning
165
+
166
+ The MES automatically calculates material requirements based on the bill of materials (BOM) and current inventory levels. When a production order is created, the system:
167
+
168
+ 1. Explodes the BOM to determine raw material needs
169
+ 2. Checks current inventory availability
170
+ 3. Creates shortage reports for missing materials
171
+ 4. Generates purchase requisitions if integrated with ERP
172
+ 5. Reserves materials for the production order
173
+
174
+ Material consumption is tracked in real-time as operators scan barcodes or enter consumption data manually. The system maintains lot traceability and automatically updates inventory levels.
175
+
176
+ 4.3 Work Order Routing
177
+
178
+ Production routing defines the sequence of operations required to manufacture a product. Each route consists of multiple work centers with specific:
179
+
180
+ - Operation sequence numbers
181
+ - Setup time requirements
182
+ - Run time per unit
183
+ - Required skills and certifications
184
+ - Quality control points
185
+ - Standard operating procedures
186
+
187
+ The MES uses routing information to:
188
+ - Calculate production lead times
189
+ - Schedule equipment and labor
190
+ - Track work-in-process inventory
191
+ - Monitor operation efficiency
192
+ - Enforce quality control procedures
193
+
194
+ ==============================================================================
195
+ 5. INVENTORY TRACKING
196
+ ==============================================================================
197
+
198
+ 5.1 Inventory Management Overview
199
+
200
+ The MES provides comprehensive inventory tracking capabilities for raw materials, work-in-process, and finished goods. All inventory movements are tracked with full traceability including lot numbers, serial numbers, and expiration dates.
201
+
202
+ Inventory Categories:
203
+ - Raw Materials: Components and materials consumed in production
204
+ - Work-in-Process: Partially completed products moving through production
205
+ - Finished Goods: Completed products ready for shipment
206
+ - Packaging Materials: Boxes, labels, and packaging components
207
+ - Maintenance Supplies: Spare parts and consumables for equipment
208
+
209
+ 5.2 Barcode Scanning and Data Capture
210
+
211
+ The system supports various barcode formats for efficient data capture:
212
+
213
+ Supported Barcode Types:
214
+ - Code 128 for general purpose identification
215
+ - GS1-128 for supply chain applications
216
+ - Data Matrix for small item marking
217
+ - QR codes for complex data encoding
218
+
219
+ Scanning Workflows:
220
+ 1. Material Receipt: Scan incoming materials to update inventory
221
+ 2. Material Issue: Scan materials when issued to production
222
+ 3. Production Reporting: Scan work orders to report progress
223
+ 4. Quality Control: Scan samples for testing and inspection
224
+ 5. Shipping: Scan finished goods during packaging and shipment
225
+
226
+ Mobile devices and handheld scanners integrate seamlessly with the MES for real-time data collection on the shop floor.
227
+
228
+ 5.3 Lot Traceability
229
+
230
+ The MES maintains complete lot genealogy for all materials and products. Traceability records include:
231
+
232
+ Forward Traceability:
233
+ - Which lots were used in specific production runs
234
+ - Where finished goods were shipped
235
+ - Customer delivery information
236
+ - Quality test results by lot
237
+
238
+ Backward Traceability:
239
+ - Source suppliers for raw materials
240
+ - Receipt dates and inspection results
241
+ - Production history and operators involved
242
+ - Environmental conditions during processing
243
+
244
+ This information is critical for regulatory compliance and enables rapid response to quality issues or recalls.
245
+
246
+ ==============================================================================
247
+ 6. QUALITY CONTROL MODULE
248
+ ==============================================================================
249
+
250
+ 6.1 Quality Control Planning
251
+
252
+ Quality control in the MES is based on predefined inspection plans that specify:
253
+
254
+ Inspection Points:
255
+ - Incoming material inspection
256
+ - In-process quality checks
257
+ - Final product inspection
258
+ - Statistical process control monitoring
259
+
260
+ For each inspection point, the system defines:
261
+ - Test procedures and specifications
262
+ - Sampling plans and frequencies
263
+ - Accept/reject criteria
264
+ - Required equipment and personnel
265
+ - Documentation requirements
266
+
267
+ 6.2 Statistical Process Control (SPC)
268
+
269
+ The MES includes built-in SPC capabilities for monitoring process variation and detecting trends that could indicate quality issues.
270
+
271
+ SPC Features:
272
+ - Real-time control charts (X-bar, R, p, np, c, u)
273
+ - Automatic out-of-control detection
274
+ - Process capability analysis (Cp, Cpk)
275
+ - Trend analysis and alerts
276
+ - Correlation analysis between variables
277
+
278
+ Control charts are automatically updated as measurement data is entered, providing immediate feedback to operators and quality personnel.
279
+
280
+ 6.3 Non-Conformance Management
281
+
282
+ When quality issues are detected, the MES provides a structured workflow for managing non-conformances:
283
+
284
+ 1. Issue Identification: Quality problems are logged with detailed descriptions
285
+ 2. Containment Actions: Immediate steps to prevent defective products from advancing
286
+ 3. Root Cause Analysis: Investigation to determine underlying causes
287
+ 4. Corrective Actions: Permanent solutions to prevent recurrence
288
+ 5. Verification: Confirmation that corrective actions are effective
289
+
290
+ The system tracks all non-conformances through resolution and maintains historical records for trend analysis and regulatory reporting.
291
+
292
+ ==============================================================================
293
+ 7. REPORTING AND ANALYTICS
294
+ ==============================================================================
295
+
296
+ 7.1 Standard Reports
297
+
298
+ The MES includes a comprehensive library of standard reports covering all aspects of manufacturing operations:
299
+
300
+ Production Reports:
301
+ - Daily Production Summary
302
+ - Work Order Status Report
303
+ - Equipment Utilization Analysis
304
+ - Labor Efficiency Report
305
+ - Schedule Adherence Summary
306
+
307
+ Quality Reports:
308
+ - Quality Control Dashboard
309
+ - Non-Conformance Trending
310
+ - First Pass Yield Analysis
311
+ - Customer Complaint Summary
312
+ - Supplier Quality Performance
313
+
314
+ Inventory Reports:
315
+ - Inventory Valuation Report
316
+ - Material Usage Analysis
317
+ - ABC Analysis by Value and Velocity
318
+ - Obsolete Inventory Report
319
+ - Lot Traceability Report
320
+
321
+ 7.2 Key Performance Indicators (KPIs)
322
+
323
+ The system tracks essential manufacturing KPIs with real-time dashboards and trend analysis:
324
+
325
+ Operational KPIs:
326
+ - Overall Equipment Effectiveness (OEE)
327
+ - First Pass Yield (FPY)
328
+ - On-Time Delivery Performance
329
+ - Inventory Turnover Ratio
330
+ - Labor Productivity
331
+
332
+ Quality KPIs:
333
+ - Defect Rate by Product
334
+ - Customer Complaint Rate
335
+ - Supplier Quality Rating
336
+ - Cost of Poor Quality
337
+ - Process Capability Indices
338
+
339
+ Financial KPIs:
340
+ - Manufacturing Cost per Unit
341
+ - Labor Cost Variance
342
+ - Material Cost Variance
343
+ - Overhead Absorption Rate
344
+ - Work Order Profitability
345
+
346
+ 7.3 Custom Report Builder
347
+
348
+ Advanced users can create custom reports using the built-in report designer:
349
+
350
+ Report Design Features:
351
+ - Drag-and-drop interface for easy report creation
352
+ - Access to all database tables and views
353
+ - Calculated fields and complex formulas
354
+ - Multiple output formats (PDF, Excel, CSV)
355
+ - Automated report scheduling and distribution
356
+
357
+ The report builder includes data visualization tools for creating charts, graphs, and dashboards that can be embedded in reports or displayed on production monitors.
358
+
359
+ ==============================================================================
360
+ 8. SYSTEM MAINTENANCE
361
+ ==============================================================================
362
+
363
+ 8.1 Database Maintenance
364
+
365
+ Regular database maintenance is essential for optimal MES performance:
366
+
367
+ Daily Tasks:
368
+ - Verify database backup completion
369
+ - Check transaction log size and growth
370
+ - Monitor active connections and locks
371
+ - Review system error logs
372
+
373
+ Weekly Tasks:
374
+ - Update database statistics
375
+ - Rebuild fragmented indexes
376
+ - Archive old transaction data
377
+ - Test backup restore procedures
378
+
379
+ Monthly Tasks:
380
+ - Review database growth trends
381
+ - Optimize query performance
382
+ - Update system documentation
383
+ - Verify disaster recovery procedures
384
+
385
+ 8.2 Performance Monitoring
386
+
387
+ The MES includes built-in performance monitoring tools to identify and resolve system bottlenecks:
388
+
389
+ Performance Metrics:
390
+ - Database response times
391
+ - Network latency measurements
392
+ - Server CPU and memory utilization
393
+ - Application response times
394
+ - User session statistics
395
+
396
+ Performance alerts are automatically generated when thresholds are exceeded, enabling proactive system management.
397
+
398
+ 8.3 Security Management
399
+
400
+ Security maintenance includes regular updates and monitoring:
401
+
402
+ Security Tasks:
403
+ - Install security patches and updates
404
+ - Review user accounts and permissions
405
+ - Monitor login attempts and access patterns
406
+ - Update antivirus and security software
407
+ - Conduct security vulnerability assessments
408
+
409
+ The system maintains audit logs of all user activities and system changes for security and compliance purposes.
410
+
411
+ ==============================================================================
412
+ 9. TROUBLESHOOTING
413
+ ==============================================================================
414
+
415
+ 9.1 Common Issues and Solutions
416
+
417
+ Database Connection Problems:
418
+ Symptoms: Users cannot log in, system responds slowly
419
+ Solutions:
420
+ - Verify SQL Server service is running
421
+ - Check network connectivity between client and server
422
+ - Validate connection string configuration
423
+ - Review firewall settings
424
+
425
+ Barcode Scanner Issues:
426
+ Symptoms: Scanner not reading barcodes, incorrect data capture
427
+ Solutions:
428
+ - Clean scanner lens and check lighting conditions
429
+ - Verify barcode format matches system configuration
430
+ - Update scanner drivers and firmware
431
+ - Test with known good barcodes
432
+
433
+ Performance Issues:
434
+ Symptoms: Slow response times, timeouts
435
+ Solutions:
436
+ - Check server resource utilization
437
+ - Review database index statistics
438
+ - Optimize slow-running queries
439
+ - Archive old transaction data
440
+
441
+ 9.2 Error Messages and Codes
442
+
443
+ The MES uses standardized error codes for easier troubleshooting:
444
+
445
+ Database Errors (ERR-DB-xxx):
446
+ ERR-DB-001: Connection timeout - Check network and server status
447
+ ERR-DB-002: Login failed - Verify username and password
448
+ ERR-DB-003: Insufficient permissions - Contact administrator
449
+
450
+ Application Errors (ERR-APP-xxx):
451
+ ERR-APP-001: Invalid work order number - Verify order exists
452
+ ERR-APP-002: Material not available - Check inventory levels
453
+ ERR-APP-003: Quality test failed - Review specifications
454
+
455
+ System Errors (ERR-SYS-xxx):
456
+ ERR-SYS-001: Service unavailable - Restart MES services
457
+ ERR-SYS-002: Configuration error - Check system settings
458
+ ERR-SYS-003: License expired - Contact vendor for renewal
459
+
460
+ 9.3 Support Contacts
461
+
462
+ For technical support beyond this troubleshooting guide:
463
+
464
+ Level 1 Support (General Issues):
465
+ - Phone: 1-800-MES-HELP
466
+ - Email: support@mes-systems.com
467
+ - Hours: Monday-Friday 8:00 AM - 6:00 PM EST
468
+
469
+ Level 2 Support (Advanced Technical Issues):
470
+ - Email: advanced-support@mes-systems.com
471
+ - Response time: Within 4 hours during business days
472
+
473
+ Emergency Support (Critical System Down):
474
+ - Phone: 1-800-MES-911
475
+ - Available 24/7/365
476
+ - Response time: Within 1 hour
477
+
478
+ ==============================================================================
479
+ 10. APPENDICES
480
+ ==============================================================================
481
+
482
+ Appendix A: Database Schema
483
+
484
+ The MES database consists of the following primary tables:
485
+
486
+ Production Tables:
487
+ - ProductionOrders: Master production order information
488
+ - WorkOrders: Individual work order details
489
+ - Operations: Production operation definitions
490
+ - Routes: Product routing specifications
491
+
492
+ Inventory Tables:
493
+ - Materials: Master material information
494
+ - Inventory: Current inventory positions
495
+ - Transactions: All inventory movements
496
+ - Lots: Lot and serial number tracking
497
+
498
+ Quality Tables:
499
+ - QualityPlans: Inspection plan definitions
500
+ - TestResults: Quality test measurements
501
+ - NonConformances: Quality issue records
502
+ - Specifications: Product quality specifications
503
+
504
+ Appendix B: API Documentation
505
+
506
+ The MES provides REST APIs for integration with external systems:
507
+
508
+ Authentication Endpoints:
509
+ POST /api/auth/login - User authentication
510
+ POST /api/auth/refresh - Token refresh
511
+ POST /api/auth/logout - User logout
512
+
513
+ Production Endpoints:
514
+ GET /api/production/orders - Retrieve production orders
515
+ POST /api/production/orders - Create new production order
516
+ PUT /api/production/orders/{id} - Update production order
517
+ DELETE /api/production/orders/{id} - Delete production order
518
+
519
+ Inventory Endpoints:
520
+ GET /api/inventory/materials - Get material list
521
+ POST /api/inventory/transactions - Record inventory transaction
522
+ GET /api/inventory/lots/{lot} - Get lot information
523
+
524
+ All API calls require authentication tokens and return JSON formatted responses.
525
+
526
+ Appendix C: System Configuration Files
527
+
528
+ Key configuration files and their purposes:
529
+
530
+ database.config: Database connection settings
531
+ security.config: User authentication and authorization
532
+ integration.config: External system integration settings
533
+ performance.config: System performance parameters
534
+
535
+ These files should only be modified by trained administrators following proper change control procedures.
embedding_config.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.embeddings import HuggingFaceEmbeddings
2
+ from utils.vector_store import get_vector_store
3
+ import os
4
+
5
+
6
+ EMBEDDING_CONFIGS = {
7
+ "General-purpose (bge-large-en)": HuggingFaceEmbeddings(
8
+ model_name="BAAI/bge-large-en",
9
+ model_kwargs={"device": "cpu"}, # or "cuda" if you have GPU
10
+ encode_kwargs={"normalize_embeddings": True}
11
+ ),
12
+ "Fast & lightweight (bge-small-en)": HuggingFaceEmbeddings(
13
+ model_name="BAAI/bge-small-en",
14
+ model_kwargs={"device": "cpu"},
15
+ encode_kwargs={"normalize_embeddings": True}
16
+ ),
17
+ "QA optimized (e5-large-v2)": HuggingFaceEmbeddings(
18
+ model_name="intfloat/e5-large-v2",
19
+ model_kwargs={"device": "cpu"},
20
+ encode_kwargs={"normalize_embeddings": True}
21
+ ),
22
+ "Instruction-tuned (instructor-large)": HuggingFaceEmbeddings(
23
+ model_name="hkunlp/instructor-large",
24
+ model_kwargs={"device": "cpu"},
25
+ encode_kwargs={"normalize_embeddings": True}
26
+ ),
27
+ }
rebuild_vector_stores.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils.vector_store import rebuild_vector_store
2
+
3
+ # Rebuild MES manual vector store
4
+ rebuild_vector_store(
5
+ doc_path="docs/mes",
6
+ persist_directory="./vector_stores/mes_db"
7
+ )
8
+
9
+ # Rebuild technical document set
10
+ rebuild_vector_store(
11
+ doc_path="docs/technical",
12
+ persist_directory="./vector_stores/tech_db"
13
+ )
14
+
15
+ # Rebuild general document set
16
+ rebuild_vector_store(
17
+ doc_path="docs/general",
18
+ persist_directory="./vector_stores/general_db"
19
+ )
requirements.txt ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # # Core API
2
+ # fastapi==0.104.1
3
+ # uvicorn[standard]==0.24.0
4
+ # gunicorn==21.2.0
5
+ # pydantic==2.5.0
6
+ # requests==2.31.0
7
+ # python-dotenv==1.0.0
8
+
9
+ # # LangChain + Vector DB
10
+ # langchain==0.1.0
11
+ # langchain-community==0.0.10
12
+ # chromadb==0.4.18
13
+ # tiktoken==0.5.2
14
+
15
+ # # Embeddings / Transformers
16
+ # sentence-transformers==2.3.0
17
+ # transformers==4.35.0
18
+ # huggingface-hub>=0.13.0,<1.0
19
+
20
+ # # CPU-only torch (lightweight)
21
+ # torch==2.7.1
22
+
23
+ # # Build tools
24
+ # setuptools>=70.0.0
25
+ # wheel>=0.41.0
26
+
27
+
28
+ # Python 11 version not working -----------
29
+
30
+
31
+
32
+ fastapi
33
+ uvicorn
34
+ langchain
35
+ chromadb
36
+ openai
37
+ tiktoken
38
+ langchain-community
39
+ transformers
40
+ torch
41
+ sentence-transformers
42
+ huggingface_hub
43
+ python-dotenv
44
+ numpy
45
+ pathlib2
46
+ gunicorn
47
+
48
+
49
+ # fastapi==0.104.1
50
+ # uvicorn[standard]==0.24.0
51
+ # requests==2.31.0
52
+ # python-dotenv==1.0.0
53
+ # pydantic==2.5.0
54
+ # chromadb==0.4.18
55
+ # langchain==0.1.0
56
+ # langchain-community==0.0.10
57
+ # sentence-transformers==2.2.2
58
+ # numpy==1.24.3
59
+ # tiktoken==0.5.2
60
+
61
+ # # Document processing
62
+ # PyPDF2==3.0.1
63
+ # python-docx==0.8.11
64
+ # openpyxl==3.1.2
65
+ # python-multipart==0.0.6
66
+
67
+ # # Additional dependencies
68
+ # typing-extensions==4.8.0
69
+ # pathlib2==2.3.7
70
+
71
+ # # Render-specific optimizations
72
+ # gunicorn==21.2.0
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.11.9
test_api.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+
5
+ def test_api_connection():
6
+ """Test if the API is running"""
7
+ try:
8
+ response = requests.get("http://localhost:8000/", timeout=5)
9
+ print("✅ API is running!")
10
+ print(f"Status: {response.json()}")
11
+ return True
12
+ except requests.exceptions.ConnectionError:
13
+ print("❌ Cannot connect to API. Make sure it's running on http://localhost:8000")
14
+ return False
15
+ except Exception as e:
16
+ print(f"❌ Error connecting to API: {e}")
17
+ return False
18
+
19
+
20
+ def ask_question(question):
21
+ """Send a question to the API"""
22
+ try:
23
+ url = "http://localhost:8000/ask"
24
+ headers = {"Content-Type": "application/json"}
25
+ data = {"query": question}
26
+
27
+ print("🤔 Processing your question...")
28
+ response = requests.post(url, headers=headers, json=data, timeout=30)
29
+
30
+ if response.status_code == 200:
31
+ result = response.json()
32
+ print("\n" + "="*60)
33
+ print("📝 ANSWER:")
34
+ print("="*60)
35
+ print(result.get("answer", "No answer provided"))
36
+
37
+ print(f"\n🤖 Model used: {result.get('model_used', 'Unknown')}")
38
+
39
+ print(
40
+ f"\n 🏪 Vector store used: {result.get("vector_store_used", 'Unknown')}")
41
+
42
+ if "sources" in result and result["sources"]:
43
+ print(f"\n📚 Sources ({len(result['sources'])}):")
44
+ for i, source in enumerate(result["sources"], 1):
45
+ print(f"{i}. {source.get('content', 'No content')}")
46
+ print("="*60)
47
+ else:
48
+ print(f"❌ Error {response.status_code}: {response.text}")
49
+
50
+ except requests.exceptions.Timeout:
51
+ print("⏰ Request timed out. The API might be processing a complex query.")
52
+ except Exception as e:
53
+ print(f"❌ Error asking question: {e}")
54
+
55
+
56
+ def interactive_loop():
57
+ """Main interactive loop"""
58
+ print("🚀 FastAPI Interactive Tester")
59
+ print("="*40)
60
+
61
+ # Test connection first
62
+ if not test_api_connection():
63
+ print("\nPlease start your FastAPI server first:")
64
+ print("cd rag_app")
65
+ print("python api/main.py")
66
+ return
67
+
68
+ print("\n💡 Type your questions below!")
69
+ print("Commands:")
70
+ print(" • Type any question to ask the API")
71
+ print(" • Type 'quit', 'exit', or 'q' to exit")
72
+ print(" • Type 'status' to check API status")
73
+ print(" • Press Ctrl+C to exit anytime")
74
+ print("-" * 40)
75
+
76
+ while True:
77
+ try:
78
+ # Get user input
79
+ question = input("\n❓ Your question: ").strip()
80
+
81
+ # Handle special commands
82
+ if question.lower() in ['quit', 'exit', 'q']:
83
+ print("👋 Goodbye!")
84
+ break
85
+ elif question.lower() == 'status':
86
+ test_api_connection()
87
+ continue
88
+ elif not question:
89
+ print("Please enter a question or 'quit' to exit.")
90
+ continue
91
+
92
+ # Ask the question
93
+ ask_question(question)
94
+
95
+ except KeyboardInterrupt:
96
+ print("\n\n👋 Goodbye!")
97
+ break
98
+ except Exception as e:
99
+ print(f"❌ Unexpected error: {e}")
100
+
101
+
102
+ if __name__ == "__main__":
103
+ interactive_loop()
test_embeddings_retriever.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # # from langchain_chroma import Chroma
2
+ # # from langchain_openai import OpenAIEmbeddings
3
+ # from langchain_community.embeddings import HuggingFaceEmbeddings
4
+ # from utils.vector_store import get_vector_store
5
+ # import os
6
+
7
+
8
+ # # Define different embedding model options
9
+ # # EMBEDDING_CONFIGS = {
10
+ # # "Accuracy (OpenAI text-embedding-3-large)": OpenAIEmbeddings(model="text-embedding-3-large"),
11
+ # # "Performance (OpenAI text-embedding-3-small)": OpenAIEmbeddings(model="text-embedding-3-small"),
12
+ # # "Instruction-based (HuggingFace bge-large-en)": HuggingFaceEmbeddings(model_name="BAAI/bge-large-en"),
13
+ # # "QA Optimized (HuggingFace e5-large-v2)": HuggingFaceEmbeddings(model_name="intfloat/e5-large-v2"),
14
+ # # }
15
+
16
+
17
+ # EMBEDDING_CONFIGS = {
18
+ # "General-purpose (bge-large-en)": HuggingFaceEmbeddings(
19
+ # model_name="BAAI/bge-large-en",
20
+ # model_kwargs={"device": "cpu"}, # or "cuda" if you have GPU
21
+ # encode_kwargs={"normalize_embeddings": True}
22
+ # ),
23
+ # "Fast & lightweight (bge-small-en)": HuggingFaceEmbeddings(
24
+ # model_name="BAAI/bge-small-en",
25
+ # model_kwargs={"device": "cpu"},
26
+ # encode_kwargs={"normalize_embeddings": True}
27
+ # ),
28
+ # "QA optimized (e5-large-v2)": HuggingFaceEmbeddings(
29
+ # model_name="intfloat/e5-large-v2",
30
+ # model_kwargs={"device": "cpu"},
31
+ # encode_kwargs={"normalize_embeddings": True}
32
+ # ),
33
+ # "Instruction-tuned (instructor-large)": HuggingFaceEmbeddings(
34
+ # model_name="hkunlp/instructor-large",
35
+ # model_kwargs={"device": "cpu"},
36
+ # encode_kwargs={"normalize_embeddings": True}
37
+ # ),
38
+ # }
39
+
40
+ # # Default vector store path
41
+ # VECTOR_STORE_PATH = "./vector_stores/mes_db"
42
+
43
+
44
+ # def test_retriever_with_embeddings(query: str, embedding_model, k: int = 3):
45
+ # """Retrieve documents using a specific embedding model."""
46
+ # vector_store = get_vector_store(
47
+ # persist_directory=VECTOR_STORE_PATH,
48
+ # embedding=embedding_model
49
+ # )
50
+ # retriever = vector_store.as_retriever(search_kwargs={"k": k})
51
+ # docs = retriever.get_relevant_documents(query)
52
+
53
+ # # Deduplicate based on page_content
54
+ # seen = set()
55
+ # unique_docs = []
56
+ # for doc in docs:
57
+ # if doc.page_content not in seen:
58
+ # seen.add(doc.page_content)
59
+ # unique_docs.append(doc)
60
+
61
+ # return unique_docs
62
+
63
+
64
+ # def compare_embeddings(query: str, k: int = 3):
65
+ # print(f"\n=== Comparing embeddings for: '{query}' ===\n")
66
+
67
+ # for name, embedding_model in EMBEDDING_CONFIGS.items():
68
+ # try:
69
+ # print(f"🔍 {name}:")
70
+ # print("-" * 50)
71
+ # docs = test_retriever_with_embeddings(query, embedding_model, k)
72
+ # for i, doc in enumerate(docs, 1):
73
+ # source = doc.metadata.get("source", "unknown")
74
+ # page = doc.metadata.get("page", "N/A")
75
+ # preview = doc.page_content[:300]
76
+ # if len(doc.page_content) > 300:
77
+ # preview += "..."
78
+ # print(f"--- Chunk #{i} ---")
79
+ # print(f"Source: {source} | Page: {page}")
80
+ # print(preview)
81
+ # print()
82
+ # print("\n" + "=" * 60 + "\n")
83
+ # except Exception as e:
84
+ # print(f"❌ Error with {name}: {e}\n")
85
+
86
+
87
+ # if __name__ == "__main__":
88
+ # print("Embedding Model Benchmark Tool")
89
+ # print("\nType 'compare: <question>' to compare all embeddings")
90
+ # print("Type 'exit' to quit\n")
91
+
92
+ # while True:
93
+ # user_input = input("\nEnter your question: ").strip()
94
+
95
+ # if user_input.lower() == "exit":
96
+ # break
97
+ # elif user_input.lower().startswith("compare: "):
98
+ # query = user_input[9:]
99
+ # compare_embeddings(query)
100
+ # else:
101
+ # print("Please use the format: compare: <question>")
102
+
103
+
104
+ from utils.vector_store import get_vector_store
105
+
106
+
107
+ def test_retriever_with_embeddings(query: str, embedding_model, k: int = 3, vector_store_path="./chroma_db"):
108
+ """Test retriever with a specific embedding model and vector store"""
109
+ vector_store = get_vector_store(
110
+ persist_directory=vector_store_path, embedding=embedding_model)
111
+ retriever = vector_store.as_retriever(search_kwargs={"k": k})
112
+ docs = retriever.get_relevant_documents(query)
113
+
114
+ # Deduplicate based on page_content
115
+ seen = set()
116
+ unique_docs = []
117
+ for doc in docs:
118
+ if doc.page_content not in seen:
119
+ seen.add(doc.page_content)
120
+ unique_docs.append(doc)
121
+
122
+ print(f"\nUsing vector store: {vector_store_path}")
123
+ print(f"Top {len(unique_docs)} unique chunks retrieved for: '{query}'\n")
124
+
125
+ for i, doc in enumerate(unique_docs, 1):
126
+ source = doc.metadata.get("source", "unknown")
127
+ page = doc.metadata.get("page", "N/A")
128
+ print(f"--- Chunk #{i} ---")
129
+ print(f"Source: {source} | Page: {page}")
130
+ preview = doc.page_content[:300]
131
+ if len(doc.page_content) > 300:
132
+ preview += "..."
133
+ print(preview)
134
+ print()
135
+
136
+
137
+ def compare_retrievers_with_embeddings(query: str, embedding_model, k: int = 3):
138
+ """Compare results from different vector stores using the same embedding model"""
139
+ stores = {
140
+ "MES Manual": "./vector_stores/mes_db",
141
+ "Technical Docs": "./vector_stores/tech_db",
142
+ "General Docs": "./vector_stores/general_db"
143
+ }
144
+
145
+ print(f"\n=== Comparing retrievers for: '{query}' ===\n")
146
+
147
+ for store_name, store_path in stores.items():
148
+ try:
149
+ print(f"🔍 {store_name}:")
150
+ print("-" * 50)
151
+ test_retriever_with_embeddings(
152
+ query, embedding_model, k=k, vector_store_path=store_path)
153
+ print("\n" + "="*60 + "\n")
154
+ except Exception as e:
155
+ print(f"❌ Could not access {store_name}: {e}\n")
156
+
157
+
158
+ if __name__ == "__main__":
159
+ from embedding_config import EMBEDDING_CONFIGS
160
+
161
+ print("Multi-Vector Store RAG Tester (with Embeddings)")
162
+ print("\nAvailable commands:")
163
+ print(" - Enter a question to test default store")
164
+ print(" - Type 'mes: <question>' for MES manual")
165
+ print(" - Type 'tech: <question>' for technical docs")
166
+ print(" - Type 'general: <question>' for general docs")
167
+ print(" - Type 'compare: <question>' to compare all stores")
168
+ print(" - Type 'exit' to quit")
169
+
170
+ # Choose embedding model at start
171
+ print("\nAvailable Embedding Models:")
172
+ for i, name in enumerate(EMBEDDING_CONFIGS.keys(), 1):
173
+ print(f" {i}. {name}")
174
+ choice = int(input("Select embedding model number: ").strip())
175
+ embedding_model = list(EMBEDDING_CONFIGS.values())[choice - 1]
176
+
177
+ while True:
178
+ user_input = input("\nEnter your question: ").strip()
179
+
180
+ if user_input.lower() == "exit":
181
+ break
182
+ elif user_input.lower().startswith("mes: "):
183
+ query = user_input[5:]
184
+ test_retriever_with_embeddings(
185
+ query, embedding_model, vector_store_path="./vector_stores/mes_db")
186
+ elif user_input.lower().startswith("tech: "):
187
+ query = user_input[6:]
188
+ test_retriever_with_embeddings(
189
+ query, embedding_model, vector_store_path="./vector_stores/tech_db")
190
+ elif user_input.lower().startswith("general: "):
191
+ query = user_input[9:]
192
+ test_retriever_with_embeddings(
193
+ query, embedding_model, vector_store_path="./vector_stores/general_db")
194
+ elif user_input.lower().startswith("compare: "):
195
+ query = user_input[9:]
196
+ compare_retrievers_with_embeddings(query, embedding_model)
197
+ else:
198
+ test_retriever_with_embeddings(
199
+ user_input, embedding_model) # Default store
test_retriever.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # from utils.vector_store import get_vector_store
2
+
3
+ # def test_retriever(query: str, k: int = 3, vector_store_path="./chroma_db"):
4
+ # """Test retriever with specific vector store"""
5
+ # vector_store = get_vector_store(persist_directory=vector_store_path)
6
+ # retriever = vector_store.as_retriever(search_kwargs={"k": k})
7
+ # docs = retriever.get_relevant_documents(query)
8
+
9
+ # # Deduplicate based on page_content
10
+ # seen = set()
11
+ # unique_docs = []
12
+ # for doc in docs:
13
+ # if doc.page_content not in seen:
14
+ # seen.add(doc.page_content)
15
+ # unique_docs.append(doc)
16
+
17
+ # print(f"\nUsing vector store: {vector_store_path}")
18
+ # print(f"Top {len(unique_docs)} unique chunks retrieved for: '{query}'\n")
19
+
20
+ # for i, doc in enumerate(unique_docs, 1):
21
+ # source = doc.metadata.get("source", "unknown")
22
+ # page = doc.metadata.get("page", "N/A")
23
+ # print(f"--- Chunk #{i} ---")
24
+ # print(f"Source: {source} | Page: {page}")
25
+ # preview = doc.page_content[:300]
26
+ # if len(doc.page_content) > 300:
27
+ # preview += "..."
28
+ # print(preview)
29
+ # print()
30
+
31
+
32
+ # def compare_retrievers(query: str, k: int = 3):
33
+ # """Compare results from different vector stores"""
34
+ # stores = {
35
+ # "MES Manual": "./vector_stores/mes_db",
36
+ # "Technical Docs": "./vector_stores/tech_db",
37
+ # "General Docs": "./vector_stores/general_db"
38
+ # }
39
+
40
+ # print(f"\n=== Comparing retrievers for: '{query}' ===\n")
41
+
42
+ # for store_name, store_path in stores.items():
43
+ # try:
44
+ # print(f"🔍 {store_name}:")
45
+ # print("-" * 50)
46
+ # test_retriever(query, k=k, vector_store_path=store_path)
47
+ # print("\n" + "="*60 + "\n")
48
+ # except Exception as e:
49
+ # print(f"❌ Could not access {store_name}: {e}\n")
50
+
51
+
52
+ # if __name__ == "__main__":
53
+ # print("Multi-Vector Store RAG Tester")
54
+ # print("\nAvailable commands:")
55
+ # print(" - Enter a question to test default store")
56
+ # print(" - Type 'mes: <question>' for MES manual")
57
+ # print(" - Type 'tech: <question>' for technical docs")
58
+ # print(" - Type 'general: <question>' for general docs")
59
+ # print(" - Type 'compare: <question>' to compare all stores")
60
+ # print(" - Type 'exit' to quit")
61
+
62
+ # while True:
63
+ # user_input = input("\nEnter your question: ").strip()
64
+
65
+ # if user_input.lower() == "exit":
66
+ # break
67
+ # elif user_input.lower().startswith("mes: "):
68
+ # query = user_input[5:]
69
+ # test_retriever(query, vector_store_path="./vector_stores/mes_db")
70
+ # elif user_input.lower().startswith("tech: "):
71
+ # query = user_input[6:]
72
+ # test_retriever(query, vector_store_path="./vector_stores/tech_db")
73
+ # elif user_input.lower().startswith("general: "):
74
+ # query = user_input[9:]
75
+ # test_retriever(query, vector_store_path="./vector_stores/general_db")
76
+ # elif user_input.lower().startswith("compare: "):
77
+ # query = user_input[9:]
78
+ # compare_retrievers(query)
79
+ # else:
80
+ # test_retriever(user_input) # Default store
81
+
82
+
83
+ from utils.vector_store import get_vector_store
84
+
85
+
86
+ def test_retriever(query: str, k: int = 3, vector_store_path="./chroma_db"):
87
+ """Test retriever with specific vector store"""
88
+ vector_store = get_vector_store(persist_directory=vector_store_path)
89
+ retriever = vector_store.as_retriever(search_kwargs={"k": k})
90
+ docs = retriever.get_relevant_documents(query)
91
+
92
+ # Deduplicate based on page_content
93
+ seen = set()
94
+ unique_docs = []
95
+ for doc in docs:
96
+ if doc.page_content not in seen:
97
+ seen.add(doc.page_content)
98
+ unique_docs.append(doc)
99
+
100
+ print(f"\nUsing vector store: {vector_store_path}")
101
+ print(f"Top {len(unique_docs)} unique chunks retrieved for: '{query}'\n")
102
+
103
+ for i, doc in enumerate(unique_docs, 1):
104
+ source = doc.metadata.get("source", "unknown")
105
+ page = doc.metadata.get("page", "N/A")
106
+ print(f"--- Chunk #{i} ---")
107
+ print(f"Source: {source} | Page: {page}")
108
+ preview = doc.page_content[:300]
109
+ if len(doc.page_content) > 300:
110
+ preview += "..."
111
+ print(preview)
112
+ print()
113
+
114
+
115
+ def compare_retrievers(query: str, k: int = 3):
116
+ """Compare results from different vector stores"""
117
+ stores = {
118
+ "MES Manual": "./vector_stores/mes_db",
119
+ "Technical Docs": "./vector_stores/tech_db",
120
+ "General Docs": "./vector_stores/general_db"
121
+ }
122
+
123
+ print(f"\n=== Comparing retrievers for: '{query}' ===\n")
124
+
125
+ for store_name, store_path in stores.items():
126
+ try:
127
+ print(f"🔍 {store_name}:")
128
+ print("-" * 50)
129
+ test_retriever(query, k=k, vector_store_path=store_path)
130
+ print("\n" + "="*60 + "\n")
131
+ except Exception as e:
132
+ print(f"❌ Could not access {store_name}: {e}\n")
133
+
134
+
135
+ if __name__ == "__main__":
136
+ print("Multi-Vector Store RAG Tester")
137
+ print("\nAvailable commands:")
138
+ print(" - Enter a question to test default store")
139
+ print(" - Type 'mes: <question>' for MES manual")
140
+ print(" - Type 'tech: <question>' for technical docs")
141
+ print(" - Type 'general: <question>' for general docs")
142
+ print(" - Type 'compare: <question>' to compare all stores")
143
+ print(" - Type 'exit' to quit")
144
+
145
+ while True:
146
+ user_input = input("\nEnter your question: ").strip()
147
+
148
+ if user_input.lower() == "exit":
149
+ break
150
+ elif user_input.lower().startswith("mes: "):
151
+ query = user_input[5:]
152
+ test_retriever(query, vector_store_path="./vector_stores/mes_db")
153
+ elif user_input.lower().startswith("tech: "):
154
+ query = user_input[6:]
155
+ test_retriever(query, vector_store_path="./vector_stores/tech_db")
156
+ elif user_input.lower().startswith("general: "):
157
+ query = user_input[9:]
158
+ test_retriever(
159
+ query, vector_store_path="./vector_stores/general_db")
160
+ elif user_input.lower().startswith("compare: "):
161
+ query = user_input[9:]
162
+ compare_retrievers(query)
163
+ else:
164
+ test_retriever(user_input) # Default store
utils/__init__.py ADDED
File without changes
utils/helpers/chat_mapper.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # def map_answer_to_chat_response(answer_obj):
2
+ # """
3
+ # Map backend output to a single assistant message for the Vercel Chatbot SDK.
4
+ # Combines the main answer with nicely formatted sources.
5
+ # """
6
+ # # Start with the main answer
7
+ # full_content = answer_obj["answer"].strip()
8
+
9
+ # # Format sources if any
10
+ # if answer_obj.get("sources"):
11
+ # sources_lines = []
12
+ # for i, src in enumerate(answer_obj["sources"], 1):
13
+ # content_preview = src["content"].strip()
14
+ # metadata = src.get("metadata", {})
15
+ # source_info = f"Source {i}"
16
+ # if "source" in metadata:
17
+ # source_info += f" ({metadata['source']})"
18
+ # if "page" in metadata:
19
+ # source_info += f", Page {metadata['page']}"
20
+ # # Limit content preview to first 300 characters
21
+ # content_preview = (
22
+ # content_preview[:300] + "...") if len(content_preview) > 300 else content_preview
23
+ # sources_lines.append(f"{source_info}: {content_preview}")
24
+
25
+ # # Add sources as a block after the main answer
26
+ # full_content += "\n\n📚 Sources:\n" + "\n".join(sources_lines)
27
+
28
+ # # Return in the format expected by the Vercel Chatbot SDK
29
+ # return {
30
+ # "id": "chatcmpl-local-1",
31
+ # "object": "chat.completion",
32
+ # "created": __import__("time").time(),
33
+ # "model": answer_obj.get("model_used", "unknown-model"),
34
+ # "choices": [
35
+ # {
36
+ # "index": 0,
37
+ # "message": {"role": "assistant", "content": full_content},
38
+ # "finish_reason": "stop"
39
+ # }
40
+ # ]
41
+ # }
42
+
43
+
44
+ def map_answer_to_chat_response(answer_obj):
45
+ """
46
+ Map backend output to a clean custom response schema.
47
+ """
48
+ return {
49
+ "id": f"chatmsg-{int(__import__('time').time())}",
50
+ "createdAt": __import__("time").time(),
51
+ "model": answer_obj.get("model_used", "unknown-model"),
52
+ "answer": answer_obj["answer"].strip(),
53
+ "sources": [
54
+ {
55
+ "id": f"source-{i}",
56
+ "content": src["content"].strip(),
57
+ "metadata": src.get("metadata", {})
58
+ }
59
+ for i, src in enumerate(answer_obj.get("sources", []), 1)
60
+ ]
61
+ }
utils/loader.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from langchain.document_loaders import TextLoader
3
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
4
+ import os
5
+
6
+
7
+ def load_documents(directory):
8
+ docs = []
9
+ for filename in os.listdir(directory):
10
+ if filename.endswith(".txt") or filename.endswith(".md"):
11
+ loader = TextLoader(os.path.join(
12
+ directory, filename), encoding='utf-8')
13
+ docs.extend(loader.load())
14
+ return docs
15
+
16
+
17
+ def split_documents(documents, chunk_size=1000, chunk_overlap=200, separators=["\n\n", "\n", " ", ""], length_function=len):
18
+ splitter = RecursiveCharacterTextSplitter(
19
+ chunk_size=chunk_size, chunk_overlap=chunk_overlap, separators=separators, length_function=length_function)
20
+ return splitter.split_documents(documents)
utils/rebuild_vector_stores.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ from langchain_community.embeddings import HuggingFaceEmbeddings
4
+ from langchain_community.vectorstores import Chroma
5
+
6
+
7
+ def rebuild_vector_store(doc_path="docs", persist_directory="./chroma_db"):
8
+ """
9
+ Completely reset and rebuild a Chroma vector store from given documents.
10
+ Deletes the old store directory before building a new one.
11
+ """
12
+ # 1. Remove old vector store directory if it exists
13
+ if os.path.exists(persist_directory):
14
+ print(f"🗑️ Removing existing vector store at {persist_directory}...")
15
+ shutil.rmtree(persist_directory)
16
+
17
+ # 2. Load and split documents
18
+ print(f"📄 Loading documents from {doc_path}...")
19
+ documents = load_documents(doc_path)
20
+ chunks = split_documents(documents)
21
+ print(f"✅ Loaded and split {len(chunks)} chunks.")
22
+
23
+ # 3. Create embeddings (fast & efficient model)
24
+ embeddings = HuggingFaceEmbeddings(
25
+ model_name="all-MiniLM-L6-v2", # or switch to mpnet for higher quality
26
+ model_kwargs={'device': 'cpu'}
27
+ )
28
+
29
+ # 4. Build vector store
30
+ print("⚙️ Building new vector store...")
31
+ vectordb = Chroma.from_documents(
32
+ documents=chunks,
33
+ embedding=embeddings,
34
+ persist_directory=persist_directory
35
+ )
36
+
37
+ # 5. Persist the new store
38
+ vectordb.persist()
39
+ print(f"✅ New vector store saved at {persist_directory}")
40
+
41
+ return vectordb
utils/vector_store.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ from langchain_community.embeddings import HuggingFaceEmbeddings
4
+ from langchain_community.vectorstores import Chroma
5
+ from .loader import load_documents, split_documents
6
+
7
+ # ---------------------------
8
+ # Embedding configuration options
9
+ # ---------------------------
10
+
11
+ # 1️⃣ High performance / fast (good for large datasets, real-time apps)
12
+ # embeddings = HuggingFaceEmbeddings(
13
+ # model_name="all-MiniLM-L6-v2", # ~22M params, fast & low memory
14
+ # model_kwargs={'device': 'cpu'} # Use 'cuda' for GPU
15
+ # )
16
+
17
+ # 2️⃣ High accuracy / better semantic matching (slower, bigger model)
18
+ embeddings = HuggingFaceEmbeddings(
19
+ model_name="all-mpnet-base-v2", # ~109M params, top accuracy for general tasks
20
+ model_kwargs={'device': 'cpu'}
21
+ )
22
+
23
+ # 3️⃣ Instruction-based materials (good for “how-to” guides, step-by-step docs)
24
+ # embeddings = HuggingFaceEmbeddings(
25
+ # model_name="hkunlp/instructor-base", # Trained for instruction-following embeddings
26
+ # model_kwargs={'device': 'cpu'}
27
+ # )
28
+
29
+ # 4️⃣ QA-focused (retrieval tuned for question-answering use cases)
30
+ # embeddings = HuggingFaceEmbeddings(
31
+ # model_name="sentence-transformers/multi-qa-mpnet-base-dot-v1",
32
+ # model_kwargs={'device': 'cpu'}
33
+ # )
34
+
35
+ # 👉 Pick one of the above and uncomment it
36
+
37
+ # ---------------------------
38
+ # Build vector store
39
+ # ---------------------------
40
+
41
+
42
+ def build_vector_store(doc_path="docs", persist_directory="./chroma_db"):
43
+ documents = load_documents(doc_path)
44
+ chunks = split_documents(documents)
45
+
46
+ vectordb = Chroma.from_documents(
47
+ documents=chunks,
48
+ embedding=embeddings,
49
+ persist_directory=persist_directory
50
+ )
51
+ vectordb.persist()
52
+ return vectordb
53
+
54
+ # ---------------------------
55
+ # Load existing vector store
56
+ # ---------------------------
57
+
58
+
59
+ def get_vector_store(persist_directory="./vector_stores/tech_db", embedding=embeddings):
60
+
61
+ vectordb = Chroma(
62
+ persist_directory=persist_directory,
63
+ embedding_function=embedding
64
+ )
65
+ return vectordb
66
+
67
+ # ---------------------------
68
+ # Rebuild (delete & recreate) vector store
69
+ # ---------------------------
70
+
71
+
72
+ def rebuild_vector_store(doc_path="docs", persist_directory="./chroma_db"):
73
+ """
74
+ Completely reset and rebuild a Chroma vector store from given documents.
75
+ Deletes the old store directory before building a new one.
76
+ """
77
+ # Remove old vector store
78
+ if os.path.exists(persist_directory):
79
+ print(f"🗑️ Removing existing vector store at {persist_directory}...")
80
+ shutil.rmtree(persist_directory)
81
+
82
+ # Load and split docs
83
+ print(f"📄 Loading documents from {doc_path}...")
84
+ documents = load_documents(doc_path)
85
+ chunks = split_documents(documents)
86
+ print(f"✅ Loaded and split {len(chunks)} chunks.")
87
+
88
+ # Build new store
89
+ print("⚙️ Building new vector store...")
90
+ vectordb = Chroma.from_documents(
91
+ documents=chunks,
92
+ embedding=embeddings,
93
+ persist_directory=persist_directory
94
+ )
95
+ vectordb.persist()
96
+ print(f"✅ New vector store saved at {persist_directory}")
97
+
98
+ return vectordb