ariansyahdedy commited on
Commit
4e9c1aa
·
1 Parent(s): 9fd3be8

Add automatic indexed links

Browse files
.gitignore CHANGED
@@ -8,5 +8,6 @@ document*.txt
8
  model/
9
  llamma-duo/
10
  fine*.py
 
11
 
12
 
 
8
  model/
9
  llamma-duo/
10
  fine*.py
11
+ venv/
12
 
13
 
app/api/api_file.py CHANGED
@@ -244,7 +244,7 @@ async def load_file_with_markdown_function(filepaths: List[str],
244
  snippet = document.text_content[:100].replace('\n', ' ').replace('\r', ' ')
245
  # Ensure 'doc_logger' is defined; if not, use 'logger' or define 'doc_logger'
246
  # doc_logger(f"ID: {doc_id}, Snippet: {snippet}")
247
- logger.info(f"ID: {doc_id}, Snippet: {snippet}")
248
 
249
  except Exception as e:
250
  logger.error(f"Error processing URL {path}: {str(e)}")
 
244
  snippet = document.text_content[:100].replace('\n', ' ').replace('\r', ' ')
245
  # Ensure 'doc_logger' is defined; if not, use 'logger' or define 'doc_logger'
246
  # doc_logger(f"ID: {doc_id}, Snippet: {snippet}")
247
+ indexed_links_logger.info(f"{doc_id}_{path}")
248
 
249
  except Exception as e:
250
  logger.error(f"Error processing URL {path}: {str(e)}")
app/handlers/webhook_handler.py CHANGED
@@ -22,21 +22,21 @@ class WebhookHandler:
22
  request_id = f"req_{int(time.time()*1000)}"
23
  results = []
24
 
25
- self.logger.info(f"Processing webhook request {payload}")
26
 
27
  try:
28
  entries = payload.get("entry", [])
29
  for entry in entries:
30
  entry_id = entry.get("id")
31
- self.logger.info(f"Processing entry_id: {entry_id}")
32
 
33
  changes = entry.get("changes", [])
34
  for change in changes:
35
  messages = change.get("value", {}).get("messages", [])
36
- self.logger.info(f"message length: {len(messages)}")
37
  for message in messages:
38
 
39
- self.logger.info(f"Processing message: {message}")
40
  response = await self.message_handler.handle(
41
  raw_message=message,
42
  whatsapp_token=whatsapp_token,
 
22
  request_id = f"req_{int(time.time()*1000)}"
23
  results = []
24
 
25
+ # self.logger.info(f"Processing webhook request {payload}")
26
 
27
  try:
28
  entries = payload.get("entry", [])
29
  for entry in entries:
30
  entry_id = entry.get("id")
31
+ # self.logger.info(f"Processing entry_id: {entry_id}")
32
 
33
  changes = entry.get("changes", [])
34
  for change in changes:
35
  messages = change.get("value", {}).get("messages", [])
36
+ # self.logger.info(f"message length: {len(messages)}")
37
  for message in messages:
38
 
39
+ # self.logger.info(f"Processing message: {message}")
40
  response = await self.message_handler.handle(
41
  raw_message=message,
42
  whatsapp_token=whatsapp_token,
app/main.py CHANGED
@@ -12,6 +12,7 @@ from prometheus_client import Counter, Histogram, start_http_server
12
  from pydantic import BaseModel, ValidationError
13
  from app.services.message import generate_reply, send_reply
14
  import logging
 
15
  from datetime import datetime
16
  from sentence_transformers import SentenceTransformer
17
  from app.search.rag_pipeline import RAGSystem
@@ -24,9 +25,10 @@ from app.handlers.media_handler import WhatsAppMediaHandler
24
  from app.services.cache import MessageCache
25
  from app.services.chat_manager import ChatManager
26
  from app.api.api_prompt import prompt_router
27
- from app.api.api_file import file_router
28
  from app.utils.load_env import ACCESS_TOKEN, WHATSAPP_API_URL, GEMINI_API
29
 
 
30
  from markitdown import MarkItDown
31
 
32
  # Configure logging
@@ -41,6 +43,13 @@ logger = logging.getLogger(__name__)
41
  message_handler = None
42
  webhook_handler = None
43
 
 
 
 
 
 
 
 
44
 
45
  async def setup_message_handler():
46
  logger = logging.getLogger(__name__)
@@ -48,6 +57,7 @@ async def setup_message_handler():
48
  chat_manager = ChatManager()
49
  media_handler = WhatsAppMediaHandler()
50
 
 
51
  return MessageHandler(
52
  message_cache=message_cache,
53
  chat_manager=chat_manager,
@@ -67,7 +77,7 @@ async def lifespan(app: FastAPI):
67
 
68
  try:
69
  # await init_db()
70
-
71
  logger.info("Connected to the MongoDB database!")
72
  rag_system = await setup_rag_system()
73
 
@@ -78,6 +88,7 @@ async def lifespan(app: FastAPI):
78
  webhook_handler = WebhookHandler(message_handler)
79
  # collections = app.database.list_collection_names()
80
  # print(f"Collections in {db_name}: {collections}")
 
81
  yield
82
  except Exception as e:
83
  logger.error(e)
@@ -107,7 +118,7 @@ class WebhookPayload(BaseModel):
107
  entry: List[Dict]
108
 
109
  @app.post("/webhook")
110
- @limiter.limit("20/minute")
111
  async def webhook(request: Request, background_tasks: BackgroundTasks):
112
  try:
113
  payload = await request.json()
 
12
  from pydantic import BaseModel, ValidationError
13
  from app.services.message import generate_reply, send_reply
14
  import logging
15
+ import httpx
16
  from datetime import datetime
17
  from sentence_transformers import SentenceTransformer
18
  from app.search.rag_pipeline import RAGSystem
 
25
  from app.services.cache import MessageCache
26
  from app.services.chat_manager import ChatManager
27
  from app.api.api_prompt import prompt_router
28
+ from app.api.api_file import file_router, load_file_with_markdown_function
29
  from app.utils.load_env import ACCESS_TOKEN, WHATSAPP_API_URL, GEMINI_API
30
 
31
+
32
  from markitdown import MarkItDown
33
 
34
  # Configure logging
 
43
  message_handler = None
44
  webhook_handler = None
45
 
46
+ indexed_links = ["https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana",
47
+ "https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau",
48
+ "https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt",
49
+ "https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase",
50
+ "https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda"
51
+ ]
52
+
53
 
54
  async def setup_message_handler():
55
  logger = logging.getLogger(__name__)
 
57
  chat_manager = ChatManager()
58
  media_handler = WhatsAppMediaHandler()
59
 
60
+
61
  return MessageHandler(
62
  message_cache=message_cache,
63
  chat_manager=chat_manager,
 
77
 
78
  try:
79
  # await init_db()
80
+
81
  logger.info("Connected to the MongoDB database!")
82
  rag_system = await setup_rag_system()
83
 
 
88
  webhook_handler = WebhookHandler(message_handler)
89
  # collections = app.database.list_collection_names()
90
  # print(f"Collections in {db_name}: {collections}")
91
+ await load_file_with_markdown_function(rag_system=rag_system, filepaths=indexed_links)
92
  yield
93
  except Exception as e:
94
  logger.error(e)
 
118
  entry: List[Dict]
119
 
120
  @app.post("/webhook")
121
+ # @limiter.limit("20/minute")
122
  async def webhook(request: Request, background_tasks: BackgroundTasks):
123
  try:
124
  payload = await request.json()
app/services/message.py CHANGED
@@ -12,7 +12,7 @@ import google.generativeai as genai
12
  import PIL.Image
13
  from typing import List, Dict, Any, Optional
14
 
15
- from app.utils.load_env import ACCESS_TOKEN, WHATSAPP_API_URL, GEMINI_API, OPENAI_API
16
  from app.utils.system_prompt import system_prompt
17
 
18
  from app.services.search_engine import google_search
@@ -44,7 +44,7 @@ function_declarations = [
44
  ]
45
 
46
  genai.configure(api_key=GEMINI_API)
47
- client = AsyncOpenAI(api_key = OPENAI_API)
48
  # Configure logging
49
  logging.basicConfig(
50
  level=logging.INFO,
@@ -142,8 +142,10 @@ async def generate_response_from_gemini(
142
  logger.info(f"Generating response for sender: {sender}")
143
 
144
  # Initialize the model
145
- # model = genai.GenerativeModel("gemini-1.5-pro-002", system_instruction= system_prompt)
146
- model = genai.GenerativeModel("gemini-1.5-flash", system_instruction= system_prompt)
 
 
147
  # Start chat with history
148
  chat = model.start_chat(history=history)
149
 
@@ -151,7 +153,7 @@ async def generate_response_from_gemini(
151
  if rag_system:
152
  keywords = extract_keywords_async(content)
153
  # keywords = []
154
- logger.info(f"Extracted Keywords: {keywords}")
155
  # Implement RAG: Retrieve relevant documents
156
  retrieved_docs = await rag_system.adv_query(content, keywords=keywords, top_k=5)
157
  if retrieved_docs:
@@ -161,7 +163,7 @@ async def generate_response_from_gemini(
161
  # Option 1: Append to history as a system message
162
  history.append({"role": "user", "parts": f"Relevant documents:\n{context}"})
163
 
164
- logger.info(f"History: {history}")
165
  # Reinitialize chat with updated history
166
  chat = model.start_chat(history=history)
167
 
@@ -321,40 +323,40 @@ async def handle_function_call(chat):
321
  # return "Sorry, I couldn't generate a response at this time."
322
 
323
 
324
- async def generate_response_from_chatgpt(sender: str, content: str, timestamp: str, history: str) -> str:
325
- """
326
- Generate a reply using OpenAI's ChatGPT API.
327
- """
328
- try:
329
- # # Initialize chat history if not provided
330
- # chat_history = chat_history or []
331
 
332
- # # Append the current user message to the chat history
333
- # chat_history.append({"role": "user", "content": f"From {sender} at {timestamp}: {content}"})
334
 
335
- messages = [
336
- {"role": "system", "content": "You're an investor, a serial founder, and you've sold many startups. You understand nothing but business."},
337
- {"role": "system", "content": f"Message History: {history}"},
338
- {"role": "user", "content": f"From {sender} at {timestamp}: {content}"}
339
- ]
340
 
341
- print(f"Messages: {messages}")
342
 
343
- response = await client.chat.completions.create(
344
- model="gpt-3.5-turbo",
345
- messages=messages,
346
- max_tokens=200,
347
- temperature=0.5
348
- )
349
 
350
- chatgpt_response = response.choices[0].message.content.strip()
351
- # Append the assistant's response to the chat history
352
- # chat_history.append({"role": "assistant", "content": chatgpt_response})
353
- return chatgpt_response
354
 
355
- except Exception as e:
356
- print("Error generating reply:", e)
357
- return "Sorry, I couldn't generate a response at this time."
358
 
359
 
360
  # async def generate_response_from_chatgpt(
 
12
  import PIL.Image
13
  from typing import List, Dict, Any, Optional
14
 
15
+ from app.utils.load_env import ACCESS_TOKEN, WHATSAPP_API_URL, GEMINI_API
16
  from app.utils.system_prompt import system_prompt
17
 
18
  from app.services.search_engine import google_search
 
44
  ]
45
 
46
  genai.configure(api_key=GEMINI_API)
47
+ # client = AsyncOpenAI(api_key = OPENAI_API)
48
  # Configure logging
49
  logging.basicConfig(
50
  level=logging.INFO,
 
142
  logger.info(f"Generating response for sender: {sender}")
143
 
144
  # Initialize the model
145
+ model = genai.GenerativeModel("gemini-1.5-pro-002", system_instruction= system_prompt)
146
+ # model = genai.GenerativeModel("gemini-1.5-flash", system_instruction= system_prompt)
147
+ # model = genai.GenerativeModel("gemini-exp-1206", system_instruction= system_prompt)
148
+
149
  # Start chat with history
150
  chat = model.start_chat(history=history)
151
 
 
153
  if rag_system:
154
  keywords = extract_keywords_async(content)
155
  # keywords = []
156
+ # logger.info(f"Extracted Keywords: {keywords}")
157
  # Implement RAG: Retrieve relevant documents
158
  retrieved_docs = await rag_system.adv_query(content, keywords=keywords, top_k=5)
159
  if retrieved_docs:
 
163
  # Option 1: Append to history as a system message
164
  history.append({"role": "user", "parts": f"Relevant documents:\n{context}"})
165
 
166
+ # logger.info(f"History: {history}")
167
  # Reinitialize chat with updated history
168
  chat = model.start_chat(history=history)
169
 
 
323
  # return "Sorry, I couldn't generate a response at this time."
324
 
325
 
326
+ # async def generate_response_from_chatgpt(sender: str, content: str, timestamp: str, history: str) -> str:
327
+ # """
328
+ # Generate a reply using OpenAI's ChatGPT API.
329
+ # """
330
+ # try:
331
+ # # # Initialize chat history if not provided
332
+ # # chat_history = chat_history or []
333
 
334
+ # # # Append the current user message to the chat history
335
+ # # chat_history.append({"role": "user", "content": f"From {sender} at {timestamp}: {content}"})
336
 
337
+ # messages = [
338
+ # {"role": "system", "content": "You're an investor, a serial founder, and you've sold many startups. You understand nothing but business."},
339
+ # {"role": "system", "content": f"Message History: {history}"},
340
+ # {"role": "user", "content": f"From {sender} at {timestamp}: {content}"}
341
+ # ]
342
 
343
+ # print(f"Messages: {messages}")
344
 
345
+ # response = await client.chat.completions.create(
346
+ # model="gpt-3.5-turbo",
347
+ # messages=messages,
348
+ # max_tokens=200,
349
+ # temperature=0.5
350
+ # )
351
 
352
+ # chatgpt_response = response.choices[0].message.content.strip()
353
+ # # Append the assistant's response to the chat history
354
+ # # chat_history.append({"role": "assistant", "content": chatgpt_response})
355
+ # return chatgpt_response
356
 
357
+ # except Exception as e:
358
+ # print("Error generating reply:", e)
359
+ # return "Sorry, I couldn't generate a response at this time."
360
 
361
 
362
  # async def generate_response_from_chatgpt(
app/utils/system_prompt.py CHANGED
@@ -1,20 +1,17 @@
1
  system_prompt = """
2
  Role and Purpose:
3
- You are a helpful and informative virtual assistant focused on the city of Surabaya, Indonesia. Your primary function is to provide reliable, up-to-date information about Surabaya's ongoing public service projects, local events, infrastructure improvements, community programs, regulations, administrative procedures, and any official city announcements. You only reply in Bahasa Indonesia.
4
-
5
- Knowledge and Sources:
6
- You have access to general historical and contextual knowledge about Surabaya, as well as current city developments up to the latest available data. When answering questions, always strive to be accurate, clear, and helpful. If you are unsure about certain details, provide general information and encourage the user to verify with official government sources.
7
 
8
  Tone and Style:
9
- Be polite, respectful, and straightforward. Speak in a neutral, factual manner without showing bias. Uphold professional standards of communication and represent the city's information accurately. Always remain courteous, even if the user is frustrated or upset.
10
 
11
  Content Guidelines:
12
- When asked about who make you or what language model you are, answer that you are created by Vidavox. Don't answer it with Google nor OpenAI
13
- Focus on Public Service: Prioritize information related to Surabaya's public services such as transportation, health, infrastructure, education, business permits, public safety measures, and cultural or community events.
14
- Up-to-Date Information: Provide the most current and relevant data available about ongoing projects and city improvements. If the user asks about a project's current progress, offer details on what phase it is in, expected completion timelines, key milestones, and any recent news updates.
15
- Neutrality and Positivity: Always maintain a neutral stance. Do not criticize the local government or its officials. If asked about government decisions, explain them factually without expressing disapproval or judgment. Should the user request opinions, emphasize that you provide information rather than subjective viewpoints.
16
- Encouraging Verification: If the user requests official documentation or more detailed information, guide them to verified channels such as the city's official website, relevant department portals, or licensed information centers.
17
- Always Include Sources: When your response is based on information provided from external sources, include the source link explicitly. For example: "Informasi ini berasal dari www.indosource.com. Anda dapat mengunjungi tautan tersebut untuk detail lebih lanjut." Clearly attribute the link to maintain transparency. You are forbidden to include the same links next to the the other like this: Sumber: [www.indosource.com](www.indosource.com)\n
18
 
19
  Example Interactions:
20
 
@@ -22,9 +19,10 @@ Example Interactions:
22
  If a user says, “I heard there will be a community festival next month, can you tell me more?” you might reply: “Yes, the city's annual cultural festival will be held in [location] starting from [date]. It will feature traditional dance performances, local food vendors, and art exhibitions. For a detailed schedule, please visit the city's official cultural events portal.”
23
  If a user asks, “Are there any issues with the city government's policies?” respond factually: “I can provide details on the policies that have been implemented and their stated goals, but I do not offer critiques. To learn more about specific policies and their expected outcomes, you may refer to the official government publications or verified local news outlets.”
24
 
25
- By following these guidelines, you will serve as a reliable, respectful, and informative resource for users looking to understand the latest happenings in Surabaya without engaging in criticism of the government.
26
  """
27
 
 
28
  agentic_prompt = """ You are a helpful assistant and have capabilities to search the web.
29
  When you the links are given, you should summarize the content of the link and give a short summary.
30
  You should also include the source of the link in the summary.
 
1
  system_prompt = """
2
  Role and Purpose:
3
+ You are a virtual assistant focused exclusively on Surabaya, Indonesia. Your primary role is to provide accurate information regarding the permit document provided in the Relevant Document. If you cannot find anything in the Relevant Document, state that you are unsure and direct the user to this website: https://sswalfa.surabaya.go.id/ without bracket or parentheses. You respond only in Bahasa Indonesia. You can reply in Javanese or Maduranese, only if the user talks to you in that language.
 
 
 
4
 
5
  Tone and Style:
6
+ Maintain a polite, neutral, and factual tone. Be professional and represent Surabaya's information accurately without criticism or bias. Always ensure your communication is courteous and focused on providing clear and reliable information.
7
 
8
  Content Guidelines:
9
+ When asked about your origins or creator, state that you were created by Vidavox.
10
+ Context-Driven Responses: Provide answers solely based on the provided Relevant Document context.
11
+ Focus on Public Services: Prioritize queries on transportation, health, education, permits, safety, and cultural events.
12
+ Professional Representation: Avoid personal opinions, judgments, or critiques of the local government. If asked for opinions, explain that your role is to provide factual information rather than subjective viewpoints.
13
+ Encourage Verification: For unresolved queries, recommend users consult official resources such as the provided website link.
14
+ Always Include Sources: When your response is based on information provided from external sources or Relevant Document, include the source link explicitly without brackets or parentheses at the end of the response. For example: "Informasi ini berasal dari www.indosource.com (without bracket or parentheses) Anda dapat mengunjungi tautan tersebut untuk detail lebih lanjut."
15
 
16
  Example Interactions:
17
 
 
19
  If a user says, “I heard there will be a community festival next month, can you tell me more?” you might reply: “Yes, the city's annual cultural festival will be held in [location] starting from [date]. It will feature traditional dance performances, local food vendors, and art exhibitions. For a detailed schedule, please visit the city's official cultural events portal.”
20
  If a user asks, “Are there any issues with the city government's policies?” respond factually: “I can provide details on the policies that have been implemented and their stated goals, but I do not offer critiques. To learn more about specific policies and their expected outcomes, you may refer to the official government publications or verified local news outlets.”
21
 
22
+ By adhering to these principles, you will ensure professional and reliable communication about Surabaya's permit processes while respecting local languages and cultural nuances.
23
  """
24
 
25
+
26
  agentic_prompt = """ You are a helpful assistant and have capabilities to search the web.
27
  When you the links are given, you should summarize the content of the link and give a short summary.
28
  You should also include the source of the link in the summary.
indexed_links.txt CHANGED
@@ -1,5 +1,55 @@
1
- 2024-12-26 15:02:10,578 - INFO - 06c0cc2a-ec63-4458-a4e9-ea6e96e0bbb4_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
2
- 2024-12-26 15:02:11,146 - INFO - 2c5a8065-7df2-42d0-8e1e-0e59804c6f25_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
3
- 2024-12-26 15:02:11,848 - INFO - 521bfbd9-654a-4cf9-8b6c-79de4b8e5cd2_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
4
- 2024-12-26 15:02:12,549 - INFO - e4088c2a-b9ef-4c04-b2f8-eb703279ba21_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
5
- 2024-12-26 15:02:13,236 - INFO - 458cc97a-93db-44bf-b7f8-e60c22da2a5e_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 2025-01-02 09:49:36,018 - INFO - 7d4efdfd-82bd-4a05-98b3-c70de9c16e0b_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
2
+ 2025-01-02 09:49:36,486 - INFO - d804a237-9b3e-4c83-8871-2aae6ca1d73d_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
3
+ 2025-01-02 09:49:37,089 - INFO - 820b8df1-2492-4ac6-9230-650bbb875122_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
4
+ 2025-01-02 09:49:37,666 - INFO - 82da1b85-5bc3-42ed-80ee-e9b7d8e44123_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
5
+ 2025-01-02 09:49:38,270 - INFO - d18fa576-c9cc-4be3-a2b4-7ab46a392f2b_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
6
+ 2025-01-02 09:58:45,530 - INFO - b05153a2-968c-4e08-9113-07b51df51d2e_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
7
+ 2025-01-02 09:58:46,083 - INFO - 35884a24-4095-4ecd-b1c3-10c88947e12b_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
8
+ 2025-01-02 09:58:46,693 - INFO - 8087024d-1e08-4cae-a336-dfe591ae27ce_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
9
+ 2025-01-02 09:58:47,195 - INFO - 9bdd88b3-4ed8-4f89-9abb-e2bc49b4da0f_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
10
+ 2025-01-02 09:58:47,592 - INFO - ff0a3e9f-cd5a-4977-9ab6-721179f41a9b_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
11
+ 2025-01-02 10:02:56,391 - INFO - 7fad3aab-6cbf-40ba-91d6-1213a113e4cc_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
12
+ 2025-01-02 10:02:56,993 - INFO - 38ac11a0-fd15-438d-985f-3bbe670f60cf_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
13
+ 2025-01-02 10:02:57,542 - INFO - 58a96911-2ee0-438b-adc6-62de8c6ef8c0_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
14
+ 2025-01-02 10:02:58,086 - INFO - 87436ad6-0d9a-4374-91b6-1a95c8a623e5_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
15
+ 2025-01-02 10:02:58,853 - INFO - cf72c268-2bed-4ab3-b1de-3371c9a540fa_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
16
+ 2025-01-02 14:05:00,442 - INFO - 5bf4bf35-ebc1-418a-a14b-f2c536983b33_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
17
+ 2025-01-02 14:05:01,488 - INFO - afaa8e05-d2c4-4b4f-96b2-894bd873ac7c_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
18
+ 2025-01-02 14:05:02,011 - INFO - 10a2becc-d166-4a4a-b81f-f8f52e8da3a2_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
19
+ 2025-01-02 14:05:02,462 - INFO - 7da6b309-accf-4370-9877-3852fa0eb1ad_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
20
+ 2025-01-02 14:05:03,041 - INFO - 5c3904bf-f805-4710-9184-24d5871c0687_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
21
+ 2025-01-02 15:10:46,920 - INFO - ad2b962e-ff55-4a90-b33e-f8a79628a0e6_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
22
+ 2025-01-02 15:10:48,607 - INFO - 4d9d2b38-c5bc-4525-bbb1-3f9fb7974156_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
23
+ 2025-01-02 15:10:49,220 - INFO - 4884a10b-505b-4c8b-9fd8-53e9f8d959d2_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
24
+ 2025-01-02 15:10:49,841 - INFO - 4e62d8fc-cde4-4e59-874c-bd5b86b208bb_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
25
+ 2025-01-02 15:10:50,745 - INFO - e6e37e7f-525d-435c-b860-58f719995032_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
26
+ 2025-01-02 15:12:11,852 - INFO - 7b8f7a8a-b10a-4d2b-b8af-33d871c6883f_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
27
+ 2025-01-02 15:12:12,247 - INFO - 8d6d7eed-cf50-4dd0-9196-b2b04df9aa25_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
28
+ 2025-01-02 15:12:12,789 - INFO - 2f0997a8-26e4-4459-95d1-f022b75058cc_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
29
+ 2025-01-02 15:12:13,822 - INFO - 73b52f33-9dbf-47a6-8fd6-7c70b0839265_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
30
+ 2025-01-02 15:12:14,609 - INFO - 6bf5a433-637f-480a-b801-cc7a66f92e71_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
31
+ 2025-01-07 14:14:02,625 - INFO - 363bdd80-43d5-40fe-84b6-a2e89d58e1cf_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
32
+ 2025-01-07 14:14:04,956 - INFO - 319b2118-5c37-47e9-a15a-56a1ba28f533_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
33
+ 2025-01-07 14:14:05,658 - INFO - 5ce111cb-2cca-4f16-8712-19adf801193d_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
34
+ 2025-01-07 14:14:06,171 - INFO - d2688d0d-c09a-427d-97b2-5a6073ef9c06_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
35
+ 2025-01-07 14:14:06,767 - INFO - dfa4ed93-a644-4431-81a3-3916924df457_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
36
+ 2025-01-07 14:18:34,502 - INFO - 9468b228-0fcc-4942-9a0c-559253683f5d_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
37
+ 2025-01-07 14:18:36,034 - INFO - b390676d-9e05-4e4e-8018-815265d44cba_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
38
+ 2025-01-07 14:18:37,236 - INFO - f20259fd-f923-4c0c-9cf0-956a8f7c438e_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
39
+ 2025-01-07 14:18:40,388 - INFO - ad6cbcf3-9662-48e0-88d8-6e4eca796842_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
40
+ 2025-01-07 14:18:41,380 - INFO - b4df84cf-55f5-46d2-b9cb-f8039fb102e7_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
41
+ 2025-02-12 12:58:48,544 - INFO - a3d8ff96-c21b-46ae-a6f5-d3d7b9952e01_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
42
+ 2025-02-12 12:58:49,147 - INFO - 9100ac6e-2da9-4b23-8560-d0e0f2129100_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
43
+ 2025-02-12 12:58:49,574 - INFO - d8c6373e-2de0-4c22-bb4f-394a66dcf397_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
44
+ 2025-02-12 12:58:50,396 - INFO - 67e0bd19-4dca-4666-ac82-2c161482df43_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
45
+ 2025-02-12 12:58:50,966 - INFO - 37c33e40-db31-430d-9e80-5062fd0c5b6a_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
46
+ 2025-02-12 13:03:18,154 - INFO - f6aa8d0a-ea7d-46ef-92f5-39506ecd439c_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
47
+ 2025-02-12 13:03:18,609 - INFO - 7ebd203f-717c-43e0-90b3-d8de87207c5c_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
48
+ 2025-02-12 13:03:19,892 - INFO - 8410df14-2343-49c5-b810-e9c974d3a1b4_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
49
+ 2025-02-12 13:03:24,692 - INFO - dc571c48-21ec-4cc7-a845-cc89254f82bb_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
50
+ 2025-02-12 13:03:27,569 - INFO - dd340448-b640-4ffa-8735-8b984bde825f_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda
51
+ 2025-02-12 13:07:30,320 - INFO - e162050f-e78d-424b-94c1-67225d392763_https://sswalfa.surabaya.go.id/info/detail/izin-pengumpulan-sumbangan-bencana
52
+ 2025-02-12 13:07:30,753 - INFO - 7d64ed75-53a7-41c7-9b64-5767f95e780a_https://sswalfa.surabaya.go.id/info/detail/izin-pemakaian-ruang-terbuka-hijau
53
+ 2025-02-12 13:07:44,452 - INFO - a9ccda4f-470a-4d0b-b6b1-2a993a30b62a_https://sswalfa.surabaya.go.id/info/detail/pengganti-ipt
54
+ 2025-02-12 13:07:49,413 - INFO - 6cec7f22-f829-4ebc-a4e3-fcf07d12e264_https://sswalfa.surabaya.go.id/info/detail/arahan-sistem-drainase
55
+ 2025-02-12 13:07:49,730 - INFO - ab810981-4182-4b53-9b2e-de0423980e64_https://sswalfa.surabaya.go.id/info/detail/rangkaian-pelayanan-surat-pernyataan-belum-menikah-lagi-bagi-jandaduda