Chibueze-Kingsley commited on
Commit
47effb2
·
verified ·
1 Parent(s): b36ef89

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. qwen_app.py +153 -0
qwen_app.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import List, Any
3
+ from chainlit.types import AskFileResponse
4
+ import tempfile
5
+ import shutil
6
+
7
+ # Text processing
8
+ from langchain.text_splitter import CharacterTextSplitter
9
+ from langchain_community.document_loaders import TextLoader, PyPDFLoader
10
+ from langchain.docstore.document import Document
11
+
12
+ # Prompt templates
13
+ from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
14
+
15
+ # Embeddings + VectorDB
16
+ from langchain_community.embeddings import HuggingFaceEmbeddings
17
+ from langchain_community.vectorstores import FAISS
18
+
19
+ # OpenRouter (Qwen via OpenAI-compatible API)
20
+ from langchain_openai import ChatOpenAI
21
+
22
+ # UI framework
23
+ import chainlit as cl
24
+
25
+
26
+ # -------------------------
27
+ # API Key Setup
28
+ # -------------------------
29
+ # Make sure you export in Colab / Terminal before running:
30
+ # os.environ["OPENROUTER_API_KEY"] = "your_api_key_here"
31
+ # os.environ["OPENAI_API_BASE"] = "https://openrouter.ai/api/v1"
32
+
33
+
34
+ # -------------------------
35
+ # File processing
36
+ # -------------------------
37
+ text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=50)
38
+
39
+ def process_file(file: AskFileResponse) -> List[Document]:
40
+ """Load and split PDF or TXT into LangChain Documents."""
41
+ suffix = f".{file.name.split('.')[-1]}"
42
+ with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as temp_file:
43
+ shutil.copyfile(file.path, temp_file.name)
44
+
45
+ if file.name.lower().endswith(".pdf"):
46
+ loader = PyPDFLoader(temp_file.name)
47
+ else:
48
+ loader = TextLoader(temp_file.name)
49
+
50
+ try:
51
+ docs = loader.load()
52
+ texts = text_splitter.split_documents(docs)
53
+ return texts
54
+ finally:
55
+ try:
56
+ os.unlink(temp_file.name)
57
+ except Exception as e:
58
+ print(f"Cleanup error: {e}")
59
+
60
+
61
+ # -------------------------
62
+ # Retrieval QA Pipeline
63
+ # -------------------------
64
+ class RetrievalAugmentedQAPipeline:
65
+ def __init__(self, llm: Any, vectorstore: FAISS) -> None:
66
+ self.llm = llm
67
+ self.vectorstore = vectorstore
68
+
69
+ # Prompt definition
70
+ system_template = (
71
+ "You are a helpful assistant. "
72
+ "Use the following context to answer a user's question. "
73
+ "If the context does not contain the answer, reply with 'I don't know'."
74
+ )
75
+ self.prompt = ChatPromptTemplate.from_messages([
76
+ SystemMessagePromptTemplate.from_template(system_template),
77
+ HumanMessagePromptTemplate.from_template("Context:\n{context}\n\nQuestion:\n{question}")
78
+ ])
79
+
80
+ async def arun_pipeline(self, user_query: str):
81
+ # Retrieve documents
82
+ docs = self.vectorstore.similarity_search(user_query, k=4)
83
+ context_text = "\n".join([doc.page_content for doc in docs])
84
+
85
+ # Format the prompt
86
+ messages = self.prompt.format_messages(context=context_text, question=user_query)
87
+
88
+ # Stream response from Qwen
89
+ async def generate_response():
90
+ async for chunk in self.llm.astream(messages):
91
+ yield chunk.content if chunk.content else ""
92
+
93
+ return {"response": generate_response(), "context": docs}
94
+
95
+
96
+ # -------------------------
97
+ # Chainlit Handlers
98
+ # -------------------------
99
+ @cl.on_chat_start
100
+ async def on_chat_start():
101
+ files = None
102
+
103
+ # Wait for user file
104
+ while files is None:
105
+ files = await cl.AskFileMessage(
106
+ content="Please upload a Text or PDF file to begin!",
107
+ accept=["text/plain", "application/pdf"],
108
+ max_size_mb=5,
109
+ timeout=180,
110
+ ).send()
111
+
112
+ file = files[0]
113
+ msg = cl.Message(content=f"Processing `{file.name}`...")
114
+ await msg.send()
115
+
116
+ # Load & process file
117
+ texts = process_file(file)
118
+ print(f"Processing {len(texts)} chunks")
119
+
120
+ # Create embeddings + vectorstore
121
+ embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
122
+ vectorstore = FAISS.from_documents(texts, embeddings)
123
+
124
+ # Initialize Qwen via OpenRouter
125
+ chat_llm = ChatOpenAI(
126
+ model="qwen/qwen2.5-vl-72b-instruct", # ✅ you can swap with qwen-3 when available
127
+ streaming=True,
128
+ temperature=0,
129
+ max_tokens=1024,
130
+ openai_api_base=os.environ.get("OPENAI_API_BASE", "https://openrouter.ai/api/v1"),
131
+ openai_api_key= "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"
132
+ )
133
+
134
+ # Create retrieval pipeline
135
+ retrieval_qa = RetrievalAugmentedQAPipeline(llm=chat_llm, vectorstore=vectorstore)
136
+
137
+ msg.content = f"Processing `{file.name}` done ✅. You can now ask questions!"
138
+ await msg.update()
139
+
140
+ cl.user_session.set("chain", retrieval_qa)
141
+
142
+
143
+ @cl.on_message
144
+ async def main(message: cl.Message):
145
+ chain = cl.user_session.get("chain")
146
+
147
+ msg = cl.Message(content="")
148
+ result = await chain.arun_pipeline(message.content)
149
+
150
+ async for stream_resp in result["response"]:
151
+ await msg.stream_token(stream_resp)
152
+
153
+ await msg.send()