Patelcoder commited on
Commit
744a700
·
verified ·
1 Parent(s): e63b380

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +43 -159
index.html CHANGED
@@ -3,9 +3,11 @@
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Story RAG Assistant (Gradio-Lite)</title>
 
7
  <script type="module" src="https://gradio-lite-previews.s3.amazonaws.com/PINNED_HF_HUB/dist/lite.js"></script>
8
  <link rel="stylesheet" href="https://gradio-lite-previews.s3.amazonaws.com/PINNED_HF_HUB/dist/lite.css" />
 
9
  <style>
10
  body {
11
  background-color: #0f172a;
@@ -17,176 +19,58 @@
17
  </style>
18
  </head>
19
  <body>
20
- <gradio-lite>
21
- <gradio-code>
22
  import gradio as gr
23
- import json
24
- from pyodide.http import pyfetch
25
-
26
- async def make_post_request(url, headers, body_dict):
27
- response = await pyfetch(
28
- url,
29
- method="POST",
30
- headers=headers,
31
- body=json.dumps(body_dict)
32
- )
33
- if response.status != 200:
34
- err_msg = await response.string()
35
- raise Exception(f"Request failed with status {response.status}: {err_msg}")
36
- return await response.json()
37
-
38
- async def get_pinecone_host(api_key, index_name):
39
- # Route control plane through corsproxy.io because Pinecone blocks browser CORS
40
- url = f"https://corsproxy.io/?url=https://api.pinecone.io/indexes/{index_name}"
41
- response = await pyfetch(
42
- url,
43
- method="GET",
44
- headers={
45
- "Api-Key": api_key,
46
- "Accept": "application/json"
47
- }
48
- )
49
- if response.status != 200:
50
- err_msg = await response.string()
51
- raise Exception(f"Failed to get Pinecone index info: {err_msg}")
52
- data = await response.json()
53
- return data["host"]
54
-
55
- async def query_pinecone(api_key, host, namespace, text, top_k=4):
56
- # Route data plane through corsproxy.io
57
- url = f"https://corsproxy.io/?url=https://{host}/query"
58
- headers = {
59
- "Api-Key": api_key,
60
- "Content-Type": "application/json",
61
- "Accept": "application/json"
62
- }
63
- body = {
64
- "namespace": namespace,
65
- "topK": top_k,
66
- "inputs": {
67
- "text": text
68
- },
69
- "includeMetadata": True
70
- }
71
- data = await make_post_request(url, headers, body)
72
- matches = data.get("matches", [])
73
- chunks = [m["metadata"].get("chunk_text", "") for m in matches if "metadata" in m]
74
- return chunks
75
 
76
- async def call_gemini(api_key, model_name, contents):
77
- # Gemini API natively supports CORS, so we do not need a proxy for it
78
- url = f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent?key={api_key}"
79
- headers = {
80
- "Content-Type": "application/json"
81
- }
82
- body = {
83
- "contents": contents,
84
- "generationConfig": {
85
- "temperature": 0.1
86
- }
87
- }
88
- data = await make_post_request(url, headers, body)
89
- try:
90
- text = data["candidates"][0]["content"]["parts"][0]["text"]
91
- return text
92
- except (KeyError, IndexError):
93
- raise Exception(f"Failed to parse Gemini response: {json.dumps(data)}")
94
-
95
- async def respond(message, history, google_key, pinecone_key, pinecone_index, pinecone_ns, google_model):
96
- if not google_key or not pinecone_key:
97
- history.append({"role": "user", "content": message})
98
- history.append({"role": "assistant", "content": "❌ Please provide both Google and Pinecone API keys in the configuration panel on the left."})
99
- return "", history
100
-
101
  try:
102
- # 1. Fetch Pinecone Host
103
- host = await get_pinecone_host(pinecone_key, pinecone_index)
104
-
105
- # 2. Search Pinecone for context
106
- chunks = await query_pinecone(pinecone_key, host, pinecone_ns, message)
107
-
108
- # 3. Format prompt
109
- sources_text = "\n\n".join(f"Source {i+1}:\n{text}" for i, text in enumerate(chunks)) if chunks else "No relevant sources found."
110
 
111
- system_prompt = (
112
- "You are an educational assistant answering questions about stories in uploaded documents.\n"
113
- "Rules:\n"
114
- "- Use ONLY facts from the retrieved sources. Never invent details.\n"
115
- "- Give a direct answer in 2-4 sentences. Do not repeat the question or show your reasoning.\n"
116
- "- If multiple stories appear, answer about the one most relevant to the question.\n"
117
- "- If the sources do not contain the answer, say you could not find it in the document."
118
  )
119
-
120
- augmented_prompt = (
121
- f"{system_prompt}\n\n"
122
- f"Retrieved sources (answer using ONLY these):\n{sources_text}\n\n"
123
- f"Question: {message}"
124
- )
125
-
126
- # 4. Construct conversation contents for Gemini
127
- contents = []
128
- for turn in history[-8:]:
129
- role = "user" if turn["role"] == "user" else "model"
130
- contents.append({
131
- "role": role,
132
- "parts": [{"text": turn["content"]}]
133
- })
134
- contents.append({
135
- "role": "user",
136
- "parts": [{"text": augmented_prompt}]
137
- })
138
-
139
- # 5. Call Gemini
140
- response_text = await call_gemini(google_key, google_model, contents)
141
-
142
- history.append({"role": "user", "content": message})
143
- history.append({"role": "assistant", "content": response_text})
144
- return "", history
145
-
146
  except Exception as e:
147
- history.append({"role": "user", "content": message})
148
- history.append({"role": "assistant", "content": f"❌ Error: {str(e)}"})
149
- return "", history
150
 
151
- # Custom WebAssembly Theme and Styling
152
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="indigo")) as demo:
153
- gr.Markdown("# 📚 Static RAG Story Assistant (Gradio-Lite)")
154
- gr.Markdown(
155
- "This application runs **entirely inside your browser** via WebAssembly (Pyodide). "
156
- "No backend server is required, and your API keys never leave your browser session (except to call Pinecone and Gemini)."
157
- )
158
 
159
  with gr.Row():
160
- with gr.Column(scale=1):
161
- gr.Markdown("### 🔑 API Configuration")
162
- google_key_input = gr.Textbox(label="Google API Key", type="password", placeholder="AIzaSy...")
163
- pinecone_key_input = gr.Textbox(label="Pinecone API Key", type="password", placeholder="pcsk_...")
164
- pinecone_index_input = gr.Textbox(label="Pinecone Index Name", value="story-llama")
165
- pinecone_ns_input = gr.Textbox(label="Pinecone Namespace", value="default")
166
- google_model_input = gr.Textbox(label="Google Model", value="gemini-2.0-flash")
167
-
168
- with gr.Column(scale=2):
169
- chatbot = gr.Chatbot(type="messages", height=450)
170
- msg_input = gr.Textbox(placeholder="Ask a question about the story...", label="Your Question")
171
-
172
- with gr.Row():
173
- submit_btn = gr.Button("Send", variant="primary")
174
- clear_btn = gr.Button("Clear Chat")
175
-
176
  submit_btn.click(
177
- respond,
178
- inputs=[msg_input, chatbot, google_key_input, pinecone_key_input, pinecone_index_input, pinecone_ns_input, google_model_input],
179
- outputs=[msg_input, chatbot]
180
- )
181
- msg_input.submit(
182
- respond,
183
- inputs=[msg_input, chatbot, google_key_input, pinecone_key_input, pinecone_index_input, pinecone_ns_input, google_model_input],
184
- outputs=[msg_input, chatbot]
185
  )
186
- clear_btn.click(lambda: [], None, chatbot)
187
 
188
  demo.launch()
189
- </gradio-code>
190
- </gradio-lite>
191
  </body>
192
- </html>
 
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AI Descriptor Agent</title>
7
+
8
  <script type="module" src="https://gradio-lite-previews.s3.amazonaws.com/PINNED_HF_HUB/dist/lite.js"></script>
9
  <link rel="stylesheet" href="https://gradio-lite-previews.s3.amazonaws.com/PINNED_HF_HUB/dist/lite.css" />
10
+
11
  <style>
12
  body {
13
  background-color: #0f172a;
 
19
  </style>
20
  </head>
21
  <body>
22
+ <gradio-app requirements="openai">
 
23
  import gradio as gr
24
+ from openai import OpenAI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ def run_descriptor_agent(openai_key, user_prompt):
27
+ if not openai_key:
28
+ return "Please enter your OpenAI API Key first!"
29
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  try:
31
+ # Initialize the OpenAI client inside the browser environment
32
+ client = OpenAI(api_key=openai_key)
 
 
 
 
 
 
33
 
34
+ # Simple agent descriptor call
35
+ response = client.chat.completions.create(
36
+ model="gpt-4o-mini",
37
+ messages=[
38
+ {"role": "system", "content": "You are a professional AI Descriptor agent. Provide structured, clear summaries and descriptions based on user requests."},
39
+ {"role": "user", "content": user_prompt}
40
+ ]
41
  )
42
+ return response.choices[0].message.content
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  except Exception as e:
44
+ return f"Error: {str(e)}"
 
 
45
 
46
+ # Define the Gradio UI
47
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="indigo")) as demo:
48
+ gr.Markdown("# 🤖 AI Descriptor Agent")
49
+ gr.Markdown("This runs entirely in your browser. Your OpenAI key is safe and is not stored anywhere on Hugging Face.")
 
 
 
50
 
51
  with gr.Row():
52
+ key_input = gr.Textbox(
53
+ label="1. Enter your OpenAI API Key",
54
+ placeholder="sk-proj-...",
55
+ type="password"
56
+ )
57
+
58
+ with gr.Row():
59
+ prompt_input = gr.Textbox(
60
+ label="2. Ask the Agent anything",
61
+ placeholder="Describe what you want me to analyze..."
62
+ )
63
+
64
+ submit_btn = gr.Button("Run Agent", variant="primary")
65
+ output_text = gr.Textbox(label="Agent Response", interactive=False)
66
+
 
67
  submit_btn.click(
68
+ fn=run_descriptor_agent,
69
+ inputs=[key_input, prompt_input],
70
+ outputs=output_text
 
 
 
 
 
71
  )
 
72
 
73
  demo.launch()
74
+ </gradio-app>
 
75
  </body>
76
+ </html>