Skip to content

Commit bff7619

Browse files
FIX: SPS Relatred Refactoring and Fixed in Prompt Service (#550)
* Refactored the prompt service related to SPS * Improved column names for manage documents modal --------- Co-authored-by: Gayathri <142381512+gaya3-zipstack@users.noreply.github.com>
1 parent 951fca2 commit bff7619

3 files changed

Lines changed: 125 additions & 121 deletions

File tree

frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ function ManageDocsModal({
299299
{
300300
title: (
301301
<Space className="w-100">
302-
<Typography.Text>Index</Typography.Text>
302+
<Typography.Text>Raw View</Typography.Text>
303303
<Typography.Text type="secondary">
304304
{"(" + getLlmProfileName(rawLlmProfile) + ")"}
305305
</Typography.Text>
@@ -308,13 +308,13 @@ function ManageDocsModal({
308308
),
309309
dataIndex: "index",
310310
key: "index",
311-
width: 260,
311+
width: 300,
312312
},
313313
{
314-
title: "Index",
314+
title: "Actions",
315315
dataIndex: "reindex",
316316
key: "reindex",
317-
width: 260,
317+
width: 200,
318318
},
319319
{
320320
title: "",
@@ -340,7 +340,7 @@ function ManageDocsModal({
340340
),
341341
dataIndex: "summary",
342342
key: "summary",
343-
width: 260,
343+
width: 300,
344344
});
345345
}
346346

prompt-service/src/unstract/prompt_service/helper.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
from dotenv import load_dotenv
88
from flask import Flask, current_app
99
from unstract.prompt_service.authentication_middleware import AuthenticationMiddleware
10+
from unstract.prompt_service.constants import PromptServiceContants as PSKeys
11+
from unstract.prompt_service.exceptions import APIError, RateLimitError
12+
from unstract.sdk.exceptions import RateLimitError as SdkRateLimitError
13+
from unstract.sdk.llm import LLM
1014

1115
load_dotenv()
1216

@@ -152,3 +156,115 @@ def _get_key_and_item(row: tuple) -> tuple[str, dict[str, Any]]:
152156
def _format_float_positional(value: float, precision: int = 10) -> str:
153157
formatted: str = f"{value:.{precision}f}"
154158
return formatted.rstrip("0").rstrip(".") if "." in formatted else formatted
159+
160+
161+
def extract_variable(
162+
structured_output: dict[str, Any],
163+
variable_names: list[Any],
164+
output: dict[str, Any],
165+
promptx: str,
166+
) -> str:
167+
logger: Logger = current_app.logger
168+
for variable_name in variable_names:
169+
if promptx.find(f"%{variable_name}%") >= 0:
170+
if variable_name in structured_output:
171+
promptx = promptx.replace(
172+
f"%{variable_name}%",
173+
str(structured_output[variable_name]),
174+
)
175+
else:
176+
raise ValueError(
177+
f"Variable {variable_name} not found " "in structured output"
178+
)
179+
180+
if promptx != output[PSKeys.PROMPT]:
181+
logger.info(f"Prompt after variable replacement: {promptx}")
182+
return promptx
183+
184+
185+
def construct_and_run_prompt(
186+
tool_settings: dict[str, Any],
187+
output: dict[str, Any],
188+
llm: LLM,
189+
context: str,
190+
prompt: str,
191+
) -> tuple[str, dict[str, Any]]:
192+
prompt = construct_prompt(
193+
preamble=tool_settings.get(PSKeys.PREAMBLE, ""),
194+
prompt=output[prompt],
195+
postamble=tool_settings.get(PSKeys.POSTAMBLE, ""),
196+
grammar_list=tool_settings.get(PSKeys.GRAMMAR, []),
197+
context=context,
198+
)
199+
return run_completion(
200+
llm=llm,
201+
prompt=prompt,
202+
)
203+
204+
205+
def construct_prompt(
206+
preamble: str,
207+
prompt: str,
208+
postamble: str,
209+
grammar_list: list[dict[str, Any]],
210+
context: str,
211+
) -> str:
212+
logger: Logger = current_app.logger
213+
# Let's cleanup the context. Remove if 3 consecutive newlines are found
214+
context_lines = context.split("\n")
215+
new_context_lines = []
216+
empty_line_count = 0
217+
for line in context_lines:
218+
if line.strip() == "":
219+
empty_line_count += 1
220+
else:
221+
if empty_line_count >= 3:
222+
empty_line_count = 3
223+
for i in range(empty_line_count):
224+
new_context_lines.append("")
225+
empty_line_count = 0
226+
new_context_lines.append(line.rstrip())
227+
context = "\n".join(new_context_lines)
228+
logger.info(
229+
f"Old context length: {len(context_lines)}, "
230+
f"New context length: {len(new_context_lines)}"
231+
)
232+
233+
prompt = (
234+
f"{preamble}\n\nContext:\n---------------{context}\n"
235+
f"-----------------\n\nQuestion or Instruction: {prompt}\n"
236+
)
237+
if grammar_list is not None and len(grammar_list) > 0:
238+
prompt += "\n"
239+
for grammar in grammar_list:
240+
word = ""
241+
synonyms = []
242+
if PSKeys.WORD in grammar:
243+
word = grammar[PSKeys.WORD]
244+
if PSKeys.SYNONYMS in grammar:
245+
synonyms = grammar[PSKeys.SYNONYMS]
246+
if len(synonyms) > 0 and word != "":
247+
prompt += f'\nNote: You can consider that the word {word} is same as \
248+
{", ".join(synonyms)} in both the quesiton and the context.' # noqa
249+
prompt += f"\n\n{postamble}"
250+
prompt += "\n\nAnswer:"
251+
return prompt
252+
253+
254+
def run_completion(
255+
llm: LLM,
256+
prompt: str,
257+
) -> tuple[str, dict[str, Any]]:
258+
logger: Logger = current_app.logger
259+
try:
260+
completion = llm.complete(prompt)
261+
262+
answer: str = completion[PSKeys.RESPONSE].text
263+
return answer
264+
# TODO: Catch and handle specific exception here
265+
except SdkRateLimitError as e:
266+
raise RateLimitError(f"Rate limit error. {str(e)}") from e
267+
except Exception as e:
268+
logger.error(f"Error fetching response for prompt: {e}.")
269+
# TODO: Publish this error as a FE update
270+
raise APIError(str(e)) from e

prompt-service/src/unstract/prompt_service/main.py

Lines changed: 4 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,18 @@
1111
from unstract.prompt_service.config import create_app
1212
from unstract.prompt_service.constants import PromptServiceContants as PSKeys
1313
from unstract.prompt_service.constants import RunLevel
14-
from unstract.prompt_service.exceptions import (
15-
APIError,
16-
ErrorResponse,
17-
NoPayloadError,
18-
RateLimitError,
19-
)
14+
from unstract.prompt_service.exceptions import APIError, ErrorResponse, NoPayloadError
2015
from unstract.prompt_service.helper import (
2116
EnvLoader,
17+
construct_and_run_prompt,
18+
extract_variable,
2219
plugin_loader,
2320
query_usage_metadata,
21+
run_completion,
2422
)
2523
from unstract.prompt_service.prompt_ide_base_tool import PromptServiceBaseTool
2624
from unstract.sdk.constants import LogLevel
2725
from unstract.sdk.embedding import Embedding
28-
from unstract.sdk.exceptions import RateLimitError as SdkRateLimitError
2926
from unstract.sdk.exceptions import SdkError
3027
from unstract.sdk.index import Index
3128
from unstract.sdk.llm import LLM
@@ -81,54 +78,6 @@ def _publish_log(
8178
)
8279

8380

84-
def construct_prompt(
85-
preamble: str,
86-
prompt: str,
87-
postamble: str,
88-
grammar_list: list[dict[str, Any]],
89-
context: str,
90-
) -> str:
91-
# Let's cleanup the context. Remove if 3 consecutive newlines are found
92-
context_lines = context.split("\n")
93-
new_context_lines = []
94-
empty_line_count = 0
95-
for line in context_lines:
96-
if line.strip() == "":
97-
empty_line_count += 1
98-
else:
99-
if empty_line_count >= 3:
100-
empty_line_count = 3
101-
for i in range(empty_line_count):
102-
new_context_lines.append("")
103-
empty_line_count = 0
104-
new_context_lines.append(line.rstrip())
105-
context = "\n".join(new_context_lines)
106-
app.logger.info(
107-
f"Old context length: {len(context_lines)}, "
108-
f"New context length: {len(new_context_lines)}"
109-
)
110-
111-
prompt = (
112-
f"{preamble}\n\nContext:\n---------------{context}\n"
113-
f"-----------------\n\nQuestion or Instruction: {prompt}\n"
114-
)
115-
if grammar_list is not None and len(grammar_list) > 0:
116-
prompt += "\n"
117-
for grammar in grammar_list:
118-
word = ""
119-
synonyms = []
120-
if PSKeys.WORD in grammar:
121-
word = grammar[PSKeys.WORD]
122-
if PSKeys.SYNONYMS in grammar:
123-
synonyms = grammar[PSKeys.SYNONYMS]
124-
if len(synonyms) > 0 and word != "":
125-
prompt += f'\nNote: You can consider that the word {word} is same as \
126-
{", ".join(synonyms)} in both the quesiton and the context.' # noqa
127-
prompt += f"\n\n{postamble}"
128-
prompt += "\n\nAnswer:"
129-
return prompt
130-
131-
13281
def authentication_middleware(func: Any) -> Any:
13382
def wrapper(*args: Any, **kwargs: Any) -> Any:
13483
token = AuthenticationMiddleware.get_token_from_auth_header(request)
@@ -736,67 +685,6 @@ def _retrieve_context(output, doc_id, vector_index, answer) -> str:
736685
return text
737686

738687

739-
def construct_and_run_prompt(
740-
tool_settings: dict[str, Any],
741-
output: dict[str, Any],
742-
llm: LLM,
743-
context: str,
744-
prompt: str,
745-
) -> tuple[str, dict[str, Any]]:
746-
prompt = construct_prompt(
747-
preamble=tool_settings.get(PSKeys.PREAMBLE, ""),
748-
prompt=output[prompt],
749-
postamble=tool_settings.get(PSKeys.POSTAMBLE, ""),
750-
grammar_list=tool_settings.get(PSKeys.GRAMMAR, []),
751-
context=context,
752-
)
753-
return run_completion(
754-
llm=llm,
755-
prompt=prompt,
756-
)
757-
758-
759-
def run_completion(
760-
llm: LLM,
761-
prompt: str,
762-
) -> tuple[str, dict[str, Any]]:
763-
try:
764-
completion = llm.complete(prompt)
765-
766-
answer: str = completion[PSKeys.RESPONSE].text
767-
return answer
768-
# TODO: Catch and handle specific exception here
769-
except SdkRateLimitError as e:
770-
raise RateLimitError(f"Rate limit error. {str(e)}") from e
771-
except Exception as e:
772-
app.logger.error(f"Error fetching response for prompt: {e}.")
773-
# TODO: Publish this error as a FE update
774-
raise APIError(str(e)) from e
775-
776-
777-
def extract_variable(
778-
structured_output: dict[str, Any],
779-
variable_names: list[Any],
780-
output: dict[str, Any],
781-
promptx: str,
782-
) -> str:
783-
for variable_name in variable_names:
784-
if promptx.find(f"%{variable_name}%") >= 0:
785-
if variable_name in structured_output:
786-
promptx = promptx.replace(
787-
f"%{variable_name}%",
788-
str(structured_output[variable_name]),
789-
)
790-
else:
791-
raise ValueError(
792-
f"Variable {variable_name} not found " "in structured output"
793-
)
794-
795-
if promptx != output[PSKeys.PROMPT]:
796-
app.logger.info(f"Prompt after variable replacement: {promptx}")
797-
return promptx
798-
799-
800688
def enable_plugins() -> None:
801689
"""Enables plugins if available."""
802690
single_pass_extration_plugin: dict[str, Any] = plugins.get(

0 commit comments

Comments
 (0)