|
30 | 30 | from persistence.cosmos import CosmosStore
|
31 | 31 | from persistence.sqlite import SqliteStore
|
32 | 32 | from tenacity import retry, stop_after_attempt, wait_random_exponential
|
| 33 | +from urllib.parse import quote_plus |
33 | 34 | import asyncio
|
34 | 35 | import html
|
35 | 36 | import re
|
|
50 | 51 | _logger = build_logger(__name__)
|
51 | 52 | _logger.info(f"claim-ai v{CONFIG.version}")
|
52 | 53 |
|
| 54 | +# Jinja templates |
53 | 55 | jinja = Environment(
|
54 | 56 | autoescape=select_autoescape(),
|
55 | 57 | enable_async=True,
|
56 | 58 | loader=FileSystemLoader("public_website"),
|
57 | 59 | )
|
| 60 | +jinja.filters["quote_plus"] = lambda x: quote_plus(str(x)) if x else "" |
| 61 | + |
| 62 | +# Azure OpenAI |
58 | 63 | _logger.info(f"Using OpenAI GPT model {CONFIG.openai.gpt_model}")
|
59 | 64 | oai_gpt = AsyncAzureOpenAI(
|
60 | 65 | api_version="2023-12-01-preview",
|
|
70 | 75 | else None
|
71 | 76 | ),
|
72 | 77 | )
|
| 78 | + |
| 79 | +# Azure Communication Services |
73 | 80 | source_caller = PhoneNumberIdentifier(CONFIG.communication_service.phone_number)
|
74 | 81 | _logger.info(f"Using phone number {str(CONFIG.communication_service.phone_number)}")
|
75 | 82 | # Cannot place calls with RBAC, need to use access key (see: https://learn.microsoft.com/en-us/azure/communication-services/concepts/authentication#authentication-options)
|
|
82 | 89 | sms_client = SmsClient(
|
83 | 90 | credential=DefaultAzureCredential(), endpoint=CONFIG.communication_service.endpoint
|
84 | 91 | )
|
| 92 | + |
| 93 | +# Persistence |
85 | 94 | db = (
|
86 | 95 | SqliteStore(CONFIG.database.sqlite)
|
87 | 96 | if CONFIG.database.mode == DatabaseMode.SQLITE
|
88 | 97 | else CosmosStore(CONFIG.database.cosmos_db)
|
89 | 98 | )
|
90 | 99 | search = AiSearchSearch(CONFIG.ai_search)
|
| 100 | + |
| 101 | +# FastAPI |
91 | 102 | _logger.info(f'Using root path "{CONFIG.api.root_path}"')
|
92 | 103 | api = FastAPI(
|
93 | 104 | contact={
|
@@ -124,23 +135,41 @@ async def health_liveness_get() -> None:
|
124 | 135 |
|
125 | 136 |
|
126 | 137 | @api.get(
|
127 |
| - "/call/report/{call_id}", |
| 138 | + "/report/{phone_number}", |
| 139 | + description="Display the history of calls in a web page.", |
| 140 | +) |
| 141 | +async def report_history_get(phone_number: str) -> HTMLResponse: |
| 142 | + calls = await db.call_asearch_all(phone_number) or [] |
| 143 | + |
| 144 | + template = jinja.get_template("history.html.jinja") |
| 145 | + render = await template.render_async( |
| 146 | + bot_company=CONFIG.workflow.bot_company, |
| 147 | + bot_name=CONFIG.workflow.bot_name, |
| 148 | + calls=calls, |
| 149 | + phone_number=phone_number, |
| 150 | + version=CONFIG.version, |
| 151 | + ) |
| 152 | + return HTMLResponse(content=render) |
| 153 | + |
| 154 | + |
| 155 | +@api.get( |
| 156 | + "/report/{phone_number}/{call_id}", |
128 | 157 | description="Display the call report in a web page.",
|
129 | 158 | )
|
130 |
| -async def call_report_get(call_id: UUID) -> HTMLResponse: |
| 159 | +async def report_call_get(phone_number: str, call_id: UUID) -> HTMLResponse: |
131 | 160 | call = await db.call_aget(call_id)
|
132 |
| - if not call: |
| 161 | + if not call or call.phone_number != phone_number: |
133 | 162 | raise HTTPException(
|
134 | 163 | status_code=status.HTTP_404_NOT_FOUND,
|
135 |
| - detail=f"Call {call_id} not found", |
| 164 | + detail=f"Call {call_id} for phone number {phone_number} not found", |
136 | 165 | )
|
137 | 166 |
|
138 |
| - template = jinja.get_template("report.html") |
| 167 | + template = jinja.get_template("report.html.jinja") |
139 | 168 | render = await template.render_async(
|
140 | 169 | bot_company=CONFIG.workflow.bot_company,
|
141 | 170 | bot_name=CONFIG.workflow.bot_name,
|
142 |
| - version=CONFIG.version, |
143 | 171 | call=call,
|
| 172 | + version=CONFIG.version, |
144 | 173 | )
|
145 | 174 | return HTMLResponse(content=render)
|
146 | 175 |
|
|
0 commit comments