resumesearch commited on
Commit
9c52a51
·
verified ·
1 Parent(s): 78bd53d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -49
app.py CHANGED
@@ -1,33 +1,44 @@
1
- # At top of your file:
2
- import tiktoken
3
- import openai
4
- from openai.error import InvalidRequestError
 
5
  import openai
 
 
 
6
 
7
- # some versions expose exceptions under openai.error, others at the root
8
  try:
9
  from openai.error import InvalidRequestError
10
  except ImportError:
11
  InvalidRequestError = openai.InvalidRequestError
12
 
13
- # Choose your model and its max context size
14
- MODEL_NAME = "gpt-4-32k"
15
- MAX_CONTEXT = 32768 # GPT-4-32k model limit
16
- SUMMARY_MAX_TOKENS = 1024 # how long each summary can be
 
 
 
 
 
17
 
18
- # Helper to count tokens
19
- def count_tokens(text: str, model: str=MODEL_NAME) -> int:
20
  enc = tiktoken.encoding_for_model(model)
21
  return len(enc.encode(text))
22
 
23
- # Simple chunker by word so each chunk’s token count ≤ limit
24
- def chunk_text(text: str, max_tokens: int, model: str=MODEL_NAME):
 
 
 
25
  words = text.split()
26
  chunks, current = [], []
27
  for w in words:
28
  current.append(w)
29
  if count_tokens(" ".join(current), model) >= max_tokens:
30
- # pop last word into next chunk
31
  last = current.pop()
32
  chunks.append(" ".join(current))
33
  current = [last]
@@ -35,77 +46,81 @@ def chunk_text(text: str, max_tokens: int, model: str=MODEL_NAME):
35
  chunks.append(" ".join(current))
36
  return chunks
37
 
38
- # Summarize a single chunk
39
  async def summarize_chunk(chunk: str) -> str:
 
40
  resp = await openai.ChatCompletion.acreate(
41
  model=MODEL_NAME,
42
  messages=[
43
- {"role":"system", "content":"You are a concise summarizer."},
44
- {"role":"user", "content": f"Summarize this text briefly, preserving key details:\n\n{chunk}"}
45
  ],
46
  max_tokens=SUMMARY_MAX_TOKENS,
47
- temperature=0.0,
48
  )
49
  return resp.choices[0].message.content.strip()
50
 
51
- # Entry-point wrapper that transparently handles over-limit inputs
52
- def safe_chat_completion(convo: list, max_tokens: int):
53
  """
54
- convo: full messages list (system, history, user)
 
55
  """
56
  try:
57
  return openai.ChatCompletion.create(
58
  model=MODEL_NAME,
59
  messages=convo,
60
  max_tokens=max_tokens,
61
- temperature=0.3,
62
  )
63
  except InvalidRequestError as e:
64
  err = str(e)
65
  if "maximum context length" not in err:
66
- raise # re-raise any other error
67
- # Token limit hit → shrink only the last user message
68
- last_msg = convo[-1]["content"]
69
- # leave 500 tokens buffer for reply
70
- allowed = MAX_CONTEXT - count_tokens("".join(m["content"] for m in convo[:-1]), MODEL_NAME) - 500
71
- # chunk & summarize
72
- raw_chunks = chunk_text(last_msg, allowed // 2, MODEL_NAME)
73
- # run summarizations
74
- import asyncio
 
 
 
75
  summaries = asyncio.get_event_loop().run_until_complete(
76
  asyncio.gather(*(summarize_chunk(c) for c in raw_chunks))
77
  )
78
- new_msg = " ".join(summaries)
79
- convo[-1]["content"] = new_msg
80
- # retry once
81
  return openai.ChatCompletion.create(
82
  model=MODEL_NAME,
83
  messages=convo,
84
  max_tokens=max_tokens,
85
- temperature=0.3,
86
  )
87
 
88
- # Then in your chat handler:
89
  def chat_handler(
90
  user_message: str,
91
- history: list,
92
- system_prompt: str,
93
- ):
 
94
  if not user_message.strip():
95
  return history, ""
96
 
97
- # build messages list
98
- convo = [{"role":"system","content":system_prompt}]
99
- for u, b in history:
100
- convo += [
101
- {"role":"user","content":u},
102
- {"role":"assistant","content":b},
103
- ]
104
- convo.append({"role":"user","content":user_message})
105
 
106
- # call via safe wrapper
 
 
 
 
 
 
 
107
  try:
108
- resp = safe_chat_completion(convo, max_tokens=2048)
109
  reply = resp.choices[0].message.content
110
  except Exception as e:
111
  reply = f"❌ OpenAI error: {e}"
@@ -113,3 +128,35 @@ def chat_handler(
113
  history = history or []
114
  history.append((user_message, reply))
115
  return history, ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ app.py – Advanced OpenAI Chatbot with Automatic Long‐Input Handling
3
+ """
4
+
5
+ import os
6
  import openai
7
+ import asyncio
8
+ import gradio as gr
9
+ import tiktoken
10
 
11
+ # Handle exception import across SDK versions
12
  try:
13
  from openai.error import InvalidRequestError
14
  except ImportError:
15
  InvalidRequestError = openai.InvalidRequestError
16
 
17
+ # Configuration
18
+ MODEL_NAME = "gpt-4-32k" # high‐capacity model
19
+ MAX_CONTEXT_TOKENS = 32768 # model’s max context
20
+ SUMMARY_MAX_TOKENS = 1024 # summary length per chunk
21
+ REPLY_MAX_TOKENS = 2048 # max tokens for reply
22
+ TEMPERATURE = 0.3
23
+
24
+ # Load API key
25
+ openai.api_key = os.getenv("OPENAI_API_KEY", "").strip()
26
 
27
+ def count_tokens(text: str, model: str = MODEL_NAME) -> int:
28
+ """Return token count for given text and model."""
29
  enc = tiktoken.encoding_for_model(model)
30
  return len(enc.encode(text))
31
 
32
+ def chunk_text(text: str, max_tokens: int, model: str = MODEL_NAME) -> list[str]:
33
+ """
34
+ Split text into chunks so each chunk’s token count ≤ max_tokens.
35
+ Splits on word boundaries.
36
+ """
37
  words = text.split()
38
  chunks, current = [], []
39
  for w in words:
40
  current.append(w)
41
  if count_tokens(" ".join(current), model) >= max_tokens:
 
42
  last = current.pop()
43
  chunks.append(" ".join(current))
44
  current = [last]
 
46
  chunks.append(" ".join(current))
47
  return chunks
48
 
 
49
  async def summarize_chunk(chunk: str) -> str:
50
+ """Async call to summarize one text chunk."""
51
  resp = await openai.ChatCompletion.acreate(
52
  model=MODEL_NAME,
53
  messages=[
54
+ {"role": "system", "content": "You are a concise summarizer."},
55
+ {"role": "user", "content": f"Summarize this text briefly, preserving key details:\n\n{chunk}"}
56
  ],
57
  max_tokens=SUMMARY_MAX_TOKENS,
58
+ temperature=0.0
59
  )
60
  return resp.choices[0].message.content.strip()
61
 
62
+ def safe_chat_completion(convo: list[dict], max_tokens: int) -> openai.openai_object.OpenAIObject:
 
63
  """
64
+ Perform ChatCompletion.create, catch context‐length errors,
65
+ summarize the last user message, and retry once.
66
  """
67
  try:
68
  return openai.ChatCompletion.create(
69
  model=MODEL_NAME,
70
  messages=convo,
71
  max_tokens=max_tokens,
72
+ temperature=TEMPERATURE
73
  )
74
  except InvalidRequestError as e:
75
  err = str(e)
76
  if "maximum context length" not in err:
77
+ raise
78
+
79
+ # Determine how many tokens remain for the latest user message
80
+ used = count_tokens("".join(m["content"] for m in convo[:-1]), MODEL_NAME)
81
+ buffer = 500 # reserve tokens for the reply
82
+ allowed_for_user = MAX_CONTEXT_TOKENS - used - buffer
83
+ if allowed_for_user < 100:
84
+ raise RuntimeError("Context too large even after trimming.")
85
+
86
+ # Chunk & summarize the last user message
87
+ last = convo[-1]["content"]
88
+ raw_chunks = chunk_text(last, allowed_for_user // 2, MODEL_NAME)
89
  summaries = asyncio.get_event_loop().run_until_complete(
90
  asyncio.gather(*(summarize_chunk(c) for c in raw_chunks))
91
  )
92
+ convo[-1]["content"] = " ".join(summaries)
93
+
94
+ # Retry once
95
  return openai.ChatCompletion.create(
96
  model=MODEL_NAME,
97
  messages=convo,
98
  max_tokens=max_tokens,
99
+ temperature=TEMPERATURE
100
  )
101
 
 
102
  def chat_handler(
103
  user_message: str,
104
+ history: list[tuple[str, str]],
105
+ system_prompt: str
106
+ ) -> tuple[list[tuple[str, str]], str]:
107
+ """Gradio handler: builds convo, calls safe_chat_completion, updates history."""
108
  if not user_message.strip():
109
  return history, ""
110
 
111
+ if not openai.api_key:
112
+ return history, "❌ OPENAI_API_KEY not set."
 
 
 
 
 
 
113
 
114
+ # Build conversation
115
+ convo = [{"role": "system", "content": system_prompt}]
116
+ for user, bot in history:
117
+ convo.append({"role": "user", "content": user})
118
+ convo.append({"role": "assistant", "content": bot})
119
+ convo.append({"role": "user", "content": user_message})
120
+
121
+ # Call OpenAI safely
122
  try:
123
+ resp = safe_chat_completion(convo, max_tokens=REPLY_MAX_TOKENS)
124
  reply = resp.choices[0].message.content
125
  except Exception as e:
126
  reply = f"❌ OpenAI error: {e}"
 
128
  history = history or []
129
  history.append((user_message, reply))
130
  return history, ""
131
+
132
+ # Gradio UI
133
+ with gr.Blocks(title="🤖 Advanced Chatbot (Long‐Input Safe)") as demo:
134
+ gr.Markdown(
135
+ """
136
+ # Advanced Chatbot
137
+ Paste arbitrarily long code or text; the bot will auto‐summarize overflow.
138
+ Expert in Python & C# with production‐grade answers.
139
+ """
140
+ )
141
+
142
+ system_txt = gr.Textbox(
143
+ lines=3,
144
+ value=(
145
+ "You are an expert software engineer specializing in Python and C#. "
146
+ "Provide detailed, production‐grade answers and include code snippets when appropriate."
147
+ ),
148
+ label="System Prompt"
149
+ )
150
+
151
+ chatbot = gr.Chatbot(label="Conversation")
152
+ user_input = gr.Textbox(placeholder="Type your message here...", label="You")
153
+ send_btn = gr.Button("Send")
154
+
155
+ send_btn.click(
156
+ fn=chat_handler,
157
+ inputs=[user_input, chatbot, system_txt],
158
+ outputs=[chatbot, user_input]
159
+ )
160
+
161
+ if __name__ == "__main__":
162
+ demo.launch()