Lucii1 commited on
Commit
8cf0f00
·
1 Parent(s): 59f4375
.env.example CHANGED
@@ -1,7 +1,9 @@
1
  SERVICE_GEOLOCATION_URL=
2
- SERVICE_AIGVDET_URL=
3
  SERVICE_REPORT_URL=
4
  SERVICE_TIMESTAMP_URL=
 
 
 
5
 
6
  MONGO_DATABASE_CONNECTION_STRING=
7
 
@@ -11,4 +13,7 @@ JWT_REFRESH_TOKEN_SECRET_KEY=
11
  JWT_REFRESH_TOKEN_EXPIRED_IN=
12
  JWT_REFRESH_TOKEN_EXTENDED_EXPIRED_IN=
13
 
14
- SAVE_DATA_PATH=
 
 
 
 
1
  SERVICE_GEOLOCATION_URL=
 
2
  SERVICE_REPORT_URL=
3
  SERVICE_TIMESTAMP_URL=
4
+ SERVICE_AIGVDET_URL=
5
+
6
+ TOKEN_HF=
7
 
8
  MONGO_DATABASE_CONNECTION_STRING=
9
 
 
13
  JWT_REFRESH_TOKEN_EXPIRED_IN=
14
  JWT_REFRESH_TOKEN_EXTENDED_EXPIRED_IN=
15
 
16
+ SAVE_DATA_PATH=
17
+
18
+ SPREADSHEET_ID =
19
+ SERVICE_ACCOUNT_FILE =
.gitignore CHANGED
@@ -200,4 +200,5 @@ google_application_credentials.json
200
  query_dataset
201
  video_cache.json
202
  processed_readme.md
203
- reports
 
 
200
  query_dataset
201
  video_cache.json
202
  processed_readme.md
203
+ reports
204
+ credentials.json
app/config.py CHANGED
@@ -6,6 +6,8 @@ class Settings(BaseSettings):
6
  SERVICE_REPORT_URL: str
7
  SERVICE_TIMESTAMP_URL: str
8
 
 
 
9
  MONGO_DATABASE_CONNECTION_STRING: str
10
 
11
  JWT_ACCESS_TOKEN_SECRET_KEY: str
@@ -16,6 +18,9 @@ class Settings(BaseSettings):
16
 
17
  SAVE_DATA_PATH: str = "reports"
18
 
 
 
 
19
  class Config:
20
  env_file = ".env"
21
 
 
6
  SERVICE_REPORT_URL: str
7
  SERVICE_TIMESTAMP_URL: str
8
 
9
+ TOKEN_HF: str
10
+
11
  MONGO_DATABASE_CONNECTION_STRING: str
12
 
13
  JWT_ACCESS_TOKEN_SECRET_KEY: str
 
18
 
19
  SAVE_DATA_PATH: str = "reports"
20
 
21
+ SPREADSHEET_ID: str
22
+ SERVICE_ACCOUNT_FILE: str
23
+
24
  class Config:
25
  env_file = ".env"
26
 
app/face_check/service.py CHANGED
@@ -14,7 +14,8 @@ class AIService:
14
  files_payload = [("files", (name, content, ctype)) for name, content, ctype in file_bytes]
15
  files_payload.append(("files", (meta_bytes[0], meta_bytes[1], meta_bytes[2])))
16
 
17
- resp = await client.post("/g3/predict", files=files_payload)
 
18
  resp.raise_for_status()
19
  await SseView.send_sse_message(client_id, {
20
  "status_service": "completed",
@@ -42,7 +43,8 @@ class AIService:
42
  files_payload = [("files", (name, content, ctype)) for name, content, ctype in file_bytes]
43
  files_payload.append(("metadata_file", (meta_bytes[0], meta_bytes[1], meta_bytes[2])))
44
 
45
- resp = await client.post("/analyze/", files=files_payload)
 
46
  resp.raise_for_status()
47
  await SseView.send_sse_message(client_id, {
48
  "status_service": "completed",
@@ -74,7 +76,8 @@ class AIService:
74
  ("file", (name, content, ctype))
75
  ]
76
 
77
- resp = await client.post("/predict", files=files_payload)
 
78
  resp.raise_for_status()
79
  await SseView.send_sse_message(client_id, {
80
  "status_service": "completed",
@@ -95,7 +98,9 @@ class AIService:
95
  async def call_Report(client_id: str, data):
96
  try:
97
  async with httpx.AsyncClient(base_url=settings.SERVICE_REPORT_URL, timeout=10000) as client:
98
- resp = await client.post("/v1/report", json=data)
 
 
99
  resp.raise_for_status()
100
  return resp.json()
101
  await SseView.send_sse_message(client_id, {
 
14
  files_payload = [("files", (name, content, ctype)) for name, content, ctype in file_bytes]
15
  files_payload.append(("files", (meta_bytes[0], meta_bytes[1], meta_bytes[2])))
16
 
17
+ headers = {"Authorization": f"Bearer {settings.TOKEN_HF}"}
18
+ resp = await client.post("/g3/predict", files=files_payload, headers=headers)
19
  resp.raise_for_status()
20
  await SseView.send_sse_message(client_id, {
21
  "status_service": "completed",
 
43
  files_payload = [("files", (name, content, ctype)) for name, content, ctype in file_bytes]
44
  files_payload.append(("metadata_file", (meta_bytes[0], meta_bytes[1], meta_bytes[2])))
45
 
46
+ headers = {"Authorization": f"Bearer {settings.TOKEN_HF}"}
47
+ resp = await client.post("/analyze/", files=files_payload, headers=headers)
48
  resp.raise_for_status()
49
  await SseView.send_sse_message(client_id, {
50
  "status_service": "completed",
 
76
  ("file", (name, content, ctype))
77
  ]
78
 
79
+ headers = {"Authorization": f"Bearer {settings.TOKEN_HF}"}
80
+ resp = await client.post("/predict", files=files_payload, headers=headers)
81
  resp.raise_for_status()
82
  await SseView.send_sse_message(client_id, {
83
  "status_service": "completed",
 
98
  async def call_Report(client_id: str, data):
99
  try:
100
  async with httpx.AsyncClient(base_url=settings.SERVICE_REPORT_URL, timeout=10000) as client:
101
+
102
+ headers = {"Authorization": f"Bearer {settings.TOKEN_HF}"}
103
+ resp = await client.post("/v1/report", json=data, headers=headers)
104
  resp.raise_for_status()
105
  return resp.json()
106
  await SseView.send_sse_message(client_id, {
app/main.py CHANGED
@@ -2,6 +2,7 @@ from fastapi import FastAPI
2
  from .auth.routers import AuthRouters
3
  from .face_check.routers import FaceCheckRouters
4
  from .sse.routers import SseRouters
 
5
  from .mongo import init_db
6
  from contextlib import asynccontextmanager
7
  from fastapi.middleware.cors import CORSMiddleware
@@ -29,3 +30,4 @@ app.add_middleware(
29
  app.include_router(AuthRouters)
30
  app.include_router(FaceCheckRouters)
31
  app.include_router(SseRouters)
 
 
2
  from .auth.routers import AuthRouters
3
  from .face_check.routers import FaceCheckRouters
4
  from .sse.routers import SseRouters
5
+ from .survey.routers import SurveyRouters
6
  from .mongo import init_db
7
  from contextlib import asynccontextmanager
8
  from fastapi.middleware.cors import CORSMiddleware
 
30
  app.include_router(AuthRouters)
31
  app.include_router(FaceCheckRouters)
32
  app.include_router(SseRouters)
33
+ app.include_router(SurveyRouters)
app/survey/routers.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from .view import SurveyView
3
+ from .schemas import SurveyPayload
4
+
5
+ SurveyRouters = APIRouter(
6
+ prefix="/v1/survey",
7
+ tags=["survey"]
8
+ )
9
+
10
+ survey_view = SurveyView()
11
+ @SurveyRouters.post("", name="survey")
12
+ async def survey(payload: SurveyPayload):
13
+ return await survey_view.update(payload)
app/survey/schemas.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class SurveyPayload(BaseModel):
5
+ q0: str
6
+ q1: str
7
+ q2: str
8
+ q3: str
9
+ q4: str
10
+ q5: str
11
+ q6: str
12
+ q7: str
13
+ q8: str
14
+ q9: str
15
+ q10: str
16
+ q11: str
17
+ q12: str
18
+ q13: str
19
+ q14: str
20
+ q15: str
21
+ q16: str
app/survey/service.py ADDED
File without changes
app/survey/view.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from fastapi.params import Header
3
+ from app.config import settings
4
+ from google.oauth2 import service_account
5
+ from googleapiclient.discovery import build
6
+ from .schemas import SurveyPayload
7
+
8
+ HEADER_RANGE = "Sheet1!A1:Q1"
9
+ DATA_RANGE = "Sheet1!A2:Q"
10
+ HEADER_VALUES = [
11
+ "How accurate was the conclusion?",
12
+ "Did the algorithm correctly classify this content?",
13
+ "Were the provided links relevant?",
14
+ "Was the technical analysis understandable?",
15
+ "Did the report contain any hallucinations (made-up facts)?",
16
+ "Did the app clearly identify the main people, organizations, or sources involved in the news item?",
17
+ "How accurate did the app's assessment of the credibility of the \"Who\" (e.g., source, expert, witness) seem to you?",
18
+ "Did the app correctly identify the central claim or action of the news story?",
19
+ "How well did the app's verification evidence address the specific details of the \"What\"?",
20
+ "Did the app clearly show when the original event/information was first published or occurred?",
21
+ "How useful was the time context (e.g., date, timeline of events) in helping you determine the news' authenticity?",
22
+ "Was the location of the event (\"Where\") specified and verified by the app's output?",
23
+ "Did the app provide sufficient evidence (e.g., images, maps, source addresses) to confirm the \"Where\" of the event?",
24
+ "How well did the app explain the motive or purpose behind the original claim (e.g., persuasion, profit, error)?",
25
+ "Did the \"Why\" section help you understand if the news was designed to be misleading or biased?",
26
+ "What is your profession?",
27
+ "Help us improve. If the verification failed, what did we miss?"
28
+ ]
29
+
30
+ class SurveyView:
31
+ def __init__(self):
32
+ self.service = self.get_service()
33
+
34
+ def get_service(self):
35
+ creds = service_account.Credentials.from_service_account_file(
36
+ settings.SERVICE_ACCOUNT_FILE,
37
+ scopes=["https://www.googleapis.com/auth/spreadsheets"]
38
+ )
39
+ return build("sheets", "v4", credentials=creds)
40
+
41
+ def ensure_header(self):
42
+ values_api = self.service.spreadsheets().values()
43
+ header_result = values_api.get(
44
+ spreadsheetId=settings.SPREADSHEET_ID,
45
+ range=HEADER_RANGE
46
+ ).execute()
47
+ header_values = header_result.get("values", [])
48
+ current = [cell.strip() for cell in header_values[0]] if header_values else []
49
+ padded = (current + ["" for _ in range(len(HEADER_VALUES))])[: len(HEADER_VALUES)]
50
+ if padded != HEADER_VALUES:
51
+ values_api.update(
52
+ spreadsheetId=settings.SPREADSHEET_ID,
53
+ range=HEADER_RANGE,
54
+ valueInputOption="RAW",
55
+ body={"values": [HEADER_VALUES]},
56
+ ).execute()
57
+
58
+ async def update(self, payload: SurveyPayload):
59
+ try:
60
+ self.ensure_header()
61
+ body = {"values": [[payload.q0, payload.q1, payload.q2, payload.q3, payload.q4, payload.q5, payload.q6,
62
+ payload.q7, payload.q8, payload.q9, payload.q10, payload.q11, payload.q12,
63
+ payload.q13, payload.q14, payload.q15, payload.q16]]}
64
+ result = self.service.spreadsheets().values().append(
65
+ spreadsheetId=settings.SPREADSHEET_ID,
66
+ range=DATA_RANGE,
67
+ valueInputOption="RAW",
68
+ insertDataOption="INSERT_ROWS",
69
+ body=body,
70
+ ).execute()
71
+ return result
72
+ except Exception as e:
73
+ return {"error": str(e)}
requirements.txt CHANGED
@@ -2,33 +2,49 @@ annotated-types==0.7.0
2
  anyio==4.10.0
3
  bcrypt==4.3.0
4
  beanie==2.0.0
 
5
  certifi==2025.8.3
6
  cffi==2.0.0
 
7
  click==8.2.1
8
  cryptography==45.0.7
9
  dnspython==2.8.0
10
  ecdsa==0.19.1
11
  email-validator==2.3.0
12
  fastapi==0.116.1
 
 
 
 
 
 
13
  h11==0.16.0
14
  httpcore==1.0.9
 
15
  httptools==0.6.4
16
  httpx==0.28.1
17
  idna==3.10
18
  lazy-model==0.3.0
19
  motor==3.7.1
 
20
  passlib==1.7.4
 
 
21
  pyasn1==0.6.1
 
22
  pycparser==2.23
23
  pydantic==2.11.9
24
  pydantic-settings==2.10.1
25
  pydantic_core==2.33.2
26
  PyJWT==2.10.1
27
  pymongo==4.15.0
 
28
  python-dotenv==1.1.1
29
  python-jose==3.5.0
30
  python-multipart==0.0.20
31
  PyYAML==6.0.2
 
 
32
  rsa==4.9.1
33
  six==1.17.0
34
  sniffio==1.3.1
@@ -36,6 +52,8 @@ sse-starlette==3.0.2
36
  starlette==0.47.3
37
  typing-inspection==0.4.1
38
  typing_extensions==4.15.0
 
 
39
  uvicorn==0.35.0
40
  uvloop==0.21.0
41
  watchfiles==1.1.0
 
2
  anyio==4.10.0
3
  bcrypt==4.3.0
4
  beanie==2.0.0
5
+ cachetools==6.2.2
6
  certifi==2025.8.3
7
  cffi==2.0.0
8
+ charset-normalizer==3.4.4
9
  click==8.2.1
10
  cryptography==45.0.7
11
  dnspython==2.8.0
12
  ecdsa==0.19.1
13
  email-validator==2.3.0
14
  fastapi==0.116.1
15
+ google-api-core==2.28.1
16
+ google-api-python-client==2.187.0
17
+ google-auth==2.41.1
18
+ google-auth-httplib2==0.2.1
19
+ google-auth-oauthlib==1.2.3
20
+ googleapis-common-protos==1.72.0
21
  h11==0.16.0
22
  httpcore==1.0.9
23
+ httplib2==0.31.0
24
  httptools==0.6.4
25
  httpx==0.28.1
26
  idna==3.10
27
  lazy-model==0.3.0
28
  motor==3.7.1
29
+ oauthlib==3.3.1
30
  passlib==1.7.4
31
+ proto-plus==1.26.1
32
+ protobuf==6.33.2
33
  pyasn1==0.6.1
34
+ pyasn1_modules==0.4.2
35
  pycparser==2.23
36
  pydantic==2.11.9
37
  pydantic-settings==2.10.1
38
  pydantic_core==2.33.2
39
  PyJWT==2.10.1
40
  pymongo==4.15.0
41
+ pyparsing==3.2.5
42
  python-dotenv==1.1.1
43
  python-jose==3.5.0
44
  python-multipart==0.0.20
45
  PyYAML==6.0.2
46
+ requests==2.32.5
47
+ requests-oauthlib==2.0.0
48
  rsa==4.9.1
49
  six==1.17.0
50
  sniffio==1.3.1
 
52
  starlette==0.47.3
53
  typing-inspection==0.4.1
54
  typing_extensions==4.15.0
55
+ uritemplate==4.2.0
56
+ urllib3==2.6.1
57
  uvicorn==0.35.0
58
  uvloop==0.21.0
59
  watchfiles==1.1.0