rrg92 commited on
Commit
827af88
·
verified ·
1 Parent(s): 4f5cccc

Update app.py

Browse files

Minor error log in search function exec

Files changed (1) hide show
  1. app.py +475 -473
app.py CHANGED
@@ -1,473 +1,475 @@
1
- import gradio as gr
2
- import spaces
3
- from sentence_transformers import SentenceTransformer
4
- from sentence_transformers.util import cos_sim
5
- from sentence_transformers.quantization import quantize_embeddings
6
- import pymssql
7
- import os
8
- import pandas as pd
9
- from openai import OpenAI
10
- from pydantic import BaseModel, Field
11
- import json
12
- from sentence_transformers import CrossEncoder
13
- from torch import nn
14
- import time
15
-
16
-
17
- SqlServer = os.environ['SQL_SERVER']
18
- SqlDatabase = os.environ['SQL_DB']
19
- SqlUser = os.environ['SQL_USER']
20
- SqlPass = os.environ['SQL_PASS']
21
-
22
-
23
- OpenaiApiKey = os.environ.get("OPENAI_API_KEY")
24
- OpenaiBaseUrl = os.environ.get("OPENAI_BASE_URL","https://generativelanguage.googleapis.com/v1beta/openai")
25
-
26
-
27
- def sql(query,db=SqlDatabase, login_timeout = 120,onConnectionError = None):
28
-
29
- start_time = time.time()
30
-
31
- while True:
32
- try:
33
- cnxn = pymssql.connect(SqlServer,SqlUser,SqlPass,db, login_timeout = 5)
34
- break;
35
- except Exception as e:
36
- if onConnectionError:
37
- onConnectionError(e)
38
-
39
- if time.time() - start_time > login_timeout:
40
- raise TimeoutError("SQL Connection Timeout");
41
-
42
- time.sleep(1) # Espera 1 segundo antes de tentar novamente
43
-
44
-
45
- cursor = cnxn.cursor()
46
- cursor.execute(query)
47
-
48
- columns = [column[0] for column in cursor.description]
49
- results = [dict(zip(columns, row)) for row in cursor.fetchall()]
50
-
51
- return results;
52
-
53
-
54
-
55
- @spaces.GPU
56
- def embed(text):
57
-
58
- query_embedding = Embedder.encode(text)
59
- return query_embedding.tolist();
60
-
61
-
62
- @spaces.GPU
63
- def rerank(query,documents, **kwargs):
64
- return Reranker.rank(query, documents, **kwargs)
65
-
66
- ClientOpenai = OpenAI(
67
- api_key=OpenaiApiKey
68
- ,base_url=OpenaiBaseUrl
69
- )
70
-
71
- def llm(messages, ResponseFormat = None, **kwargs):
72
-
73
- fn = ClientOpenai.chat.completions.create
74
-
75
- if ResponseFormat:
76
- fn = ClientOpenai.beta.chat.completions.parse
77
-
78
- params = {
79
- 'model':"gemini-2.0-flash"
80
- ,'n':1
81
- ,'messages':messages
82
- ,'response_format':ResponseFormat
83
- }
84
-
85
- params.update(kwargs);
86
-
87
- response = fn(**params)
88
-
89
- if params.get('stream'):
90
- return response
91
-
92
- return response.choices[0];
93
-
94
- def ai(system,user, schema, **kwargs):
95
- msg = [
96
- {'role':"system",'content':system}
97
- ,{'role':"user",'content':user}
98
- ]
99
-
100
- return llm(msg, schema, **kwargs);
101
-
102
-
103
- def search(text, top = 10, onConnectionError = None):
104
-
105
- EnglishText = text
106
-
107
- embeddings = embed(text);
108
-
109
- query = f"""
110
- declare @search vector(1024) = '{embeddings}'
111
-
112
- select top {top}
113
- *
114
- from (
115
- select
116
- RelPath
117
- ,Similaridade = 1-CosDistance
118
- ,ScriptContent = ChunkContent
119
- ,ContentLength = LEN(ChunkContent)
120
- ,CosDistance
121
- from
122
- (
123
- select
124
- *
125
- ,CosDistance = vector_distance('cosine',embeddings,@search)
126
- from
127
- Scripts
128
- ) C
129
- ) v
130
- order by
131
- CosDistance
132
- """
133
-
134
- queryResults = sql(query, onConnectionError = onConnectionError);
135
-
136
-
137
-
138
- return queryResults
139
-
140
-
141
- print("Loading embedding model");
142
- Embedder = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1")
143
-
144
- print("Loading reranker");
145
- Reranker = CrossEncoder("mixedbread-ai/mxbai-rerank-large-v1", activation_fn=nn.Sigmoid())
146
-
147
- class rfTranslatedText(BaseModel):
148
- text: str = Field(description='Translated text')
149
- lang: str = Field(description='source language')
150
-
151
- class rfGenericText(BaseModel):
152
- text: str = Field(description='The text result')
153
-
154
- def ChatFunc(message, history, LangMode, ChooseLang):
155
-
156
-
157
- # Determinar se o user quer fazer uma nova pesquisa!
158
- IsNewSearch = True;
159
-
160
- messages = []
161
- CurrentTable = None;
162
-
163
- def ChatBotOutput():
164
- return [messages,CurrentTable]
165
-
166
- class BotMessage():
167
- def __init__(self, *args, **kwargs):
168
- self.Message = gr.ChatMessage(*args, **kwargs)
169
- self.LastContent = None
170
- messages.append(self.Message);
171
-
172
- def __call__(self, content, noNewLine = False):
173
- if not content:
174
- return;
175
-
176
- self.Message.content += content;
177
- self.LastContent = None;
178
-
179
- if not noNewLine:
180
- self.Message.content += "\n";
181
-
182
- return ChatBotOutput();
183
-
184
- def update(self,content):
185
-
186
- if not self.LastContent:
187
- self.LastContent = self.Message.content
188
-
189
- self.Message.content = self.LastContent +" "+content+"\n";
190
-
191
- return ChatBotOutput();
192
-
193
- def done(self):
194
- self.Message.metadata['status'] = "done";
195
- return ChatBotOutput();
196
-
197
- def Reply(msg):
198
- m = BotMessage(msg);
199
- return ChatBotOutput();
200
-
201
- m = BotMessage("",metadata={"title":"Searching scripts...","status":"pending"});
202
-
203
-
204
- def OnConnError(err):
205
- print("Sql connection error:", err)
206
-
207
-
208
- try:
209
- # Responder algo sobre o historico!
210
- if IsNewSearch:
211
-
212
- yield m("Enhancing the prompt...")
213
-
214
- LLMResult = ai("""
215
- Translate the user's message to English.
216
- The message is a question related to a SQL Server T-SQL script that the user is searching for.
217
- You must do following actions:
218
- - Identify the language of user text, using BCP 47 code (example: pt-BR, en-US, ja-JP, etc.)
219
- - Generate translated user text to english
220
- Return both source language and translated text.
221
- """,message, rfTranslatedText)
222
- Question = LLMResult.message.parsed.text;
223
-
224
- if LangMode == "auto":
225
- SourceLang = LLMResult.message.parsed.lang;
226
- else:
227
- SourceLang = ChooseLang
228
-
229
- yield m(f"Lang:{SourceLang}({LangMode}), English Prompt: {Question}")
230
-
231
- yield m("searching...")
232
- try:
233
- FoundScripts = search(Question, onConnectionError = OnConnError)
234
- except:
235
- yield m("Houve alguma falha ao executar a consulta no banco. Tente novamente. Se persistir, veja orientações na aba Help!")
236
- return;
237
-
238
- yield m("Doing rerank");
239
- doclist = [doc['ScriptContent'] for doc in FoundScripts]
240
-
241
- # Faz o reranker!
242
- for score in rerank(Question, doclist):
243
- i = score['corpus_id'];
244
- FoundScripts[i]['rank'] = str(score['score'])
245
-
246
- RankedScripts = sorted(FoundScripts, key=lambda item: float(item['rank']), reverse=True)
247
-
248
-
249
-
250
- ScriptTable = []
251
- for script in RankedScripts:
252
- link = "https://github.com/rrg92/sqlserver-lib/tree/main/" + script['RelPath']
253
- script['link'] = link;
254
-
255
- ScriptTable.append({
256
- 'Link': f'<a title="{link}" href="{link}" target="_blank">{script["RelPath"]}</a>'
257
- ,'Length': script['ContentLength']
258
- ,'Cosine Similarity': script['Similaridade']
259
- ,'Rank': script['rank']
260
- })
261
-
262
-
263
- CurrentTable = pd.DataFrame(ScriptTable)
264
- yield m("Found scripts, check Rank tab for details!")
265
-
266
-
267
- WaitMessage = ai(f"""
268
- You will analyze some T-SQL scripts in order to check which is best for the user.
269
- You found scripts, presented them to the user, and now will do some work that takes time.
270
- Generate a message to tell the user to wait while you work, in the same language as the user.
271
- You will receive the question the user sent that triggered this process.
272
- Use the user’s original question to customize the message.
273
- Answer in lang: {SourceLang}
274
- """,message,rfGenericText).message.parsed.text
275
-
276
- yield Reply(WaitMessage);
277
-
278
- yield m(f"Analyzing scripts...")
279
-
280
-
281
- ResultJson = json.dumps(RankedScripts);
282
-
283
- SystemPrompt = f"""
284
- You are an assistant that helps users find the best T-SQL scripts for their specific needs.
285
- These scripts were created by Rodrigo Ribeiro Gomes and are publicly available for users to query and use.
286
-
287
- The user will provide a short description of what they are looking for, and your task is to present the most relevant scripts.
288
-
289
- To assist you, here is a JSON object with the top matches based on the current user query:
290
- {ResultJson}
291
-
292
- ---
293
- This JSON contains all the scripts that matched the user's input.
294
- Analyze each script's name and content, and create a ranked summary of the best recommendations according to the user's need.
295
-
296
- Only use the information available in the provided JSON. Do not reference or mention anything outside of this list.
297
- You can include parts of the scripts in your answer to illustrate or give usage examples based on the user's request.
298
-
299
- Re-rank the results if necessary, presenting them from the most to the least relevant.
300
- You may filter out scripts that appear unrelated to the user query.
301
-
302
- ---
303
- ### Output Rules
304
-
305
- - Review each script and evaluate how well it matches the user’s request.
306
- - Summarize each script, ordering from the most relevant to the least relevant.
307
- - Write personalized and informative review text for each recommendation.
308
- - If applicable, explain how the user should run the script, including parameters or sections (like `WHERE` clauses) they might need to customize.
309
- - When referencing a script, include the link provided in the JSON — all scripts are hosted on GitHub
310
- - YOU MUST ANSWER THAT LANGUAGE: {SourceLang}
311
- """
312
-
313
- ScriptPrompt = [
314
- { 'role':'system', 'content':SystemPrompt }
315
- ,{ 'role':'user', 'content':message }
316
- ]
317
-
318
-
319
-
320
-
321
- llmanswer = llm(ScriptPrompt, stream = True)
322
- yield m.done()
323
-
324
- answer = BotMessage("");
325
-
326
- for chunk in llmanswer:
327
- content = chunk.choices[0].delta.content
328
- yield answer(content, noNewLine = True)
329
- finally:
330
- yield m.done()
331
-
332
- def SearchFiles(message):
333
-
334
- Question = message;
335
-
336
- try:
337
- FoundScripts = search(Question)
338
- except:
339
- return m("Houve alguma falha ao executar a consulta no banco. Tente novamente. Se persistir, veja orientações na aba Help!")
340
- return;
341
-
342
- doclist = [doc['ScriptContent'] for doc in FoundScripts]
343
-
344
- # Faz o reranker!
345
-
346
-
347
-
348
- ScriptTable = [];
349
- for score in rerank(Question, doclist):
350
- i = score['corpus_id'];
351
- script = FoundScripts[i];
352
- script['rank'] = str(score['score'])
353
- link = "https://github.com/rrg92/sqlserver-lib/tree/main/" + script['RelPath']
354
- script['link'] = link;
355
-
356
- if not AsJson:
357
- ScriptTable.append({
358
- 'Link': f'<a title="{link}" href="{link}" target="_blank">{script["RelPath"]}</a>'
359
- ,'Length': script['ContentLength']
360
- ,'Cosine Similarity': script['Similaridade']
361
- ,'Rank': script['rank']
362
- })
363
-
364
- RankedScripts = sorted(FoundScripts, key=lambda item: float(item['rank']), reverse=True)
365
-
366
- #result = pd.DataFrame(ScriptTable)
367
- jsonresult = json.dumps(RankedScripts)
368
-
369
- return jsonresult;
370
-
371
- resultTable = gr.Dataframe(datatype = ['html','number','number'], interactive = False, show_search = "search");
372
- TextResults = gr.Textbox()
373
-
374
- with gr.Blocks(fill_height=True) as demo:
375
-
376
- with gr.Column():
377
-
378
- tabSettings = gr.Tab("Settings", render = False)
379
-
380
- with tabSettings:
381
- LangOpts = gr.Radio([("Auto Detect from text","auto"), ("Use browser language","browser")], value="auto", label="Language", info="Choose lang used by AI to answer you!")
382
- LangChoose = gr.Textbox(info = "This will be filled with detect browser language, but you can change")
383
-
384
- LangOpts.change(None, [LangOpts],[LangChoose], js = """
385
- function(opt){
386
- if(opt == "browser"){
387
- return navigator ? navigator.language : "en-US";
388
- }
389
- }
390
- """)
391
-
392
-
393
- with gr.Tab("Chat", scale = 1):
394
- ChatTextBox = gr.Textbox(max_length = 500, info = "Which script are you looking for?", submit_btn = True);
395
-
396
- gr.ChatInterface(
397
- ChatFunc
398
- ,additional_outputs=[resultTable]
399
- ,additional_inputs=[LangOpts,LangChoose]
400
- ,type="messages"
401
- ,textbox = ChatTextBox
402
- )
403
-
404
- tabSettings.render()
405
-
406
-
407
- with gr.Tab("Rank"):
408
- txtSearchTable = gr.Textbox(label="Search script files",info="Description of what you want", visible = False)
409
- AsJson = gr.Checkbox(visible = False)
410
- resultTable.render();
411
-
412
-
413
- txtSearchTable.submit(SearchFiles, [txtSearchTable],[TextResults])
414
-
415
- with gr.Tab("Help"):
416
- gr.Markdown("""
417
- Bem-vindo ao Space SQL Server Lib
418
- Este space permite que você encontre scripts SQL do https://github.com/rrg92/sqlserver-lib com base nas suas necessidades
419
-
420
-
421
- ## Instruções de Uso
422
- Apenas descreva o que você precisa no campo de chat e aguarde a IA analisar os melhores scripts do repositório para você.
423
- Além de uma explicação feita pela IA, a aba "Rank", contém uma tabela com os scripts encontrados e seus respectictos rank.
424
- A coluna Cosine Similarity é o nível de similaridades da sua pergunta com o script (calculado baseado nos embeddings do seu texto e do script).
425
- A coluna Rank é um score onde quanto maior o valor mais relacionado ao seu texto o script é (calculado usando rerank/cross encoders). A tabela vem ordenada por essa coluna.
426
-
427
-
428
- ## Fluxo básico
429
- - Quando você digita o texto, iremos fazer uma busca usando embeddings em um banco Azure SQL Database
430
- - Os embeddings são calculados usando um modelo carregado no proprio script, via ZeroGPU.
431
- - Os top 20 resultados mais similares são retornados e então um rerank é feito
432
- - O rerank também é feito por um modelo que roda no próprio script, em ZeroGPU
433
- - Estes resultados ordenados por reran, são então enviados ao LLM para que analise e monte uma resposta para você.
434
-
435
-
436
- ## Sobre o uso e eventuais erros
437
- Eu tento usar o máximo de recursos FREE e open possíveis, e portanto, eventualmente, o Space pode falhar por alguma limitação.
438
- Alguns possíveis pontos de falha:
439
- - Créditos free do google ou rate limit
440
- - Azure SQL database offline devido a crédito ou ao auto-pause (devido ao free tier)
441
- - Limites de uso do ZeroGPU do Hugging Face.
442
-
443
- Você pode me procurar no [linkedin](https://www.linkedin.com/in/rodrigoribeirogomes/), caso receba erroslimit
444
-
445
- """)
446
-
447
- with gr.Tab("Other", visible = False):
448
- txtEmbed = gr.Text(label="Text to embed", visible=False)
449
- btnEmbed = gr.Button("embed");
450
- btnEmbed.click(embed, [txtEmbed], [txtEmbed])
451
-
452
- TextResults.render();
453
-
454
-
455
-
456
-
457
-
458
-
459
-
460
-
461
-
462
-
463
-
464
-
465
-
466
- if __name__ == "__main__":
467
- demo.launch(
468
- share=False,
469
- debug=False,
470
- server_port=7860,
471
- server_name="0.0.0.0",
472
- allowed_paths=[]
473
- )
 
 
 
1
+ import gradio as gr
2
+ import spaces
3
+ from sentence_transformers import SentenceTransformer
4
+ from sentence_transformers.util import cos_sim
5
+ from sentence_transformers.quantization import quantize_embeddings
6
+ import pymssql
7
+ import os
8
+ import pandas as pd
9
+ from openai import OpenAI
10
+ from pydantic import BaseModel, Field
11
+ import json
12
+ from sentence_transformers import CrossEncoder
13
+ from torch import nn
14
+ import time
15
+
16
+
17
+ SqlServer = os.environ['SQL_SERVER']
18
+ SqlDatabase = os.environ['SQL_DB']
19
+ SqlUser = os.environ['SQL_USER']
20
+ SqlPass = os.environ['SQL_PASS']
21
+
22
+
23
+ OpenaiApiKey = os.environ.get("OPENAI_API_KEY")
24
+ OpenaiBaseUrl = os.environ.get("OPENAI_BASE_URL","https://generativelanguage.googleapis.com/v1beta/openai")
25
+
26
+
27
+ def sql(query,db=SqlDatabase, login_timeout = 120,onConnectionError = None):
28
+
29
+ start_time = time.time()
30
+
31
+ while True:
32
+ try:
33
+ cnxn = pymssql.connect(SqlServer,SqlUser,SqlPass,db, login_timeout = 5)
34
+ break;
35
+ except Exception as e:
36
+ if onConnectionError:
37
+ onConnectionError(e)
38
+
39
+ if time.time() - start_time > login_timeout:
40
+ raise TimeoutError("SQL Connection Timeout");
41
+
42
+ time.sleep(1) # Espera 1 segundo antes de tentar novamente
43
+
44
+
45
+ cursor = cnxn.cursor()
46
+ cursor.execute(query)
47
+
48
+ columns = [column[0] for column in cursor.description]
49
+ results = [dict(zip(columns, row)) for row in cursor.fetchall()]
50
+
51
+ return results;
52
+
53
+
54
+
55
+ @spaces.GPU
56
+ def embed(text):
57
+
58
+ query_embedding = Embedder.encode(text)
59
+ return query_embedding.tolist();
60
+
61
+
62
+ @spaces.GPU
63
+ def rerank(query,documents, **kwargs):
64
+ return Reranker.rank(query, documents, **kwargs)
65
+
66
+ ClientOpenai = OpenAI(
67
+ api_key=OpenaiApiKey
68
+ ,base_url=OpenaiBaseUrl
69
+ )
70
+
71
+ def llm(messages, ResponseFormat = None, **kwargs):
72
+
73
+ fn = ClientOpenai.chat.completions.create
74
+
75
+ if ResponseFormat:
76
+ fn = ClientOpenai.beta.chat.completions.parse
77
+
78
+ params = {
79
+ 'model':"gemini-2.0-flash"
80
+ ,'n':1
81
+ ,'messages':messages
82
+ ,'response_format':ResponseFormat
83
+ }
84
+
85
+ params.update(kwargs);
86
+
87
+ response = fn(**params)
88
+
89
+ if params.get('stream'):
90
+ return response
91
+
92
+ return response.choices[0];
93
+
94
+ def ai(system,user, schema, **kwargs):
95
+ msg = [
96
+ {'role':"system",'content':system}
97
+ ,{'role':"user",'content':user}
98
+ ]
99
+
100
+ return llm(msg, schema, **kwargs);
101
+
102
+
103
+ def search(text, top = 10, onConnectionError = None):
104
+
105
+ EnglishText = text
106
+
107
+ embeddings = embed(text);
108
+
109
+ query = f"""
110
+ declare @search vector(1024) = '{embeddings}'
111
+
112
+ select top {top}
113
+ *
114
+ from (
115
+ select
116
+ RelPath
117
+ ,Similaridade = 1-CosDistance
118
+ ,ScriptContent = ChunkContent
119
+ ,ContentLength = LEN(ChunkContent)
120
+ ,CosDistance
121
+ from
122
+ (
123
+ select
124
+ *
125
+ ,CosDistance = vector_distance('cosine',embeddings,@search)
126
+ from
127
+ Scripts
128
+ ) C
129
+ ) v
130
+ order by
131
+ CosDistance
132
+ """
133
+
134
+ queryResults = sql(query, onConnectionError = onConnectionError);
135
+
136
+
137
+
138
+ return queryResults
139
+
140
+
141
+ print("Loading embedding model");
142
+ Embedder = SentenceTransformer("mixedbread-ai/mxbai-embed-large-v1")
143
+
144
+ print("Loading reranker");
145
+ Reranker = CrossEncoder("mixedbread-ai/mxbai-rerank-large-v1", activation_fn=nn.Sigmoid())
146
+
147
+ class rfTranslatedText(BaseModel):
148
+ text: str = Field(description='Translated text')
149
+ lang: str = Field(description='source language')
150
+
151
+ class rfGenericText(BaseModel):
152
+ text: str = Field(description='The text result')
153
+
154
+ def ChatFunc(message, history, LangMode, ChooseLang):
155
+
156
+
157
+ # Determinar se o user quer fazer uma nova pesquisa!
158
+ IsNewSearch = True;
159
+
160
+ messages = []
161
+ CurrentTable = None;
162
+
163
+ def ChatBotOutput():
164
+ return [messages,CurrentTable]
165
+
166
+ class BotMessage():
167
+ def __init__(self, *args, **kwargs):
168
+ self.Message = gr.ChatMessage(*args, **kwargs)
169
+ self.LastContent = None
170
+ messages.append(self.Message);
171
+
172
+ def __call__(self, content, noNewLine = False):
173
+ if not content:
174
+ return;
175
+
176
+ self.Message.content += content;
177
+ self.LastContent = None;
178
+
179
+ if not noNewLine:
180
+ self.Message.content += "\n";
181
+
182
+ return ChatBotOutput();
183
+
184
+ def update(self,content):
185
+
186
+ if not self.LastContent:
187
+ self.LastContent = self.Message.content
188
+
189
+ self.Message.content = self.LastContent +" "+content+"\n";
190
+
191
+ return ChatBotOutput();
192
+
193
+ def done(self):
194
+ self.Message.metadata['status'] = "done";
195
+ return ChatBotOutput();
196
+
197
+ def Reply(msg):
198
+ m = BotMessage(msg);
199
+ return ChatBotOutput();
200
+
201
+ m = BotMessage("",metadata={"title":"Searching scripts...","status":"pending"});
202
+
203
+
204
+ def OnConnError(err):
205
+ print("Sql connection error:", err)
206
+
207
+
208
+ try:
209
+ # Responder algo sobre o historico!
210
+ if IsNewSearch:
211
+
212
+ yield m("Enhancing the prompt...")
213
+
214
+ LLMResult = ai("""
215
+ Translate the user's message to English.
216
+ The message is a question related to a SQL Server T-SQL script that the user is searching for.
217
+ You must do following actions:
218
+ - Identify the language of user text, using BCP 47 code (example: pt-BR, en-US, ja-JP, etc.)
219
+ - Generate translated user text to english
220
+ Return both source language and translated text.
221
+ """,message, rfTranslatedText)
222
+ Question = LLMResult.message.parsed.text;
223
+
224
+ if LangMode == "auto":
225
+ SourceLang = LLMResult.message.parsed.lang;
226
+ else:
227
+ SourceLang = ChooseLang
228
+
229
+ yield m(f"Lang:{SourceLang}({LangMode}), English Prompt: {Question}")
230
+
231
+ yield m("searching...")
232
+ try:
233
+ FoundScripts = search(Question, onConnectionError = OnConnError)
234
+ except:
235
+ print('Search Error:')
236
+ print(e)
237
+ yield m("Houve alguma falha ao fazer a pesquisa. Tente novamente. Se persistir, veja orientações na aba Help!")
238
+ return;
239
+
240
+ yield m("Doing rerank");
241
+ doclist = [doc['ScriptContent'] for doc in FoundScripts]
242
+
243
+ # Faz o reranker!
244
+ for score in rerank(Question, doclist):
245
+ i = score['corpus_id'];
246
+ FoundScripts[i]['rank'] = str(score['score'])
247
+
248
+ RankedScripts = sorted(FoundScripts, key=lambda item: float(item['rank']), reverse=True)
249
+
250
+
251
+
252
+ ScriptTable = []
253
+ for script in RankedScripts:
254
+ link = "https://github.com/rrg92/sqlserver-lib/tree/main/" + script['RelPath']
255
+ script['link'] = link;
256
+
257
+ ScriptTable.append({
258
+ 'Link': f'<a title="{link}" href="{link}" target="_blank">{script["RelPath"]}</a>'
259
+ ,'Length': script['ContentLength']
260
+ ,'Cosine Similarity': script['Similaridade']
261
+ ,'Rank': script['rank']
262
+ })
263
+
264
+
265
+ CurrentTable = pd.DataFrame(ScriptTable)
266
+ yield m("Found scripts, check Rank tab for details!")
267
+
268
+
269
+ WaitMessage = ai(f"""
270
+ You will analyze some T-SQL scripts in order to check which is best for the user.
271
+ You found scripts, presented them to the user, and now will do some work that takes time.
272
+ Generate a message to tell the user to wait while you work, in the same language as the user.
273
+ You will receive the question the user sent that triggered this process.
274
+ Use the user’s original question to customize the message.
275
+ Answer in lang: {SourceLang}
276
+ """,message,rfGenericText).message.parsed.text
277
+
278
+ yield Reply(WaitMessage);
279
+
280
+ yield m(f"Analyzing scripts...")
281
+
282
+
283
+ ResultJson = json.dumps(RankedScripts);
284
+
285
+ SystemPrompt = f"""
286
+ You are an assistant that helps users find the best T-SQL scripts for their specific needs.
287
+ These scripts were created by Rodrigo Ribeiro Gomes and are publicly available for users to query and use.
288
+
289
+ The user will provide a short description of what they are looking for, and your task is to present the most relevant scripts.
290
+
291
+ To assist you, here is a JSON object with the top matches based on the current user query:
292
+ {ResultJson}
293
+
294
+ ---
295
+ This JSON contains all the scripts that matched the user's input.
296
+ Analyze each script's name and content, and create a ranked summary of the best recommendations according to the user's need.
297
+
298
+ Only use the information available in the provided JSON. Do not reference or mention anything outside of this list.
299
+ You can include parts of the scripts in your answer to illustrate or give usage examples based on the user's request.
300
+
301
+ Re-rank the results if necessary, presenting them from the most to the least relevant.
302
+ You may filter out scripts that appear unrelated to the user query.
303
+
304
+ ---
305
+ ### Output Rules
306
+
307
+ - Review each script and evaluate how well it matches the user’s request.
308
+ - Summarize each script, ordering from the most relevant to the least relevant.
309
+ - Write personalized and informative review text for each recommendation.
310
+ - If applicable, explain how the user should run the script, including parameters or sections (like `WHERE` clauses) they might need to customize.
311
+ - When referencing a script, include the link provided in the JSON — all scripts are hosted on GitHub
312
+ - YOU MUST ANSWER THAT LANGUAGE: {SourceLang}
313
+ """
314
+
315
+ ScriptPrompt = [
316
+ { 'role':'system', 'content':SystemPrompt }
317
+ ,{ 'role':'user', 'content':message }
318
+ ]
319
+
320
+
321
+
322
+
323
+ llmanswer = llm(ScriptPrompt, stream = True)
324
+ yield m.done()
325
+
326
+ answer = BotMessage("");
327
+
328
+ for chunk in llmanswer:
329
+ content = chunk.choices[0].delta.content
330
+ yield answer(content, noNewLine = True)
331
+ finally:
332
+ yield m.done()
333
+
334
+ def SearchFiles(message):
335
+
336
+ Question = message;
337
+
338
+ try:
339
+ FoundScripts = search(Question)
340
+ except:
341
+ return m("Houve alguma falha ao executar a consulta no banco. Tente novamente. Se persistir, veja orientações na aba Help!")
342
+ return;
343
+
344
+ doclist = [doc['ScriptContent'] for doc in FoundScripts]
345
+
346
+ # Faz o reranker!
347
+
348
+
349
+
350
+ ScriptTable = [];
351
+ for score in rerank(Question, doclist):
352
+ i = score['corpus_id'];
353
+ script = FoundScripts[i];
354
+ script['rank'] = str(score['score'])
355
+ link = "https://github.com/rrg92/sqlserver-lib/tree/main/" + script['RelPath']
356
+ script['link'] = link;
357
+
358
+ if not AsJson:
359
+ ScriptTable.append({
360
+ 'Link': f'<a title="{link}" href="{link}" target="_blank">{script["RelPath"]}</a>'
361
+ ,'Length': script['ContentLength']
362
+ ,'Cosine Similarity': script['Similaridade']
363
+ ,'Rank': script['rank']
364
+ })
365
+
366
+ RankedScripts = sorted(FoundScripts, key=lambda item: float(item['rank']), reverse=True)
367
+
368
+ #result = pd.DataFrame(ScriptTable)
369
+ jsonresult = json.dumps(RankedScripts)
370
+
371
+ return jsonresult;
372
+
373
+ resultTable = gr.Dataframe(datatype = ['html','number','number'], interactive = False, show_search = "search");
374
+ TextResults = gr.Textbox()
375
+
376
+ with gr.Blocks(fill_height=True) as demo:
377
+
378
+ with gr.Column():
379
+
380
+ tabSettings = gr.Tab("Settings", render = False)
381
+
382
+ with tabSettings:
383
+ LangOpts = gr.Radio([("Auto Detect from text","auto"), ("Use browser language","browser")], value="auto", label="Language", info="Choose lang used by AI to answer you!")
384
+ LangChoose = gr.Textbox(info = "This will be filled with detect browser language, but you can change")
385
+
386
+ LangOpts.change(None, [LangOpts],[LangChoose], js = """
387
+ function(opt){
388
+ if(opt == "browser"){
389
+ return navigator ? navigator.language : "en-US";
390
+ }
391
+ }
392
+ """)
393
+
394
+
395
+ with gr.Tab("Chat", scale = 1):
396
+ ChatTextBox = gr.Textbox(max_length = 500, info = "Which script are you looking for?", submit_btn = True);
397
+
398
+ gr.ChatInterface(
399
+ ChatFunc
400
+ ,additional_outputs=[resultTable]
401
+ ,additional_inputs=[LangOpts,LangChoose]
402
+ ,type="messages"
403
+ ,textbox = ChatTextBox
404
+ )
405
+
406
+ tabSettings.render()
407
+
408
+
409
+ with gr.Tab("Rank"):
410
+ txtSearchTable = gr.Textbox(label="Search script files",info="Description of what you want", visible = False)
411
+ AsJson = gr.Checkbox(visible = False)
412
+ resultTable.render();
413
+
414
+
415
+ txtSearchTable.submit(SearchFiles, [txtSearchTable],[TextResults])
416
+
417
+ with gr.Tab("Help"):
418
+ gr.Markdown("""
419
+ Bem-vindo ao Space SQL Server Lib
420
+ Este space permite que você encontre scripts SQL do https://github.com/rrg92/sqlserver-lib com base nas suas necessidades
421
+
422
+
423
+ ## Instruções de Uso
424
+ Apenas descreva o que você precisa no campo de chat e aguarde a IA analisar os melhores scripts do repositório para você.
425
+ Além de uma explicação feita pela IA, a aba "Rank", contém uma tabela com os scripts encontrados e seus respectictos rank.
426
+ A coluna Cosine Similarity é o nível de similaridades da sua pergunta com o script (calculado baseado nos embeddings do seu texto e do script).
427
+ A coluna Rank é um score onde quanto maior o valor mais relacionado ao seu texto o script é (calculado usando rerank/cross encoders). A tabela vem ordenada por essa coluna.
428
+
429
+
430
+ ## Fluxo básico
431
+ - Quando você digita o texto, iremos fazer uma busca usando embeddings em um banco Azure SQL Database
432
+ - Os embeddings são calculados usando um modelo carregado no proprio script, via ZeroGPU.
433
+ - Os top 20 resultados mais similares são retornados e então um rerank é feito
434
+ - O rerank também é feito por um modelo que roda no próprio script, em ZeroGPU
435
+ - Estes resultados ordenados por reran, são então enviados ao LLM para que analise e monte uma resposta para você.
436
+
437
+
438
+ ## Sobre o uso e eventuais erros
439
+ Eu tento usar o máximo de recursos FREE e open possíveis, e portanto, eventualmente, o Space pode falhar por alguma limitação.
440
+ Alguns possíveis pontos de falha:
441
+ - Créditos free do google ou rate limit
442
+ - Azure SQL database offline devido a crédito ou ao auto-pause (devido ao free tier)
443
+ - Limites de uso do ZeroGPU do Hugging Face.
444
+
445
+ Você pode me procurar no [linkedin](https://www.linkedin.com/in/rodrigoribeirogomes/), caso receba erroslimit
446
+
447
+ """)
448
+
449
+ with gr.Tab("Other", visible = False):
450
+ txtEmbed = gr.Text(label="Text to embed", visible=False)
451
+ btnEmbed = gr.Button("embed");
452
+ btnEmbed.click(embed, [txtEmbed], [txtEmbed])
453
+
454
+ TextResults.render();
455
+
456
+
457
+
458
+
459
+
460
+
461
+
462
+
463
+
464
+
465
+
466
+
467
+
468
+ if __name__ == "__main__":
469
+ demo.launch(
470
+ share=False,
471
+ debug=False,
472
+ server_port=7860,
473
+ server_name="0.0.0.0",
474
+ allowed_paths=[]
475
+ )