muryshev commited on
Commit
f908316
·
1 Parent(s): 541ff5e

Перевод на дипинфру

Browse files
Files changed (2) hide show
  1. app.py +1 -1
  2. lib/llm_3_deepinfra.py +643 -0
app.py CHANGED
@@ -6,7 +6,7 @@ import pytesseract
6
  from pdf2image import convert_from_bytes
7
  from flask_cors import CORS
8
  from lib import ocr_2 as ocr
9
- from lib import llm_3 as llm
10
 
11
  os.environ['TESSDATA_PREFIX'] = '/usr/share/tesseract-ocr/5/tessdata'
12
 
 
6
  from pdf2image import convert_from_bytes
7
  from flask_cors import CORS
8
  from lib import ocr_2 as ocr
9
+ from lib import llm_3_deepinfra as llm
10
 
11
  os.environ['TESSDATA_PREFIX'] = '/usr/share/tesseract-ocr/5/tessdata'
12
 
lib/llm_3_deepinfra.py ADDED
@@ -0,0 +1,643 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import os
3
+ import numpy as np
4
+ import requests
5
+ import httpx
6
+ import json
7
+ import pandas as pd
8
+
9
+ typedf = pd.read_excel('types.xlsx')
10
+ verbose = False
11
+ # s = 'Тип обращения: Жалобы > Сектор: Акционерные общества/эмитенты эмиссионных ценных бумаг > Продукт: Дивиденды'
12
+ # s = 'Тип обращения: Прочие обращения (запрос, заявление, вопрос) > Сектор: Субъекты страхового дела > Продукт: Прочие обращения (страхование) > Проблема: Иные обращения: Страхование > Обращение может быть типологизировано по иной проблеме: Нет'
13
+ level = 'Тип обращения'
14
+ level = 'Сектор'
15
+ level = 'Продукт'
16
+ level = 'Проблема'
17
+ level = 'Проблема'
18
+
19
+ def getType(str, level) :
20
+ type = ''
21
+ t = level + ': [^>]+'
22
+ # t = r'Сектор\: \w+/\w+ >'
23
+ m = re.search(t, str)
24
+ if m :
25
+ substr = str[m.start() : m.end()]
26
+ substr
27
+ m = re.search('\: [\w ]+', substr)
28
+ subsubstr = substr[m.start() + 2 : ]
29
+ # subsubstr
30
+ type = subsubstr.strip()
31
+
32
+ return type
33
+
34
+ def getQuestionAnswer(str) :
35
+ q = ''
36
+ a = ''
37
+ l = str.split('>')
38
+ if len(l) == 5 :
39
+ q = l[4][1 :]
40
+ x = q.find(':')
41
+ a = q[x + 2 :]
42
+ q = q[: x]
43
+
44
+ return q, a
45
+
46
+ types = []
47
+ sectors = []
48
+ products = {}
49
+ problems = {}
50
+ for index, row in typedf.iterrows() :
51
+ text = row['Путь до вершины']
52
+ text = str(text)
53
+ if text != '' :
54
+ apptype = getType(text, 'Тип обращения')
55
+ sector = getType(text, 'Сектор')
56
+ product = getType(text, 'Продукт')
57
+ problem = getType(text, 'Проблема')
58
+ sector = sector.replace(' ', ' ')
59
+ product = product.replace(' ', ' ')
60
+ problem = problem.replace(' ', ' ')
61
+
62
+ if apptype == 'Жалобы' and sector != '' and product != '' and problem != '' :
63
+ if sector not in sectors :
64
+ sectors.append(sector)
65
+
66
+ if sector not in products :
67
+ products[sector] = []
68
+
69
+ if product not in products[sector] :
70
+ products[sector].append(product)
71
+
72
+ if sector not in problems :
73
+ problems[sector] = {}
74
+
75
+ if product not in problems[sector] :
76
+ problems[sector][product] = []
77
+
78
+ if problem not in problems[sector][product] :
79
+ problems[sector][product].append(problem)
80
+
81
+ def getCategory(text, categories) :
82
+ found = False
83
+ text = text.lower()
84
+ for category in categories :
85
+ if category.lower() in text :
86
+ found = True
87
+ break
88
+
89
+ if found == False :
90
+ category = ''
91
+
92
+ return category
93
+
94
+ def create_headers():
95
+ api_key = os.getenv("DEEPINFRA_API_KEY", None)
96
+ if api_key is None:
97
+ print("DEEPINFRA_API_KEY is not set!")
98
+ headers = {"Content-Type": "application/json"}
99
+ headers["Authorization"] = os.getenv("DEEPINFRA_API_KEY", None)
100
+ return headers
101
+
102
+ def create_messages(self, prompt, system_prompt = None):
103
+ messages = []
104
+
105
+ if system_prompt is not None:
106
+ messages.append({"role": "system", "content": system_prompt})
107
+ messages.append({"role": "user", "content": prompt})
108
+ return messages
109
+
110
+ def create_request(self, prompt, system_prompt = None):
111
+ request = {
112
+ "stream": False,
113
+ "model": os.getenv("DEEPINFRA_MODEL", "meta-llama/Llama-3.3-70B-Instruct-Turbo"),
114
+ "temperature": 0.14,
115
+ "top_p": 0.95,
116
+ "min_p": 0.05,
117
+ "frequency_penalty":-0.001,
118
+ "presence_penalty": 1.3,
119
+ "seed": 42,
120
+ "max_tokens": 1000
121
+ }
122
+
123
+ request["messages"] = create_messages(prompt, system_prompt)
124
+ return request
125
+
126
+ async def getResponse(prompt):
127
+ headers = {
128
+ 'Content-Type': 'application/json'
129
+ }
130
+
131
+ async with httpx.AsyncClient() as client:
132
+ request = create_request(prompt, system_prompt)
133
+ response = await client.post(f"https://api.deepinfra.com/v1/openai/chat/completions", headers=create_headers(), json=request, timeout=httpx.Timeout(connect=5.0, read=60.0, write=180, pool=10))
134
+ if response.status_code == 200:
135
+ return response.json()["choices"][0]["message"]["content"]
136
+ else:
137
+ logging.error(f"Request failed: status code {response.status_code}")
138
+ logging.error(response.text)
139
+
140
+ def getCategoryFromLLM(prompt, categories) :
141
+ category = ''
142
+ for j in range(5) :
143
+ result = getResponse(prompt)
144
+ category = getCategory(result, categories)
145
+ if category != '' :
146
+ break
147
+
148
+ prompt += '.'
149
+
150
+ return category, result
151
+
152
+ def getAccuracy(answers, trueanswers) :
153
+ count = 0
154
+ for i in range(len(trueanswers)) :
155
+ if answers[i] == trueanswers[i] :
156
+ count += 1
157
+
158
+ return count / len(trueanswers)
159
+
160
+ def getAnswers(applications, prefix, categories, answers) :
161
+ # print(categories)
162
+ output = []
163
+ for i in range(len(applications)) :
164
+ text = applications[i]
165
+ prompt = prefix + text
166
+ category, response = getCategoryFromLLM(prompt, categories)
167
+
168
+ answer = ''
169
+ for j in range(len(categories)) :
170
+ if category == categories[j] :
171
+ answer = answers[j]
172
+ break
173
+
174
+ brief = response.replace('\n', '')
175
+ if len(brief) > 80 :
176
+ brief = brief[:80] + '...'
177
+
178
+ if verbose :
179
+ print(i, ':', answer, ' \tLLM output :', brief)
180
+
181
+ output.append(answer)
182
+
183
+ return output
184
+
185
+ def getSector(application) :
186
+
187
+ sectortext = ''
188
+ for j in range(len(sectors)) :
189
+ sectortext += str(j) + '. ' + sectors[j] + '. '
190
+
191
+ prompt = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты сортируешь заявления клиентов.
192
+ Ты не отвечаешь на вопросы, не комментируешь, не выражаешь эмоций, не выражаешь соображений по теме заявления.
193
+ Ты извлекаешь информацию. Ты не анализируешь.
194
+ Ты выполняешь только эту задачу: ты определяешь категорию заявления. Для этого ты используешь ТОЛЬКО список возможных категорий, который я тебе предоставляю.
195
+ Ты выбираешь только ТУ категорию, которая на сто процентов соответсвует обращению. Проверь свой ответ дважды.
196
+ Ты всегда используешь такой формат ответа: "название категории".
197
+ Если в тексте обращения есть аббревиатуры "МФО", "МФК" или "МКК", ты должен выбрать категорию "Микрофинансовые организации".
198
+ Если в тексте обращения есть аббревиатуры "ОСАГО" или "КАСКО", ты должен выбрать категорию "Субъекты страхового дела".
199
+ Список категорий:
200
+ ''' + sectortext + '\nЗаявление: ' + application
201
+
202
+ # prompt = '''<s>[INST]Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты сортируешь заявления клиентов.
203
+ # Ты не отвечаешь на вопросы, не комментируешь, не выражаешь эмоций, не выражаешь соображений по теме заявления.
204
+ # Ты извлекаешь информацию. Ты не анализируешь.
205
+ # Ты выполняешь только эту задачу: ты определяешь категорию заявления. Для этого ты используешь ТОЛЬКО список возможных категорий, который я тебе предоставляю.
206
+ # Ты выбираешь только ТУ категорию, которая на сто процентов соответсвует обращению. Проверь свой ответ дважды.
207
+ # Ты всегда используешь такой формат ответа: "название категории".
208
+ # Если в тексте обращения есть аббревиатуры "МФО", "МФК" или "МКК", ты должен выбрать категорию "Микрофинансовые организации".
209
+ # Если в тексте обращения есть аббревиатуры "ОСАГО" или "КАСКО", ты должен выбрать категорию "Субъекты страхового дела".
210
+ # Список категорий:
211
+ # ''' + sectortext + 'Заявление: ' + application + '/INST'
212
+
213
+ sector, response = getCategoryFromLLM(prompt, sectors)
214
+
215
+ if verbose :
216
+ print(i, ':', sector)
217
+
218
+ return sector
219
+
220
+ def getProduct(application, sector) :
221
+ product = ''
222
+ # sector = appsectors[i]
223
+ if sector != '' :
224
+ subproducts = products[sector]
225
+
226
+ producttext = ''
227
+ for j in range(len(subproducts)) :
228
+ producttext += str(j) + '. ' + subproducts[j] + '. '
229
+
230
+ prompt = 'Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты сортируешь заявления клиентов. Ты не отвечаешь на вопросы, не комментируешь, \
231
+ не выражаешь эмоций, не выражаешь соображений по теме обращения. Ты извлекаешь персональные данные. Ты не анализируешь. \
232
+ Ты выполняешь только эту задачу: \
233
+ ты определяешь категорию заявления. Для этого ты используешь ТОЛЬКО список возможных категорий, который я тебе предоставляю. \
234
+ Ты выбираешь только ТУ категорию, которая на сто процентов соответсвует заявлению. Проверь свой ответ дважды. \
235
+ Ты всегда используешь такой формат ответа: "название категории". \n\
236
+ Список категорий:\n' + producttext + '\nЗаявление: ' + application
237
+
238
+ product, response = getCategoryFromLLM(prompt, subproducts)
239
+
240
+ if verbose :
241
+ print(product)
242
+
243
+ return product
244
+
245
+ def getProblem(application, sector, product) :
246
+ problem = ''
247
+ if sector != '' and product != '':
248
+ subpproblems = problems[sector][product]
249
+
250
+ problemtext = ''
251
+ for j in range(len(subpproblems)) :
252
+ problemtext += str(j) + '. ' + subpproblems[j] + '. '
253
+
254
+ prompt = 'Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты сортируешь заявления клиентов. Ты не отвечаешь на вопросы, не комментируешь, \
255
+ не выражаешь эмоций, не выражаешь соображений по теме обращения. Ты извлекаешь персональные данные. Ты не анализируешь. \
256
+ Ты выполняешь только эту задачу: \
257
+ ты определяешь категорию заявления. Для этого ты используешь ТОЛЬКО список возможных категорий, который я тебе предоставляю. \
258
+ Ты выбираешь только ТУ категорию, которая на сто процентов соответсвует заявлению. Проверь свой ответ дважды. \
259
+ Ты всегда используешь такой формат ответа: "название категории". \n\
260
+ Список категорий:\n' + problemtext + '\nЗаявление: ' + application
261
+
262
+ problem, response = getCategoryFromLLM(prompt, subpproblems)
263
+
264
+ if verbose :
265
+ print(problem)
266
+
267
+ return problem
268
+
269
+ def getAuthor(application) :
270
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты не отвечаешь на вопросы, не комментируешь,
271
+ не выражаешь эмоций, не выражаешь соображений по теме обращения.
272
+ Ты извлекаешь информацию из заявления. Ты отвечаешь на МОЙ вопрос:
273
+ "Кто является заявителем в заявлении?". Ты называешь имя заявителя в формате: "Заявитель: Фамилия Имя Отчество".
274
+ Если заявиитель не указан в заявлении, ты отвечаешь: "Заявитель: не указан".
275
+ Ты не комментируешь, не обясняешь, не выражаешь мысли, вообще ничего больше не говоришь.
276
+ Обращение: '''
277
+
278
+ prompt = prefix + application
279
+ # prompt = prefix + appdata.loc[i, 'Текст обращения обезличенный']
280
+ response = getResponse(prompt)
281
+ response = response.replace('.', '. ')
282
+ name = 'не указан'
283
+ if name not in response :
284
+ m = re.search(r'Заявитель: [А-Я][а-я][\w\.]+ [А-Я][\w\.]+ [А-Я][\w\.]+', response)
285
+ if m :
286
+ name = response[m.start() + 11 : m.end()]
287
+ else :
288
+ m = re.search(r'Заявитель: [А-Я][а-я][\w]+ [А-Я][а-я][\w]+', response)
289
+ if m :
290
+ name = response[m.start() + 11 : m.end()]
291
+
292
+ if verbose :
293
+ print(name, '\n', response[:100].replace('\n', ' '))
294
+
295
+ return name
296
+
297
+ def checkContractNumber(application) :
298
+ categories = ['да', 'нет']
299
+ answers = ['да', 'нет']
300
+
301
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты извлекаешь информацию из заявлений.
302
+ Ты не отвечаешь на вопросы, не комментируешь, не выражаешь эмоций, не выражаешь соображений по теме обращения.
303
+ Ты только отвечаешь на МОЙ вопрос: "Имеется ли в заявлении указ��нный номер договора?".
304
+ Ты отвечаешь либо ТАК "ответ: да, имеется" ЛИБО так "ответ: нет, не имеется". Конец ответа.
305
+ Если в заявлении нет слова "договор", ты отвечаешь "ответ: нет, не имеется"
306
+ Ты не комментируешь, не объясняешь, не выражаешь мысли, вообще ничего больше не говоришь.
307
+ Заявление: '''
308
+
309
+ ifcontract = getAnswers([application], prefix, categories, answers)
310
+
311
+ return ifcontract[0]
312
+
313
+ def checkIfIdentified(application) :
314
+ сategories = ['нельзя', 'можно']
315
+ answers = ['нет', 'да']
316
+
317
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке.
318
+ Ты не отвечаешь на вопросы, не комментируешь, не выражаешь эмоций, не выражаешь соображений по теме жалобы.
319
+ Ты ищешь в заявлении объект жалобы: "Можно ли идентицифировать в заявлении объект жалобы (тот, на кого жалуется заявитель)?".
320
+ Твой ответ ВСЕГДА состоит из ТРЕХ слов: ты отвечаешь либо ТАК "да, можно", ЛИБО так "нет, нельзя".
321
+ Ты не комментируешь, не объясняешь, не выражаешь мысли, вообще ничего больше не говоришь.
322
+ Жалоба: '''
323
+
324
+ ifidentified = getAnswers([application], prefix, сategories, answers)
325
+
326
+ return ifidentified[0]
327
+
328
+ def checkIfPerson(application) :
329
+ categories = ['физическое лицо', 'юридическое лицо']
330
+ answers = ['Физ.лицо', 'Юр.лицо']
331
+
332
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты сортируешь "заявления" клиентов.
333
+ Ты не отвечаешь на вопросы, не комментируешь, не выражаешь эмоций, не выражаешь соображений по теме обращения.
334
+ Ты извлекаешь информацию. Ты не анализируешь.
335
+ Ты отвечаешь ТОЛЬКО на мои вопросы. Ты определяешь кем является заявитель: "физическое лицо" или "юридическое лицо".
336
+ Условие: если заявление написано в первом лице (местоимения Я, МНЕ, МНОЮ, МОЕ, МЕНЯ), то это физическое лицо, НО если заявление написано в третьем лице, то это юридическое лицо.
337
+ Ты отвечаешь только так: "Заявитель: юрдическое лицо" или "Заявитель: физическое лицо".
338
+ Ты не комментируешь, не обясняешь, не выражаешь мысли, вообще ничего больше не говоришь.
339
+ Заявление: '''
340
+
341
+ ifperson = getAnswers([application], prefix, categories, answers)
342
+
343
+ return ifperson[0]
344
+
345
+ def checkIfcomission(application) :
346
+ categories = ['не касается', 'касается']
347
+ answers = ['нет', 'да']
348
+
349
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты извлекаешь информацию из заявлений.
350
+ Ты не отвечаешь на вопросы, не комментируешь, не выражаешь эмоций, не выражаешь соображений по теме обращения.
351
+ Ты только отвечаешь на МОЙ вопрос: "Касается ли заявление комиссии за обслуживание рублевого счета?".
352
+ Ты отвечаешь либо ТАК "ответ: да, касается" ЛИБО так "ответ: нет, не касается". Конец ответа.
353
+ Если в заявлении нет слова "комиссия", ты отвечаешь "ответ: нет, не касается"
354
+ Ты не комментируешь, не объясняешь, не выражаешь мысли, вообще ничего больше не говоришь.
355
+ Заявление: '''
356
+
357
+ ifсomission = getAnswers([application], prefix, categories, answers)
358
+
359
+ return ifсomission[0]
360
+
361
+ def getContractData(application) :
362
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты не отвечаешь на вопросы, не комментируешь,
363
+ не выражаешь эмоций, не выражаешь соображений по теме обращения.Ты выполняешь только ��ту задачу:
364
+ ты извлекаешь из заявления только *номер ДОГОВОРА* и "дата ДОГОВОРА".
365
+ Ты всегда используешь только такой формат: "Номер договора: *номер ДОГОВОРА*, Дата: *дата этого договора*;".
366
+ Если указан любой другой номер, но НЕ номер ДОГОВОРА, то ты отвечаешь так: "Номер договора не указан."
367
+ Ты должен убедиться, что слово "договор" присутствует рядом с указанным номером и исключить другие документы, такие как счета или заказы,
368
+ например: "В соответствии с Договором № 0001 от 01.01.2022 года...".
369
+ В этом примере номером договора является "0001" и датой договора является "01.01.2022".
370
+ Даты договоров должны быть указаны в формате "дд.мм.гггг", где "дд" - это число от 01 до 31, "мм" - число от 01 до 12,
371
+ а "гггг" - четырехзначное число года. Между днями, месяцами и годами должны быть разделители, например, точки или тире.
372
+ Ты больше НИЧЕГО не говоришь, не комментируешь, не объясняешь, не добавляешь.
373
+ Заявление: '''
374
+
375
+ prompt = prefix + application
376
+ response = getResponse(prompt)
377
+ response = response.replace(';', '\n')
378
+ response = response.replace('\\\\', '')
379
+ l = response.split('\n')
380
+ ll = []
381
+ for s in l :
382
+ s = s.strip()
383
+ if 'Номер договора:' == s[:15] :
384
+ ll.append(s)
385
+
386
+ result = '\n'.join(ll)
387
+
388
+ if result == '' :
389
+ result = 'не указаны'
390
+
391
+ if verbose :
392
+ print(result)
393
+ # print(name, '\n', response.strip()[:100].replace('\n', ' '))
394
+
395
+ return result
396
+
397
+ def getPersons(application) :
398
+ # prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты сортируешь заявления клиентов. Ты не отвечаешь на вопросы, не комментируешь,
399
+ # не выражаешь эмоций, не выражаешь соображений по теме заявления. Ты извлекаешь ВСЕ персональные данные из заявлений. Ты не анализируешь.
400
+ # Ты выполняешь только эту задачу:
401
+ # ты читаешь заявление и извлекаешь из заявления все встретившиеся Фамилии Имена Отчества.
402
+ # Ты всегда используешь только такой формат: "ФИО пользователя". Перед ответом убедись, что "ФИО" - это человеческие фамилия, имя, отчество.
403
+ # Ты больше ничего не говоришь, не комментируешь, не объясняешь, не добавляешь. Отвечай так: "ФИО;"; ЛИБО: "ФИО не указано".
404
+ # Заявление: '''
405
+
406
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты излекаешь информацию из заявления. Ты не отвечаешь на вопросы, не комментируешь,
407
+ не выражаешь эмоций, не выражаешь соображений по теме заявления. Ты извлекаешь персональные данные. Ты не анализируешь.
408
+ Ты выполняешь только эту задачу:
409
+ ты читаешь заявление и извлекаешь из заявления все встретившиеся Фамилии Имена Отчества.
410
+ Ты отвечаешь в формате: "ФИО: Фамилия Имя Отчество ;" или "ФИО: Фамилия И. О. ;".
411
+ Если в заявлении не указаны имена людей, ты отвечаешь "ФИО не указаны".
412
+ Перед ответом убедись, что "ФИО" - это человеческие фамилия, имя, отчество.
413
+ Ты больше ничего не говоришь, не комментируешь, не объясняешь, не добавляешь.
414
+ Заявление: '''
415
+
416
+ prompt = prefix + application
417
+ # prompt = prefix + appdata.loc[i, 'Текст обращения обезличенный']
418
+ response = getResponse(prompt)
419
+ response = response.replace('указаны.', 'указаны')
420
+ response = response.replace('.', '. ')
421
+ response = response.replace(';', '\n')
422
+ # response = response.replace('\\\\', '')
423
+ l = response.split('\n')
424
+ ll = []
425
+ for s in l :
426
+ s = s.strip()
427
+ if 'ФИО: ' == s[:5] and 'ФИО: не указаны' not in s:
428
+ ss = ''
429
+ s = s[5:]
430
+ s = re.sub('\(.+\)', '', s)
431
+ s = s.replace('ч.', 'ч')
432
+ s = s.replace('а.', 'а')
433
+ s = s.replace('Президент Российской Федерации', '')
434
+ s = s.replace(',', '').strip()
435
+ # n = len(s.split(' '))
436
+ # print(n, s.split(' '))
437
+ # if n > 1 and n < 4 :
438
+ # ll.append(s)
439
+ m = re.search(r'[А-Я][а-я][\w\.]+ [А-Я][\w\.]+ [А-Я][\w\.]+', s)
440
+ if m :
441
+ ss = s[m.start() : m.end()]
442
+ else :
443
+ m = re.search(r'[А-Я][а-я][\w]+ [А-Я][а-я][\w]+', s)
444
+ if m :
445
+ ss = s[m.start(): m.end()]
446
+
447
+ if ss != '' :
448
+ ll.append(ss)
449
+
450
+ result = '\n'.join(ll)
451
+
452
+ if result == '' :
453
+ result = 'не указаны'
454
+
455
+ names = result
456
+
457
+ if verbose :
458
+ print(names, '\n', response[:100].replace('\n', ' '))
459
+
460
+ return names
461
+
462
+ def ifLatin(s) :
463
+ ss = s.lower()
464
+ result = False
465
+ for c in ss :
466
+ if c in 'abcdefghijklmnopqrstuvwxyz' :
467
+ result = True
468
+ break
469
+
470
+ return result
471
+
472
+ stoplist = ['микрофинансовые организации',
473
+ 'полиция',
474
+ 'Мурманский край',
475
+ 'Перми',
476
+ 'Краснодар',
477
+ 'центр занятости населения Владимирской области',
478
+ 'банкомат N 7032 банка РСБ',
479
+ 'банк',
480
+ 'Криптобиржа',
481
+ 'Nasdaq',
482
+ 'Государство',
483
+ 'Департаменты Москвы',
484
+ '"Волгабанк" и Никулин',
485
+ 'Тендеры',
486
+ 'Уголовные дела',
487
+ 'Управляющими финансовой пирамидой "Волгабанк"',
488
+ 'Санации банка',
489
+ 'Криптобиржи',
490
+ 'Уголовная ответственность',
491
+ 'Статьей 185.3 УК РФ',
492
+ 'С ТОЙОТА КРАУН Х568ПУ69',
493
+ 'Республика Беларусь',
494
+ 'Минфин Республики Беларусь',
495
+ 'Московская биржа (АО НРД)',
496
+ 'АО',
497
+ 'прокуратура РФ',
498
+ 'приемная президента РФ',
499
+ 'страховая компания.',
500
+ 'микрофинансовые организации',
501
+ 'Следственный комитет',
502
+ 'прокуратура',
503
+ 'юристы',
504
+ 'ИНН 7854523125',
505
+ 'кредитная организация',
506
+ 'прокуратура РФ',
507
+ 'приемная президента РФ.',
508
+ 'фин услуги',
509
+ 'суд',
510
+ 'банк',
511
+ 'микрофинансовые организации',
512
+ 'Государственный рееestr МФО',
513
+ 'полиция',
514
+ 'Прокуратура РФ',
515
+ 'Приемная президента РФ',
516
+ 'фирма',
517
+ 'скоринг бюро',
518
+ 'правоохранительные органы',
519
+ 'Департамент здравоохранения г',
520
+ 'Страховщик',
521
+ 'Статьей 185']
522
+
523
+ def getCompanies(application) :
524
+ prefix = '''Ты мой помощник. Ты отвечаешь только на РУССКОМ языке. Ты извлекаешь информацию из заявления.
525
+ Ты не отвечаешь на вопросы, не комментируешь, не выражаешь эмоций, не выражаешь соображений по теме заявления.
526
+ Ты выполняешь только эту задачу: ты извлекаешь из заявления только *названия юридических ОРГАНИЗАЦИЙ*.
527
+ Ты всегда используешь только этот формат: "Организация: *название организации*;".
528
+ Ты больше НИЧЕГО не говоришь, не комментируешь, не объясняешь, не добавляешь.
529
+ Если названия организаций отсутствуют, то ты даешь только ТАКОЙ ответ: "не указано".
530
+ Твой ответ состоит только из одного слова - *название организации.* Тебе запрещено общаться, ты всегда следуешь формату.
531
+ Польуйся моими советами, как определить, что это действительно название организации:
532
+ Памятка: Юридическая форма: Название может содержать слова, указывающие на юридическую форму организации, такие как "корпорация",
533
+ "общество с ограниченной ответственностью", "партнерство" и т.д. Название может состоять из аббревиату��ы,
534
+ которая представляет собой сокращение от полного названия организации. Название может содержать описательные слова или фразы,
535
+ которые указывают на вид деятельности организации, ее цели или ценности.
536
+ Соответствие формальным требованиям: Названия организаций, связанных с денежно-кредитной политикой, платёжной системой и финансовым регулированием,
537
+ обычно соответствуют определенным формальным требованиям, таким как использование определенных слов, например "банк", "компания", "организация" и т.д.
538
+ Заявление: '''
539
+
540
+ prompt = prefix + application
541
+ response = getResponse(prompt)
542
+ l = response.split('Организация: ')
543
+ ll = []
544
+ for i in range(len(l)) :
545
+ Inf = 1000000
546
+ s = l[i]
547
+ x = s.find(';')
548
+ y = s.find('.')
549
+ z = s.find('(')
550
+ if x == -1 :
551
+ x = Inf
552
+
553
+ if y == -1 :
554
+ y = Inf
555
+
556
+ if z == -1 :
557
+ z = Inf
558
+
559
+ x = min(x, y, z)
560
+
561
+ if x != -1 :
562
+ s = l[i][:x]
563
+
564
+ s = s.strip()
565
+ if s != '' and not ifLatin(s) and s not in ll and s not in stoplist:
566
+ ll.append(s)
567
+
568
+ result = '\n'.join(ll)
569
+
570
+ if result == '' :
571
+ result = 'не указаны'
572
+
573
+ if verbose :
574
+ print(result)
575
+
576
+ return result
577
+
578
+ def getApplicationInfo(application) :
579
+ author = getAuthor(application)
580
+ persons = getPersons(application)
581
+ companies = getCompanies(application)
582
+ contractdata = getContractData(application)
583
+ sector = getSector(application)
584
+ product = getProduct(application, sector)
585
+ problem = getProblem(application, sector, product)
586
+
587
+ ifcontract = checkContractNumber(application)
588
+ ifidentified = checkIfIdentified(application)
589
+ ifperson = checkIfPerson(application)
590
+ ifcomission = checkIfcomission(application)
591
+
592
+ app_info = {}
593
+ app_info['Заявитель'] = author
594
+ app_info['Физлица'] = persons
595
+ app_info['Организации'] = companies
596
+ app_info['Данные договора'] = contractdata
597
+ app_info['Заявитель физическое или юридическое лицо?'] = ifperson
598
+ app_info['Можно ли идентифицировать лицо, на которого пожаловались?'] = ifidentified
599
+ app_info['Указан ли в обращении номер договора?'] = ifcontract
600
+ app_info['Жалоба касается комиссии за обслуживание рублевого счета?'] = ifcomission
601
+ app_info['Сектор'] = sector
602
+ app_info['Продукт'] = product
603
+ app_info['Проблема'] = problem
604
+
605
+ if verbose :
606
+ print()
607
+ print(i)
608
+ print('Заявитель', author)
609
+ print('Физлица', persons)
610
+ print('Организации', companies)
611
+ print('Данные договора', contractdata)
612
+ print('Заявитель физическое или юридическое лицо?', ifperson)
613
+ print('Можно ли идентифицировать лицо, на которого пожаловались?', ifidentified)
614
+ print('Указан ли в обращении номер договора?', ifcontract)
615
+ print('Жалоба касается комиссии за обслуживание рублевого счета?', ifcomission)
616
+ print('Сектор', sector)
617
+ print('Продукт', product)
618
+ print('Проблема', problem)
619
+
620
+ return app_info
621
+
622
+ # application = '''Я, Кристенгоф Оксана Михайловна, заключила кредитный договор с ПАО Камабанк № 59875 и № 456835645645654
623
+ # и договор на выдачу кредитной карты с ПАО "БСТ-Банк" №4567652124534235 и №4561254153412.
624
+ # 12.08.2020 года направила в банки заявление на истребование кредитной документации заказным письмом с уведомлением,
625
+ # но банки мне так ничего и не прислали. Прошу поспособствовать в том,что кредитные организации выслали мне кредитные договоры.
626
+ # '''
627
+
628
+ # verbose = False
629
+ # app_info = getApplicationInfo(application)
630
+ # print(app_info)
631
+
632
+ # Результат:
633
+ # {'Заявитель': 'Кристенгоф Оксана Михайловна',
634
+ # 'Физлица': 'Кристенгоф Оксана ��ихайловна',
635
+ # 'Организации': 'ПАО Камабанк\nПАО "БСТ-Банк"',
636
+ # 'Данные договора': 'Номер договора: 59875, Дата: 12.08.2020\nНомер договора: 456835645645654, Дата: 12.08.2020',
637
+ # 'Заявитель физическое или юридическое лицо?': 'Физ.лицо',
638
+ # 'Можно ли идентифицировать лицо, на которого пожаловались?': 'да',
639
+ # 'Указан ли в обращении номер договора?': 'да',
640
+ # 'Жалоба касается комиссии за обслуживание рублевого счета?': 'нет',
641
+ # 'Сектор': 'Кредитные организации',
642
+ # 'Продукт': 'Кредитные истории',
643
+ # 'Проблема': 'Иные виды (КО)'}