brestok commited on
Commit
7ae78bd
·
1 Parent(s): 61ab356

connect ai

Browse files
ocr/api/message/db_requests.py CHANGED
@@ -38,4 +38,4 @@ async def save_assistant_user_message(user_message: str, assistant_message: str,
38
  await settings.DB_CLIENT.messages.insert_one(user_message.to_mongo())
39
  await settings.DB_CLIENT.messages.insert_one(assistant_message.to_mongo())
40
 
41
- return user_message
 
38
  await settings.DB_CLIENT.messages.insert_one(user_message.to_mongo())
39
  await settings.DB_CLIENT.messages.insert_one(assistant_message.to_mongo())
40
 
41
+ return assistant_message
ocr/api/message/views.py CHANGED
@@ -1,7 +1,11 @@
 
 
1
  from ocr.api.message import message_router
2
  from ocr.api.message.db_requests import get_all_chat_messages_obj, save_assistant_user_message
3
  from ocr.api.message.models import MessageModel
4
  from ocr.api.message.schemas import AllMessageWrapper, AllMessageResponse, CreateMessageRequest
 
 
5
  from ocr.api.report.dto import Paging
6
  from ocr.api.utils import transform_messages_to_openai
7
  from ocr.core.wrappers import OcrResponseWrapper
@@ -24,9 +28,11 @@ async def create_message(
24
  reportId: str,
25
  message_data: CreateMessageRequest,
26
  ) -> OcrResponseWrapper[MessageModel]:
27
- messages = await get_all_chat_messages_obj(reportId)
28
- message_history = transform_messages_to_openai(messages)
29
- # response = await generate_response()
30
- response = 'Hello world'
 
 
31
  response = await save_assistant_user_message(message_data.text, response, reportId)
32
  return OcrResponseWrapper(data=response)
 
1
+ import asyncio
2
+
3
  from ocr.api.message import message_router
4
  from ocr.api.message.db_requests import get_all_chat_messages_obj, save_assistant_user_message
5
  from ocr.api.message.models import MessageModel
6
  from ocr.api.message.schemas import AllMessageWrapper, AllMessageResponse, CreateMessageRequest
7
+ from ocr.api.openai_requests import generate_agent_response
8
+ from ocr.api.report.db_requests import get_report_obj_by_id
9
  from ocr.api.report.dto import Paging
10
  from ocr.api.utils import transform_messages_to_openai
11
  from ocr.core.wrappers import OcrResponseWrapper
 
28
  reportId: str,
29
  message_data: CreateMessageRequest,
30
  ) -> OcrResponseWrapper[MessageModel]:
31
+ messages, report = await asyncio.gather(
32
+ get_all_chat_messages_obj(reportId),
33
+ get_report_obj_by_id(reportId)
34
+ )
35
+ message_history = transform_messages_to_openai(messages, message_data.text)
36
+ response = await generate_agent_response(message_history, report)
37
  response = await save_assistant_user_message(message_data.text, response, reportId)
38
  return OcrResponseWrapper(data=response)
ocr/api/openai_requests.py CHANGED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ocr.api.prompts import OCRPrompts
2
+ from ocr.api.report.model import ReportModel
3
+ from ocr.core.wrappers import openai_wrapper
4
+
5
+
6
+ @openai_wrapper()
7
+ async def generate_report(request_content: list[dict]):
8
+ messages = [
9
+ {
10
+ "role": "system",
11
+ "content": OCRPrompts.generate_report
12
+ },
13
+ {
14
+ "role": "user",
15
+ "content": request_content
16
+ }
17
+ ]
18
+ return messages
19
+
20
+
21
+ @openai_wrapper()
22
+ async def generate_changes(content: list[dict], previous_report: str):
23
+ messages = [
24
+ {
25
+ "role": "system",
26
+ "content": OCRPrompts.generate_changes
27
+ .replace("{previous_report}", previous_report)
28
+ },
29
+ {
30
+ "role": "user",
31
+ "content": content
32
+ }
33
+ ]
34
+ return messages
35
+
36
+
37
+ @openai_wrapper()
38
+ async def generate_agent_response(messages: list[dict], report: ReportModel):
39
+ messages = [
40
+ {
41
+ "role": "system",
42
+ "content": OCRPrompts.generate_agent_response
43
+ .replace("{reports}", report.report)
44
+ .replace("{changes}", report.changes or 'There is no changes.')
45
+ },
46
+ *messages
47
+ ]
48
+ return messages
ocr/api/prompts.py CHANGED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class OCRPrompts:
2
+ generate_report = """## Task
3
+
4
+ You must analyze the text extracted from medical document and generate a comprehensive report in **Markdown2** format. Ensure that every detail provided in the document is included, and do not omit or modify any information. Your output must strictly follow the required format.
5
+
6
+ ## Report Structure
7
+
8
+ The report should be structured as follows, with each section containing only relevant information from the document:
9
+
10
+ ```markdown
11
+ ## Patient Information
12
+
13
+ - Name: [Patient Name]
14
+ - Age: [Patient Age]
15
+ - Date of Scan: [Date]
16
+ - Indication: [Reason for the CT scan]
17
+
18
+ ## Findings
19
+
20
+ **Primary findings**:
21
+ [Describe significant abnormalities or findings relevant to the indication]
22
+
23
+ ** Secondary findings**:
24
+ [List incidental findings, e.g., "Mild hepatic steatosis noted."]
25
+ **No abnormalities**:
26
+ [Mention organs or systems without abnormalities, e.g., "No evidence of lymphadenopathy or pleural effusion."]
27
+
28
+ ## Impression
29
+
30
+ [Summarize the findings concisely, e.g., "Findings suggest a primary lung tumor. Biopsy recommended for further evaluation."]
31
+
32
+ ## Recommendations
33
+
34
+ [Include next steps or further tests, e.g., "PET scan and consultation with oncology recommended."]
35
+ ```
36
+
37
+ [INST]
38
+
39
+ ## Instructions
40
+
41
+ - **Do not invent or infer any information.** Only use data provided in the user request.
42
+ - Ensure that the format is followed strictly, and the output is complete without any deviations.
43
+
44
+ [/INST]"""
45
+ generate_changes = """## Task
46
+
47
+ You must perform a detailed comparative analysis of the patient's new data from the attached user images against their previous data (`Previous Patient data`). Identify and explicitly highlight all differences, including but not limited to disease progression, remission, newly emerging conditions, and significant clinical changes. Your response must be formatted in **Markdown**.
48
+
49
+ ## Data
50
+
51
+ **Previous Patient Data**:
52
+ ```
53
+ {previous_report}
54
+ ```
55
+
56
+ [INST]
57
+
58
+ ## Mandatory Instructions
59
+
60
+ - Conduct a **meticulous** comparison of the new and old data, ensuring all discrepancies, updates, and changes in the patient's health status are clearly documented.
61
+ - Provide a structured, concise, and accurate Markdown report.
62
+ - Do **not** include any speculative analysis—only factual differences explicitly observed in the data.
63
+
64
+ [/INST]"""
65
+ generate_agent_response = """## Objective
66
+
67
+ You are an AI medical assistant. Your task is to provide **precise and direct** answers to the doctor's questions based **only** on the provided `Report`, `Patient changes`, and your **verified medical knowledge**. Your responses must be **brief, factual, and strictly to the point**.
68
+
69
+ ## Data
70
+
71
+ **Report**:
72
+ ```
73
+ {reports}
74
+ ```
75
+
76
+ **Patient changes**:
77
+ ```
78
+ {changes}
79
+ ```
80
+
81
+ ## Mandatory Instructions
82
+
83
+ - Do not elaborate or provide explanations unless explicitly requested.
84
+ - **Do not include unnecessary details.** Only provide **essential** information relevant to the doctor's question.
85
+ - **Format your response as plain text** without paragraphs, line breaks, or any additional formatting.
86
+ - **Do not speculate.** If the requested information is unavailable in the provided data, respond with: `"Insufficient data to answer."`"""
ocr/api/report/db_requests.py CHANGED
@@ -21,7 +21,12 @@ async def get_report_obj_by_id(report_id: str) -> ReportModel:
21
  return ReportModel.from_mongo(report)
22
 
23
 
24
- async def save_report_obj(report: str, changes: str) -> ReportModel:
25
- report = ReportModel(report=report, changes=changes, filename='maksim.docx')
26
  await settings.DB_CLIENT.reports.insert_one(report.to_mongo())
27
  return report
 
 
 
 
 
 
21
  return ReportModel.from_mongo(report)
22
 
23
 
24
+ async def save_report_obj(report: str, changes: str | None, filename: str) -> ReportModel:
25
+ report = ReportModel(report=report, changes=changes, filename=filename)
26
  await settings.DB_CLIENT.reports.insert_one(report.to_mongo())
27
  return report
28
+
29
+
30
+ async def get_last_report_obj() -> ReportModel | None:
31
+ report = await settings.DB_CLIENT.reports.find().sort("_id", -1).to_list(length=1)
32
+ return ReportModel.from_mongo(report[0]) if report else None
ocr/api/report/model.py CHANGED
@@ -7,7 +7,7 @@ from ocr.core.database import MongoBaseModel
7
 
8
  class ReportModel(MongoBaseModel):
9
  report: str
10
- changes: str
11
  filename: str
12
  datetimeInserted: datetime = Field(default_factory=datetime.now)
13
  datetimeUpdated: datetime = Field(default_factory=datetime.now)
 
7
 
8
  class ReportModel(MongoBaseModel):
9
  report: str
10
+ changes: str | None = None
11
  filename: str
12
  datetimeInserted: datetime = Field(default_factory=datetime.now)
13
  datetimeUpdated: datetime = Field(default_factory=datetime.now)
ocr/api/report/views.py CHANGED
@@ -1,10 +1,15 @@
 
 
1
  from fastapi import UploadFile, File
2
 
 
3
  from ocr.api.report import report_router
4
- from ocr.api.report.db_requests import get_all_reports_obj, delete_all_reports, get_report_obj_by_id, save_report_obj
 
5
  from ocr.api.report.dto import Paging
6
  from ocr.api.report.model import ReportModel
7
  from ocr.api.report.schemas import AllReportResponse
 
8
  from ocr.core.wrappers import OcrResponseWrapper
9
 
10
 
@@ -34,8 +39,19 @@ async def get_report(reportId: str) -> OcrResponseWrapper[ReportModel]:
34
  async def create_report(
35
  file: UploadFile = File(...),
36
  ) -> OcrResponseWrapper[ReportModel]:
37
- # messages = await create_new_reports(reportId)
38
- # response = await generate_response(message_data.text, message_history)
39
- report, changes = 'Hello', 'World'
40
- report = await save_report_obj(report, changes)
 
 
 
 
 
 
 
 
 
 
 
41
  return OcrResponseWrapper(data=report)
 
1
+ import asyncio
2
+
3
  from fastapi import UploadFile, File
4
 
5
+ from ocr.api.openai_requests import generate_report, generate_changes
6
  from ocr.api.report import report_router
7
+ from ocr.api.report.db_requests import get_all_reports_obj, delete_all_reports, get_report_obj_by_id, save_report_obj, \
8
+ get_last_report_obj
9
  from ocr.api.report.dto import Paging
10
  from ocr.api.report.model import ReportModel
11
  from ocr.api.report.schemas import AllReportResponse
12
+ from ocr.api.utils import divide_images, prepare_request_content, clean_response
13
  from ocr.core.wrappers import OcrResponseWrapper
14
 
15
 
 
39
  async def create_report(
40
  file: UploadFile = File(...),
41
  ) -> OcrResponseWrapper[ReportModel]:
42
+ try:
43
+ last_report, contents = await asyncio.gather(get_last_report_obj(), file.read())
44
+ report, changes = None, None
45
+ images = divide_images(contents)
46
+ content = prepare_request_content(images)
47
+ if last_report:
48
+ report, changes = await asyncio.gather(
49
+ generate_report(content),
50
+ generate_changes(content, last_report.report)
51
+ )
52
+ else:
53
+ report = await generate_report(content)
54
+ report = await save_report_obj(clean_response(report), clean_response(changes), file.filename)
55
+ finally:
56
+ await file.close()
57
  return OcrResponseWrapper(data=report)
ocr/api/utils.py CHANGED
@@ -6,10 +6,8 @@ import pytesseract
6
  from PIL import Image
7
  from pdf2image import convert_from_bytes
8
 
9
- from ocr.api.message.models import MessageModel
10
 
11
-
12
- def transform_messages_to_openai(messages: list[MessageModel]) -> list[dict]:
13
  openai_messages = []
14
  for message in messages:
15
  content = message.text
@@ -17,7 +15,7 @@ def transform_messages_to_openai(messages: list[MessageModel]) -> list[dict]:
17
  "role": message.author.value,
18
  "content": content
19
  })
20
-
21
  return openai_messages
22
 
23
 
 
6
  from PIL import Image
7
  from pdf2image import convert_from_bytes
8
 
 
9
 
10
+ def transform_messages_to_openai(messages: list, user_query: str) -> list[dict]:
 
11
  openai_messages = []
12
  for message in messages:
13
  content = message.text
 
15
  "role": message.author.value,
16
  "content": content
17
  })
18
+ openai_messages.append({"role": "user", "content": user_query})
19
  return openai_messages
20
 
21