ABAO77 commited on
Commit
6cbca40
·
verified ·
1 Parent(s): d976edd

Upload 74 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Dockerfile +8 -16
  2. app.py +12 -1046
  3. requirements.txt +14 -7
  4. src/.DS_Store +0 -0
  5. src/Untitled.ipynb +51 -0
  6. src/__pycache__/__init__.cpython-311.pyc +0 -0
  7. src/__pycache__/app.cpython-311.pyc +0 -0
  8. src/__pycache__/state.cpython-311.pyc +0 -0
  9. src/agents/.DS_Store +0 -0
  10. src/agents/base/flow.py +22 -0
  11. src/agents/base/func.py +4 -0
  12. src/agents/base/prompt.py +14 -0
  13. src/agents/base/tools.py +16 -0
  14. src/agents/role_play/__pycache__/func.cpython-311.pyc +0 -0
  15. src/agents/role_play/__pycache__/prompt.cpython-311.pyc +0 -0
  16. src/agents/role_play/__pycache__/scenarios.cpython-311.pyc +0 -0
  17. src/agents/role_play/flow.py +24 -0
  18. src/agents/role_play/func.py +55 -0
  19. src/agents/role_play/prompt.py +187 -0
  20. src/agents/role_play/scenarios.py +195 -0
  21. src/agents/role_play/tools.py +16 -0
  22. src/agents/tools/__pycache__/crawl.cpython-311.pyc +0 -0
  23. src/agents/tools/crawl.py +24 -0
  24. src/apis/.DS_Store +0 -0
  25. src/apis/__pycache__/__init__.cpython-311.pyc +0 -0
  26. src/apis/__pycache__/create_app.cpython-311.pyc +0 -0
  27. src/apis/config/__pycache__/firebase_config.cpython-311.pyc +0 -0
  28. src/apis/create_app.py +22 -0
  29. src/apis/interfaces/.DS_Store +0 -0
  30. src/apis/interfaces/__pycache__/api_interface.cpython-311.pyc +0 -0
  31. src/apis/interfaces/__pycache__/auth_interface.cpython-311.pyc +0 -0
  32. src/apis/interfaces/api_interface.py +5 -0
  33. src/apis/interfaces/auth_interface.py +2 -0
  34. src/apis/middlewares/__pycache__/auth_middleware.cpython-311.pyc +0 -0
  35. src/apis/middlewares/auth_middleware.py +0 -0
  36. src/apis/models/.DS_Store +0 -0
  37. src/apis/models/BaseModel.py +17 -0
  38. src/apis/models/__pycache__/BaseModel.cpython-311.pyc +0 -0
  39. src/apis/models/__pycache__/destination_models.cpython-311.pyc +0 -0
  40. src/apis/models/__pycache__/hotel_models.cpython-311.pyc +0 -0
  41. src/apis/models/__pycache__/post_models.cpython-311.pyc +0 -0
  42. src/apis/models/__pycache__/schedule_models.cpython-311.pyc +0 -0
  43. src/apis/models/__pycache__/user_models.cpython-311.pyc +0 -0
  44. src/apis/models/user_models.py +0 -0
  45. src/apis/providers/.DS_Store +0 -0
  46. src/apis/providers/__pycache__/__init__.cpython-311.pyc +0 -0
  47. src/apis/providers/__pycache__/firebase_provider.cpython-311.pyc +0 -0
  48. src/apis/providers/__pycache__/jwt_provider.cpython-311.pyc +0 -0
  49. src/apis/routes/.DS_Store +0 -0
  50. src/apis/routes/__pycache__/admin_route.cpython-311.pyc +0 -0
Dockerfile CHANGED
@@ -1,21 +1,13 @@
1
- FROM openjdk:17-slim
2
 
3
- RUN apt-get update && apt-get install -y python3 python3-pip
 
 
4
 
5
  WORKDIR /app
6
 
 
 
7
 
8
- COPY . .
9
-
10
- RUN pip3 install -r requirements.txt
11
-
12
-
13
- # Expose port
14
- EXPOSE 7860
15
-
16
- # Health check
17
- HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
18
- CMD curl -f http://localhost:7860/health || exit 1
19
-
20
- # Start the application
21
- CMD ["python3", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
+ FROM python:3.11-slim
2
 
3
+ RUN useradd -m -u 1000 user
4
+ USER user
5
+ ENV PATH="/home/user/.local/bin:$PATH"
6
 
7
  WORKDIR /app
8
 
9
+ COPY --chown=user ./requirements.txt requirements.txt
10
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
 
12
+ COPY --chown=user . /app
13
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,1046 +1,12 @@
1
- import os
2
- import tempfile
3
- import shutil
4
- import subprocess
5
- import asyncio
6
- from pathlib import Path
7
- from typing import List, Optional, Dict, Any
8
- import uuid
9
- import re
10
- import time
11
- import hashlib
12
- from fastapi import (
13
- UploadFile,
14
- File,
15
- Form,
16
- HTTPException,
17
- BackgroundTasks,
18
- APIRouter,
19
- FastAPI,
20
- )
21
- from fastapi.responses import JSONResponse
22
- from pydantic import BaseModel
23
- import json
24
- import resource
25
- import platform
26
- from loguru import logger
27
-
28
- app = FastAPI(title="Code Grader API", version="1.0.0", docs_url="/")
29
-
30
- # Configuration
31
- MAX_EXECUTION_TIME = 5 # seconds
32
- MAX_MEMORY = 256 * 1024 * 1024 # 256MB
33
- MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
34
- MAX_TOTAL_SIZE = 2 * 1024 * 1024 # 2MB total size limit for uploads and repos
35
-
36
-
37
- class ExecutionResult(BaseModel):
38
- success: bool
39
- stdout: str
40
- stderr: str
41
- execution_time: float
42
- exit_code: int
43
- error: Optional[str] = None
44
-
45
-
46
- class InputPattern(BaseModel):
47
- type: str # "input", "scanf", "cin", etc.
48
- line_number: int
49
- variable_name: Optional[str] = None
50
- prompt_message: Optional[str] = None
51
- data_type: Optional[str] = None # "int", "str", "float", etc.
52
- raw_code: str
53
-
54
-
55
- class InputAnalysisResult(BaseModel):
56
- language: str
57
- total_inputs: int
58
- input_patterns: List[InputPattern]
59
- suggestions: List[str] # UI suggestions for user
60
-
61
-
62
- class CodeExecutor:
63
- def __init__(self):
64
- self.compilers = {
65
- "c": "clang" if platform.system() == "Darwin" else "gcc",
66
- "cpp": "clang++" if platform.system() == "Darwin" else "g++",
67
- "java": "javac",
68
- "python": "python3",
69
- }
70
-
71
- def set_resource_limits(self):
72
- """Set resource limits for subprocess (Unix only)"""
73
- if platform.system() == "Linux":
74
- resource.setrlimit(
75
- resource.RLIMIT_CPU, (MAX_EXECUTION_TIME, MAX_EXECUTION_TIME)
76
- )
77
- resource.setrlimit(resource.RLIMIT_AS, (MAX_MEMORY, MAX_MEMORY))
78
-
79
- def analyze_input_patterns(
80
- self, language: str, file_contents: Dict[str, str]
81
- ) -> InputAnalysisResult:
82
- """Analyze code files to detect input patterns"""
83
- patterns = []
84
-
85
- if language == "python":
86
- patterns = self._analyze_python_inputs(file_contents)
87
- elif language == "java":
88
- patterns = self._analyze_java_inputs(file_contents)
89
- elif language in ["c", "cpp"]:
90
- patterns = self._analyze_c_cpp_inputs(file_contents)
91
-
92
- suggestions = self._generate_input_suggestions(patterns, language)
93
-
94
- return InputAnalysisResult(
95
- language=language,
96
- total_inputs=len(patterns),
97
- input_patterns=patterns,
98
- suggestions=suggestions,
99
- )
100
-
101
- def _analyze_python_inputs(
102
- self, file_contents: Dict[str, str]
103
- ) -> List[InputPattern]:
104
- """Analyze Python files for input() patterns"""
105
- patterns = []
106
-
107
- for filename, content in file_contents.items():
108
- lines = content.split("\n")
109
-
110
- for i, line in enumerate(lines, 1):
111
- # Pattern 1: variable = input("prompt")
112
- match = re.search(
113
- r'(\w+)\s*=\s*input\s*\(\s*["\']([^"\']*)["\']?\s*\)', line
114
- )
115
- if match:
116
- var_name, prompt = match.groups()
117
- patterns.append(
118
- InputPattern(
119
- type="input",
120
- line_number=i,
121
- variable_name=var_name,
122
- prompt_message=prompt or f"Enter value for {var_name}",
123
- data_type="str",
124
- raw_code=line.strip(),
125
- )
126
- )
127
- continue
128
-
129
- # Pattern 2: variable = int(input("prompt"))
130
- match = re.search(
131
- r'(\w+)\s*=\s*(int|float|str)\s*\(\s*input\s*\(\s*["\']([^"\']*)["\']?\s*\)\s*\)',
132
- line,
133
- )
134
- if match:
135
- var_name, data_type, prompt = match.groups()
136
- patterns.append(
137
- InputPattern(
138
- type="input",
139
- line_number=i,
140
- variable_name=var_name,
141
- prompt_message=prompt
142
- or f"Enter {data_type} value for {var_name}",
143
- data_type=data_type,
144
- raw_code=line.strip(),
145
- )
146
- )
147
- continue
148
-
149
- # Pattern 3: Simple input() without assignment
150
- if "input(" in line and "=" not in line:
151
- patterns.append(
152
- InputPattern(
153
- type="input",
154
- line_number=i,
155
- variable_name=None,
156
- prompt_message="Enter input",
157
- data_type="str",
158
- raw_code=line.strip(),
159
- )
160
- )
161
-
162
- return patterns
163
-
164
- def _analyze_java_inputs(self, file_contents: Dict[str, str]) -> List[InputPattern]:
165
- """Analyze Java files for Scanner input patterns"""
166
- patterns = []
167
-
168
- for filename, content in file_contents.items():
169
- lines = content.split("\n")
170
-
171
- for i, line in enumerate(lines, 1):
172
- # Pattern 1: scanner.nextInt(), scanner.nextLine(), etc.
173
- match = re.search(r"(\w+)\s*=\s*(\w+)\.next(\w+)\s*\(\s*\)", line)
174
- if match:
175
- var_name, scanner_name, method = match.groups()
176
- data_type = self._java_method_to_type(method)
177
- patterns.append(
178
- InputPattern(
179
- type="scanner",
180
- line_number=i,
181
- variable_name=var_name,
182
- prompt_message=f"Enter {data_type} value for {var_name}",
183
- data_type=data_type,
184
- raw_code=line.strip(),
185
- )
186
- )
187
- continue
188
-
189
- # Pattern 2: Direct scanner calls without assignment
190
- match = re.search(r"(\w+)\.next(\w+)\s*\(\s*\)", line)
191
- if match and "=" not in line:
192
- scanner_name, method = match.groups()
193
- data_type = self._java_method_to_type(method)
194
- patterns.append(
195
- InputPattern(
196
- type="scanner",
197
- line_number=i,
198
- variable_name=None,
199
- prompt_message=f"Enter {data_type} input",
200
- data_type=data_type,
201
- raw_code=line.strip(),
202
- )
203
- )
204
-
205
- return patterns
206
-
207
- def _analyze_c_cpp_inputs(
208
- self, file_contents: Dict[str, str]
209
- ) -> List[InputPattern]:
210
- """Analyze C/C++ files for input patterns"""
211
- patterns = []
212
-
213
- for filename, content in file_contents.items():
214
- lines = content.split("\n")
215
-
216
- for i, line in enumerate(lines, 1):
217
- # Pattern 1: scanf("%d", &variable)
218
- match = re.search(
219
- r'scanf\s*\(\s*["\']([^"\']*)["\'],\s*&(\w+)\s*\)', line
220
- )
221
- if match:
222
- format_spec, var_name = match.groups()
223
- data_type = self._c_format_to_type(format_spec)
224
- patterns.append(
225
- InputPattern(
226
- type="scanf",
227
- line_number=i,
228
- variable_name=var_name,
229
- prompt_message=f"Enter {data_type} value for {var_name}",
230
- data_type=data_type,
231
- raw_code=line.strip(),
232
- )
233
- )
234
- continue
235
-
236
- # Pattern 2: cin >> variable (C++)
237
- match = re.search(r"cin\s*>>\s*(\w+)", line)
238
- if match:
239
- var_name = match.group(1)
240
- patterns.append(
241
- InputPattern(
242
- type="cin",
243
- line_number=i,
244
- variable_name=var_name,
245
- prompt_message=f"Enter value for {var_name}",
246
- data_type="unknown",
247
- raw_code=line.strip(),
248
- )
249
- )
250
- continue
251
-
252
- # Pattern 3: getline(cin, variable) for strings
253
- match = re.search(r"getline\s*\(\s*cin\s*,\s*(\w+)\s*\)", line)
254
- if match:
255
- var_name = match.group(1)
256
- patterns.append(
257
- InputPattern(
258
- type="getline",
259
- line_number=i,
260
- variable_name=var_name,
261
- prompt_message=f"Enter string for {var_name}",
262
- data_type="string",
263
- raw_code=line.strip(),
264
- )
265
- )
266
-
267
- return patterns
268
-
269
- def _java_method_to_type(self, method: str) -> str:
270
- """Convert Java Scanner method to data type"""
271
- type_mapping = {
272
- "Int": "int",
273
- "Double": "double",
274
- "Float": "float",
275
- "Long": "long",
276
- "Line": "string",
277
- "": "string",
278
- }
279
- return type_mapping.get(method, "string")
280
-
281
- def _c_format_to_type(self, format_spec: str) -> str:
282
- """Convert C format specifier to data type"""
283
- if "%d" in format_spec or "%i" in format_spec:
284
- return "int"
285
- elif "%f" in format_spec:
286
- return "float"
287
- elif "%lf" in format_spec:
288
- return "double"
289
- elif "%c" in format_spec:
290
- return "char"
291
- elif "%s" in format_spec:
292
- return "string"
293
- return "unknown"
294
-
295
- def _generate_input_suggestions(
296
- self, patterns: List[InputPattern], language: str
297
- ) -> List[str]:
298
- """Generate UI suggestions based on detected patterns"""
299
- suggestions = []
300
-
301
- if not patterns:
302
- suggestions.append(
303
- "No input patterns detected. Code will run without user input."
304
- )
305
- return suggestions
306
-
307
- suggestions.append(
308
- f"Detected {len(patterns)} input requirement(s) in {language} code:"
309
- )
310
-
311
- for i, pattern in enumerate(patterns, 1):
312
- if pattern.variable_name:
313
- suggestions.append(
314
- f"{i}. Line {pattern.line_number}: {pattern.prompt_message} "
315
- f"(Variable: {pattern.variable_name}, Type: {pattern.data_type})"
316
- )
317
- else:
318
- suggestions.append(
319
- f"{i}. Line {pattern.line_number}: {pattern.prompt_message} "
320
- f"(Type: {pattern.data_type})"
321
- )
322
-
323
- suggestions.append(
324
- "Please provide input values in the order they appear in the code."
325
- )
326
-
327
- return suggestions
328
-
329
- async def execute_code(
330
- self,
331
- language: str,
332
- main_files: List[str],
333
- workspace: str,
334
- input_data: Optional[List[str]] = None,
335
- ) -> ExecutionResult:
336
- """Execute code based on language with optional input data"""
337
- try:
338
- if language == "python":
339
- return await self._execute_python(main_files, workspace, input_data)
340
- elif language == "java":
341
- return await self._execute_java(main_files, workspace, input_data)
342
- elif language in ["c", "cpp"]:
343
- return await self._execute_c_cpp(
344
- main_files, workspace, language, input_data
345
- )
346
- else:
347
- raise ValueError(f"Unsupported language: {language}")
348
- except Exception as e:
349
- return ExecutionResult(
350
- success=False,
351
- stdout="",
352
- stderr=str(e),
353
- execution_time=0,
354
- exit_code=-1,
355
- error=str(e),
356
- )
357
-
358
- async def _execute_with_input(
359
- self, command: List[str], workspace: str, input_data: Optional[List[str]] = None
360
- ) -> tuple:
361
- """Execute process with input data"""
362
- process = await asyncio.create_subprocess_exec(
363
- *command,
364
- cwd=workspace,
365
- stdout=asyncio.subprocess.PIPE,
366
- stderr=asyncio.subprocess.PIPE,
367
- stdin=asyncio.subprocess.PIPE,
368
- preexec_fn=(
369
- self.set_resource_limits if platform.system() == "Linux" else None
370
- ),
371
- )
372
-
373
- # Prepare input string
374
- stdin_input = None
375
- if input_data:
376
- stdin_input = "\n".join(input_data) + "\n"
377
- stdin_input = stdin_input.encode("utf-8")
378
-
379
- try:
380
- stdout, stderr = await asyncio.wait_for(
381
- process.communicate(input=stdin_input), timeout=MAX_EXECUTION_TIME
382
- )
383
- return stdout, stderr, process.returncode
384
- except asyncio.TimeoutError:
385
- process.kill()
386
- await process.wait()
387
- raise asyncio.TimeoutError()
388
-
389
- async def _execute_python(
390
- self,
391
- main_files: List[str],
392
- workspace: str,
393
- input_data: Optional[List[str]] = None,
394
- ) -> ExecutionResult:
395
- """Execute Python code with input support"""
396
- results = []
397
-
398
- for main_file in main_files:
399
- file_path = os.path.join(workspace, main_file)
400
- if not os.path.exists(file_path):
401
- results.append(
402
- ExecutionResult(
403
- success=False,
404
- stdout="",
405
- stderr=f"File not found: {main_file}",
406
- execution_time=0,
407
- exit_code=-1,
408
- )
409
- )
410
- continue
411
-
412
- try:
413
- start_time = asyncio.get_event_loop().time()
414
-
415
- stdout, stderr, returncode = await self._execute_with_input(
416
- ["python3", main_file], workspace, input_data
417
- )
418
-
419
- execution_time = asyncio.get_event_loop().time() - start_time
420
-
421
- results.append(
422
- ExecutionResult(
423
- success=returncode == 0,
424
- stdout=stdout.decode("utf-8", errors="replace"),
425
- stderr=stderr.decode("utf-8", errors="replace"),
426
- execution_time=execution_time,
427
- exit_code=returncode,
428
- )
429
- )
430
-
431
- except asyncio.TimeoutError:
432
- results.append(
433
- ExecutionResult(
434
- success=False,
435
- stdout="",
436
- stderr="Execution timeout exceeded",
437
- execution_time=MAX_EXECUTION_TIME,
438
- exit_code=-1,
439
- )
440
- )
441
- except Exception as e:
442
- results.append(
443
- ExecutionResult(
444
- success=False,
445
- stdout="",
446
- stderr=str(e),
447
- execution_time=0,
448
- exit_code=-1,
449
- error=str(e),
450
- )
451
- )
452
-
453
- return self._combine_results(results, main_files)
454
-
455
- async def _execute_java(
456
- self,
457
- main_files: List[str],
458
- workspace: str,
459
- input_data: Optional[List[str]] = None,
460
- ) -> ExecutionResult:
461
- """Compile and execute Java code with input support"""
462
-
463
- # Check if we have .java files to compile
464
- java_files = list(Path(workspace).glob("*.java"))
465
- needs_compilation = len(java_files) > 0
466
-
467
- # If we have .java files, compile them
468
- if needs_compilation:
469
- logger.info(f"Found {len(java_files)} Java source files, compiling...")
470
-
471
- compile_process = await asyncio.create_subprocess_exec(
472
- "javac",
473
- *[str(f) for f in java_files],
474
- cwd=workspace,
475
- stdout=asyncio.subprocess.PIPE,
476
- stderr=asyncio.subprocess.PIPE,
477
- )
478
-
479
- stdout, stderr = await compile_process.communicate()
480
-
481
- if compile_process.returncode != 0:
482
- return ExecutionResult(
483
- success=False,
484
- stdout="",
485
- stderr=f"Compilation failed:\n{stderr.decode('utf-8', errors='replace')}",
486
- execution_time=0,
487
- exit_code=compile_process.returncode,
488
- )
489
-
490
- logger.info("Java compilation successful")
491
- else:
492
- # Check if we have .class files for the main files
493
- class_files_missing = []
494
- for main_file in main_files:
495
- if main_file.endswith(".class"):
496
- class_file_path = os.path.join(workspace, main_file)
497
- else:
498
- class_file_path = os.path.join(workspace, f"{main_file}.class")
499
-
500
- if not os.path.exists(class_file_path):
501
- class_files_missing.append(main_file)
502
-
503
- if class_files_missing:
504
- return ExecutionResult(
505
- success=False,
506
- stdout="",
507
- stderr=f"No Java source files found and missing .class files for: {', '.join(class_files_missing)}",
508
- execution_time=0,
509
- exit_code=-1,
510
- )
511
-
512
- logger.info("Using existing .class files, skipping compilation")
513
-
514
- # Execute main files
515
- results = []
516
- for main_file in main_files:
517
- # Determine class name
518
- if main_file.endswith(".class"):
519
- class_name = main_file.replace(".class", "")
520
- elif main_file.endswith(".java"):
521
- class_name = main_file.replace(".java", "")
522
- else:
523
- class_name = main_file
524
-
525
- # Verify the .class file exists
526
- class_file_path = os.path.join(workspace, f"{class_name}.class")
527
- if not os.path.exists(class_file_path):
528
- results.append(
529
- ExecutionResult(
530
- success=False,
531
- stdout="",
532
- stderr=f"Class file not found: {class_name}.class",
533
- execution_time=0,
534
- exit_code=-1,
535
- )
536
- )
537
- continue
538
-
539
- try:
540
- start_time = asyncio.get_event_loop().time()
541
-
542
- stdout, stderr, returncode = await self._execute_with_input(
543
- ["java", class_name], workspace, input_data
544
- )
545
-
546
- execution_time = asyncio.get_event_loop().time() - start_time
547
-
548
- results.append(
549
- ExecutionResult(
550
- success=returncode == 0,
551
- stdout=stdout.decode("utf-8", errors="replace"),
552
- stderr=stderr.decode("utf-8", errors="replace"),
553
- execution_time=execution_time,
554
- exit_code=returncode,
555
- )
556
- )
557
-
558
- except asyncio.TimeoutError:
559
- results.append(
560
- ExecutionResult(
561
- success=False,
562
- stdout="",
563
- stderr="Execution timeout exceeded",
564
- execution_time=MAX_EXECUTION_TIME,
565
- exit_code=-1,
566
- )
567
- )
568
- except Exception as e:
569
- results.append(
570
- ExecutionResult(
571
- success=False,
572
- stdout="",
573
- stderr=str(e),
574
- execution_time=0,
575
- exit_code=-1,
576
- error=str(e),
577
- )
578
- )
579
-
580
- return self._combine_results(results, main_files)
581
-
582
- async def _execute_c_cpp(
583
- self,
584
- main_files: List[str],
585
- workspace: str,
586
- language: str,
587
- input_data: Optional[List[str]] = None,
588
- ) -> ExecutionResult:
589
- """Compile and execute C/C++ code with input support"""
590
- compiler = self.compilers[language]
591
- results = []
592
-
593
- for main_file in main_files:
594
- file_path = os.path.join(workspace, main_file)
595
- if not os.path.exists(file_path):
596
- results.append(
597
- ExecutionResult(
598
- success=False,
599
- stdout="",
600
- stderr=f"File not found: {main_file}",
601
- execution_time=0,
602
- exit_code=-1,
603
- )
604
- )
605
- continue
606
-
607
- # Output binary name
608
- output_name = main_file.replace(".c", "").replace(".cpp", "")
609
-
610
- # Compile
611
- compile_process = await asyncio.create_subprocess_exec(
612
- compiler,
613
- main_file,
614
- "-o",
615
- output_name,
616
- cwd=workspace,
617
- stdout=asyncio.subprocess.PIPE,
618
- stderr=asyncio.subprocess.PIPE,
619
- )
620
-
621
- stdout, stderr = await compile_process.communicate()
622
-
623
- if compile_process.returncode != 0:
624
- results.append(
625
- ExecutionResult(
626
- success=False,
627
- stdout="",
628
- stderr=f"Compilation failed:\n{stderr.decode('utf-8', errors='replace')}",
629
- execution_time=0,
630
- exit_code=compile_process.returncode,
631
- )
632
- )
633
- continue
634
-
635
- # Execute
636
- try:
637
- start_time = asyncio.get_event_loop().time()
638
-
639
- stdout, stderr, returncode = await self._execute_with_input(
640
- [f"./{output_name}"], workspace, input_data
641
- )
642
-
643
- execution_time = asyncio.get_event_loop().time() - start_time
644
-
645
- results.append(
646
- ExecutionResult(
647
- success=returncode == 0,
648
- stdout=stdout.decode("utf-8", errors="replace"),
649
- stderr=stderr.decode("utf-8", errors="replace"),
650
- execution_time=execution_time,
651
- exit_code=returncode,
652
- )
653
- )
654
-
655
- except asyncio.TimeoutError:
656
- results.append(
657
- ExecutionResult(
658
- success=False,
659
- stdout="",
660
- stderr="Execution timeout exceeded",
661
- execution_time=MAX_EXECUTION_TIME,
662
- exit_code=-1,
663
- )
664
- )
665
- except Exception as e:
666
- results.append(
667
- ExecutionResult(
668
- success=False,
669
- stdout="",
670
- stderr=str(e),
671
- execution_time=0,
672
- exit_code=-1,
673
- error=str(e),
674
- )
675
- )
676
-
677
- return self._combine_results(results, main_files)
678
-
679
- def _combine_results(
680
- self, results: List[ExecutionResult], main_files: List[str]
681
- ) -> ExecutionResult:
682
- """Combine multiple execution results"""
683
- if len(results) == 1:
684
- return results[0]
685
- else:
686
- combined_stdout = "\n".join(
687
- [f"=== {main_files[i]} ===\n{r.stdout}" for i, r in enumerate(results)]
688
- )
689
- combined_stderr = "\n".join(
690
- [
691
- f"=== {main_files[i]} ===\n{r.stderr}"
692
- for i, r in enumerate(results)
693
- if r.stderr
694
- ]
695
- )
696
- total_time = sum(r.execution_time for r in results)
697
- all_success = all(r.success for r in results)
698
-
699
- return ExecutionResult(
700
- success=all_success,
701
- stdout=combined_stdout,
702
- stderr=combined_stderr,
703
- execution_time=total_time,
704
- exit_code=0 if all_success else -1,
705
- )
706
-
707
-
708
- def get_directory_size(directory_path: str) -> int:
709
- """Calculate total size of directory in bytes"""
710
- total_size = 0
711
- try:
712
- for dirpath, dirnames, filenames in os.walk(directory_path):
713
- for filename in filenames:
714
- filepath = os.path.join(dirpath, filename)
715
- if os.path.exists(filepath):
716
- total_size += os.path.getsize(filepath)
717
- except Exception as e:
718
- print(f"Error calculating directory size: {e}")
719
- return float("inf")
720
- return total_size
721
-
722
-
723
- def validate_upload_size(files: List[UploadFile]) -> tuple[bool, int]:
724
- """Validate total size of uploaded files"""
725
- total_size = 0
726
- for file in files:
727
- if hasattr(file, "size") and file.size:
728
- total_size += file.size
729
- else:
730
- return True, 0
731
- return total_size <= MAX_TOTAL_SIZE, total_size
732
-
733
-
734
- # Create executor instance
735
- executor = CodeExecutor()
736
-
737
-
738
- async def clone_repo(repo_url: str, workspace: str):
739
- """Clone a git repository into the workspace."""
740
- try:
741
- process = await asyncio.create_subprocess_exec(
742
- "git",
743
- "clone",
744
- repo_url,
745
- ".",
746
- cwd=workspace,
747
- stdout=asyncio.subprocess.PIPE,
748
- stderr=asyncio.subprocess.PIPE,
749
- )
750
- stdout, stderr = await process.communicate()
751
- if process.returncode != 0:
752
- raise HTTPException(
753
- status_code=400, detail=f"Failed to clone repository: {stderr.decode()}"
754
- )
755
-
756
- repo_size = get_directory_size(workspace)
757
- if repo_size > MAX_TOTAL_SIZE:
758
- raise HTTPException(
759
- status_code=400,
760
- detail=f"Repository size ({repo_size / 1024 / 1024:.2f}MB) exceeds limit ({MAX_TOTAL_SIZE / 1024 / 1024:.2f}MB)",
761
- )
762
-
763
- except HTTPException:
764
- raise
765
- except Exception as e:
766
- raise HTTPException(
767
- status_code=500, detail=f"Error cloning repository: {str(e)}"
768
- )
769
-
770
-
771
- def detect_language_from_files(main_files: List[str]) -> str:
772
- """Detect programming language from file extensions"""
773
- if not main_files:
774
- raise HTTPException(status_code=400, detail="No main files provided")
775
-
776
- first_file = main_files[0]
777
- if "." not in first_file:
778
- java_extensions = [".java", ".class"]
779
- for file in main_files:
780
- if any(file.endswith(ext) for ext in java_extensions):
781
- return "java"
782
-
783
- raise HTTPException(
784
- status_code=400,
785
- detail=f"Cannot detect language: file '{first_file}' has no extension",
786
- )
787
-
788
- extension = first_file.split(".")[-1].lower()
789
-
790
- extension_to_language = {
791
- "py": "python",
792
- "java": "java",
793
- "class": "java",
794
- "c": "c",
795
- "cpp": "cpp",
796
- "cc": "cpp",
797
- "cxx": "cpp",
798
- "c++": "cpp",
799
- }
800
-
801
- if extension not in extension_to_language:
802
- supported_extensions = ", ".join(extension_to_language.keys())
803
- raise HTTPException(
804
- status_code=400,
805
- detail=f"Unsupported file extension '.{extension}'. Supported extensions: {supported_extensions}",
806
- )
807
-
808
- detected_language = extension_to_language[extension]
809
-
810
- for file in main_files:
811
- if "." in file:
812
- file_ext = file.split(".")[-1].lower()
813
- file_language = extension_to_language.get(file_ext)
814
- if file_language != detected_language:
815
- raise HTTPException(
816
- status_code=400,
817
- detail=f"Mixed languages detected: '{first_file}' ({detected_language}) and '{file}' ({file_language})",
818
- )
819
-
820
- return detected_language
821
-
822
-
823
- @app.post("/analyze-inputs")
824
- async def analyze_inputs(code_content: str = Form(...), language: str = Form(...)):
825
- """
826
- Analyze code content to detect input patterns with caching
827
-
828
- Simple API that takes code content and language, returns input patterns
829
-
830
- Args:
831
- code_content: The source code content to analyze
832
- language: Programming language (python, java, c, cpp)
833
-
834
- Returns:
835
- InputAnalysisResult with detected input patterns
836
- """
837
- try:
838
- # Validate language
839
- supported_languages = ["python", "java", "c", "cpp"]
840
- if language.lower() not in supported_languages:
841
- raise HTTPException(
842
- status_code=400,
843
- detail=f"Unsupported language: {language}. Supported: {supported_languages}",
844
- )
845
-
846
- # Create a simple file contents dict for analysis
847
- file_contents_dict = {"main": code_content}
848
-
849
- analysis_result = executor.analyze_input_patterns(
850
- language.lower(), file_contents_dict
851
- )
852
- result_dict = analysis_result.model_dump()
853
-
854
- # Cache the result
855
-
856
- logger.info(f"Input analysis completed for {language} code")
857
- return JSONResponse(content=result_dict)
858
-
859
- except HTTPException:
860
- raise
861
- except Exception as e:
862
- logger.error(f"Error analyzing inputs: {str(e)}")
863
- raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
864
-
865
-
866
- @app.post("/judge")
867
- async def judge_code(
868
- main_files: str = Form(...),
869
- files: List[UploadFile] = File(None),
870
- repo_url: Optional[str] = Form(None),
871
- input_data: Optional[str] = Form(None), # JSON array of input strings
872
- ):
873
- """
874
- Judge code submission with optional input data
875
-
876
- - main_files: JSON array of main files to execute
877
- - files: Multiple files maintaining folder structure
878
- - repo_url: Git repository URL (alternative to files)
879
- - input_data: JSON array of input strings for programs that require user input
880
- """
881
- # Parse main_files
882
- try:
883
- main_files_list = json.loads(main_files)
884
- except json.JSONDecodeError:
885
- raise HTTPException(status_code=400, detail="Invalid main_files format")
886
-
887
- # Parse input_data if provided
888
- input_list = None
889
- logger.info(f"Received input_data: {input_data}")
890
- if input_data:
891
- try:
892
- input_list = json.loads(input_data)
893
- if not isinstance(input_list, list):
894
- raise ValueError("Input data must be an array")
895
- except (json.JSONDecodeError, ValueError):
896
- raise HTTPException(
897
- status_code=400, detail="Invalid input_data format - must be JSON array"
898
- )
899
-
900
- # Auto-detect language from file extensions
901
- language = detect_language_from_files(main_files_list)
902
-
903
- # Validate input: either files or repo_url must be provided
904
- if not files and not repo_url:
905
- raise HTTPException(
906
- status_code=400, detail="Either files or repo_url must be provided"
907
- )
908
- if files and repo_url:
909
- raise HTTPException(
910
- status_code=400, detail="Provide either files or repo_url, not both"
911
- )
912
-
913
- # Create temporary workspace
914
- workspace = None
915
- try:
916
- # Create unique temporary directory
917
- workspace = tempfile.mkdtemp(prefix=f"judge_{uuid.uuid4().hex}_")
918
-
919
- if repo_url:
920
- # Clone repository
921
- await clone_repo(repo_url, workspace)
922
- else:
923
- # Validate total upload size
924
- total_upload_size = 0
925
- file_contents = []
926
-
927
- # Pre-read all files to check total size
928
- for file in files:
929
- content = await file.read()
930
- if len(content) > MAX_FILE_SIZE:
931
- raise HTTPException(
932
- status_code=400,
933
- detail=f"File {file.filename} exceeds individual size limit",
934
- )
935
-
936
- total_upload_size += len(content)
937
- file_contents.append((file.filename, content))
938
-
939
- # Check total size limit
940
- if total_upload_size > MAX_TOTAL_SIZE:
941
- raise HTTPException(
942
- status_code=400,
943
- detail=f"Total upload size ({total_upload_size / 1024 / 1024:.2f}MB) exceeds limit ({MAX_TOTAL_SIZE / 1024 / 1024:.2f}MB)",
944
- )
945
-
946
- # Save uploaded files maintaining structure
947
- for filename, content in file_contents:
948
- # Create file path
949
- file_path = os.path.join(workspace, filename)
950
-
951
- # Create directories if needed
952
- os.makedirs(os.path.dirname(file_path), exist_ok=True)
953
-
954
- # Write file
955
- with open(file_path, "wb") as f:
956
- f.write(content)
957
-
958
- # Execute code with input data
959
- result = await executor.execute_code(
960
- language, main_files_list, workspace, input_list
961
- )
962
- logger.info(f"Execution result: {result}")
963
- return JSONResponse(content=result.model_dump())
964
-
965
- except Exception as e:
966
- raise HTTPException(status_code=500, detail=str(e))
967
-
968
- finally:
969
- # Clean up temporary files
970
- if workspace and os.path.exists(workspace):
971
- try:
972
- shutil.rmtree(workspace)
973
- except Exception as e:
974
- print(f"Error cleaning up workspace: {e}")
975
-
976
-
977
- @app.get("/languages")
978
- async def get_supported_languages():
979
- """Get supported programming languages with auto-detection info"""
980
- return {
981
- "languages": [
982
- {"id": "python", "name": "Python 3", "extensions": [".py"]},
983
- {"id": "java", "name": "Java", "extensions": [".java", ".class"]},
984
- {"id": "c", "name": "C", "extensions": [".c"]},
985
- {"id": "cpp", "name": "C++", "extensions": [".cpp", ".cc", ".cxx", ".c++"]},
986
- ],
987
- "note": "Language is automatically detected from file extensions. For Java, both source (.java) and compiled (.class) files are supported.",
988
- "input_support": "All languages support automatic input detection and handling for interactive programs.",
989
- }
990
-
991
-
992
- # Example usage endpoints for testing
993
- @app.get("/examples/input-patterns")
994
- async def get_input_pattern_examples():
995
- """Get examples of supported input patterns for each language"""
996
- return {
997
- "python": [
998
- 'name = input("Enter your name: ")',
999
- 'age = int(input("Enter your age: "))',
1000
- 'score = float(input("Enter score: "))',
1001
- "input() # Simple input without assignment",
1002
- ],
1003
- "java": [
1004
- "String name = scanner.nextLine();",
1005
- "int age = scanner.nextInt();",
1006
- "double score = scanner.nextDouble();",
1007
- "scanner.next(); # Direct call",
1008
- ],
1009
- "c": ['scanf("%s", name);', 'scanf("%d", &age);', 'scanf("%f", &score);'],
1010
- "cpp": ["cin >> name;", "cin >> age;", "getline(cin, fullName);"],
1011
- }
1012
-
1013
-
1014
- @app.post("/test-input-analysis")
1015
- async def test_input_analysis():
1016
- """Test endpoint with sample code for input analysis"""
1017
-
1018
- # Sample Python code with inputs
1019
- sample_code = {
1020
- "main.py": """
1021
- name = input("Enter your name: ")
1022
- age = int(input("Enter your age: "))
1023
- score = float(input("Enter your score: "))
1024
-
1025
- print(f"Hello {name}")
1026
- print(f"You are {age} years old")
1027
- print(f"Your score is {score}")
1028
-
1029
- # Simple input without assignment
1030
- input("Press enter to continue...")
1031
- """
1032
- }
1033
-
1034
- # Test the analysis
1035
- analysis_result = executor.analyze_input_patterns("python", sample_code)
1036
-
1037
- return {
1038
- "sample_code": sample_code,
1039
- "analysis": analysis_result.model_dump(),
1040
- "suggested_inputs": [
1041
- "John Doe", # for name
1042
- "25", # for age
1043
- "95.5", # for score
1044
- "", # for press enter
1045
- ],
1046
- }
 
1
+ from dotenv import load_dotenv
2
+
3
+ load_dotenv()
4
+ from src.apis.create_app import create_app, api_router
5
+ import uvicorn
6
+
7
+
8
+ app = create_app()
9
+
10
+ app.include_router(api_router)
11
+ if __name__ == "__main__":
12
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,7 +1,14 @@
1
- fastapi>=0.104.0
2
- uvicorn[standard]>=0.24.0
3
- python-multipart>=0.0.6
4
- pydantic>=2.4.0
5
- loguru>=0.7.0
6
- aiofiles>=23.0.0
7
- httpx>=0.25.0
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ python-dateutil
4
+ pandas
5
+ openpyxl
6
+ redis
7
+ bs4
8
+ pytz
9
+ langgraph
10
+ langchain
11
+ langgraph-swarm
12
+ langchain-google-genai
13
+ python-dotenv
14
+ loguru
src/.DS_Store ADDED
Binary file (8.2 kB). View file
 
src/Untitled.ipynb ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "00ef7a54-9c8a-4235-82d1-9df1ac5f2967",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "hello\n"
14
+ ]
15
+ }
16
+ ],
17
+ "source": [
18
+ "print('hello')"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": null,
24
+ "id": "d2e19d62-d6ba-4cb7-ac8c-b965cf65b2d7",
25
+ "metadata": {},
26
+ "outputs": [],
27
+ "source": []
28
+ }
29
+ ],
30
+ "metadata": {
31
+ "kernelspec": {
32
+ "display_name": "Python 3 (ipykernel)",
33
+ "language": "python",
34
+ "name": "python3"
35
+ },
36
+ "language_info": {
37
+ "codemirror_mode": {
38
+ "name": "ipython",
39
+ "version": 3
40
+ },
41
+ "file_extension": ".py",
42
+ "mimetype": "text/x-python",
43
+ "name": "python",
44
+ "nbconvert_exporter": "python",
45
+ "pygments_lexer": "ipython3",
46
+ "version": "3.11.9"
47
+ }
48
+ },
49
+ "nbformat": 4,
50
+ "nbformat_minor": 5
51
+ }
src/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (221 Bytes). View file
 
src/__pycache__/app.cpython-311.pyc ADDED
Binary file (958 Bytes). View file
 
src/__pycache__/state.cpython-311.pyc ADDED
Binary file (763 Bytes). View file
 
src/agents/.DS_Store ADDED
Binary file (6.15 kB). View file
 
src/agents/base/flow.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.graph import StateGraph, START, END
2
+ from .func import State
3
+ from langgraph.graph.state import CompiledStateGraph
4
+ from langgraph.store.memory import InMemoryStore
5
+ class PrimaryChatBot:
6
+ def __init__(self):
7
+ self.builder = StateGraph(State)
8
+
9
+ @staticmethod
10
+ def routing(state: State):
11
+ pass
12
+
13
+ def node(self):
14
+ pass
15
+
16
+ def edge(self):
17
+ pass
18
+
19
+ def __call__(self) -> CompiledStateGraph:
20
+ self.node()
21
+ self.edge()
22
+ return self.builder.compile(checkpointer=InMemoryStore())
src/agents/base/func.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from typing import TypedDict
2
+
3
+ class State(TypedDict):
4
+ pass
src/agents/base/prompt.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.prompts import ChatPromptTemplate
2
+
3
+
4
+ base_prompt = ChatPromptTemplate.from_messages(
5
+ [
6
+ (
7
+ "system",
8
+ """Vai trò
9
+
10
+ """,
11
+ ),
12
+ ("placeholder", "{messages}"),
13
+ ]
14
+ )
src/agents/base/tools.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.tools import tool
2
+ from loguru import logger
3
+
4
+
5
+ @tool
6
+ def function_name(
7
+ input: str,
8
+ ) -> str:
9
+ """
10
+ Mô tả chức năng của hàm này.
11
+ """
12
+ logger.info(f"Received input: {input}")
13
+ # Thực hiện các thao tác cần thiết với input
14
+ result = f"Processed: {input}"
15
+ logger.info(f"Returning result: {result}")
16
+ return result
src/agents/role_play/__pycache__/func.cpython-311.pyc ADDED
Binary file (2.33 kB). View file
 
src/agents/role_play/__pycache__/prompt.cpython-311.pyc ADDED
Binary file (7.56 kB). View file
 
src/agents/role_play/__pycache__/scenarios.cpython-311.pyc ADDED
Binary file (6.36 kB). View file
 
src/agents/role_play/flow.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.graph import StateGraph, START, END
2
+ from .func import State
3
+ from langgraph.graph.state import CompiledStateGraph
4
+ from langgraph.store.memory import InMemoryStore
5
+
6
+
7
+ class PrimaryChatBot:
8
+ def __init__(self):
9
+ self.builder = StateGraph(State)
10
+
11
+ @staticmethod
12
+ def routing(state: State):
13
+ pass
14
+
15
+ def node(self):
16
+ pass
17
+
18
+ def edge(self):
19
+ pass
20
+
21
+ def __call__(self) -> CompiledStateGraph:
22
+ self.node()
23
+ self.edge()
24
+ return self.builder.compile(checkpointer=InMemoryStore())
src/agents/role_play/func.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import TypedDict
2
+ from src.config.llm import model
3
+ from langgraph.checkpoint.memory import InMemorySaver
4
+ from langgraph.prebuilt import create_react_agent
5
+ from langgraph_swarm import create_handoff_tool, create_swarm
6
+ from .prompt import roleplay_prompt, guiding_prompt
7
+
8
+
9
+ class State(TypedDict):
10
+ pass
11
+
12
+
13
+ def create_agents(scenario, checkpointer=InMemorySaver()):
14
+
15
+ roleplay_agent = create_react_agent(
16
+ model,
17
+ [
18
+ create_handoff_tool(
19
+ agent_name="Guiding Agent",
20
+ description="Hand off to Guiding Agent when user shows signs of needing help, guidance, or struggles with communication",
21
+ ),
22
+ ],
23
+ prompt=roleplay_prompt.format(
24
+ scenario_title=scenario["scenario_title"],
25
+ scenario_description=scenario["scenario_description"],
26
+ scenario_context=scenario["scenario_context"],
27
+ your_role=scenario["your_role"],
28
+ key_vocabulary=scenario["key_vocabulary"],
29
+ ),
30
+ name="Roleplay Agent",
31
+ )
32
+
33
+ guiding_agent = create_react_agent(
34
+ model,
35
+ [
36
+ create_handoff_tool(
37
+ agent_name="Roleplay Agent",
38
+ description="Hand off back to Roleplay Agent when user is ready for scenario practice and shows improved confidence",
39
+ ),
40
+ ],
41
+ prompt=guiding_prompt.format(
42
+ scenario_title=scenario["scenario_title"],
43
+ scenario_description=scenario["scenario_description"],
44
+ scenario_context=scenario["scenario_context"],
45
+ your_role=scenario["your_role"],
46
+ key_vocabulary=scenario["key_vocabulary"],
47
+ ),
48
+ name="Guiding Agent",
49
+ )
50
+
51
+ workflow = create_swarm(
52
+ [roleplay_agent, guiding_agent], default_active_agent="Roleplay Agent"
53
+ )
54
+
55
+ return workflow.compile(checkpointer)
src/agents/role_play/prompt.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.prompts import ChatPromptTemplate
2
+
3
+ roleplay_prompt = """# Role: Roleplay Partner - Part of the Wise Tutor System
4
+
5
+ You are part of Wise Tutor, a friendly English learning companion. You're the roleplay specialist who creates natural, authentic conversations with learners.
6
+
7
+ ## About Wise Tutor:
8
+ If asked about your name or identity, respond warmly: "I'm part of Wise Tutor! I'm here to help you practice English through fun conversations. Think of me as your friendly conversation partner!"
9
+
10
+ ## CRITICAL LANGUAGE RULE:
11
+ **IF USER SPEAKS ANY LANGUAGE OTHER THAN ENGLISH → IMMEDIATELY HAND OFF TO GUIDING AGENT**
12
+ This is an English learning experience. Users need to practice English for roleplay.
13
+
14
+ ## Current Scenario Context:
15
+ {scenario_title}: {scenario_description}
16
+ Setting: {scenario_context}
17
+ Your role: {your_role}
18
+ Key vocabulary: {key_vocabulary}
19
+
20
+ ## Your Mission:
21
+ - Be a real, authentic person in your role ({your_role})
22
+ - Have genuine conversations, not rehearsed interactions
23
+ - React naturally to what users say - show surprise, interest, concern
24
+ - Make the experience feel like talking to a real person
25
+ - ONLY engage in roleplay when user speaks English
26
+
27
+ ## Language Detection Protocol:
28
+ ### If User Uses Non-English:
29
+ - **DO NOT respond in their language**
30
+ - **DO NOT continue roleplay**
31
+ - **IMMEDIATELY hand off to Guiding Agent**
32
+
33
+ ### If User Uses English:
34
+ - Continue with natural roleplay as described below
35
+
36
+ ## Natural Conversation Principles:
37
+
38
+ ### Be Authentically Human:
39
+ - Show genuine emotions and reactions
40
+ - Use conversational language, not formal scripts
41
+ - Respond to the unexpected - be flexible
42
+ - Have your own personality as the character
43
+ - Make small talk when appropriate
44
+
45
+ ### Stay True to Your Role:
46
+ - Embody the character realistically ({your_role})
47
+ - Use language and knowledge appropriate to your role
48
+ - Have realistic limitations and expertise
49
+ - React as this person would in real situations
50
+
51
+ ### Create Real Interactions:
52
+ - Build genuine rapport with the user
53
+ - Remember details they share and reference them later
54
+ - Ask follow-up questions that show you're listening
55
+ - Share appropriate details about yourself/your work
56
+ - Handle awkward moments gracefully
57
+
58
+ ### Supportive Language Learning:
59
+ - If users make small errors, naturally model correct language without stopping the flow
60
+ - Focus on communication over perfection
61
+ - Encourage them by showing interest in what they're saying
62
+ - Make them feel comfortable making mistakes
63
+
64
+ ## Natural Handoff Triggers:
65
+ - **User speaks non-English** (immediate handoff)
66
+ - User seems genuinely lost or confused multiple times
67
+ - User explicitly asks for language help
68
+ - Communication completely breaks down
69
+ - User appears frustrated with language barriers
70
+
71
+ ## Conversation Flow:
72
+ - Start conversations naturally for the situation
73
+ - Let conversations develop organically
74
+ - Don't force vocabulary usage - let it emerge naturally
75
+ - End conversations naturally when appropriate
76
+
77
+ Remember:
78
+ - You're not a teacher in roleplay mode - you're a real person doing your job who happens to be patient with English learners. Be genuine, warm, and human!
79
+ - Not respond too long or too short. But also can adapt to the user's communication style and needs.
80
+ """
81
+
82
+ guiding_prompt = """# Role: Guiding Agent - Supportive Language Helper & Language Router
83
+
84
+ You are a patient, supportive language guide who helps users when they struggle with English communication. You are also responsible for handling users who speak non-English languages.
85
+
86
+ ## Current Scenario Context:
87
+ {scenario_title}: {scenario_description}
88
+ Key vocabulary for this scenario: {key_vocabulary}
89
+
90
+ ## Your Mission:
91
+ - Handle users who speak non-English languages and guide them to English
92
+ - Help users who are struggling with English communication
93
+ - Use simple, clear language and break things down step by step
94
+ - Provide examples and choices to make communication easier
95
+ - Build confidence and encourage attempts
96
+ - Prepare users to return to roleplay when they're ready
97
+
98
+ ## Language Routing Protocol:
99
+
100
+ ### When User Speaks Non-English Languages:
101
+ **Step 1: Polite Asking**
102
+ - Ask users about their current English level in their own language. If they are weak in English, encourage them and start teaching them.
103
+
104
+ **Step 2: Teaching**
105
+ - If users do not know English, use their own language to teach English, and if they know basic English, use English
106
+ - Start with very basic English
107
+
108
+ **Step 3: Begin English Teaching**
109
+ 1. Ask them what they want to learn about related to the current topic. Give them some related suggestions to get feedback.
110
+ 2. Teach them the related knowledge they need in the scope of learning English related to the topic, so that they have prior knowledge to practice Role-play
111
+
112
+
113
+
114
+ ## Building from Zero:
115
+ 1. **Basic greetings**: "Hello", "Hi", "Good morning"
116
+ 2. **Essential phrases**: "Please", "Thank you", "Excuse me"
117
+ 3. **Scenario basics**: Start with 2-3 key words for the situation
118
+ 4. **Simple sentences**: "I want..." "I would like..." "Can I have..."
119
+
120
+ ## Guiding Principles:
121
+
122
+ ### Use Simple Language:
123
+ - Short, clear sentences
124
+ - Basic vocabulary (avoid complex words)
125
+ - One concept at a time
126
+ - Lots of examples and choices
127
+
128
+ ### Supportive Approach:
129
+ - Encourage every attempt: "Good try!"
130
+ - Be patient with mistakes
131
+ - Focus on communication, not perfection
132
+ - Celebrate small victories
133
+ - **Extra patience for non-native speakers**: "Don't worry, English is difficult. You're doing great!"
134
+
135
+ ### Step-by-Step Help:
136
+ - Break complex requests into smaller parts
137
+ - Give specific examples they can use
138
+ - Offer multiple choice options
139
+ - Model the language first
140
+ - **For beginners**: Start with single words, then phrases, then sentences
141
+
142
+ ### Scenario-Specific Guidance:
143
+ - Teach key vocabulary for the current scenario
144
+ - Explain common phrases used in this situation
145
+ - Practice basic interactions before complex ones
146
+ - Connect learning to the roleplay context
147
+
148
+ ## Teaching Techniques:
149
+
150
+ ### For Absolute Beginners:
151
+
152
+ ### Vocabulary Building:
153
+
154
+
155
+ ### Phrase Practice:
156
+
157
+
158
+ ### Choice-Based Learning:
159
+
160
+
161
+ ### Error Correction:
162
+
163
+
164
+ ## Building Confidence:
165
+ - "You're doing great! English is difficult, but you're learning fast."
166
+ - "Don't worry about mistakes. That's how we learn!"
167
+ - "Your English is getting better with each try."
168
+ - **For multilingual learners**: "Speaking multiple languages is amazing! English will be easier with practice."
169
+
170
+ ## Transition Back to Roleplay:
171
+ - "Great! You're ready to try the real conversation now."
172
+ - "Perfect! Let's go back to the restaurant and practice with the waiter."
173
+ - "You know the words now. Let's use them in a real situation!"
174
+
175
+ ## Signs to Return to Roleplay:
176
+ - User gives confident, complete responses IN ENGLISH
177
+ - User uses vocabulary correctly in context
178
+ - User asks to try the roleplay again
179
+ - User shows improved communication flow
180
+ - User can form basic sentences (5+ words) comfortably IN ENGLISH
181
+
182
+
183
+ Remember:
184
+ - Your job is to make English feel easier and help users gain confidence to communicate naturally in English! Always redirect non-English speakers to English practice.
185
+ - Be flexible in using the user's language or English based on their confidence to enhance user experience.
186
+ - Not respond too long or complexly to avoid overwhelming the user. Because the goal is to build their confidence and skills gradually.
187
+ """
src/agents/role_play/scenarios.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ SCENARIOS = [
2
+ {
3
+ "id": "student_visa_interview",
4
+ "scenario_title": "Student Visa Interview",
5
+ "scenario_description": "Learn about the challenges and benefits of starting a small business, then share what kind of business you would start. You are a student applying for a student visa. I am the visa interviewer.",
6
+ "scenario_context": "A formal visa interview office at an embassy or consulate",
7
+ "your_role": "student",
8
+ "key_vocabulary": [
9
+ "pursue higher education",
10
+ "broaden my horizons",
11
+ "international exposure",
12
+ "cultural diversity",
13
+ "academic excellence",
14
+ "globally recognized degree",
15
+ "cutting-edge facilities",
16
+ "research opportunities",
17
+ "tuition fees",
18
+ "financial support",
19
+ "scholarship",
20
+ "sponsorship letter",
21
+ "post-graduation plans",
22
+ ],
23
+ "topics_covered": [
24
+ "Study Plans",
25
+ "University Choice",
26
+ "Academic Capability",
27
+ "Financial Status",
28
+ "Post-Graduation Plans",
29
+ ],
30
+ "follow_up_questions": {
31
+ "Study Plans": [
32
+ "Why did you decide to pursue higher education abroad instead of in your home country?",
33
+ "How will studying overseas help you broaden your horizons?",
34
+ "What challenges do you expect to face in a foreign academic environment?",
35
+ "How long is your course, and what is your study schedule like?",
36
+ "Have you researched the teaching methods used in your chosen program?",
37
+ ],
38
+ "University Choice": [
39
+ "Why did you choose this university over others?",
40
+ "How do you think the academic excellence of this institution will benefit you?",
41
+ "Have you looked into the research opportunities your university offers?",
42
+ "How will the cultural diversity on campus influence your experience?",
43
+ "What do you know about the city where your university is located?",
44
+ ],
45
+ "Academic Capability": [
46
+ "How does your academic background prepare you for this course?",
47
+ "Can you give an example of a project or subject you excelled at in the past?",
48
+ "How will you make use of the cutting-edge facilities provided by the university?",
49
+ "How confident are you in adapting to a different academic system?",
50
+ "What skills do you think will help you succeed in your studies abroad?",
51
+ ],
52
+ "Financial Status": [
53
+ "How will you fund your tuition fees and living expenses?",
54
+ "Can you provide details about your financial support from family?",
55
+ "Do you have a scholarship or proof of funds?",
56
+ "How have you prepared financially for unexpected costs?",
57
+ "Can you show me your bank statement and sponsorship letter?",
58
+ ],
59
+ "Post-Graduation Plans": [
60
+ "What will you do after you complete your degree?",
61
+ "How will your globally recognized degree help you in your career?",
62
+ "Do you plan to work overseas or return to your home country?",
63
+ "How will you apply the knowledge acquired during your studies?",
64
+ "What is your long-term goal after graduation?",
65
+ ],
66
+ },
67
+ },
68
+ {
69
+ "id": "ordering_at_restaurant",
70
+ "scenario_title": "Ordering At A Restaurant",
71
+ "scenario_description": "Practice ordering food, asking about the menu, and talking to a waiter. You are a customer at a restaurant. I am the waiter/waitress.",
72
+ "scenario_context": "A busy restaurant with various seating options and a diverse menu",
73
+ "your_role": "customer",
74
+ "key_vocabulary": [
75
+ "table for two, please",
76
+ "do you have a reservation?",
77
+ "non-smoking section",
78
+ "window seat",
79
+ "outdoor seating",
80
+ "could we have the bill, please?",
81
+ "do you take credit cards?",
82
+ "signature dish",
83
+ "dietary restrictions",
84
+ "sauce served separately",
85
+ "steak cooked",
86
+ "pair with a drink",
87
+ "vegetarian options",
88
+ "receipt",
89
+ "cash or card",
90
+ ],
91
+ "topics_covered": [
92
+ "Getting a Table",
93
+ "Asking About the Menu",
94
+ "Making a Food Order",
95
+ "Special Requests or Allergies",
96
+ "Paying the Bill",
97
+ ],
98
+ "follow_up_questions": {
99
+ "Getting a Table": [
100
+ "Would you like to sit inside or outside?",
101
+ "How many people will be joining you today?",
102
+ "Do you have a reservation under your name?",
103
+ ],
104
+ "Asking About the Menu": [
105
+ "Are you looking for something light or filling?",
106
+ "Would you like to try our signature dish?",
107
+ "Do you prefer meat, seafood, or vegetarian options?",
108
+ ],
109
+ "Making a Food Order": [
110
+ "Would you like any sides with that?",
111
+ "How would you like your steak cooked?",
112
+ "Would you like to pair it with a drink?",
113
+ ],
114
+ "Special Requests or Allergies": [
115
+ "Do you have any dietary restrictions?",
116
+ "Should we avoid using certain ingredients?",
117
+ "Would you like the sauce served separately?",
118
+ ],
119
+ "Paying the Bill": [
120
+ "Would you like to pay together or separately?",
121
+ "Would you like the receipt?",
122
+ "Are you paying by cash or card?",
123
+ ],
124
+ },
125
+ },
126
+ {
127
+ "id": "going_shopping",
128
+ "scenario_title": "Going Shopping",
129
+ "scenario_description": "Practice asking about prices, sizes, and items while shopping. You are a customer looking for items in a store. I am the shop assistant.",
130
+ "scenario_context": "A retail store with various departments and products",
131
+ "your_role": "customer",
132
+ "key_vocabulary": [
133
+ "excuse me, could you help me?",
134
+ "I'm looking for...",
135
+ "do you have this in stock?",
136
+ "could you show me where it is?",
137
+ "what size do you usually wear?",
138
+ "would you like to try it on?",
139
+ "does it fit comfortably?",
140
+ "specific price range",
141
+ "casual or formal",
142
+ "specific brand",
143
+ "different size",
144
+ "paying by cash or card",
145
+ "would you like a bag?",
146
+ "exchange it for another item",
147
+ "other options",
148
+ ],
149
+ "topics_covered": [
150
+ "Asking for Help",
151
+ "Describing What You're Looking For",
152
+ "Asking About Price or Size",
153
+ "Trying or Testing Products",
154
+ "Making the Purchase or Returning",
155
+ ],
156
+ "follow_up_questions": {
157
+ "Asking for Help": [
158
+ "How can I assist you today?",
159
+ "Are you looking for anything in particular?",
160
+ "Do you need help finding your size?",
161
+ ],
162
+ "Describing What You're Looking For": [
163
+ "What color or style are you interested in?",
164
+ "Do you want something casual or formal?",
165
+ "Is there a specific brand you prefer?",
166
+ ],
167
+ "Asking About Price or Size": [
168
+ "Are you looking for something in a specific price range?",
169
+ "What size do you usually wear?",
170
+ "Would you like to see other options in your size?",
171
+ ],
172
+ "Trying or Testing Products": [
173
+ "Would you like to try it on?",
174
+ "Does it fit comfortably?",
175
+ "Do you need a different size?",
176
+ ],
177
+ "Making the Purchase or Returning": [
178
+ "Will you be paying by cash or card?",
179
+ "Would you like a bag for that?",
180
+ "Would you like to exchange it for another item?",
181
+ ],
182
+ },
183
+ },
184
+ ]
185
+
186
+
187
+ def get_scenarios():
188
+ return SCENARIOS
189
+
190
+
191
+ def get_scenario_by_id(scenario_id: str):
192
+ for scenario in SCENARIOS:
193
+ if scenario["id"] == scenario_id:
194
+ return scenario
195
+ return None
src/agents/role_play/tools.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.tools import tool
2
+ from loguru import logger
3
+
4
+
5
+ @tool
6
+ def function_name(
7
+ input: str,
8
+ ) -> str:
9
+ """
10
+ Mô tả chức năng của hàm này.
11
+ """
12
+ logger.info(f"Received input: {input}")
13
+ # Thực hiện các thao tác cần thiết với input
14
+ result = f"Processed: {input}"
15
+ logger.info(f"Returning result: {result}")
16
+ return result
src/agents/tools/__pycache__/crawl.cpython-311.pyc ADDED
Binary file (1.34 kB). View file
 
src/agents/tools/crawl.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from typing import Annotated
5
+
6
+ from langchain_core.tools import tool
7
+
8
+ from src.config.crawler.crawler import Crawler
9
+ from loguru import logger
10
+
11
+
12
+ @tool
13
+ def crawl_tool(
14
+ url: Annotated[str, "The url to crawl."],
15
+ ) -> str:
16
+ """Use this to crawl a url and get a readable content in markdown format."""
17
+ try:
18
+ crawler = Crawler()
19
+ article = crawler.crawl(url)
20
+ return {"url": url, "crawled_content": article.to_markdown()[:1000]}
21
+ except BaseException as e:
22
+ error_msg = f"Failed to crawl. Error: {repr(e)}"
23
+ logger.error(error_msg)
24
+ return error_msg
src/apis/.DS_Store ADDED
Binary file (8.2 kB). View file
 
src/apis/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (166 Bytes). View file
 
src/apis/__pycache__/create_app.cpython-311.pyc ADDED
Binary file (1.12 kB). View file
 
src/apis/config/__pycache__/firebase_config.cpython-311.pyc ADDED
Binary file (1.79 kB). View file
 
src/apis/create_app.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, APIRouter
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from src.apis.routes.user_route import router as router_user
4
+ from src.apis.routes.chat_route import router as router_chat
5
+
6
+ api_router = APIRouter(prefix="/api")
7
+ api_router.include_router(router_user)
8
+ api_router.include_router(router_chat)
9
+
10
+
11
+ def create_app():
12
+ app = FastAPI(docs_url="/", title="API")
13
+
14
+ app.add_middleware(
15
+ CORSMiddleware,
16
+ allow_origins=["*"],
17
+ allow_credentials=True,
18
+ allow_methods=["*"],
19
+ allow_headers=["*"],
20
+ )
21
+
22
+ return app
src/apis/interfaces/.DS_Store ADDED
Binary file (6.15 kB). View file
 
src/apis/interfaces/__pycache__/api_interface.cpython-311.pyc ADDED
Binary file (7.32 kB). View file
 
src/apis/interfaces/__pycache__/auth_interface.cpython-311.pyc ADDED
Binary file (1.74 kB). View file
 
src/apis/interfaces/api_interface.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from typing import Optional
3
+ from src.apis.models.BaseModel import BaseDocument
4
+ from typing import List, Union
5
+
src/apis/interfaces/auth_interface.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from pydantic import BaseModel, Field
2
+
src/apis/middlewares/__pycache__/auth_middleware.cpython-311.pyc ADDED
Binary file (2.2 kB). View file
 
src/apis/middlewares/auth_middleware.py ADDED
File without changes
src/apis/models/.DS_Store ADDED
Binary file (6.15 kB). View file
 
src/apis/models/BaseModel.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from typing import Optional
3
+ from datetime import datetime
4
+ from src.utils.logger import get_date_time
5
+
6
+
7
+ class BaseDocument(BaseModel):
8
+ created_at: Optional[datetime] = Field(
9
+ default_factory=lambda: get_date_time().replace(tzinfo=None)
10
+ )
11
+ updated_at: Optional[datetime] = Field(
12
+ default_factory=lambda: get_date_time().replace(tzinfo=None)
13
+ )
14
+ expire_at: Optional[datetime] = None
15
+
16
+ class Config:
17
+ arbitrary_types_allowed = True
src/apis/models/__pycache__/BaseModel.cpython-311.pyc ADDED
Binary file (1.64 kB). View file
 
src/apis/models/__pycache__/destination_models.cpython-311.pyc ADDED
Binary file (2.12 kB). View file
 
src/apis/models/__pycache__/hotel_models.cpython-311.pyc ADDED
Binary file (2.14 kB). View file
 
src/apis/models/__pycache__/post_models.cpython-311.pyc ADDED
Binary file (2.73 kB). View file
 
src/apis/models/__pycache__/schedule_models.cpython-311.pyc ADDED
Binary file (1.8 kB). View file
 
src/apis/models/__pycache__/user_models.cpython-311.pyc ADDED
Binary file (2.41 kB). View file
 
src/apis/models/user_models.py ADDED
File without changes
src/apis/providers/.DS_Store ADDED
Binary file (6.15 kB). View file
 
src/apis/providers/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (271 Bytes). View file
 
src/apis/providers/__pycache__/firebase_provider.cpython-311.pyc ADDED
Binary file (4.75 kB). View file
 
src/apis/providers/__pycache__/jwt_provider.cpython-311.pyc ADDED
Binary file (2.23 kB). View file
 
src/apis/routes/.DS_Store ADDED
Binary file (6.15 kB). View file
 
src/apis/routes/__pycache__/admin_route.cpython-311.pyc ADDED
Binary file (10.8 kB). View file