getGO007 commited on
Commit
52ea0db
·
verified ·
1 Parent(s): fcd1c09

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -58
app.py CHANGED
@@ -1,64 +1,129 @@
 
 
 
 
 
1
  import gradio as gr
2
- from huggingface_hub import InferenceClient
3
-
4
- """
5
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
6
- """
7
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
8
-
9
-
10
- def respond(
11
- message,
12
- history: list[tuple[str, str]],
13
- system_message,
14
- max_tokens,
15
- temperature,
16
- top_p,
17
- ):
18
- messages = [{"role": "system", "content": system_message}]
19
-
20
- for val in history:
21
- if val[0]:
22
- messages.append({"role": "user", "content": val[0]})
23
- if val[1]:
24
- messages.append({"role": "assistant", "content": val[1]})
25
-
26
- messages.append({"role": "user", "content": message})
27
-
28
- response = ""
29
-
30
- for message in client.chat_completion(
31
- messages,
32
- max_tokens=max_tokens,
33
- stream=True,
34
- temperature=temperature,
35
- top_p=top_p,
36
- ):
37
- token = message.choices[0].delta.content
38
-
39
- response += token
40
- yield response
41
-
42
-
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- demo = gr.ChatInterface(
47
- respond,
48
- additional_inputs=[
49
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
50
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
51
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
52
- gr.Slider(
53
- minimum=0.1,
54
- maximum=1.0,
55
- value=0.95,
56
- step=0.05,
57
- label="Top-p (nucleus sampling)",
58
- ),
59
- ],
60
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
 
62
 
63
  if __name__ == "__main__":
64
  demo.launch()
 
1
+ import os
2
+ import shutil
3
+ import asyncio
4
+ from pathlib import Path
5
+
6
  import gradio as gr
7
+ from PyPDF2 import PdfReader # pip install PyPDF2
8
+
9
+ from helper import get_openai_api_key, get_llama_cloud_api_key
10
+ from llama_parse import LlamaParse
11
+ from llama_index.core import (
12
+ Settings, VectorStoreIndex, StorageContext, load_index_from_storage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  )
14
+ from llama_index.llms.openai import OpenAI
15
+ from llama_index.embeddings.openai import OpenAIEmbedding
16
+ from llama_index.core.tools import QueryEngineTool
17
+ from llama_index.core.query_engine import SubQuestionQueryEngine
18
+ from llama_index.core.agent.workflow import FunctionAgent
19
+ from llama_index.core.workflow import Context
20
+
21
+ # ---- 1. Global Settings & API Keys ----
22
+ Settings.llm = OpenAI(model="gpt-4o")
23
+ Settings.embed_model = OpenAIEmbedding(model_name="text-embedding-3-large")
24
+ Settings.chunk_size = 512
25
+ Settings.chunk_overlap = 64
26
+
27
+ os.environ["OPENAI_API_KEY"] = get_openai_api_key()
28
+ os.environ["LLAMA_CLOUD_API_KEY"] = get_llama_cloud_api_key()
29
+
30
+ # ---- 2. Parser Setup ----
31
+ parser = LlamaParse(
32
+ api_key = os.getenv("LLAMA_CLOUD_API_KEY"),
33
+ base_url = os.getenv("LLAMA_CLOUD_BASE_URL"),
34
+ result_type = "markdown",
35
+ content_guideline_instruction = (
36
+ "You are processing a PDF slide deck. "
37
+ "Produce Markdown with slide metadata, cleaned bullets, tables, "
38
+ "charts summaries, figures captions, metrics, and a 1–2 sentence takeaway."
39
+ ),
40
+ verbose=True
41
+ )
42
+
43
+ # ---- 3. Core “Answer” Logic ----
44
+ async def answer(uploaded_files: list[gr.FileData], question: str) -> str:
45
+ # Validate uploads
46
+ if not uploaded_files:
47
+ return "❗ Please upload at least one PDF."
48
+ if len(uploaded_files) > 5:
49
+ return "❗ You can upload up to 5 PDF files."
50
+
51
+ # Ensure user_data directory
52
+ user_dir = Path("./user_data")
53
+ user_dir.mkdir(exist_ok=True)
54
+
55
+ # Prepare list of QueryEngineTools
56
+ tools = []
57
+ for file_obj in uploaded_files:
58
+ # Read page count
59
+ try:
60
+ reader = PdfReader(file_obj.name)
61
+ except Exception as e:
62
+ return f"❗ Error reading {file_obj.name}: {e}"
63
+ if len(reader.pages) > 20:
64
+ return f"❗ {Path(file_obj.name).name} has {len(reader.pages)} pages (>20)."
65
+
66
+ # Copy file to persistent location
67
+ dest = user_dir / Path(file_obj.name).name
68
+ shutil.copyfile(file_obj.name, dest) # permanent copy :contentReference[oaicite:3]{index=3}
69
+
70
+ # Parse PDF into Documents
71
+ docs = parser.load_data(dest)
72
+
73
+ # Index folder named after file stem
74
+ stem = dest.stem
75
+ idx_dir = Path(f"./index_data/{stem}")
76
+
77
+ # Load or build index
78
+ if idx_dir.exists() and any(idx_dir.iterdir()):
79
+ sc = StorageContext.from_defaults(persist_dir=str(idx_dir))
80
+ idx = load_index_from_storage(sc)
81
+ else:
82
+ sc = StorageContext.from_defaults()
83
+ idx = VectorStoreIndex.from_documents(docs, storage_context=sc)
84
+ sc.persist(persist_dir=str(idx_dir)) # persist per-file index :contentReference[oaicite:4]{index=4}
85
+
86
+ # Create a QueryEngineTool for this index
87
+ qe_tool = QueryEngineTool.from_defaults(
88
+ query_engine=idx.as_query_engine(),
89
+ name=f"vector_index_{stem}",
90
+ description=f"Query engine for slides in {stem}.pdf"
91
+ )
92
+ tools.append(qe_tool)
93
+
94
+ # Combine into SubQuestionQueryEngine + Agent
95
+ subq = SubQuestionQueryEngine.from_defaults(query_engine_tools=tools)
96
+ tools.append(
97
+ QueryEngineTool.from_defaults(
98
+ query_engine=subq,
99
+ name="sub_question_query_engine",
100
+ description="Multi-file comparative queries"
101
+ )
102
+ )
103
+ agent = FunctionAgent(tools=tools, llm=OpenAI(model="gpt-4o"))
104
+ ctx = Context(agent)
105
+
106
+ # Run agent
107
+ response = await agent.run(question, ctx=ctx)
108
+ return str(response)
109
+
110
+ # ---- 4. Gradio UI ----
111
+ with gr.Blocks() as demo:
112
+ gr.Markdown("# 📄 PDF Slide Deck Q&A Bot")
113
+ with gr.Row():
114
+ file_input = gr.UploadButton(
115
+ "Upload up to 5 PDFs",
116
+ file_types=[".pdf"],
117
+ file_count="multiple" # support multiple uploads
118
+ )
119
+ question = gr.Textbox(
120
+ lines=2,
121
+ placeholder="Ask your question about the uploaded slide decks..."
122
+ )
123
+ output = gr.Textbox(label="Answer")
124
+ submit = gr.Button("Ask")
125
 
126
+ submit.click(fn=answer, inputs=[file_input, question], outputs=output)
127
 
128
  if __name__ == "__main__":
129
  demo.launch()