visuddhinanda 1 рік тому
батько
коміт
84a2fd4ecb

+ 47 - 0
api-v8/app/Http/Api/AiAssistantApi.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Http\Api;
+
+use App\Models\AiModel;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Facades\App;
+
+class AiAssistantApi
+{
+    public static function getByUuid($id)
+    {
+        $user = AiModel::where('uid', $id)->first();
+        return self::userInfo($user);
+    }
+    public static function userInfo($user)
+    {
+        if (!$user) {
+            Log::error('$user=null;');
+            return [
+                'id' => 0,
+                'nickName' => 'unknown',
+                'userName' => 'unknown',
+                'realName' => 'unknown',
+                'avatar' => '',
+            ];
+        }
+        $data = [
+            'id' => $user->uid,
+            'nickName' => $user->name,
+            'userName' => $user->real_name,
+            'realName' => $user->real_name,
+            'sn' => 0,
+        ];
+
+        if ($user->avatar) {
+            $img = str_replace('.jpg', '_s.jpg', $user->avatar);
+            if (App::environment('local')) {
+                $data['avatar'] = Storage::url($img);
+            } else {
+                $data['avatar'] = Storage::temporaryUrl($img, now()->addDays(6));
+            }
+        }
+        return $data;
+    }
+}

+ 87 - 0
api-v8/app/Http/Controllers/AiAssistantController.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\AiModel;
+use Illuminate\Http\Request;
+use App\Http\Resources\AiAssistantResource;
+
+class AiAssistantController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        //
+        $table = AiModel::whereNotNull('owner_id');
+        if ($request->has('keyword')) {
+            $table = $table->where('name', 'like', '%' . $request->get('keyword') . '%');
+        }
+        $count = $table->count();
+
+        $table = $table->orderBy(
+            $request->get('order', 'created_at'),
+            $request->get('dir', 'asc')
+        );
+
+        $table = $table->skip($request->get("offset", 0))
+            ->take($request->get('limit', 1000));
+
+        $result = $table->get();
+
+        return $this->ok(
+            [
+                "rows" => AiAssistantResource::collection(resource: $result),
+                "count" => $count,
+            ]
+        );
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\AiModel  $aiModel
+     * @return \Illuminate\Http\Response
+     */
+    public function show(AiModel $aiModel)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\AiModel  $aiModel
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, AiModel $aiModel)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\AiModel  $aiModel
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(AiModel $aiModel)
+    {
+        //
+    }
+}

+ 94 - 0
api-v8/app/Http/Controllers/ModelLogController.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\ModelLog;
+use Illuminate\Http\Request;
+use App\Http\Api\AuthApi;
+use App\Http\Resources\ModelLogResource;
+
+class ModelLogController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        //
+        $user = AuthApi::current($request);
+        if (!$user) {
+            return $this->error(__('auth.failed'));
+        }
+        switch ($request->get('view')) {
+            case 'model':
+                # code..
+                $table = ModelLog::where('model_id', $request->get('id'));
+                break;
+
+            default:
+                # code...
+                break;
+        }
+        if ($request->has('search')) {
+            $table = $table->where('email', 'like', '%' . $request->get('search') . "%");
+        }
+        $count = $table->count();
+        $table = $table->orderBy(
+            $request->get('order', 'updated_at'),
+            $request->get('dir', 'desc')
+        );
+
+        $table = $table->skip($request->get('offset', 0))
+            ->take($request->get('limit', 1000));
+
+        $result = $table->get();
+        return $this->ok(["rows" => ModelLogResource::collection($result), "count" => $count]);
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\ModelLog  $modelLog
+     * @return \Illuminate\Http\Response
+     */
+    public function show(ModelLog $modelLog)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\ModelLog  $modelLog
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, ModelLog $modelLog)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\ModelLog  $modelLog
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(ModelLog $modelLog)
+    {
+        //
+    }
+}

+ 19 - 0
api-v8/app/Http/Resources/AiAssistant.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class AiAssistant extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        return parent::toArray($request);
+    }
+}

+ 24 - 0
api-v8/app/Http/Resources/AiAssistantResource.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class AiAssistantResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        $data = [
+            'id' => $this->uid,
+            'userName' => $this->real_name,
+            'nickName' => $this->name,
+        ];
+        return $data;
+    }
+}

+ 19 - 0
api-v8/app/Http/Resources/ModelLogResource.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class ModelLogResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        return parent::toArray($request);
+    }
+}

+ 18 - 0
api-v8/app/Models/ModelLog.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class ModelLog extends Model
+{
+    use HasFactory;
+    protected $primaryKey = 'uid';
+    protected $casts = [
+        'uid' => 'string'
+    ];
+    protected $dates = [
+        'request_at'
+    ];
+}

+ 39 - 0
api-v8/database/migrations/2025_02_04_081924_create_model_logs_table.php

@@ -0,0 +1,39 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateModelLogsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('model_logs', function (Blueprint $table) {
+            $table->id();
+            $table->uuid('uid')->unique();
+            $table->uuid('model_id')->index();
+            $table->text('request_url');
+            $table->json('request_data');
+            $table->json('response_data')->nullable();
+            $table->integer('status')->index();
+            $table->boolean('success')->default(true);
+            $table->timestamp('request_at')->index();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('model_logs');
+    }
+}

+ 77 - 0
dashboard-v4/dashboard/src/components/ai/AiAssistantSelect.tsx

@@ -0,0 +1,77 @@
+import { ProFormSelect, RequestOptionsType } from "@ant-design/pro-components";
+import { useIntl } from "react-intl";
+
+import { get } from "../../request";
+import { IUserListResponse } from "../api/Auth";
+
+interface IWidget {
+  name?: string;
+  width?: number | "md" | "sm" | "xl" | "xs" | "lg";
+  multiple?: boolean;
+  hidden?: boolean;
+  hiddenTitle?: boolean;
+  required?: boolean;
+  initialValue?: string | string[] | null;
+  options?: RequestOptionsType[];
+}
+const UserSelectWidget = ({
+  name = "user",
+  multiple = false,
+  width = "md",
+  hidden = false,
+  hiddenTitle = false,
+  required = true,
+  options = [],
+  initialValue,
+}: IWidget) => {
+  const intl = useIntl();
+  console.log("UserSelect options", options);
+  return (
+    <ProFormSelect
+      name={name}
+      label={
+        hiddenTitle
+          ? undefined
+          : intl.formatMessage({ id: "labels.ai-assistant" })
+      }
+      hidden={hidden}
+      width={width}
+      initialValue={initialValue}
+      showSearch
+      debounceTime={300}
+      fieldProps={{
+        mode: multiple ? "tags" : undefined,
+      }}
+      request={async ({ keyWords }) => {
+        console.log("keyWord", keyWords);
+
+        if (typeof keyWords === "string") {
+          const json = await get<IUserListResponse>(
+            `/v2/ai-assistant?keyword=${keyWords}`
+          );
+          console.info("api response user select", json);
+          const userList: RequestOptionsType[] = json.data.rows.map((item) => {
+            return {
+              value: item.id,
+              label: `${item.nickName}`,
+            };
+          });
+          console.log("json", userList);
+          return userList;
+        } else {
+          const defaultOptions: RequestOptionsType[] = options.map((item) => {
+            return { label: item.label, value: item.value?.toString() };
+          });
+          return defaultOptions;
+        }
+      }}
+      rules={[
+        {
+          required: required,
+        },
+      ]}
+    />
+  );
+};
+
+export default UserSelectWidget;

+ 114 - 0
dashboard-v4/dashboard/src/components/ai/AiModelLogList.tsx

@@ -0,0 +1,114 @@
+import { ProList } from "@ant-design/pro-components";
+import { Button, Space, Tabs, Tag, Typography } from "antd";
+import type { Key } from "react";
+import { useState } from "react";
+
+import { CheckOutlined, WarningOutlined } from "@ant-design/icons";
+
+import { IAiModelLogData, IAiModelLogListResponse } from "../api/ai";
+import { get } from "../../request";
+import moment from "moment";
+
+const { Text } = Typography;
+
+interface IWidget {
+  modelId?: string;
+}
+const AiModelLogList = ({ modelId }: IWidget) => {
+  const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
+
+  return (
+    <ProList<IAiModelLogData>
+      rowKey="title"
+      headerTitle="logs"
+      toolBarRender={() => {
+        return [
+          <Button key="3" type="primary">
+            新建
+          </Button>,
+        ];
+      }}
+      expandable={{ expandedRowKeys, onExpandedRowsChange: setExpandedRowKeys }}
+      metas={{
+        title: {},
+        subTitle: {
+          render: (dom, entity, index, action, schema) => {
+            return (
+              <Space size={0}>
+                <Tag color="blue">{entity.status}</Tag>
+              </Space>
+            );
+          },
+        },
+        description: {
+          render: (dom, entity, index, action, schema) => {
+            return (
+              <>
+                <Tabs
+                  items={[
+                    {
+                      label: "request",
+                      key: "request",
+                      children: <div>{entity.request_data}</div>,
+                    },
+                    {
+                      label: "response",
+                      key: "response",
+                      children: <div>{entity.response_data}</div>,
+                    },
+                  ]}
+                />
+              </>
+            );
+          },
+        },
+        avatar: {
+          render(dom, entity, index, action, schema) {
+            return (
+              <>
+                {entity.success ? (
+                  <CheckOutlined style={{ color: "green" }} />
+                ) : (
+                  <WarningOutlined color="error" />
+                )}
+              </>
+            );
+          },
+        },
+        actions: {
+          render: (dom, entity, index, action, schema) => {
+            const date = moment(entity.created_at).toLocaleString();
+            return <Text type="secondary">{date}</Text>;
+          },
+        },
+      }}
+      bordered
+      pagination={{
+        showQuickJumper: true,
+        showSizeChanger: true,
+      }}
+      search={false}
+      options={{
+        search: true,
+      }}
+      request={async (params = {}, sorter, filter) => {
+        console.log(params, sorter, filter);
+        let url = `/v2/model-log?view=model&id=${modelId}`;
+        const offset = ((params.current ?? 1) - 1) * (params.pageSize ?? 20);
+        url += `&limit=${params.pageSize}&offset=${offset}`;
+        url += params.keyword ? "&search=" + params.keyword : "";
+
+        console.info("ai model log api request", url);
+        const res = await get<IAiModelLogListResponse>(url);
+        console.info("ai model log api response", res);
+        return {
+          total: res.data.total,
+          succcess: res.ok,
+          data: res.data.rows,
+        };
+      }}
+    />
+  );
+};
+
+export default AiModelLogList;

+ 8 - 0
dashboard-v4/dashboard/src/pages/studio/ai/model_logs.tsx

@@ -0,0 +1,8 @@
+import { useParams } from "react-router-dom";
+import AiModelLogList from "../../../components/ai/AiModelLogList";
+
+const Widget = () => {
+  const { modelId } = useParams(); //url 参数
+  return <AiModelLogList modelId={modelId} />;
+};
+export default Widget;