MTeguri commited on
Commit
84a4d04
·
1 Parent(s): 964a973

Add Supabase data import functionality and environment variable support

Browse files

- Introduced a new .gitignore file to exclude virtual environment and configuration files.
- Enhanced app.py to load environment variables for Supabase connection and added functions for creating tables and importing data from CSV files.
- Updated README.md to reflect changes in project title and SDK version.
- Added requirements.txt to manage dependencies including Gradio, Supabase, and dotenv.

Files changed (4) hide show
  1. .gitignore +3 -0
  2. README.md +6 -9
  3. app.py +144 -64
  4. requirements.txt +4 -0
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ .venv/
2
+ *.un~
3
+ .env
README.md CHANGED
@@ -1,15 +1,12 @@
1
  ---
2
- title: Operation Data Analysis3
3
- emoji: 💬
4
- colorFrom: yellow
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.42.0
8
  app_file: app.py
9
  pinned: false
10
- hf_oauth: true
11
- hf_oauth_scopes:
12
- - inference-api
13
  ---
14
 
15
- An example chatbot using [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index), and the [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).
 
1
  ---
2
+ title: Operation Data Analysis
3
+ emoji: 🦀
4
+ colorFrom: gray
5
+ colorTo: gray
6
  sdk: gradio
7
+ sdk_version: 5.44.1
8
  app_file: app.py
9
  pinned: false
 
 
 
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,70 +1,150 @@
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
- from huggingface_hub import InferenceClient
3
-
4
-
5
- def respond(
6
- message,
7
- history: list[dict[str, str]],
8
- system_message,
9
- max_tokens,
10
- temperature,
11
- top_p,
12
- hf_token: gr.OAuthToken,
13
- ):
 
 
 
 
 
 
 
 
 
 
 
14
  """
15
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
16
  """
17
- client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
18
-
19
- messages = [{"role": "system", "content": system_message}]
20
-
21
- messages.extend(history)
22
-
23
- messages.append({"role": "user", "content": message})
24
-
25
- response = ""
26
-
27
- for message in client.chat_completion(
28
- messages,
29
- max_tokens=max_tokens,
30
- stream=True,
31
- temperature=temperature,
32
- top_p=top_p,
33
- ):
34
- choices = message.choices
35
- token = ""
36
- if len(choices) and choices[0].delta.content:
37
- token = choices[0].delta.content
38
-
39
- response += token
40
- yield response
41
-
42
-
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- chatbot = gr.ChatInterface(
47
- respond,
48
- type="messages",
49
- additional_inputs=[
50
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
51
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
52
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
53
- gr.Slider(
54
- minimum=0.1,
55
- maximum=1.0,
56
- value=0.95,
57
- step=0.05,
58
- label="Top-p (nucleus sampling)",
59
- ),
60
- ],
61
- )
62
 
63
- with gr.Blocks() as demo:
64
- with gr.Sidebar():
65
- gr.LoginButton()
66
- chatbot.render()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
- if __name__ == "__main__":
70
- demo.launch()
 
1
+ from dotenv import load_dotenv
2
+ load_dotenv()
3
+
4
+ import os
5
+ # 環境変数から取得
6
+ SUPABASE_URL = os.environ.get('SUPABASE_URL')
7
+
8
+ SUPABASE_KEY = os.environ.get('SUPABASE_KEY')
9
+
10
  import gradio as gr
11
+ import pandas as pd
12
+ import math
13
+
14
+ # ▼ Supabaseクライアントは事前に初期化しておく必要があります
15
+ # from supabase import create_client
16
+ # supabase_client = create_client(SUPABASE_URL, SUPABASE_KEY)
17
+
18
+
19
+ def pandas_dtype_to_supabase_type(dtype):
20
+ """Maps pandas data types to Supabase SQL data types."""
21
+ if pd.api.types.is_integer_dtype(dtype):
22
+ return "integer"
23
+ elif pd.api.types.is_float_dtype(dtype):
24
+ return "double precision"
25
+ elif pd.api.types.is_bool_dtype(dtype):
26
+ return "boolean"
27
+ elif pd.api.types.is_datetime64_any_dtype(dtype):
28
+ return "timestamp with time zone"
29
+ else:
30
+ return "text"
31
+
32
+
33
+ def create_table_if_not_exists(db_name, dataframe):
34
  """
35
+ Creates a table in Supabase if it doesn't exist, using RPC `exec_sql`.
36
  """
37
+ columns = []
38
+ for col_name, dtype in dataframe.dtypes.items():
39
+ supabase_type = pandas_dtype_to_supabase_type(dtype)
40
+ columns.append(f'"{col_name}" {supabase_type}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ columns_sql = ", ".join(columns)
43
+ create_table_sql = f"""
44
+ CREATE TABLE IF NOT EXISTS public."{db_name}" (
45
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
46
+ {columns_sql}
47
+ );
48
+ """
49
+ print(f"Executing SQL for table creation:\n{create_table_sql}")
50
+
51
+ try:
52
+ response = supabase_client.rpc("exec_sql", {"sql": create_table_sql}).execute()
53
+
54
+ resp_data = getattr(response, "data", None)
55
+ resp_error = getattr(response, "error", None)
56
+
57
+ if resp_error:
58
+ return False, f"Error creating table: {getattr(resp_error, 'message', str(resp_error))}"
59
+
60
+ if resp_data:
61
+ return True, f"Table '{db_name}' created or already exists. RPC returned data: {resp_data}"
62
+ else:
63
+ return True, f"Table '{db_name}' created or already exists. (no data returned)"
64
 
65
+ except Exception as e:
66
+ print(f"Exception during table creation RPC call: {e}")
67
+ return False, f"Exception during table creation: {e}"
68
+
69
+
70
+ def clean_dataframe_for_json(df: pd.DataFrame):
71
+ """
72
+ Convert DataFrame to JSON-compliant list of dicts
73
+ (replace NaN, NaT, inf, -inf with None).
74
+ """
75
+ records = df.to_dict(orient="records")
76
+ cleaned = []
77
+ for row in records:
78
+ new_row = {}
79
+ for k, v in row.items():
80
+ if v is None:
81
+ new_row[k] = None
82
+ elif isinstance(v, float) and (math.isnan(v) or math.isinf(v)):
83
+ new_row[k] = None
84
+ else:
85
+ new_row[k] = v
86
+ cleaned.append(new_row)
87
+ return cleaned
88
+
89
+
90
+ def import_data_to_supabase(csv_file, db_name):
91
+ """
92
+ Imports data from a CSV file to a Supabase table,
93
+ creating the table if it doesn't exist.
94
+ """
95
+ global supabase_client
96
+ full_message = []
97
+
98
+ if not csv_file or not db_name:
99
+ return "Please upload a CSV file and provide a table name."
100
+
101
+ try:
102
+ # 1. CSV読込
103
+ df = pd.read_csv(csv_file.name)
104
+
105
+ # 2. テーブル作成
106
+ table_creation_success, table_creation_msg = create_table_if_not_exists(db_name, df)
107
+ full_message.append(f"Table Creation Status: {table_creation_msg}")
108
+
109
+ # 3. JSON対応にクリーニング(NaN, NaT, inf → None)
110
+ data = clean_dataframe_for_json(df)
111
+
112
+ if not data:
113
+ full_message.append("Data Insertion Status: CSV file empty or not parsed. No data inserted.")
114
+ return "\n".join(full_message)
115
+
116
+ # 4. データ挿入
117
+ print(f"Attempting to insert {len(data)} rows into table '{db_name}'.")
118
+ response = supabase_client.table(db_name).insert(data).execute()
119
+
120
+ resp_data = getattr(response, "data", None)
121
+ resp_error = getattr(response, "error", None)
122
+
123
+ if resp_error:
124
+ full_message.append(
125
+ f"Data Insertion Status: Error inserting data - {getattr(resp_error, 'message', str(resp_error))}"
126
+ )
127
+ elif resp_data:
128
+ full_message.append(f"Data Insertion Status: Successfully inserted {len(resp_data)} rows.")
129
+ else:
130
+ full_message.append("Data Insertion Status: Insert executed, but no data returned.")
131
+
132
+ except Exception as e:
133
+ full_message.append(f"An unexpected error occurred during processing: {e}")
134
+
135
+ return "\n".join(full_message)
136
+
137
+
138
+ # Gradio アプリ
139
+ iface = gr.Interface(
140
+ fn=import_data_to_supabase,
141
+ inputs=[
142
+ gr.File(label="Upload CSV File"),
143
+ gr.Textbox(label="Supabase Database Table Name")
144
+ ],
145
+ outputs="text",
146
+ title="Supabase Data Importer",
147
+ description="CSVファイルをアップロードし、データをSupabaseデータベースのテーブルにインポートします。指定されたテーブルが存在しない場合は新しく作成します。"
148
+ )
149
 
150
+ iface.launch(mcp_server=True)
 
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio[mcp]
2
+ supabase
3
+ numpy
4
+ python-dotenv