omgy commited on
Commit
91ef5c3
·
verified ·
1 Parent(s): ff67cf9

Update gemini_utils.py

Browse files
Files changed (1) hide show
  1. gemini_utils.py +68 -128
gemini_utils.py CHANGED
@@ -1,10 +1,11 @@
1
  import os
2
  import json
3
  import re
4
- from typing import Optional, Tuple
5
 
6
  from openai import OpenAI
7
 
 
8
  # Environment configuration
9
  NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY")
10
  NIM_BASE_URL = os.getenv("NIM_BASE_URL", "https://integrate.api.nvidia.com/v1")
@@ -12,156 +13,63 @@ NIM_MODEL_DEFAULT = os.getenv("NIM_MODEL", "meta/llama-3.1-8b-instruct")
12
 
13
  # Sanitization utilities
14
  _PREFACE_RE = re.compile(r"^(okay[, ]|sure[, ]|here(?:'|’)s|summary:?|note:?|context:)\b", re.I)
15
- # Customize anchors to your domain. These help clamp to the main heading if present.
16
  _ANCHOR_RE = re.compile(r"\b(meeting\s*minutes|minutes\s*of\s*meeting|invoice|report|summary)\b", re.I)
17
  _DOC_BLOCK_RE = re.compile(r"\[\[\[DOC\]\]\](.*)\[\[\[\/DOC\]\]\]", re.S)
18
 
 
19
  def _sanitize_preface(text: str) -> str:
 
20
  s = (text or "").lstrip()
 
 
21
  lines = s.splitlines()
22
  while lines and _PREFACE_RE.match(lines[0].strip()):
23
  lines.pop(0)
24
  s = "\n".join(lines).lstrip()
25
 
 
26
  m = _ANCHOR_RE.search(s)
27
  if m:
28
  s = s[m.start():]
29
 
30
  return s.strip()
31
 
 
32
  def _extract_marked_block(text: str) -> Optional[str]:
 
33
  m = _DOC_BLOCK_RE.search(text or "")
34
  if m:
35
  return m.group(1).strip()
36
  return None
37
 
38
- def _finalize(out: str, fallback: str) -> str:
39
- # Hard clamp to markers if present
40
- block = _extract_marked_block(out)
41
- if block:
42
- out = block
43
- out = _sanitize_preface(out)
44
- return out or fallback
45
-
46
- def _nim_call_with_tools(
47
- client: OpenAI, model_name: str, system: str, user: str, timeout_s: int
48
- ) -> str:
49
- """
50
- Strict mode: require a function call so the model must return arguments only.
51
- Parse tool_calls and extract enhanced_text from function.arguments.
52
- """
53
- resp = client.chat.completions.create(
54
- model=model_name,
55
- messages=[
56
- {"role": "system", "content": system},
57
- {"role": "user", "content": user},
58
- ],
59
- temperature=0.0,
60
- top_p=1.0,
61
- max_tokens=8192,
62
- tools=[{
63
- "type": "function",
64
- "function": {
65
- "name": "return_enhanced_text",
66
- "description": "Return the enhanced document text only.",
67
- "parameters": {
68
- "type": "object",
69
- "properties": {"enhanced_text": {"type": "string"}},
70
- "required": ["enhanced_text"]
71
- }
72
- }
73
- }],
74
- # Require the function; some NIM deployments fully support this,
75
- # others may error. We'll catch and fallback if needed.
76
- tool_choice={"type": "function", "function": {"name": "return_enhanced_text"}},
77
- timeout=timeout_s,
78
- )
79
-
80
- msg = resp.choices[0].message
81
- # OpenAI-compatible: tool_calls array with function name + arguments JSON
82
- tool_calls = getattr(msg, "tool_calls", None)
83
- if tool_calls:
84
- for tc in tool_calls:
85
- fn = tc.function
86
- if fn and fn.name == "return_enhanced_text":
87
- try:
88
- args = json.loads(fn.arguments or "{}")
89
- val = args.get("enhanced_text")
90
- if isinstance(val, str) and val.strip():
91
- return val.strip()
92
- except Exception:
93
- pass
94
-
95
- # If the provider didn’t do a tool call or arguments failed to parse,
96
- # try content JSON as a fallback path in this same response.
97
- content = (msg.content or "").strip()
98
- if content:
99
- try:
100
- obj = json.loads(content)
101
- val = obj.get("enhanced_text")
102
- if isinstance(val, str) and val.strip():
103
- return val.strip()
104
- except json.JSONDecodeError:
105
- pass
106
-
107
- # No usable output
108
- return (msg.content or "").strip()
109
-
110
- def _nim_call_json_only(
111
- client: OpenAI, model_name: str, system: str, user: str, timeout_s: int
112
- ) -> str:
113
- """
114
- JSON-only mode: enforce response_format={"type": "json_object"} and parse enhanced_text.
115
- """
116
- resp = client.chat.completions.create(
117
- model=model_name,
118
- messages=[
119
- {"role": "system", "content": system},
120
- {"role": "user", "content": user},
121
- ],
122
- temperature=0.1,
123
- top_p=1.0,
124
- max_tokens=8192,
125
- response_format={"type": "json_object"},
126
- timeout=timeout_s,
127
- )
128
- content = (resp.choices[0].message.content or "").strip()
129
- try:
130
- obj = json.loads(content)
131
- val = obj.get("enhanced_text")
132
- if isinstance(val, str) and val.strip():
133
- return val.strip()
134
- except json.JSONDecodeError:
135
- pass
136
- return content
137
 
138
- def enhance_doc(
139
  extracted_text: str,
140
  user_prompt: str,
141
- nim_model: Optional[str] = None,
142
  timeout_s: int = 60,
143
  ) -> str:
144
  """
145
- Public entrypoint (NIM only):
146
- 1) Try strict function-calling
147
- 2) Fallback to JSON-only
148
- 3) Final clamps (markers + preface removal)
149
- 4) Return enhanced text or original on failure
150
  """
151
  if not NVIDIA_API_KEY:
 
152
  return extracted_text
153
 
154
- model_name = nim_model or NIM_MODEL_DEFAULT
155
  client = OpenAI(api_key=NVIDIA_API_KEY, base_url=NIM_BASE_URL)
156
 
157
  system = (
158
  "You are a professional document editor. Edit and improve the provided document according to the user's "
159
  "instructions while preserving meaning, structure, headings, lists, and tone. "
160
  "Do not include any preface, summary, or explanation. "
161
- "Return the result only via a function call named 'return_enhanced_text' with a single string field "
162
- "'enhanced_text'. If you cannot call the function, return only JSON with a single field 'enhanced_text'. "
163
- "If you produce any extra commentary, it will be discarded.\n"
164
- "If you must show raw text, wrap the final edited document strictly between [[[DOC]]] and [[[/DOC]]]."
165
  )
166
 
167
  user = f"""User instructions:
@@ -171,22 +79,54 @@ Original document:
171
  {extracted_text}
172
  """
173
 
174
- # 1) Strict function-calling attempt
175
  try:
176
- out = _nim_call_with_tools(client, model_name, system, user, timeout_s)
177
- if out:
178
- return _finalize(out, extracted_text)
179
- except Exception:
180
- # Some NIM deployments may not support tool_choice strictly; fall back.
181
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
- # 2) JSON-only attempt
184
- try:
185
- out = _nim_call_json_only(client, model_name, system, user, timeout_s)
186
- if out:
187
- return _finalize(out, extracted_text)
188
  except Exception:
189
- pass
 
 
190
 
191
- # 3) Last resort
192
- return extracted_text
 
 
 
 
 
 
 
 
 
1
  import os
2
  import json
3
  import re
4
+ from typing import Optional
5
 
6
  from openai import OpenAI
7
 
8
+
9
  # Environment configuration
10
  NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY")
11
  NIM_BASE_URL = os.getenv("NIM_BASE_URL", "https://integrate.api.nvidia.com/v1")
 
13
 
14
  # Sanitization utilities
15
  _PREFACE_RE = re.compile(r"^(okay[, ]|sure[, ]|here(?:'|’)s|summary:?|note:?|context:)\b", re.I)
16
+ # Customize anchors for your domain if you have reliable headings
17
  _ANCHOR_RE = re.compile(r"\b(meeting\s*minutes|minutes\s*of\s*meeting|invoice|report|summary)\b", re.I)
18
  _DOC_BLOCK_RE = re.compile(r"\[\[\[DOC\]\]\](.*)\[\[\[\/DOC\]\]\]", re.S)
19
 
20
+
21
  def _sanitize_preface(text: str) -> str:
22
+ """Remove typical LLM prefaces and trim to a reliable anchor if present."""
23
  s = (text or "").lstrip()
24
+
25
+ # Remove obvious preface lines at the start
26
  lines = s.splitlines()
27
  while lines and _PREFACE_RE.match(lines[0].strip()):
28
  lines.pop(0)
29
  s = "\n".join(lines).lstrip()
30
 
31
+ # If your documents have a reliable heading/anchor, trim to it
32
  m = _ANCHOR_RE.search(s)
33
  if m:
34
  s = s[m.start():]
35
 
36
  return s.strip()
37
 
38
+
39
  def _extract_marked_block(text: str) -> Optional[str]:
40
+ """Keep only [[[DOC]]] ... [[[/DOC]]] if present."""
41
  m = _DOC_BLOCK_RE.search(text or "")
42
  if m:
43
  return m.group(1).strip()
44
  return None
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
+ def enhance_with_nim(
48
  extracted_text: str,
49
  user_prompt: str,
50
+ model: Optional[str] = None,
51
  timeout_s: int = 60,
52
  ) -> str:
53
  """
54
+ Enhance document using NVIDIA NIM (OpenAI-compatible Chat Completions).
55
+ Enforces JSON-only output: {"enhanced_text": "..."}.
56
+ Returns only the enhanced text (string). On any failure, returns original text.
 
 
57
  """
58
  if not NVIDIA_API_KEY:
59
+ # No key available -> return original text
60
  return extracted_text
61
 
62
+ model_name = model or NIM_MODEL_DEFAULT
63
  client = OpenAI(api_key=NVIDIA_API_KEY, base_url=NIM_BASE_URL)
64
 
65
  system = (
66
  "You are a professional document editor. Edit and improve the provided document according to the user's "
67
  "instructions while preserving meaning, structure, headings, lists, and tone. "
68
  "Do not include any preface, summary, or explanation. "
69
+ "Return only JSON with a single field 'enhanced_text'. "
70
+ "If you add any extra commentary, it will be ignored.\n"
71
+ "Optionally, also wrap the final edited document between markers [[[DOC]]] and [[[/DOC]]] "
72
+ "if you must return any non-JSON content."
73
  )
74
 
75
  user = f"""User instructions:
 
79
  {extracted_text}
80
  """
81
 
 
82
  try:
83
+ resp = client.chat.completions.create(
84
+ model=model_name,
85
+ messages=[
86
+ {"role": "system", "content": system},
87
+ {"role": "user", "content": user},
88
+ ],
89
+ temperature=0.1,
90
+ top_p=1.0,
91
+ max_tokens=8192,
92
+ response_format={"type": "json_object"}, # enforce JSON
93
+ timeout=timeout_s,
94
+ )
95
+
96
+ content = (resp.choices[0].message.content or "").strip()
97
+
98
+ # Expect a JSON object like {"enhanced_text": "..."}
99
+ try:
100
+ obj = json.loads(content)
101
+ out = obj.get("enhanced_text")
102
+ if isinstance(out, str) and out.strip():
103
+ out = out.strip()
104
+ else:
105
+ out = content
106
+ except json.JSONDecodeError:
107
+ # If model ignored JSON, use raw (then clamp below)
108
+ out = content
109
+
110
+ # Final clamps
111
+ block = _extract_marked_block(out)
112
+ if block:
113
+ out = block
114
+ out = _sanitize_preface(out)
115
+
116
+ return out or extracted_text
117
 
 
 
 
 
 
118
  except Exception:
119
+ # On any error, return original text
120
+ return extracted_text
121
+
122
 
123
+ def enhance_doc(
124
+ extracted_text: str,
125
+ user_prompt: str,
126
+ nim_model: Optional[str] = None,
127
+ ) -> str:
128
+ """
129
+ Public entrypoint: enhance via NIM only.
130
+ Returns the enhanced text or the original text on failure.
131
+ """
132
+ return enhance_with_nim(extracted_text, user_prompt, model=nim_model)