shashankkandimalla
commited on
Commit
·
2bb9056
1
Parent(s):
8889a55
Add application file
Browse files- .env +4 -0
- Dockerfile +26 -0
- app.py +162 -0
- requirements.txt +4 -0
.env
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
WCS_URL= https://nhrgftystjszqyeb3oxzgq.c0.us-west3.gcp.weaviate.cloud
|
2 |
+
WCS_API_KEY= jbV3I1v4iuYs2YoAToG0T2ZvZ4OaZCowTUMH
|
3 |
+
OPENAI_API_KEY= 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
|
4 |
+
WEAVIATE_COLLECTION_NAME=RAGESGDocuments1
|
Dockerfile
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use an official Python runtime as the base image
|
2 |
+
FROM python:3.9-slim
|
3 |
+
|
4 |
+
# Set up a non-root user
|
5 |
+
RUN useradd -m -u 1000 user
|
6 |
+
|
7 |
+
# Set the working directory in the container
|
8 |
+
WORKDIR /app
|
9 |
+
|
10 |
+
# Copy the requirements file into the container
|
11 |
+
COPY requirements.txt .
|
12 |
+
|
13 |
+
# Install the required packages
|
14 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
15 |
+
|
16 |
+
# Copy the current directory contents into the container
|
17 |
+
COPY . .
|
18 |
+
|
19 |
+
# Switch to the non-root user
|
20 |
+
USER user
|
21 |
+
|
22 |
+
# Make port 7860 available to the world outside this container
|
23 |
+
EXPOSE 7860
|
24 |
+
|
25 |
+
# Run the Gradio app when the container launches
|
26 |
+
CMD ["python", "app.py"]
|
app.py
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import weaviate
|
3 |
+
from weaviate.embedded import EmbeddedOptions
|
4 |
+
import os
|
5 |
+
from openai import OpenAI
|
6 |
+
from dotenv import load_dotenv
|
7 |
+
import textwrap
|
8 |
+
|
9 |
+
# Load environment variables
|
10 |
+
load_dotenv()
|
11 |
+
|
12 |
+
# Set up OpenAI client
|
13 |
+
openai_client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
|
14 |
+
|
15 |
+
# Connect to Weaviate
|
16 |
+
client = weaviate.Client(
|
17 |
+
url=os.getenv('WCS_URL'),
|
18 |
+
auth_client_secret=weaviate.auth.AuthApiKey(os.getenv('WCS_API_KEY')),
|
19 |
+
additional_headers={
|
20 |
+
"X-OpenAI-Api-Key": os.getenv('OPENAI_API_KEY')
|
21 |
+
}
|
22 |
+
)
|
23 |
+
|
24 |
+
# Get the collection name from environment variable
|
25 |
+
COLLECTION_NAME = os.getenv('WEAVIATE_COLLECTION_NAME')
|
26 |
+
|
27 |
+
def get_embedding(text):
|
28 |
+
response = openai_client.embeddings.create(
|
29 |
+
input=text,
|
30 |
+
model="text-embedding-3-large"
|
31 |
+
)
|
32 |
+
return response.data[0].embedding
|
33 |
+
|
34 |
+
def search_multimodal(query: str, limit: int = 30, alpha: float = 0.6):
|
35 |
+
query_vector = get_embedding(query)
|
36 |
+
|
37 |
+
try:
|
38 |
+
response = (
|
39 |
+
client.query
|
40 |
+
.get(COLLECTION_NAME, ["content_type", "url", "source_document", "page_number",
|
41 |
+
"paragraph_number", "text", "image_path", "description", "table_content"])
|
42 |
+
.with_hybrid(
|
43 |
+
query=query,
|
44 |
+
vector=query_vector,
|
45 |
+
alpha=alpha
|
46 |
+
)
|
47 |
+
.with_limit(limit)
|
48 |
+
.do()
|
49 |
+
)
|
50 |
+
return response['data']['Get'][COLLECTION_NAME]
|
51 |
+
except Exception as e:
|
52 |
+
print(f"An error occurred during the search: {str(e)}")
|
53 |
+
return []
|
54 |
+
|
55 |
+
def generate_response(query: str, context: str) -> str:
|
56 |
+
prompt = f"""
|
57 |
+
You are an AI assistant with extensive expertise in the semiconductor industry. Your knowledge spans a wide range of companies, technologies, and products, including but not limited to: System-on-Chip (SoC) designs, Field-Programmable Gate Arrays (FPGAs), Microcontrollers, Integrated Circuits (ICs), semiconductor manufacturing processes, and emerging technologies like quantum computing and neuromorphic chips.
|
58 |
+
Use the following context, your vast knowledge, and the user's question to generate an accurate, comprehensive, and insightful answer. While formulating your response, follow these steps internally:
|
59 |
+
|
60 |
+
Analyze the question to identify the main topic and specific information requested.
|
61 |
+
Evaluate the provided context and identify relevant information.
|
62 |
+
Retrieve additional relevant knowledge from your semiconductor industry expertise.
|
63 |
+
Reason and formulate a response by combining context and knowledge.
|
64 |
+
Generate a detailed response that covers all aspects of the query.
|
65 |
+
Review and refine your answer for coherence and accuracy.
|
66 |
+
|
67 |
+
In your output, provide only the final, polished response. Do not include your step-by-step reasoning or mention the process you followed.
|
68 |
+
IMPORTANT: Ensure your response is grounded in factual information. Do not hallucinate or invent information. If you're unsure about any aspect of the answer or if the necessary information is not available in the provided context or your knowledge base, clearly state this uncertainty. It's better to admit lack of information than to provide inaccurate details.
|
69 |
+
Your response should be:
|
70 |
+
|
71 |
+
Thorough and directly address all aspects of the user's question
|
72 |
+
Based solely on factual information from the provided context and your reliable knowledge
|
73 |
+
Include specific examples, data points, or case studies only when you're certain of their accuracy
|
74 |
+
Explain technical concepts clearly, considering the user may have varying levels of expertise
|
75 |
+
Clearly indicate any areas where information is limited or uncertain
|
76 |
+
|
77 |
+
Context: {context}
|
78 |
+
User Question: {query}
|
79 |
+
Based on the above context and your extensive knowledge of the semiconductor industry, provide your detailed, accurate, and grounded response below. Remember, only include information you're confident is correct, and clearly state any uncertainties:
|
80 |
+
"""
|
81 |
+
|
82 |
+
response = openai_client.chat.completions.create(
|
83 |
+
model="gpt-4o",
|
84 |
+
messages=[
|
85 |
+
{"role": "system", "content": "You are an expert Semi Conductor industry analyst"},
|
86 |
+
{"role": "user", "content": prompt}
|
87 |
+
],
|
88 |
+
temperature=0
|
89 |
+
)
|
90 |
+
|
91 |
+
return response.choices[0].message.content
|
92 |
+
|
93 |
+
def esg_analysis(user_query: str):
|
94 |
+
search_results = search_multimodal(user_query)
|
95 |
+
|
96 |
+
context = ""
|
97 |
+
for item in search_results:
|
98 |
+
if item['content_type'] == 'text':
|
99 |
+
context += f"Text from {item['source_document']} (Page {item['page_number']}, Paragraph {item['paragraph_number']}): {item['text']}\n\n"
|
100 |
+
elif item['content_type'] == 'image':
|
101 |
+
context += f"Image Description from {item['source_document']} (Page {item['page_number']}, Path: {item['image_path']}): {item['description']}\n\n"
|
102 |
+
elif item['content_type'] == 'table':
|
103 |
+
context += f"Table Description from {item['source_document']} (Page {item['page_number']}): {item['description']}\n\n"
|
104 |
+
|
105 |
+
response = generate_response(user_query, context)
|
106 |
+
|
107 |
+
sources = []
|
108 |
+
for item in search_results[:5]: # Limit to top 5 sources
|
109 |
+
source = {
|
110 |
+
"type": item.get("content_type", "Unknown"),
|
111 |
+
"document": item.get("source_document", "N/A"),
|
112 |
+
"page": item.get("page_number", "N/A"),
|
113 |
+
}
|
114 |
+
if item.get("content_type") == 'text':
|
115 |
+
source["paragraph"] = item.get("paragraph_number", "N/A")
|
116 |
+
elif item.get("content_type") == 'image':
|
117 |
+
source["image_path"] = item.get("image_path", "N/A")
|
118 |
+
sources.append(source)
|
119 |
+
|
120 |
+
return response, sources
|
121 |
+
|
122 |
+
def wrap_text(text, width=120):
|
123 |
+
return textwrap.fill(text, width=width)
|
124 |
+
|
125 |
+
def gradio_interface(user_question):
|
126 |
+
ai_response, sources = esg_analysis(user_question)
|
127 |
+
|
128 |
+
# Format AI response
|
129 |
+
formatted_response = f"""
|
130 |
+
## AI Response
|
131 |
+
|
132 |
+
{ai_response}
|
133 |
+
"""
|
134 |
+
|
135 |
+
# Format sources
|
136 |
+
source_text = "## Top 5 Sources\n\n"
|
137 |
+
for i, source in enumerate(sources, 1):
|
138 |
+
source_text += f"### Source {i}\n"
|
139 |
+
source_text += f"- **Type:** {source['type']}\n"
|
140 |
+
source_text += f"- **Document:** {source['document']}\n"
|
141 |
+
source_text += f"- **Page:** {source['page']}\n"
|
142 |
+
if 'paragraph' in source:
|
143 |
+
source_text += f"- **Paragraph:** {source['paragraph']}\n"
|
144 |
+
if 'image_path' in source:
|
145 |
+
source_text += f"- **Image Path:** {source['image_path']}\n"
|
146 |
+
source_text += "\n"
|
147 |
+
|
148 |
+
return formatted_response, source_text
|
149 |
+
|
150 |
+
iface = gr.Interface(
|
151 |
+
fn=gradio_interface,
|
152 |
+
inputs=gr.Textbox(lines=2, placeholder="Enter your question about the semiconductor industry..."),
|
153 |
+
outputs=[
|
154 |
+
gr.Markdown(label="AI Response"),
|
155 |
+
gr.Markdown(label="Sources")
|
156 |
+
],
|
157 |
+
title="Semiconductor Industry ESG Analysis",
|
158 |
+
description="Ask questions about the semiconductor industry and get AI-powered answers with sources.",
|
159 |
+
)
|
160 |
+
|
161 |
+
if __name__ == "__main__":
|
162 |
+
iface.launch(server_name="0.0.0.0", server_port=7860)
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
weaviate-client==4.7.1
|
3 |
+
openai
|
4 |
+
python-dotenv
|