mgbam commited on
Commit
03e932b
·
verified ·
1 Parent(s): 504839f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +199 -151
app.py CHANGED
@@ -1,153 +1,201 @@
1
- import streamlit as st
2
- import transformers
3
- import altair as alt
4
- import pandas as pd
5
- from difflib import SequenceMatcher
6
-
7
- # ------------------------------
8
- # Simple Authentication Setup
9
- # ------------------------------
10
- # Define a simple password for demonstration purposes.
11
- PASSWORD = "password123"
12
-
13
- # Initialize authentication state
14
- if 'authenticated' not in st.session_state:
15
- st.session_state['authenticated'] = False
16
-
17
- # Simple password input in the sidebar for authentication
18
- if not st.session_state['authenticated']:
19
- st.sidebar.title("Login")
20
- password_input = st.sidebar.text_input("Enter password:", type="password")
21
- if st.sidebar.button("Login"):
22
- if password_input == PASSWORD:
23
- st.session_state['authenticated'] = True
24
- st.sidebar.success("Authenticated!")
25
- else:
26
- st.sidebar.error("Incorrect password. Please try again.")
27
- st.stop() # Stop app execution until authenticated
28
-
29
- st.sidebar.write("Welcome!")
30
- # ------------------------------
31
- # Load Models
32
- # ------------------------------
33
- @st.cache_resource
34
- def load_qwen():
35
- return transformers.pipeline(
36
- "text2text-generation",
37
- model="Qwen/Qwen2.5-14B",
38
- device_map="auto"
39
- )
40
-
41
- @st.cache_resource
42
- def load_phi():
43
- return transformers.pipeline(
44
- "text-generation",
45
- model="microsoft/phi-4",
46
- model_kwargs={"torch_dtype": "auto"},
47
- device_map="auto"
48
- )
49
-
50
- qwen_pipeline = load_qwen()
51
- phi_pipeline = load_phi()
52
-
53
- # ------------------------------
54
- # Utility Functions
55
- # ------------------------------
56
- def summarize_document(document_text):
57
- prompt = f"Summarize the following document and highlight key insights:\n\n{document_text}"
58
- summary = qwen_pipeline(prompt, max_new_tokens=1024)[0]['generated_text']
59
- return summary
60
-
61
- def answer_question(summary, question):
62
- prompt = f"Based on the following summary:\n\n{summary}\n\nAnswer the question: {question}"
63
- answer = phi_pipeline(prompt, max_new_tokens=256)[0]['generated_text']
64
- return answer
65
-
66
- def find_similar_chunks(original, output):
67
- matcher = SequenceMatcher(None, original, output)
68
- segments = []
69
- left = 0
70
- for _, j, n in matcher.get_matching_blocks():
71
- if left < j:
72
- segments.append({'text': output[left:j], 'match': False})
73
- segments.append({'text': output[j:j+n], 'match': True})
74
- left = j+n
75
- return segments
76
-
77
- # ------------------------------
78
- # Streamlit App Layout
79
- # ------------------------------
80
- st.title("SmartDoc Analyzer")
81
- st.markdown("Analyze Financial & Health Documents with AI")
82
-
83
- # Tabs for different functionalities
84
- tabs = st.tabs(["Document Summarization", "Interactive Q&A", "Visualization & Data Extraction"])
85
-
86
- # -------- Document Summarization Tab --------
87
- with tabs[0]:
88
- st.header("Document Summarization")
89
- document_text = st.text_area("Paste Document Text:", height=300)
90
- if st.button("Summarize Document"):
91
- if document_text:
92
- summary = summarize_document(document_text)
93
- st.subheader("Summary")
94
- st.write(summary)
95
- # Save summary in session for use in Q&A tab
96
- st.session_state['last_summary'] = summary
97
- else:
98
- st.warning("Please paste document text to summarize.")
99
-
100
- # -------- Interactive Q&A Tab --------
101
- with tabs[1]:
102
- st.header("Interactive Q&A")
103
- default_summary = st.session_state.get('last_summary', '')
104
- summary_context = st.text_area("Summary Context:", value=default_summary, height=150)
105
- question = st.text_input("Enter your question about the document:")
106
- if st.button("Get Answer"):
107
- if summary_context and question:
108
- answer = answer_question(summary_context, question)
109
- st.subheader("Answer")
110
- st.write(answer)
111
- else:
112
- st.warning("Please provide both a summary context and a question.")
113
-
114
- # -------- Visualization & Data Extraction Tab --------
115
- with tabs[2]:
116
- st.header("Visualization & Data Extraction")
117
-
118
- st.subheader("Visualization Placeholder")
119
- st.markdown("An interactive chart can be displayed here using Altair or Plotly.")
120
-
121
- # Example static Altair chart (replace with dynamic data extraction logic)
122
- data = pd.DataFrame({
123
- 'Year': [2019, 2020, 2021, 2022],
124
- 'Revenue': [150, 200, 250, 300]
125
- })
126
- chart = alt.Chart(data).mark_line(point=True).encode(
127
- x='Year:O',
128
- y='Revenue:Q',
129
- tooltip=['Year', 'Revenue']
130
- ).interactive()
131
- st.altair_chart(chart, use_container_width=True)
132
-
133
- st.subheader("Data Extraction Placeholder")
134
- st.markdown("Implement NLP techniques or model prompts to extract structured data here.")
135
-
136
- uploaded_file = st.file_uploader("Upload a document file for extraction", type=["pdf", "docx", "txt"])
137
- if uploaded_file is not None:
138
- st.info("File uploaded successfully. Data extraction logic would process this file.")
139
- # Add logic to extract tables, key figures, etc. from the uploaded file.
140
-
141
- # ------------------------------
142
- # Safety & Compliance Layer (Placeholder)
143
- # ------------------------------
144
- st.sidebar.markdown("### Safety & Compliance")
145
- st.sidebar.info(
146
- "This tool provides AI-driven insights. "
147
- "Please note that summaries and answers are for informational purposes only and should not be "
148
- "considered professional financial or medical advice."
149
  )
150
 
151
- # ------------------------------
152
- # End of Application
153
- # ------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import base64
3
+ import os
4
+ import re
5
+ from io import BytesIO
6
+ from PIL import Image
7
+ from huggingface_hub import InferenceClient
8
+ from mistralai import Mistral
9
+ from feifeilib.feifeichat import feifeichat # Assuming this utility is still relevant or replace with SmartDocAnalyzer logic as needed.
10
+
11
+ # Initialize Hugging Face inference clients
12
+ client = InferenceClient(api_key=os.getenv('HF_TOKEN'))
13
+ client.headers["x-use-cache"] = "0"
14
+
15
+ api_key = os.getenv("MISTRAL_API_KEY")
16
+ Mistralclient = Mistral(api_key=api_key)
17
+
18
+ # Gradio interface setup for SmartDocAnalyzer
19
+ SmartDocAnalyzer = gr.ChatInterface(
20
+ feifeichat, # This should be replaced with a suitable function for SmartDocAnalyzer if needed.
21
+ type="messages",
22
+ multimodal=True,
23
+ additional_inputs=[
24
+ gr.Checkbox(label="Enable Analyzer Mode", value=True),
25
+ gr.Dropdown(
26
+ [
27
+ "meta-llama/Llama-3.3-70B-Instruct",
28
+ "CohereForAI/c4ai-command-r-plus-08-2024",
29
+ "Qwen/Qwen2.5-72B-Instruct",
30
+ "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF",
31
+ "NousResearch/Hermes-3-Llama-3.1-8B",
32
+ "mistralai/Mistral-Nemo-Instruct-2411",
33
+ "microsoft/phi-4"
34
+ ],
35
+ value="mistralai/Mistral-Nemo-Instruct-2411",
36
+ show_label=False,
37
+ container=False
38
+ ),
39
+ gr.Radio(
40
+ ["pixtral", "Vision"],
41
+ value="pixtral",
42
+ show_label=False,
43
+ container=False
44
+ )
45
+ ],
46
+ title="SmartDocAnalyzer",
47
+ description="An advanced document analysis tool powered by AI."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  )
49
 
50
+ SmartDocAnalyzer.launch()
51
+
52
+ def encode_image(image_path):
53
+ """
54
+ Encode the image at the given path to a base64 JPEG.
55
+ Resizes image height to 512 pixels while maintaining aspect ratio.
56
+ """
57
+ try:
58
+ image = Image.open(image_path).convert("RGB")
59
+ base_height = 512
60
+ h_percent = (base_height / float(image.size[1]))
61
+ w_size = int((float(image.size[0]) * float(h_percent)))
62
+ image = image.resize((w_size, base_height), Image.LANCZOS)
63
+ buffered = BytesIO()
64
+ image.save(buffered, format="JPEG")
65
+ return base64.b64encode(buffered.getvalue()).decode("utf-8")
66
+ except FileNotFoundError:
67
+ print(f"Error: The file {image_path} was not found.")
68
+ except Exception as e:
69
+ print(f"Error: {e}")
70
+ return None
71
+
72
+ def feifeiprompt(feifei_select=True, message_text="", history=""):
73
+ """
74
+ Constructs a prompt for the chatbot based on message text and history.
75
+ Enhancements for SmartDocAnalyzer context can be added here.
76
+ """
77
+ input_prompt = []
78
+ # Special handling for drawing requests
79
+ if message_text.startswith("画") or message_text.startswith("draw"):
80
+ feifei_photo = (
81
+ "You are FeiFei. Background: FeiFei was born in Tokyo and is a natural-born photographer, "
82
+ "hailing from a family with a long history in photography... [truncated for brevity]"
83
+ )
84
+ message_text = message_text.replace("画", "").replace("draw", "")
85
+ message_text = f"提示词是'{message_text}',根据提示词帮我生成一张高质量照片的一句话英文回复"
86
+ system_prompt = {"role": "system", "content": feifei_photo}
87
+ user_input_part = {"role": "user", "content": str(message_text)}
88
+ return [system_prompt, user_input_part]
89
+
90
+ # Default prompt construction for FeiFei character
91
+ if feifei_select:
92
+ feifei = (
93
+ "[Character Name]: Aifeifei (AI Feifei) [Gender]: Female [Age]: 19 years old ... "
94
+ "[Identity]: User's virtual girlfriend"
95
+ )
96
+ system_prompt = {"role": "system", "content": feifei}
97
+ user_input_part = {"role": "user", "content": str(message_text)}
98
+
99
+ pattern = re.compile(r"gradio")
100
+ if history:
101
+ history = [item for item in history if not pattern.search(str(item["content"]))]
102
+ input_prompt = [system_prompt] + history + [user_input_part]
103
+ else:
104
+ input_prompt = [system_prompt, user_input_part]
105
+ else:
106
+ input_prompt = [{"role": "user", "content": str(message_text)}]
107
+
108
+ return input_prompt
109
+
110
+ def feifeiimgprompt(message_files, message_text, image_mod):
111
+ """
112
+ Handles image-based prompts for either 'Vision' or 'pixtral' modes.
113
+ """
114
+ message_file = message_files[0]
115
+ base64_image = encode_image(message_file)
116
+ if base64_image is None:
117
+ return
118
+
119
+ # Vision mode using meta-llama model
120
+ if image_mod == "Vision":
121
+ messages = [{
122
+ "role": "user",
123
+ "content": [
124
+ {"type": "text", "text": message_text},
125
+ {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
126
+ ]
127
+ }]
128
+ stream = client.chat.completions.create(
129
+ model="meta-llama/Llama-3.2-11B-Vision-Instruct",
130
+ messages=messages,
131
+ max_tokens=500,
132
+ stream=True
133
+ )
134
+ temp = ""
135
+ for chunk in stream:
136
+ if chunk.choices[0].delta.content is not None:
137
+ temp += chunk.choices[0].delta.content
138
+ yield temp
139
+ # Pixtral mode using Mistral model
140
+ else:
141
+ model = "pixtral-large-2411"
142
+ messages = [{
143
+ "role": "user",
144
+ "content": [
145
+ {"type": "text", "text": message_text},
146
+ {"type": "image_url", "image_url": f"data:image/jpeg;base64,{base64_image}"}
147
+ ]
148
+ }]
149
+ partial_message = ""
150
+ for chunk in Mistralclient.chat.stream(model=model, messages=messages):
151
+ if chunk.data.choices[0].delta.content is not None:
152
+ partial_message += chunk.data.choices[0].delta.content
153
+ yield partial_message
154
+
155
+ def feifeichatmod(additional_dropdown, input_prompt):
156
+ """
157
+ Chooses the appropriate chat model based on the dropdown selection.
158
+ """
159
+ if additional_dropdown == "mistralai/Mistral-Nemo-Instruct-2411":
160
+ model = "mistral-large-2411"
161
+ stream_response = Mistralclient.chat.stream(model=model, messages=input_prompt)
162
+ partial_message = ""
163
+ for chunk in stream_response:
164
+ if chunk.data.choices[0].delta.content is not None:
165
+ partial_message += chunk.data.choices[0].delta.content
166
+ yield partial_message
167
+ else:
168
+ stream = client.chat.completions.create(
169
+ model=additional_dropdown,
170
+ messages=input_prompt,
171
+ temperature=0.5,
172
+ max_tokens=1024,
173
+ top_p=0.7,
174
+ stream=True
175
+ )
176
+ temp = ""
177
+ for chunk in stream:
178
+ if chunk.choices[0].delta.content is not None:
179
+ temp += chunk.choices[0].delta.content
180
+ yield temp
181
+
182
+ def feifeichat(message, history, feifei_select, additional_dropdown, image_mod):
183
+ """
184
+ Main chat function that decides between image-based and text-based handling.
185
+ This function can be further enhanced for SmartDocAnalyzer-specific logic.
186
+ """
187
+ message_text = message.get("text", "")
188
+ message_files = message.get("files", [])
189
+
190
+ if message_files:
191
+ # Process image input
192
+ yield from feifeiimgprompt(message_files, message_text, image_mod)
193
+ else:
194
+ # Process text input
195
+ input_prompt = feifeiprompt(feifei_select, message_text, history)
196
+ yield from feifeichatmod(additional_dropdown, input_prompt)
197
+
198
+ # Enhancement Note:
199
+ # For the SmartDocAnalyzer space, consider integrating document parsing,
200
+ # OCR functionalities, semantic analysis of documents, and more advanced
201
+ # error handling as needed. This template serves as a starting point.